自动初始化Gitalk评论

最近重新将博客整理了一下,之前忙的都没有时间取打理。其中一下是用Gitalk更换原来的评论系统。
Gitalk是利用了GithubAPI,将网站的评论转写到Github上指定仓库的Issues里,相当于做了一个代理。风格做的简约漂亮,但每种不足的是每次发表了新博文后,需要自己用管理员账号登陆下评论系统,否则就会:

所以就萌生了写个nodejs代码去代替人工初始化的想法。

Gitalk安装

总体来说,使用还是比较简单的,具体步骤请参阅官网,这里就不再赘述了。重点讲下配置。
首先,是Github上申请OAuth App的配置

然后,是Gitalk的配置

1
2
3
4
5
6
7
8
9
var gitalk = new Gitalk({
clientID: 'xxxxxxxxxxxxxx',
clientSecret: 'xxxxxxxxxxxxxxxx',
repo: 'GitHub repo',
owner: 'GitHub repo owner',
admin: ['GitHub repo owner and collaborators, only these guys can initialize github issues'],
id: md5(window.location.pathname), // Ensure uniqueness and length less than 50
distractionFreeMode: false // Facebook-like distraction free mode
})

这里,重点有三个地方:

  • owenr是Github上的ID。有些人(比如我),登陆时习惯用邮箱,放这里就不行了。一定得是自己的ID!
  • repo,要填的是用来存储评论的Issues所对应的仓库的名字,记住后面不要有.git
  • 配置中的id,是唯一表示当前评论页面的主键。Gitalk用它作为Github Issue的Label,而Github对Label的长度有限制,最多50个字符,所以这里比较好的解决方案是对pathname做MD5,以保证长度和唯一性。
    需要引入md5的js,可以使用JavaScript-MD5.

申请Personal Access Token

GithubAPI对一些接口有调用限制,具体可以查看Rate limiting的解释。对于不同的认证方式,调用限制不同。

Gitalk使用的是Github的OAuth认证,请求时必须要有clientIDclientSecret,这种方式每小时的Rate limiting60。如果只是发表评论,肯定是够了。
而如果要批量创建所有文章对应的Issue来作为这些文章的评论存储,可能就未必够了。

好在Github提供了另一种认证方式——Personal access token,这种方式每小时的限制高达5000次。所以,第一步就是申请这个token。

从Github的Personal access token页面,点击Generate new token

创建完成后,获得一个Token。

代码

我用NodeJs写了个简单的批量刷新工具,是基于网站的sitemap的。如果你的网站没有sitemap,可以自行修改。

安装依赖

1
2
npm install sitemapper -S
npm install cheerio -S

NodeJS文件

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
var request = require('request');
var Sitemapper = require('sitemapper');
var cheerio = require('cheerio');
var crypto = require('crypto');

// 配置信息
const username = "EdisonXu" //github账号,对应Gitalk配置中的owner
const repo_name = "repo" //用于存储Issue的仓库名,对应Gitalk配置中的repo
const token = "xxxxxxxxxxxxxxxxxxxxxxxxxxx" //前面申请的personal access token
const sitemap_url = "http://edisonxu.com/sitemap.xml" // 自己站点的sitemap地址

var base_url = "https://api.github.com/repos/"+ username + "/" + repo_name + "/issues"

var sitemap = new Sitemapper();

sitemap.fetch(sitemap_url)
.then(function (sites) {
sites.sites.forEach(function (site, index) {
if (site.endsWith('404.html')) {
console.log('跳过404')
return
}
request({
url: site,
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
}, function (err, resp, bd) {
if (err || resp.statusCode != 200)
return
const $ = cheerio.load(bd);
var title = $('title').text();
var desc = site + "\n\n" + $("meta[name='description']").attr("content");
var path = site.split(".com")[1]
var md5 = crypto.createHash('md5');
var label = md5.update(path).digest('hex')
var options = {
headers: {
'Authorization': 'token '+token,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
'Accept': 'application/json'
},
url: base_url+ "?labels="+"Gitalk," + label,
method: 'GET'
}
// 检查issue是否被初始化过
request(options, function (error, response, body) {
if (error || response.statusCode != 200) {
console.log('检查['+site+']对应评论异常')
return
}
var jbody = JSON.parse(body)
if(jbody.length>0)
return
//创建issue
var request_body = {"title": title, "labels": ["Gitalk", label], "body": desc}
//console.log("创建内容: "+JSON.stringify(request_body));
var create_options = {
headers: {
'Authorization': 'token '+token,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
},
url: base_url,
body: JSON.stringify(request_body),
method: 'POST'
}
request(create_options, function(error, response, body){
if (!error && response.statusCode == 201)
console.log("地址: ["+site+"] Gitalk初始化成功")
})
});
});
});
})
.catch(function (err) {
console.log(err);
});

注意
代码里默认将path做了MD5化,如果你的Gitalk配置里没有使用MD5后的值作为ID,这里要相应修改!

Gulp调用

我的博客是Hexo+Gulp,所以我把Gitalk初始化也做到了Gulp里,这样每次写完文章压缩、发布、初始化评论一条龙。用法比较简单:

1
2
var $ = require('gulp-load-plugins')();
gulp.task('init-gitalk', ['deploy'], $.shell.task('node init_gitalk.js'));

最后将init-gitalk的task自己加到你的gulp任务序列去就好了。
由于我博客的配置文件里已经有了username和sitemap地址,另外gitalk配置和上门代码的配置也有部分重复,所以我又添加了读取配置的功能,有需要的自行挑选。

添加依赖

1
npm install js-yaml -S

配置文件中增加

1
2
3
4
5
gitalk:
githubId: xxx
repo: xxxxxxxxxx
owner: xxxxxxxxxxxxx
token: xxxxxxxxxxxxxx

修改脚本

1
2
3
4
5
6
7
8
9
10
11
var yml = require('js-yaml');
var fs = require('fs');

//读取配置文件
var file = process.cwd()+"\\_config.yml";
var config = yml.safeLoad(fs.readFileSync(file, 'utf8'))

const username = config.gitalk.githubId
const repo_name = config.gitalk.repo
const token = config.gitalk.token
const sitemap_url = config.url+"/"+config.sitemap.path

至此,Gitalk自动初始化就完成了,再也不要手动初始化了。NodeJS非我之长,所以写不出”信达雅”,只保证能用,起个抛砖引玉的效果。

本文由 EdisonXu - 徐焱飞 创作,采用 CC BY 4.0 CN协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。
本文链接为http://edisonxu.com/2018/10/31/gitalk-auto-init.html
如果您觉得文章不错,可以请我喝一杯咖啡!
Gitalk, blog, gulp, nodejs