Steem Links:《Steem指南》子项目 | Subproject of Steem Guides

Steem Links:《Steem指南》子项目 | Subproject of Steem Guides

缘由

‌在微信群里经常看到大家在询问各种链接:‌

  1. 《Steem指南》的链接(我经常被召唤。。。);
  2. 各种移动客户端的APK文件的链接(Partiko, Wherein, eSteem);
  3. steem-engine 的链接;
  4. 查看各种数据的链接;
  5. 各种工具的链接;
  6. 最新活动的链接;

为了方便大家找这些链接,《Steem指南》创建了一个子项目:steem links,用于整理和分享各种最常用的链接。‌

好了,就是这样一个很简单的项目。‌

介绍

‌steem link 收录了最常用的平台、客户端、工具、数据统计、dApp、教程、人物介绍、活动等最常用的一些链接,如下图所示。

‌screenshots from https://steem-guides.github.io/links/zh

如果要找某些常用的链接,记住上面这个链接收集的帖子就好了,再也不用到处找了。欢迎收藏这个链接页面,以及转发分享、帮助其他人!!

当然,现在内容还很不完善,欢迎大家一起来提供建议和补充最常用的链接。‌

参与

‌如果希望分享一个或几个新的链接,加入到 steem links里,有三种基本的方式:‌

  1. 如果你会用GitHub可以点击页面上的编辑链接,通过commit、pull request的方式来提交改动;
  2. 如果你不太了解GitHub的pull request的话,可以点击提交建议链接,通过填写 issue 的方式来提交;
  3. 如果以上两种都不会,可以直接在本帖下面留言提供你的建议。

提交建议的示例:

‌screenshot from GitHub: https://github.com/steem-guides/links/issues/new

对于有价值的贡献,@steem-guides 将提供一定的 NBC 和 点赞奖励(Steem和SCT),期待大家的建议~ 也希望这个页面对你有用。‌

参考文献



Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/steem-links%ef%bc%9a%e3%80%8asteem%e6%8c%87%e5%8d%97%e3%80%8b%e5%ad%90%e9%a1%b9%e7%9b%ae-subproject-of-steem-guides


This page is synchronized from the post: Steem Links:《Steem指南》子项目 | Subproject of Steem Guides

steemblog: Steem时光机 | Steem Time Machine

steemblog: Steem时光机 | Steem Time Machine

本文我们将介绍 steemblog 的最新的进展。‌

‌Image Source: Pixabay

#1 回顾

‌steemblog 是一项 Steem 文章镜像服务。‌

如果你还不了解这个服务,或许你可以通过访问:https://steemblog.github.io/@team-cn/ 作为一个案例体验一下。‌

在文章《用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog》中,我们提到过创建steemblog 服务的缘由,主要是为了更好的查看历史文章。‌

现在来看,它主要带来了以下几点助益:‌

  1. 首先,steemblog 作为一份档案和历史记录,将 steem 数据以便于阅读和查询的方式保存;虽然区块链技术被认为具有数据不可毁灭的潜力,但有一份额外的备份也存在价值;
  2. 其次,它提供了更好的用户体验访问速度,对于查询、搜索、整合个人或组织的文章,效率更高、更有愉悦感;
  3. 再次,它目前每日更新,虽然是存档,但基本可以保持是近实时的,多于过去几日的文章,也可以一并处理。

根据上一篇文章和微信群中的留言,我们已经帮以下12个账号部署了每日更新的博客镜像服务:‌

  1. @robertyan
  2. @andrewma
  3. @ericet
  4. @julian2013
  5. @annepink
  6. @bring
  7. @sunai
  8. @nostalgic1212
  9. @m18207319997
  10. @iguazi123
  11. @team-cn
  12. @lemooljiang

‌每日北京时间凌晨0点,steemblog 会自动同步镜像一次。‌

总体而言,对我来说 steemblog 是一个还比较好用的时光机(Time Machine),可以更好地学习和了解 steem 上各种有趣的事情。

下面举几个例子来看看吧:‌

#2 场景

‌以下是steemblog的几个有意思的应用场景。

(1)新手村访谈

初入CN区或者新手村的新人,想要了解一下社区内的朋友,其实没有看上去那么容易。去逐个翻看各个用户的历史文章,效率很低。‌

但新手村访谈部分解决了这个问题,我们只要看 #cn-interview 这个标签下的文章就行,但由于steemit / busy 查看标签历史或多或少都有点问题,所以也很难流畅地阅读。在以前,大概有2种方式:‌

  1. 看新手村的索引贴,例如2018版的:https://busy.org/@team-cn/2018-x61niax2i4/
  2. 阅读《Steem指南》的新手村计划部分:https://steem-guides.github.io/steemh/fl.html#section-17.3

但这两种方法更新可能不太及时,最近的访谈没有录入,而 steemblog 是及时更新的。 steemblog 的搜索功能也更快速和有针对性。‌

通过链接:https://steemblog.github.io/@team-cn/tags/cn-interview/,我们可以看到新手村历史上所有的访谈的记录:‌

最新的访谈:

最初的访谈:

按村名搜索:

screenshots from steemblog: https://steemblog.github.io/@team-cn/tags/cn-interview/

想要了解新手村 @team-cn 里的各位朋友,用 steemblog 看一看就一目了然了,确实很有趣。 这对新人也很有帮助,建议你们来看看。‌

(2)社区名人录

‌Steem是个社区,社区是由人组成的,其中有些人由于各种原因成为舆论的焦点或实际的掌权派,总是在历史上不断发生的事情。‌

—-‌

最近 #sct 标签称霸舆论,对于创始人之一的 Jack @jack8831 也接受到了大量的八卦和追捧。但要看家里有矿的男神的生辰八字,也不是这么容易的事啊。‌

steemblog 可以帮你解决这个问题。昨天服务器花了6分钟备份了 Jack @jack8831 的历史文章:https://steemblog.github.io/@jack8831/

然后,要阅读 Jack 的最新动态、历史观点、常用的标签,就容易多了。

不过韩文/朝鲜语我不懂,所以读起来还是需要借助机器翻译的力量。但不可思议的是,下面早期文章的图中的“基本英语”我居然看懂了!!

Jack 好像曾经喜欢给韩国朋友们分享英文,标题中也有“鲑鱼”(연어)的前缀:https://steemblog.github.io/@jack8831/tags/englishforkorean/

所以 steemcoinpan 上鲑鱼泛滥,似乎也在情理之中了。

‌screenshots from steemblog: https://steemblog.github.io/@jack8831/

Jack和团队做的 steemcoinpan 风头正劲,要向韩国朋友们学习,也不妨了解下他们的过往~‌

—-‌

回到CN区。‌

我之前读过《Steem指南》中的 《Steem 十讲》,觉得 刘美女 @deanliu 的观点和文章很独到,所以特地同步了刘美女的文章到 steemblog (服务器时间 18 分钟,刘美女的文章和标签都很多,同步较慢):https://steemblog.github.io/@deanliu/

刘美女已经写了 1400+ 文章,可谓笔耕不辍、涉猎广泛。

最常用的首标签(类别):除了CN区话题,摄影、旅游、美食、讨论 steem / blockchain、以及聊娃(TT)是日常。

最初的文章都是英文,拓荒时期CN区还没有形成规模吧:

老道茶馆的一些过往:https://steemblog.github.io/@deanliu/tags/laodr-teahouse/

‌screenshots from steemblog: https://steemblog.github.io/@deanliu/

不过其实之前 大鹏 @dapeng 也曾经帮助 刘美女 @deanliu 备份过文章( GitHub上的 文章 Markdown 源码 / Netlify 备份站点 ),只是并没有设置成自动更新、以及网站模板较简单罢了。从备份的角度,steemblog 也只是另一种工具和服务而已,并不新奇,但希望它也有所帮助。‌

—‌

我不是很喜欢八卦,所以八卦社区名人和豪杰们的任务,就交给大家自己去完成了。不过想要用 steemblog 来八卦哪些名人倒是可以给我提供一个名单,我可以帮助备份到 steemblog。‌

(3)活动的回顾

‌活动一般以标签的形式进行推广,所以与上面看到的以个人账户为主的文章展示方式并不相同。对于标签文章的备份,steemblog 也可以支持,但目前并没有部署单独对标签进行备份的案例,而且需要对界面做少量修改。‌

这里展示一下 我 @robertyan 主办的对联活动如何查看。‌

以 https://steemblog.github.io/@{username}/tags/{tag}/ 的格式,就能查看标签下的文章。由于对联活动的文章都是我发表的,所以可以这样查看:https://steemblog.github.io/@robertyan/tags/cn-couplet/

‌screenshot from steemblog: https://steemblog.github.io/@robertyan/tags/cn-couplet/

已经办到第四期了,欢迎对语言和文化有兴趣的朋友参与。这期的题目是给刚刚升级到50/60/70级的朋友们写寿联https://busy.org/@robertyan/qs55nyh8x9

(4)奇文共欣赏

‌第四种用途对我还是挺有帮助的:Steem上有一些极度认真的作者,对于喜欢看好文章用户,现在的steemit/busy/steempeak等界面都满足不了需求。‌

上面提到过我推崇 刘美女 @deanliu 的文章并在昨天同步到了 steemblog。其实更早之前,我还同步了 维参 @crowflew 的文章,是我之前在 steem 看到的最有意思的文章系列之一吧:https://steemblog.github.io/@crowflew/

对于阅读博客,steemblog 会显示目录方便作者通览全文和跳转到章节:

可以方便的跳转到前后文章、找到 steem的原文,以及回到顶部等:

‌screenshots from steemblog: https://steemblog.github.io/@crowflew/or-or-or-or/

当然,steem 上的奇文还有很多,如果你有觉得仔细希望阅读的作者,也不妨把他的账户分享给我,一起欣赏一下。‌

(5)揭秘黑历史

‌steemblog 不但能让有用的信息能够被快速查询到,还能让罪行无处遁形。是不是听着挺像一位侦探的?‌

好吧,下面我们来看看 机机 @julian2013 和 村长 @ericet 是如何互黑的。(其实你们是不是更愿意看 软哥 @softmetal 和 小P @pgr 互黑的桥段?)‌

到 steemblog 页面上,点击右上角的搜索进行“侦查”。‌

—-‌

机机谈论村长:

‌screenshots from https://steemblog.github.io/@julian2013/

—-‌

村长评价机机:

‌screenshots from https://steemblog.github.io/@ericet/

—-‌

看上去机机从来没说过村长“坏”话,而村长可不是这样。真的是这样吗?

那么到底究竟说了什么呢?还是要各位自己去看才行。真相永远只有一个,看了以后不妨告诉我。‌

(6)组织的起源

‌其实相比查看人的文章,我更感兴趣组织的发展历史和起源,以及它们的生长过程,比如 @team-cn、@steemstem、@utopian-io,这里也为他们备份了镜像以便于追根溯源、温故知新:‌

@team-cn

‌screenshot from https://steemblog.github.io/@team-cn/page/45/

—-‌

@steemstem

‌screenshot from https://steemblog.github.io/@steemstem/page/28/

—-‌

@utopian-io

‌screenshot from https://steemblog.github.io/@utopian-io/page/33/

希望这些团队不忘初心,破除艰险、勇往直前。‌

—-‌

以上这些例子,不知对你来说是不是也同样有趣或有帮助。‌

如果需要帮你镜像博客,可以在文章后面留言,本次提供5个免费服务名额,先到先得~‌

#3 进展

‌相比于《用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog》中的描述,steemblog 最近也有一些功能和性能更新,这里简要介绍:‌

  1. 编译性能优化:编译速度提高了大约有20~100倍。
  2. 多平台部署:支持备份镜像到Netlify等平台。
  3. 渲染优化:由于采用了组件,进行了优化以保证用户体验
  4. 问题修复:比如类别(category)显示顺序、编译内存溢出等

(1)编译性能优化

‌其实 steemblog 的功能实现是相对比较简单的(可以参考上一篇文章)。但真正有困难的是在 hexo 的编译速度。‌

hexo 虽然号称速度极快,但实际编译的时候简直是灾难。当然,原因不能完全归罪与 hexo 框架本身,更多是 hexo theme的问题。‌

例如,以下是几个账户一开始的编译所有文章花费的时间:

@andrewma: 400+ posts, 80+ tags, ~20 mins

@ericet: 630+ posts, 260+ tags, > 60 mins

很多人的文章数量都接近这个量级,如果要全都同步的话,时间耗费还是很大的,每天更新就要消耗很多资源。‌

除了优化编译方式,另一种是采用增量更新(即只编译新增加的文章), hexo 虽然自称是支持增量更新的,但实际情况是基本不支持、且有很多潜在的问题。‌

—-‌

(a) 优化编译过程

其实原先我只打算做一个简单的服务,不想在主题(theme)优化上花太多功夫,但真正用起来才发现开源世界并不是那么美好 :) ‌

为了完成给大家的每天更新的承诺,以下是优化的方案。‌

  1. 修改主题:由于我们采用的主题(https://github.com/ppoffice/hexo-theme-icarus)较多的使用了各种控件和大量使用了标签和分类等,使得功能较为强大,但带来的问题是编译成静态页面时的成本也很高,为了修复这个主题的问题,我们fork原来的项目,采用了修改后的主题:https://github.com/steemblog/hexo-theme-icarus
  2. 大量使用缓存(cache):hexo 自带有fragment_cache和partial方法,以方便缓存重复使用的组件(如head, footer, sidebar等),但 theme 的作者有时候不清楚可以这样使用,所以我们需要修改。
  3. 控件页面分离:除了使用cache,像很多组件是可以通过 iframe 或者 ajax 异步加载的形式来展示的,这样可以在实现静态页面的时候减少很多冗余的 控件的 html,减少文件大小、提高效率。
  4. 采用时间线布局:原来的 index、tag、archive等页面,都采用了直接展示文章内容的布局,其实不是很有必要,不方便阅读而且使得静态 html 页面变得很庞大。所以我们改成了 timeline 的 layout。
  5. 增加每页文章数量:默认的分页是 6 篇文章一页,对于时间线模式是太少了,所以改成了 20 篇文章一页。编译的速度受页面数量影响很大,而一页展示的文章多了,html 页面总数自然就少了、速度会有明显提高。

策略1:修改主题:

.gitmodules

1
[submodule "theme"] path = themes/icarus url = https://github.com/steemblog/hexo-theme-icarus.git

‌‌code from https://github.com/steemblog/blog | MIT License

策略2:大量使用缓存(cache)

themes/icarus/layout/layout.ejs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<% if (page.__widget) { %>
<%- body %>
<% } else { %>
<!DOCTYPE html>
<html <%- has_config('language') ? ' lang="' + get_config('language').substring(0, 2) + '"' : '' %>>
<head>
<%- partial('common/head', {}, {cache: false}) %>
</head>
<body class="is-<%= column_count() %>-column">
<%- partial('common/navbar', { page }) %>
<% function main_column_class() {
switch (column_count()) {
case 1:
return 'is-12';
case 2:
return 'is-8-tablet is-8-desktop is-8-widescreen';
case 3:
return 'is-8-tablet is-8-desktop is-6-widescreen'
}
return '';
} %>
<section class="section">
<div class="container">
<div class="columns">
<%- partial('common/widget', { position: 'left' }) %>
<%- partial('common/widget', { position: 'right' }) %>
<%- partial('component/pjax_widget_js', {}, {cache: true}) %>
<div class="column <%= main_column_class() %> has-order-2 column-main"><%- body %></div>
</div>
</div>
</section>
<%- partial('common/footer', {}, {cache: true}) %>
<%- partial('common/scripts', {}, {cache: true}) %>

<% if (has_config('search.type')) { %>
<%- partial('search/' + get_config('search.type'), {}, {cache: true}) %>
<% } %>
</body>
</html>
<% } %>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

对于重复的模块,使用 partial(‘component’, {param}, {cache: true}) 来替换原来的实现‌

策略3:控件页面分离

将原来的 profile, recent_posts, category, tag, tagcloud, archive 等组件,生成独立的 html 页面,减少冗余的 html。此外,组件采用独立的页面也是实现增量编译所必须完成的,所以这一步必须要做。‌

themes/icarus/layout/layout.ejs 需要修改 generators,生成新的 widgets 页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Widget page generator
*/
module.exports = function (hexo) {
hexo.extend.generator.register('widget', function (locals) {
const widgets = hexo.extend.helper.get('get_config').bind(this)('widgets');
const component_widgets = widgets.filter((w) => (w.component))

return component_widgets.map(function(widget){
return {
path: `widgets/${widget.type}.html`,
layout: 'component/pjax_widget_src',
data: {
widget: widget,
__widget: true
}
};
});
});
}

‌code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/layout/component/pjax_widget_ref.ejs 将原来的组件用对页面的引用替换。

1
2
3
4
5
<div class="card widget">
<div class="card-content">
<div id="widget-<%= widget.type %>" data-pjax="<%= `${get_config("root")}widgets/${widget.type}` %>.html" style="position: relative; width: 100%; display: block;"></div>
</div>
</div>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/layout/component/pjax_widget_src.ejs 对不同的组件,获取对应的内容

1
<%- partial(`widget/content/${page.widget.type}`, {widget: page.widget}) %>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/source/js/pjax_widget.js 在页面加载时通过 ajax 来通过url获取组件的 html,替换控件的内容为实际内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if (typeof(jQuery) !== 'undefined') {
(function($){
function load_pjax(element) {
// $.pjax({url: element.attr("data-pjax"), container: "#"+element.attr("id")})
$.get(element.attr("data-pjax"), function(data) {
element.html(data);
});
}
$("div[data-pjax]").each(function(){
load_pjax($(this));

})
})(jQuery);
} else {
(function(){
window.$ = document.querySelectorAll.bind(document);
function load_pjax(element) {
const url = element.getAttribute("data-pjax")
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = function() {
element.innerHTML = xhr.responseText;
};
xhr.send();
}
for (const e of $("div[data-pjax]")) {
load_pjax(e);
}
})();
}

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

themes/icarus/layout/common/widget.ejs 对控件,也要添加 cache 模式,减少冗余。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<% function render_widget(widget) {
const component = widget.component || false;
const cache = widget.cache || false;
if (component) {
const cahced_prefix = cache ? 'cached_' : '';
const template = `component/${cahced_prefix}pjax_widget_ref`;
return partial(template, { widget })
} else {
return partial('widget/' + widget.type, { widget, post: page }, {cache: cache});
}
} %>
<div class="column <%= side_column_class() %> <%= visibility_class() %> <%= order_class() %> column-<%= position %> <%= sticky_class(position) %>">
<% get_widgets(position).forEach(widget => {%>
<%- render_widget(widget) %>
<% }) %>
<% if (position === 'left') { %>
<div class="column-right-shadow is-hidden-widescreen <%= sticky_class('right') %>">
<% get_widgets('right').forEach(widget => {%>
<%- render_widget(widget) %>
<% }) %>
</div>
<% } %>
</div>
<% } %>

‌code from https://github.com/steemblog/hexo-theme-icarus | MIT License

此外,每个组件都要重构将内容独立出来,这里不详细解释了。‌

策略4:采用时间线布局

将categories和tags页面的布局都显示为时间线模式,更容易浏览,且页面所占空间更小。‌

以 category 为例,展示为时间线 + 分页:‌

themes/icarus/layout/category.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="card">
<div class="card-content">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><a href="<%- url_for('/categories') %>"><%= _p('common.category', Infinity) %></a></li>
<% page.parents.forEach(category => { %>
<li><a href="<%- url_for(category.path) %>"><%= category.name %></a></li>
<% }) %>
<li class="is-active"><a href="#" aria-current="page"><%= page.category %></a></li>
</ul>
</nav>
</div>
</div>
<%- partial("component/timeline", {posts: page.posts}) %>
<% if (page.total > 1) { %>
<%- partial('common/paginator') %>
<% } %>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

采用时间线以后,同时也会每个展示的 item 添加 cache:‌

themes/icarus/layout/component/timeline.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="card widget">
<div class="card-content">
<% if (typeof(head) !== 'undefined' &amp;&amp; head) { %>
<h3 class="tag is-link">
<%= head %>
</h3>
<% } %>
<div class="timeline">
<% posts.each(post => { %>
<%- partial("component/cached_item", {post}) %>
<% }) %>
</div>
</div>
</div>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

策略5:增加每页的文章数量

可以有效减少页面总数,减少编译的负担。‌

blog/message.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Pagination
## Set per_page to 0 to disable pagination
per_page: 6
pagination_dir: page

index_generator:
per_page: 6

archive_generator:
per_page: 20
yearly: true
monthly: true

category_generator:
per_page: 20

tag_generator:
per_page: 20

code from https://github.com/steemblog/blog | MIT License

经过以上各类方案,编译所有文章的速度已经得到的极大的提高,大约已经提到了10~50倍了。

@andrewma: 400+ posts, 80+ tags, 1~2 mins

@ericet: 630+ posts, 260+ tags, 1~2 mins

(b) 实现增量编译

但我们的目标是增量更新,为了实现这个目的,我们需要做两方面修改:‌

  1. 增量生成markdown:无须每次都从 steem 获取 posts 并生成 markdown;
  2. 只编译受影响的 html 文件:修改 hexo 的 tag, category, archive, 和 post的generators,只在 html 受影响时生成。

步骤1:增量生成 markdown

为了不重复生成过去的posts的 markdown 文件,我们用 git repo 来管理过去已经生成的 markdown 文件,并只更新最近1天左右的文章。‌

同时,我们需要和之前的 source 对比,从而知道哪些文章需要更新。‌

blog/builder.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def setup_source_repo(self):
git_clone_cmd = "git clone --depth 1 --branch {} --single-branch https://{}github.com/{}.git {}".format(SOURCE_BRANCH, self._get_github_pat(), self._get_repo(prefix=False), SOURCE_REPO_FOLDER)
os.system(git_clone_cmd)
# on `source` branch after clone
logger.info("Cloned source repo into workspace: {}".format(SOURCE_REPO_FOLDER))

def _commit_source(self):
os.chdir(SOURCE_REPO_FOLDER)
# commit the files into source repo
os.system("git add --all *")
res = os.system('git commit -m "Source updated: {}"'.format(get_uct_time_str()))
os.chdir("..")

if res == 0:
logger.info("Commited source into [{}] folder".format(SOURCE_REPO_FOLDER))
return True
else:
logger.info("Failed to add new source into [{}] folder".format(SOURCE_REPO_FOLDER))
return False

def _diff_files(self):
os.chdir(SOURCE_REPO_FOLDER)
res = subprocess.run(['git', 'diff', 'HEAD', 'HEAD~1', '--name-only'], stdout=subprocess.PIPE).stdout.decode('utf-8')
os.chdir("..")
files = [f for f in res.split("\n") if len(f) > 0]
logger.info("{} different files:\n{}".format(len(files), res))
return files

code from https://github.com/steemblog/blog | MIT License

为了保证每个用户运行时,文章的内容不会混乱,需要多source的workspace也做一些管理,这里不详细叙述了。‌

步骤2:只编译受影响的 html 文件

在用主题进行编译时,也需要知道哪些 markdown 文件需要更新,以及由此判断更新哪些 html。‌

themes/icarus/includes/helpers/diff.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
hexo.extend.helper.register('list_updated_posts', function (link) {
if (_posts.length == 0) {
process.chdir("source")
const res = execSync("git diff --name-only --cached").toString('utf8');
process.chdir("..")

const paths = res.split("\n").filter((p)=>(p.length > 0))
_posts = paths
}
return _posts
});

hexo.extend.helper.register('list_updated_categories', function (link) {
if (_categoreis.length == 0) {
const _list_updated_posts = hexo.extend.helper.get('list_updated_posts').bind(this)
const updated_posts = _list_updated_posts();

if (updated_posts.length > 0) {
for (const path of updated_posts) {
let post = Post.findOne({source: path})
if (post) {
_merge_categories(post.categories);
}
}
}
}
return _categoreis
});

hexo.extend.helper.register('list_updated_tags', function (link) {
if (_tags.length == 0) {
const _list_updated_posts = hexo.extend.helper.get('list_updated_posts').bind(this)
const updated_posts = _list_updated_posts();

if (updated_posts.length > 0) {
for (const path of updated_posts) {
let post = Post.findOne({source: path})
if (post) {
_merge_tags(post.tags);
}
}
}
}
return _tags
});

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

在 generators 中,只考虑那些受影响的文件。以category 为例:‌

themes/icarus/includes/generators/category.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function needs_update(category) {
if (config.incremental) {
// in incremental mode, update the affected category pages only
const updated_categories = list_updated_categories();
if (updated_categories &amp;&amp; updated_categories.length > 0 &amp;&amp;
updated_categories.indexOf(category['name']) != -1) {
return true;
}
return false;
}
return true;
}

return locals.categories.reduce(function(result, category){
if (! needs_update(category)) {
return result;
}

const posts = category.posts.sort('-date');
const data = pagination(category.path, posts, {
perPage: perPage,
layout: ['category', 'archive', 'index'],
format: paginationDir + '/%d/',
data: {
category: category.name,
parents: findParent(category)
}
});

return result.concat(data);
}, []);

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

需要注意的是,这里需要找到 hexo 对应的几个 generator 的源码,并将其进行替换,例如 hexo-generator-tag、hexo-generator-category、hexo-generator-archive ‌

—‌

实现增量编译以后,经过测试,大概每天更新时,每个账户消耗的时间大约在几秒钟 到1分钟之间。12个账户更新时,总的耗时大约在2分钟至10分钟左右,包括环境部署的时间。

@andrewma: 400+ posts, 80+ tags, ~17s

@ericet: 630+ posts, 260+ tags, < 1min

—-‌

至此,编译性能优化的工作告一段落,可以支持更多账户的镜像同步了。‌

(2)多平台部署

‌除了 GitHub pages,现在常用的静态网站部署方式还有Netlify等。只需要按照Netlify的界面上步骤操作即可,或者参考 hexo deployment 一节的描述。‌

作为结果,我们可以将页面部署到不同环境:‌

‌注意:Netlify上目前只部署了 @robertyan 的文章,但也可以支持其他账户。‌

(3)渲染优化

‌由于采用了组件化的 html 页面内,在上文提到过需要动态加载 widget 的页面,由于页面加载资源的阻塞等问题,我们需要对页面做一些优化才能保证 widget 的渲染不被图片等资源影响太大。‌

这里主要是在 widget 的占位符组件被渲染以后,立即调用 ajax 加载组件的代码,以尽早显示这些 widgets;否则,首页打开时的卡顿还是挺明显的。‌

themes/icarus/layout/layout.ejs

1
2
3
4
5
6
7
8
9
10
<section class="section">
<div class="container">
<div class="columns">
<%- partial('common/widget', { position: 'left' }) %>
<%- partial('common/widget', { position: 'right' }) %>
<%- partial('component/pjax_widget_js', {}, {cache: true}) %>
<div class="column <%= main_column_class() %> has-order-2 column-main"><%- body %></div>
</div>
</div>
</section>

code from https://github.com/steemblog/hexo-theme-icarus | MIT License

主要需要优化的渲染过程就是组件的渲染,其余目前并未做更多测试。‌

(4)问题修复

‌除了以上提到的问题,由于在编译或展示时还需要一些别的问题,也一同修复了。‌

  1. @andrewma 想可以将 category 和 tag 等按使用频率从大到小排序;
  2. 编译 @lemooljiang 的博客时,产生 node / v8 的内存溢出问题,编译失败。

这些问题较容易修改:前者只需渲染前进行排序;后者需要对node运行的参数进行配置,改上限为8GB。后者的修改在:‌

blog/command.py

1
2
3
def configure():
settings.set_env_var("NODE_OPTIONS", "--max-old-space-size=8192")
os.system("cp -f _config.theme.yml themes/icarus/_config.yml")

#4 未来

‌steemblog 实现时 只是为了满足更好的阅读、搜索文章的需要。简言之,它是一个更好的博客“阅读器”(当然也是一个有趣的“时光机”),并不具有写的功能。‌

这是它想要解决的问题决定的,但它的未来可以有着有趣的发展方向,我们从小和大两个方面来讲。‌

—-‌

:从steemblog的角度来讲,我们可以做各类改进,包括功能、性能、运营等。‌

  • 功能:支持语言切换、主题切换、留言(原来就有,为了性能隐藏了)、图片本地保存等
  • 性能:hexo 模板的渲染速度可进一步优化
  • 运营:可以扩展现有系统以支持更多用户、可以考虑付费模式以满足更多需求(费用可能是一次性 10 STEEM 之类的)
  • 扩展:用户可以借助此框架和其他建站服务,快速构建基于 steem 数据的各种网站,包括博客、简历、图库等,以及各种基于 steem 数据的展示组件、基于 steem-js 的写操作 等等;

‌—-

:steemblog 展示了一种基于blockchain 的 app 的更多的可能性。为什么这么说呢?主要原因如下:‌

  • 一份数据、多种展示:与传统数据库相比,blockchain 数据库的公开性和可访问性使得它可以被方便用于基于同一份数据构建多种应用。这也是dApp有趣的方面。steemblog 通过 将 steem blockchain 的数据,进行二次加工,形成了不同的展示方式,这体现了一份数据、多种应用场景的特点。 steemblog 的意图和 steemit 等客户端不完全相同。这里强调的展示有更多 “数据应用”(data apps)的意味,并不全然是 web app 或者 mobile app的视角。
  • 分久必合、强调综合:steem 等区块链平台,现在流行的 dApp 以web app的思维,不断产生新的应用和平台,使得数据不断分化、分裂,到了一定复杂度后,需要一个可以集中管理各类数据与事务的调度中心,steemblog 对于历史的总览体现了这一种思想的一个方面。
  • 数据基础的改进方向:steem 类应用的用户体验的局限性一部分在于其数据基础设施的不灵活与低效,steemblog 通过分离数据读和写,改进了用户体验,但这只是一个方向。blockchain 数据基础设施有着更多的发展的可能性。
  • 社会:生产还是消费?:steemblog 把 steem 数据展现出的一个用户的能力、经验、历史等方面,更有效的展现出来,这是一个更具有生产、企业或产业角度的意义的展示。 steemblog 可以让我们更清楚地看到一个用户的时间是如何被应用与转化的。这种方式对于大规模协作的价值大于娱乐消费型 app 的需要。

这只是一个大致的方向,或许随着思考的深入我们可以把它演变成新的应用。‌

但有三点应该是对的:(1)你在 steem 的历史不会消失;(2)更好的时光机将会不断被发明出来;(3)未来必定会来到。‌

基于这些前提,我们或许能不断看到更多有趣的应用吧。‌

—-‌

昨天 @holger80 在 discord 和我聊到了关于 hexo theme 的问题,同时创建了 steemsites 这个项目(https://github.com/holgern/steemsites),可能也有通过 steem 构建站点,或者其他方面的考虑。‌

对于 steemblog 和相关的项目,我们在之后会进一步思考和探索。如有任何建议请随时留言讨论~‌

参考文献

  1. Hexo博客框架:https://hexo.io
  2. Hexo icaru 主题:
    1. 修改后:https://github.com/steemblog/hexo-theme-icarus
    2. 原作者:https://github.com/ppoffice/hexo-theme-icarus
  3. steemblog 博客镜像服务:https://steemblog.github.io/ (源码:https://github.com/steemblog/blog | MIT License)


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/steemblog-steem%e6%97%b6%e5%85%89%e6%9c%ba-steem-time-machine


This page is synchronized from the post: steemblog: Steem时光机 | Steem Time Machine

贺寿与建祠

贺寿与建祠

上一期《对偶与春秋》中,我们谈到了对联的对称/阴阳本质,以及人类对时间的观念的变迁。本文循着时间这条路,我们简单谈谈时间相关的对联。‌

写人物的对联大概有婚联、寿联、挽联,如果是兼有祠堂的名人,则还包括祠堂的楹联。今天就说说贺寿和建祠过程中的一些对联。‌

–‌

贺寿

‌大多数寿联都是送给生者的“人情”,阿谀之辞在所难免。寿联大多属于应酬之作,感情一假,便不足为观。不过虽然平庸之作占了大多数,但佳作也是有的。以下选自《名联观止》[1]中一些不俗的寿联,可作一观。‌

如郑板桥的六十寿联,可见真性情:

常如作客,何问康宁;但使囊有余钱,瓮有余酿,釜有余粮,取数叶赏心旧纸,放浪吟哦,兴要阔,皮要顽,五官灵动胜千官,过到六旬犹少;

定欲成仙,空生烦恼;只令耳无俗声,眼无俗物,胸无俗事,将几枝随意新花,纵横穿插,睡得迟,起得早,一日清闲似两日,算来百岁已多。

‌郑板桥曾任山东范县、潍县知县,因得罪地方豪绅,托病弃官,寄居扬州卖画,称为“扬州八怪”之一,诗、书、画均不俗,人称“三绝”。曾做一四言诗:

学诗不成,去而学写。学写不成,去而学画。

日卖万钱,以代耕稼。实救困贫,托名风雅。

免谒当途,乞求官舍。座有清风,门无车马。

与自寿联一道,可见他的真性情。‌

光绪三十四年(1908年,戊申年)八月,袁世凯五十生辰,大开寿筵,有谄媚者献寿联:

戊戌八月,戊申八月;

我佛万年,我公万年。

‌”戊戌八月“为袁世凯得势之始(靠出卖维新变法之立宪派,即谭嗣同等),且此联也颂慈禧(”老佛爷“)。同年十月,慈禧病故,名士祝竹岩改此联为:

戊戌八月,戊申十月;

我佛万年,我公明年。

‌虽然袁项城未能明年就死,但此联也传诵一时。‌

image source: Wikipedia – 生日

建祠

‌寿联贺生人,挽联敬死者,祠联题名士。挽联今次先不谈,我们先看祠联。‌

祠联甚多,其中诸葛祠甚为有名,由杜甫《蜀相》(”丞相祠堂何处寻“)可知。‌

这里录两则短联,分别题张良与韩信。‌

于右任题张良庙联:

辞汉万户;

送秦一椎。

山西霍山题韩信墓联:

生死一知己;

存亡两妇人。

这里且卖一关子,能说明联中典故,奖励1 STEEM~‌

活动

上一期活动,我们以“四时(春夏秋冬)与四方(东南西北)‌”为题,两人一组对联。‌‌

下面为活动结果。‌‌

参与:

(上联)春夏秋冬四时雨 | @cecilian

(下联)东南西北八方客 | @mia-cc

(下联)东南西北四面风 | @doveyan

(上联)东邪西毒南帝北丐中神通 | @andrewma

(下联)春华秋实夏蝉冬雪光似水 | @julian2013

(下联)春生夏长秋收冬藏中养生 | @doveyan

(下联)東暖西凉南熱北寒中誼居 | @hertz300

(上联)东成西就 | @teamcn-shop

(下联)南辕北辙 | @annepink

(下联)南来北往 | julian2013

(下联)春华秋实 | @xiaoshancun

(上联)春夜漫漫无心睡 | @julian2013

(下联)秋昼绵绵惹人醉 | @andrewma

(下联)秋日私语情意长 | @annepnik

(下联)过来让我抱一下 | @softmetal

(下联)秋波漪漪想美丽 | @julian2013

(下联)望穿秋水盼君归 | @doveyan

以下都是上联,但没有人对下联。

春夏秋來又一年,南方四季缺冬天。 | @hertz300

春不覺來秋已去,南方天氣无冬天。 | @hertz300

春夏秋冬四季,南北西东八方。 | @zy-sb

点评:‌‌

  • 这期参与很活跃,也有很多有趣的作品,谢谢大家~

奖励:‌‌

经综合评价,以下两联较为妥当,分享 3 STEEM奖励,每人获得0.75 。其余每人0.1 STEEM奖励。奖励稍后发放。

春夏秋冬四时雨 | @cecilian

东南西北八方客 | @mia-cc

东邪西毒南帝北丐中神通 | @andrewma

春华秋实夏蝉冬雪光似水 | @julian2013

‌‌

—-‌‌

以下为本期对联活动内容:寿联,由本周内刚满50、60或70级的寿星报名,由其他人为其做寿联。

形式:‌

  1. 寿星自由报名
  2. 其他人自由发挥,为寿星做寿联
  3. 上面”建祠“部分有猜谜活动,也有奖励

规则:‌‌

  1. 满足对联的基本规则;
  2. 不许抄袭任何别人的成果;
  3. 不应当使用机器协助,如微软亚洲研究院开发的“自动对联”

奖励:寿星奖励 1 STEEM(有人帮他写对联为有效,最多3名,先到先得);最佳作品奖励 2 STEEM;参与奖,各0.1 STEEM,前10名都有奖 :)‌‌

参与方式:回复本文‌‌

评价方式:由寿星评判‌

时间:本文发布起7日内有效‌‌

参考文献

  1. 梁羽生,《名联观止》,北京大学出版社,2017年


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/%e8%b4%ba%e5%af%bf%e4%b8%8e%e5%bb%ba%e7%a5%a0


This page is synchronized from the post: 贺寿与建祠

用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog

用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog

本文介绍将Steem文章同步到GitHub pages的开源工具和免费服务:‌

  1. 开源工具 “blog”:https://think-in-universe.github.io/blog/
  2. 免费服务 “steemblog”:https://steemblog.github.io/

Image Source: Pixabay

缘由

最近在用steem的时候,觉得不管是用busy, steempeak还是steemit等,它们的界面设计对于看自己以前的文章并不太方便(当然想看其他人的旧文章也比较麻烦),并且由于国内的网络访问这些站点的速度都不太快,所以以博客服务来看,用户体验是挺差的;至于要方便地搜索、归类自己的文章就更麻烦了。‌

之前曾经有过一些浏览历史文章较方便的服务(如chinabb和steemitfriends),似乎也或者关闭或者收费了,因此暂时没有找到好用的服务。‌

于是想到可以把Steem上的文章备份成镜像,每日自动同步,便于自己梳理和分析;虽然我文章写的不多,但如同在《标签的本质 | The Nature of Tags(一)》里提到的,组织信息是人类的本能,于是便实现了这里的工具和服务。‌

GitHub镜像博客

关于为什么需要自己写文章同步工具,其实是值得询问的:‌

  1. 首先,博客镜像的工作相信之前有人也已经做过了,这并非什么新想法(但我简单搜了一下也没有找到可以立即复用的工具)。但是搭建博客镜像是一项需要适应自身需求的工作,所以自己动手的话可以有更高的灵活性和掌控度。
  2. 其次,即便之前有类似工作的话,可能也并不是同步到GitHub,或者也未必会做到近实时的更新,所以这项工作也可以作为一种服务,也并非完全没有价值。

为了完成这项工作,我们基于steem API、GitHub pagesHexo[1]框架创建了博客镜像搭建工具,效果如下(示例:https://think-in-universe.github.io/blog/):‌

1. 博客首页

左侧是用户的profile,右侧是近期的文章,中间为最近文章。

‌screenshot from https://think-in-universe.github.io/blog/

2. 侧边栏:类别和标签

Steem上的标签和类别,会同步到hexo框架下面,并能够正常显示。遗憾的地方在于由于steem上没有类别层级的概念,所以要分类文章,相对来说没有那么灵活。

‌screenshots from https://think-in-universe.github.io/blog/

3. 侧边栏:近期文章和归档

‌显示最近5篇文章,以及每个月的文章数量。可以看出,作为写作者而言,我是比较懒惰的 :) 和大家比还有很大差距。

‌screenshots from https://think-in-universe.github.io/blog/

4. 文章展示:右侧目录、代码高亮和原文链接

‌在右侧添加了一个目录控件,对于阅读长文是有帮助的。‌

代码高亮对类似本文的有代码的文章有一定帮助,steemit对代码高亮的处理是比较初级的。‌

原文链接其实是为了方便我自己有时候引用文章需要,在steem上找文章比较低效。

‌screenshots from https://think-in-universe.github.io/blog/

5. 搜索

‌搜索功能对于想要快速查阅或引用自己的文章,较有帮助。点击右上角的搜索按钮,可以进行快速搜索。

‌screenshot from https://think-in-universe.github.io/blog/

6. 独立的归档、类别、标签页等

‌如果要单独查看这些信息,可以到分别的独立页面下查看,如有需要,也可以建立其他的标签页。例如,归档页面的时间线,比steem看起来简洁一点:https://think-in-universe.github.io/blog/archives/

‌screenshots from https://think-in-universe.github.io/blog/

页面展示大体如此,主要的价值在于从文章的角度,信息的组织更为清晰。如果想要获得一个类似的博客镜像,大抵有两种方法:‌

  1. 如果你了解GitHub和GitHub pages如何使用,可以使用本文发布的开源代码(https://github.com/think-in-universe/blog),根据其中的README,搭建一个类似的镜像就行了。
  2. 如果你希望可以使用一个免费的博客镜像服务,可以参考文章最后一章提到的 steemblog 博客镜像服务,或者直接联系我。

如何实现博客镜像工具?

‌为了实现以上功能,我们可以基于博客框架Hexo[1],搭建从Steem同步数据、并发布到GitHub pages的博客镜像工具,可以支持基于用户名、标签、日期等查询方式的数据同步。下面简要介绍如何实现这一博客镜像工具。‌

工具的代码在GitHub开源:https://github.com/think-in-universe/blog

关于具体如何使用此工具,可以参考上面项目中的README的介绍:可以在本地安装后使用,也可以通过travis-ci部署。‌

本项目的代码里重用了 @cn-hello 小门童实现时的一些基本框架,所以需要增加的功能较少。工具的工作流程如下,也比较简单:‌

  1. 下载你的Steem文章;
  2. 用Hexo编译成静态文件;
  3. 用GitHub pages部署博客;

(1)下载你的Steem文章

‌由于重用了之前的SteemReader的方法,我们可以指定通过账户或者标签以及时间(天数)来获取文章。‌

blog/builder.py

1
2
3
4
5
6
7
8
9
10
11
class BlogBuilder(SteemReader):

def __init__(self, account=None, tag=None, days=None):
SteemReader.__init__(self, account=account, tag=tag, days=days)

def download(self):
if len(self.posts) == 0:
self.get_latest_posts()
if len(self.posts) > 0:
for post in self.posts:
self._write_content(post)

‌code from https://github.com/think-in-universe/blog | MIT License

为了将文章下载为hexo可识别的markdown格式,需要在markdown中加入相关ymal或json的元数据。以下为markdown模板,包含了标题、类别、日期、标签等信息,并指定显示文章的目录。‌

blog/message.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MESSAGES["blog"] = """
---
title: "{title}"
catalog: true
toc_nav_num: true
toc: true
date: {date}
categories:
- {category}
tags:
{tags}
thumbnail: {thumbnail}
---


{body}
"""

code from https://github.com/think-in-universe/blog | MIT License

使用Steem API,获取steem文章的元数据和markdown文本。‌

blog/builder.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def _write_content(self, post):
folder = self._get_content_folder()
c = SteemComment(comment=post)

# retrieve necessary data from steem
title = post.title.replace('"', '')
body = post.body
date_str = post.json()["created"]
date = date_str.replace('T', ' ')
tags = "\n".join(["- {}".format(tag) for tag in c.get_tags()])
category = c.get_tags()[0]
thumbnail = c.get_pic_url() or ''
url = c.get_url()

# build content with template
template = get_message("blog")
content = template.format(title=title, date=date, tags=tags, category=category, thumbnail=thumbnail, body=body, url=url)

# write into MD files
filename = os.path.join(folder, "{}_{}.md".format(date_str.split('T')[0], post["permlink"]))
with open(filename, "w", encoding="utf-8") as f:
f.write(content)

logger.info("Download post [{}] into file {}".format(title, filename))

code from https://github.com/think-in-universe/blog | MIT License

(2)用Hexo编译成静态文件

‌我们需要为建立的博客设置一个美观的主题。‌

我们这里使用了 https://github.com/ppoffice/hexo-theme-icarus 主题,需要将其作为一个git submodule加入到git repository中。‌

.gitmodules

1
2
3
[submodule "theme"]
path = themes/icarus
url = https://github.com/ppoffice/hexo-theme-icarus.git

‌code from https://github.com/think-in-universe/blog | MIT License

随后使用hexo命令来将markdown转换成生成静态的文档。‌

blog/command.py

1
2
3
4
5
6
7
@task(help={
})
def build(ctx):
""" build the static pages from steem posts """

os.system("cp -f _config.theme.yml themes/icarus/_config.yml")
os.system("hexo generate")

‌code from https://github.com/think-in-universe/blog | MIT License

(3)用GitHub pages部署博客

‌正式部署时,我们有两种方式,一是在本地使用hexo命令部署,或者在travis-ci 中定期每日进行同步。‌

hexo命令部署:blog/command.py

1
2
3
4
5
6
7
@task(help={
})
def deploy(ctx):
""" deploy the static blog to the GitHub pages """

build(ctx)
os.system("hexo deploy")

‌code from https://github.com/think-in-universe/blog | MIT License

travis-ci部署:.travis/deploy.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[ -z "${GITHUB_PAT}" ] &amp;&amp; exit 0
[ "${TRAVIS_BRANCH}" != "master" ] &amp;&amp; exit 0

git config --global user.email "${GIT_EMAIL}"
git config --global user.name "${GIT_USERNAME}"

git clone --depth 1 --branch gh-pages --single-branch https://${GITHUB_PAT}@github.com/${TRAVIS_REPO_SLUG}.git site
cd site
cp -r ../public/* ./

NOW=$(date +"%Y-%m-%d %H:%M:%S %z")
git add --all *
git commit -m "Site updated: ${NOW}" || true
git push -q origin gh-pages

‌code from https://github.com/think-in-universe/blog | MIT License

另外,需要注意,由于用travis-ci 部署时需要用户提供Git用户信息(用于commit到gh-pages)以及GitHub的token,所以需要以环境变量的方式进行配置。‌

博客镜像服务 http://steemblog.github.io/

‌今天在微信群中 岩哥 @andrewma 提到想要一个分析文章标签的服务,我想起搭建的这个博客镜像也有标签云和标签统计,所以帮助建一个类似的镜像服务就能解决该问题。‌

但由于岩哥对GitHub并不熟悉,使用上面提到的博客镜像工具可能较为困难,所以在此基于https://github.com/think-in-universe/blog 项目,建一个organization account用户管理博客,帮助有需要的人建博客镜像的子目录,这就是steemblog。‌

1. 如何使用博客镜像服务

‌目前,这个博客镜像服务可以在 https://steemblog.github.io 找到。‌

如果要添加一个新的用户到镜像同步中,只需添加账户到用户列表中即可(目前是手动添加的)。例如,我们添加了 @robertyan 和 @andrewma 到列表中。我们可以在以下链接访问他们的博客镜像:‌

  1. https://steemblog.github.io/@robertyan/
  2. https://steemblog.github.io/@andrewma/

与之前的工具需要手动配置用户信息不同,这里自动从steem同步了用户的profile。(不过跟我手动配置的差不多)

‌screenshot from https://steemblog.github.io/@robertyan/

@andrewma的博客镜像也创建成功了,不过头像和缩略图的处理可能需要做一些改进。

‌screenshot from https://steemblog.github.io/@andrewma/

比如岩哥关心的标签信息,可以在https://steemblog.github.io/@andrewma/ 中找到:

‌screenshots from https://steemblog.github.io/@andrewma/

同样的,我们可以继续添加新的用户,他们的镜像可以在 https://steemblog.github.io/@{账户名} 中找到。‌

对于这样的博客镜像,如有需要或建议,可以在文章后面留言讨论。‌

2. 如何建立博客镜像服务

https://github.com/steemblog/blog 是在 https://github.com/think-in-universe/blog 的基础上构建的,为了适应多用户的子目录的需要,需要对原来的项目的目录结构和部署方式做一些调整。‌

(1)从steem下载文章的同时,自动同步用户信息

通过steem获取的账户信息,自动更新_config.yml_config.theme.yml

相对应的模板在 blog/message.py 中,由于内容太长,这里不贴出。‌

blog/builder.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def update_config(self):
if not self.account:
return

organization = BLOG_ORGANIZATION
logo = BLOG_AVATAR
favicon = BLOG_FAVICON

language = settings.get_env_var("LANGUAGE") or "en"

a = SteemAccount(self.account)
author = self.account
name = a.get_profile("name") or ""
# about = a.get_profile("about") or ""
location = a.get_profile("location") or ""
avatar = a.get_profile("profile_image") or ""
website = a.get_profile("website") or ""

# build config file with template
template = get_message("config")
config = template.format(organization=organization, language=language,
name=name, author=author)
filename = CONFIG_FILE
with open(filename, "w", encoding="utf-8") as f:
f.write(config)
logger.info("{} file has been updated for the account @{}".format(filename, author))

# build config theme file with template
template = get_message("config.theme")
config = template.format(organization=organization,
favicon=favicon, logo=logo,
author=author, name=name, location=location,
avatar=avatar, website=website)
filename = CONFIG_THEME_FILE
with open(filename, "w", encoding="utf-8") as f:
f.write(config)
logger.info("{} file has been updated for the account @{}".format(filename, author))

‌code from https://github.com/steemblog/blog | MIT License

(2)在生成静态网页时,相互隔离不同用户的路径

将不同账户的页面放置到@account子目录下。‌

blog/message.py

1
2
3
4
5
6
7
8
9
10
# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://{organization}.github.io
root: /@{author}/
permalink: :category/:post_title/
permalink_defaults:

# Directory
source_dir: source
public_dir: public/@{author}

‌code from https://github.com/steemblog/blog | MIT License

编译指定的steem用户的文章为静态页面,隔离放置在发布目录下。‌

blog/command.py

1
2
3
4
5
6
7
8
9
10
11
@task(help={
})
def build_all(ctx):
""" download the posts of all the accounts, and generate pages """

accounts = settings.get_env_var("STEEM_ACCOUNTS") or []
if accounts and len(accounts) > 0:
for account in accounts.split(","):
clean(ctx)
download(ctx, account)
build(ctx)

‌code from https://github.com/steemblog/blog | MIT License

(3)部署时,将页面推送到 steemblog.github.io‌

只需修改 .travis/deploy.sh 中的目标代码仓库的参数即可。‌

最后

‌究其本质,本文是对steem上的数据进行处理的一种尝试,在开放的区块链数据的基础上,我们可以根据场景,采取多种灵活的数据展现方式,这里的镜像博客无疑又是其中的一种。‌

希望本文提供的工具或服务对你有帮助,如果需要帮助你开启博客镜像服务,可以在本文留言,我会尽量提供支持。由于travis的使用也有一些限制,优先帮助前5位留言的朋友提供服务 :)‌

参考文献

  1. https://hexo.io
  2. Hexo icarus主题:https://github.com/ppoffice/hexo-theme-icarus
  3. 博客镜像工具:https://think-in-universe.github.io/blog/
  4. 博客镜像服务:https://steemblog.github.io/


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/%e7%94%a8github%e5%88%9b%e5%bb%basteem%e6%96%87%e7%ab%a0%e9%95%9c%e5%83%8f-mirroring-your-steem-blogs-on-github-%e5%85%8d%e8%b4%b9%e5%8d%9a%e5%ae%a2%e5%a4%87%e4%bb%bd%e6%9c%8d%e5%8a%a1%ef%bc%9a-st


This page is synchronized from the post: 用GitHub创建Steem文章镜像 | Mirroring Your Steem Blogs on GitHub | 免费博客备份服务: steemblog

借问师友何处有,门童遥指新手村 | 关于 @cn-hello 小友的来历

借问师友何处有,门童遥指新手村 | 关于 @cn-hello 小友的来历

最近,CN区多了一位叫 @cn-hello 的小朋友,自称是CN区的小门童,每天在CN区路口守望,看到新人便上去提供一些建议,比如:“少侠,我看你能量很少了啊,休息会来村里喝杯茶坐坐吧” ,“那个谁,请你不要抄别人文章啊,会被举报的啊”,……,顺便给新人点个小小的赞。‌

随后又开始忽悠新人:“少年,我看你骨骼清奇,这本《Steem指南》似乎很适合你,10块钱卖你了吧?什么,没钱?那白送你了。” / “小伙,我们村里藏龙卧虎、灵气充沛,只要你肯按时做作业,可保你练成盖世神功,你来还是来还是来?”‌

他看到新人通常都很热情,但新人有时却一脸懵逼,不明白这货是干嘛来了。。。但cn-hello却很自我,每天都要炫耀一下自己勾搭了几位新人。。。‌

其实,@cn-hello 原来是一为牛角挂书的小牧童,本是勤于读书问道解惑的,但有了一些学问之后,却有些好为人师,看到迷途之人,免不了希望上前寒暄两句、指教一二。结果就从牧童变成了门童,负责村中的接引、指路一事了。‌

本文以下简单介绍一下他的来历,相关的一些想法,以及之后的计划。欢迎大家给这位小朋友提供建议。

image source: Wikipedia – 颐和园长廊彩绘 | CC BY-SA 2.0

小门童的介绍

来历

设计 @cn-hello 这个机器人(bot)的意义是颇为直接的,相信很多人也遇到过这个场景:刚来Steem发帖的时候,兴冲冲发了一个帖子,却无人问津,想要找前辈们请教一下,却不知道应该找谁,到其他作者或大佬帖子下留言,也不见得会被回复。所以cn-hello最初的功能便是为了主动发现身处迷雾之中的新人,告诉他们第一步该怎么走、接下来该怎么做、加入什么组织。‌

然而,本质上说 @cn-hello 也只是另一个欢迎机器人罢了(yet another welcome bot),有些欢迎机器人也确实并不令人喜欢,但或许也有一些差异:‌

  1. 他只关注用中文发帖的新人,只给中文用户留言;提供的建议也只用中文表达;
  2. 他提供的帮助信息,如新手村 @team-cn,如《Steem指南》,都是专为中文社区的新人们所创建的,更有针对性与亲切感
  3. 与其他某些欢迎机器人(welcome bot)相比,他并不以私利为目的而留言或点赞,他不发广告、不求赞,只是希望更好的发现和帮助新人。

虽然只运行了几天,但在帮助新人获取信息、找到团体方面也确实有一些帮助,也帮助我们更好地了解和认识了新人们的生存状态。在后文我们会进一步介绍这些内容。‌

—-‌

除了上面提到的这个显而易见的痛点,开始要写这个机器人的动机也有两方面:‌

  1. 一方面是在讨论《Steem指南》相关问题时,发现虽然有《指南》但很多人还是没有阅读的习惯,所以考虑是否可以实现一个发布攻略的小助手(advisor),根据新人发帖的情况,给他提供相应的修改建议;
  2. 另一方面,源于和村长 @ericet 的交流,关于平时是如何找新人进村的,村长说一般是自己去看的,没用什么工具。所以我想可以写个工具和机器人自动化这部分工作,村长也提到已经注册了 @cn-hello 这个账号,想来做类似的事情。

于是大概简单实现了目前的这位 @cn-hello 小门童,或许以后会有更多的功能,也欢迎大家提供建议,目的仍然是切实帮助到新手们。‌

—-‌

实际上,#cn-hello 过去是一个CN区新人常用的自我介绍的标签,最近似乎用的人少了很多。这里用 @cn-hello 作账户,用意也在于帮助新人,所以在意义上较为接近的。‌

功能

目前 @cn-hello 主要有两方面的功能:‌

(1)欢迎新人并提供建议

搜索1天内在 #cn 标签下用中文发表帖子的新人,并在他们的文章下回复新人可能遇到的困难,以及相关的建议,如下图所示:

image source: screenshot from the account @cn-hello ‘s comment‌

特别地,由于很多新人不了解RC的消耗,回复中添加了新人目前的能量可以发表的文章或回帖的总数,以及每天恢复的能量能发帖的数量。‌

关于中文区新人的定义,目前采用的是如下规则:‌

  1. 声望在 [25, 35] 的区间内;
  2. SP < 100;
  3. 帖子使用中文发表

(2)统计1日和7日的新人动态

现在 @cn-hello 定时于北京时间每日晚10点运行,首先搜索新人并回复,然后发布新人相关的统计信息,如2019年05月10日的帖子。统计信息包括:‌

  1. 文章推荐:今日发布帖子的新人以及推荐其中一篇帖子(通常是最新一篇);
  2. 7日新人统计:罗列过去7日发现的新人,以及他们的声望、能量(RC)、帖子数、粉丝数等信息。

这部分统计设计时主要是为了方便老用户为新人提供建议或支持,也可以帮助关注自己在初期的一些关键指标。如下图所示:

image source: screenshot from the account @cn-hello ‘s post

image source: screenshot from the account @cn-hello ‘s post‌

—-‌

目前功能是较为简单的,但对于发现新人,确实也有一些帮助;村长也会根据统计和@的通知,找到新人的帖子并帮助一些新手加入村内。‌

同时,也存在一些问题,似乎并不太容易解决,例如:‌

  1. 获取反馈困难:一般很难知道新手是不是读了 @cn-hello 的建议,以及对建议的反馈如何;确实也有一些新人看到了相关的回复,然后主动联系,但总体来说相当少;
  2. 新手可能不理解规则或建议:推荐的新手的文章有一部分是有抄袭或搬砖的问题的,虽然回复新人时指出了这一点,但可能新手并不理解实际的情况或不愿意相信,依然我行我素,结果还是被踩了。

源码

总体来说,这是一个较为简单的工程,但基本包括了一个论坛机器人常见的功能:监控、过滤、文本分析、回复、点赞、发表文章、通知,等等。‌

下面是本项目的源代码,开源在 @steem-guides 的GitHub账户下。‌

该机器人提供了如下命令,可供执行:

1
2
3
4
5
6
7
8
Available tasks:

cn-hello.reply reply to a post by cn-hello
cn-hello.search search the latest posts by newbies
cn-hello.summarize publish summary post for daily and weekly update
cn-hello.vote vote a post by cn-hello
cn-hello.welcome send welcome messages to newbies
steem.list-posts list the post by account, tag, keyword, etc.


代码较为简单,这里不赘述。但或许有一些基础类可以被复用,这里简单提一下:‌

  1. steem 模块
    1. collector.py:封装了以账户、标签、天数、数量等查询文章和回复的基本方法,如有需要做此类查询的,或许可以复用其中的 get_posts() / get_comments();
    2. comment.py 和 account.py:封装了一些常用操作,如各类常用信息的查询、是否被某人赞或者踩、纯文本的提取等;
  2. data 模块
    1. page_language.py:对文本使用的语言检测的封装;
    2. reader.py:可帮助实现监听某tag最新文章;
  3. cn_hello 模块
    1. bot.py, command.py, message.py, newbies.py: 稍作修改可创建一个新的机器人。
1
2
3
4
5
6
├── cn_hello
│ ├── __init__.py
│ ├── bot.py # the behaviors of the bot
│ ├── command.py # the commands that trigger the bot to act
│ ├── message.py # the messages for the bot to speak
│ └── newbies.py # the data operations of newbies

对于如何安装、执行命令等,可以参考GitHub repo的readme中的介绍。‌

所以,如果希望自己快速创建一个机器人实现点赞、回复、监控、通知等功能,或许可以参考这里的开源代码。‌

—-‌

关于识别中文,这里直接使用了 langdetect 这个 package,是对https://code.google.com/p/language-detection/ 项目的python移植。‌

具体可参见Language Detection Library for Java 中对算法的介绍。其核心是采用了Naive Bayes with character n-gram,计算不同字符拼写特征在哪种语言中出现的概率最高。‌

核心代码在项目的detector.py文件中,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def get_probabilities(self):
if self.langprob is None:
self._detect_block()
return self._sort_probability(self.langprob)

def _detect_block(self):
self.cleaning_text()
ngrams = self._extract_ngrams()
if not ngrams:
raise LangDetectException(ErrorCode.CantDetectError, 'No features in text.')

self.langprob = [0.0] * len(self.langlist)

self.random.seed(self.seed)
for t in xrange(self.n_trial):
prob = self._init_probability()
alpha = self.alpha + self.random.gauss(0.0, 1.0) * self.ALPHA_WIDTH

i = 0
while True:
self._update_lang_prob(prob, self.random.choice(ngrams), alpha)
if i % 5 == 0:
if self._normalize_prob(prob) > self.CONV_THRESHOLD or i >= self.ITERATION_LIMIT:
break
if self.verbose:
six.print_('>', self._sort_probability(prob))
i += 1
for j in xrange(len(self.langprob)):
self.langprob[j] += prob[j] / self.n_trial
if self.verbose:
six.print_('==>', self._sort_probability(prob))

def _extract_ngrams(self):
'''Extract n-grams from target text.'''
RANGE = list(xrange(1, NGram.N_GRAM + 1))

result = []
ngram = NGram()
for ch in self.text:
ngram.add_char(ch)
if ngram.capitalword:
continue
for n in RANGE:
# optimized w = ngram.get(n)
if len(ngram.grams) < n:
break
w = ngram.grams[-n:]
if w and w != ' ' and w in self.word_lang_prob_map:
result.append(w)
return result

code from langdetect project | license: Apache License 2.0‌

未来

目前 @cn-hello 小门童的工作主要以接待和引导新人为主。之后的拓展依然以尽力帮助新人为目的,主要的改进可能在以下几个方面,但总体而言目前的优先级并不是非常高:‌

  1. 提供改进建议:根据作者对标签的使用、收益的情况、文章的主题等,提供在标签使用、活动参与等方面的建议,将《Steem指南》中的特定章节也会一并推送;
  2. 优化新人统计信息:给新人推荐其他steem数据分析平台的链接,方便新人了解掌握自己主要的状态和潜在的改进方向,可能只看统计帖子并不是很方便或有效;
  3. 优化文章推荐:推荐新人高质量的文章,以及包括提高新人在snax等注意力奖励平台上的收益等。这点似乎很多机器人都在做了,所以或许并不是 @cn-hello 的重点。

对小门童有任何建议,或者希望他还能帮新人们做些什么,请在文章下面留言哦~

小门童的思考

对新人的观察

透过 @cn-hello 每日对新人的访问和记录,我们也能获得一些关于新人的观察:‌

  1. 搬砖的倾向:在过去7人接待的28位新人中,至少有5位由于搬砖(抄袭)的问题声望被踩到25以下。一方面,我们的提醒没有达成特别好的效果;另一方面,新人不了解规则并希望轻松撸币容易有搬砖的倾向。
  2. “老”新人:大部分 @cn-hello 找到的新人都是1个月以内的创建的(18 / 28),但也有部分账户(6 / 20)已经创建了 1年左右或以上的。或许当时新人来访时,没有很快找到融入社区的方式,所以一直呈现若离若即的状态,希望 cn-hello能帮助缓解这一问题,目前看来似乎也并不容易。
  3. 积极的新人:目前积极回应 @cn-hello 的新人只有 (6 / 28)个,并不算很多,但能得到一些有效回应,也算部分完成任务了。

对新人不够友好(同时也是为了防止小号和机器人的泛滥),是Steem的一个严重的问题,也是比较奇怪的地方,但恐怕也是无奈之举。从实际上确实阻碍了新生力量的入场,给新玩家设置了较高的门槛。或许本质上这是西方文明“人性恶”的假设在作怪吧。‌

为了对抗新人面对的挑战,小门童表示不打算放弃新人“拯救”计划。‌

机器人的印象

小门童 @cn-hello 是机器人,但令他感到不解的是,steem上很多机器人并不打算遵循阿基莫夫的机器人三大定律或者四大定律,甚至恶行昭彰。

第零法则:机器人不得伤害整体人类,或坐视整体人类受到伤害;

第一法则:除非违背第零法则,否则机器人不得伤害人类,或坐视人类受到伤害;

第二法则:除非违背第零或第一法则,否则机器人必须服从人类命令;

第三法则:除非违背第零、第一或第二法则,否则机器人必须保护自己。

‌总体来说,steem上机器人给人的整体印象是不够正面的,既不智能、也不正义(不仁、不智)。‌

事实上,像“三大定律”这样义务化的伦理确实不适合steem上的机器人,他们不过是人的延伸,并不具有被编码的“道德”。或许在可预见的未来,人工智能的潜在危害也不过是“恶”的延伸,问题不在与机器本身有多智能,而首先在于设计和使用它的人是否能约束自身的贪婪和享乐的倾向。‌

—-‌

如果想要进一步了解steem上的机器人,《Steem指南》的机器人篇对于机器人有一些不完全的介绍,可作参考。‌

在帮助新人方面,@cn-hello 也只不过是其中之一。CN区还有很多可爱的机器人,有些依然活跃,有些则已经进入休假状态,比如 @cn-cutie.pie 和 @cn-naughty.boy。‌

之前的一些过去关于机器人问题的讨论,或许也可以作为参考:‌

  1. 聊聊机器人🤖 / Robots on STEEMIT
  2. steemit 还是机器人的天下
  3. 机器人是否会破坏steemit上的生态平衡?

‌@maiyude 的机器人教程,也可供初学者阅读,我们稍后也会整合到《Steem指南》中。‌

  1. steem-python 介绍:(1)(2)
  2. 点赞机器人开发:(1)(2)(3)

—-‌

虽然对于steem上的机器人存在许多争议,但所谓“自反而缩,虽千万人,吾往矣”,小门童希望能尽自己的一点绵薄之力,便已经足够了 :)‌

参考文献

  1. Wikipedia,机器人三定律
  2. Shuyo NakataniLanguage Detection Library for Java,2010年


Posted from my blog with SteemPress : https://robertyan.000webhostapp.com/2019/05/%e5%80%9f%e9%97%ae%e5%b8%88%e5%8f%8b%e4%bd%95%e5%a4%84%e6%9c%89%ef%bc%8c%e9%97%a8%e7%ab%a5%e9%81%a5%e6%8c%87%e6%96%b0%e6%89%8b%e6%9d%91-%e5%85%b3%e4%ba%8e-cn-hello-%e5%b0%8f%e5%8f%8b%e7%9a%84


This page is synchronized from the post: 借问师友何处有,门童遥指新手村 | 关于 @cn-hello 小友的来历

Snax authentication post

I want to link my Steem account with my account on Snax blockchain using https://snax.one Please, create Snax account for me! My authentication hash: 28bd868698bd0b64a2d9c10300fdc66e5f30c01ca7dcf91a551270c7f00b23d7


This page is synchronized from the post: Snax authentication post

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×