-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathwebpushr.js
238 lines (204 loc) · 7.86 KB
/
webpushr.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
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
'use strict';
const util = require('hexo-util');
const fs = require('hexo-fs');
const moment = require('moment');
const axios = require('axios');
const config = hexo.config.webpushr;
const endpoint = config.endpoint || 'segment';
let newPostOnlineSite;
let topic = [];
let actionButtons = [];
if (config.enable) {
// 排序获得最新文章信息,并写入本地文件
hexo.on('generateAfter', async () => {
const posts = hexo.locals.get('posts').data;
const sortBy = config.sort === 'date' ? 'date' : 'updated';
const updatedSortedPosts = posts.sort((a, b) => b[sortBy] - a[sortBy]);
const newPost = updatedSortedPosts[0];
if (sortBy === 'date') newPost.updated = newPost.date;
const JSONFeed = createJSONFeed(newPost);
await fs.writeFile('public/newPost.json', JSON.stringify(JSONFeed));
});
// 生成 sw-js 文件
if (!config.sw_self) {
hexo.on('generateAfter', async () => {
await fs.writeFile('public/webpushr-sw.js', 'importScripts("https://cdn.webpushr.com/sw-server.min.js");');
});
}
// 生成 html 后插入代码
hexo.extend.filter.register('after_render:html', data => {
const swOption = config.sw_self ? "'none'" : "undefined";
const payload = generatePayload(swOption);
return data.replace(/<body.+?>(?!<\/body>).+?<\/body>/s, str => str.replace('</body>', `<script>${decodeURI(payload)}</script></body>`));
});
// 部署前获取在线 newPost.json(旧版本)
hexo.on("deployBefore", async () => {
hexo.log.info('正在获取 在线 最新文章信息');
newPostOnlineSite = async () => {
try {
const result = await axios.get(`${hexo.config.url}/newPost.json`, {
headers: { Accept: 'application/json' }
});
return result.data;
} catch (e) {
return {};
}
};
});
// 部署后读取本地和部署前获取到的在线版本信息
hexo.on('deployAfter', async () => {
const newPostLocal = await getNewPostLocal();
if (!newPostLocal) return;
const newPostOnlineSiteData = await getNewPostOnlineSite();
if (!newPostOnlineSiteData) return;
if (shouldPushNotification(newPostLocal, newPostOnlineSiteData)) {
await pushNotification(newPostLocal);
}
});
}
function createJSONFeed(newPost) {
return {
title: newPost.title,
updated: newPost.updated.format(),
message: newPost.description || util.stripHTML(newPost.excerpt),
target_url: newPost.permalink,
image: newPost.cover || config.image,
categories: newPost.categories.data.map(v => v.name),
schedule: newPost.schedule || moment().add(config.delay || 10, 'minutes'),
expire: newPost.expire || config.expire || '7d',
auto_hide: newPost.auto_hide || config.auto_hide || '1',
webpushr: newPost.webpushr
};
}
function generatePayload(swOption) {
return `(function (w, d, s, id) {
if (typeof (w.webpushr) !== 'undefined') return;
w.webpushr = w.webpushr || function () { (w.webpushr.q = w.webpushr.q || []).push(arguments) };
var js, fjs = d.getElementsByTagName(s)[0];
js = d.createElement(s);
js.id = id;
js.async = 1;
js.src = "https://cdn.webpushr.com/app.min.js";
fjs.parentNode.appendChild(js);
}(window, document, 'script', 'webpushr-jssdk'));
webpushr('setup', {
'key': '${config.trackingCode}',
'sw': ${swOption}
});
`;
}
async function getNewPostLocal() {
try {
return JSON.parse(await fs.readFileSync('public/newPost.json'));
} catch (e) {
hexo.log.error('获取本地版本 "newPost.json" 失败,可能为未生成文件或读取超时');
return false;
}
}
async function getNewPostOnlineSite() {
try {
return await newPostOnlineSite();
} catch (e) {
hexo.log.error('获取在线版本 "newPost.json" 失败,可能为首次推送更新或站点无法访问');
return false;
}
}
function isValidPostCategory(newPostLocal) {
if (endpoint === 'segment' && config.categories && config.segment) {
for (let i = 0; i < newPostLocal.categories.length; i++) {
const index = config.categories.indexOf(newPostLocal.categories[i]);
if (index === -1) return false;
topic[i] = config.segment[index];
}
}
return true;
}
function shouldPushNotification(newPostLocal, newPostOnlineSiteData) {
if (newPostLocal.webpushr === false) {
hexo.log.info('本文章配置为不推送,已跳过本次推送');
return false;
}
if (endpoint === 'sid' && !config.sid) {
hexo.log.error('未配置具体 sid');
return false;
}
if (endpoint === 'segment' && (!config.categories || !config.segment)) {
hexo.log.error('默认为按主题推送,需配置categories及segment');
return false;
}
if (endpoint === 'segment' && !isValidPostCategory(newPostLocal)) {
hexo.log.info('未满足分类条件,已跳过本次推送');
return false;
}
if (newPostOnlineSiteData.updated === newPostLocal.updated) {
hexo.log.info('文章无更新,已跳过本次推送');
return false;
}
hexo.log.info('检测到文章更新,准备推送通知');
return true;
}
async function pushNotification(newPostLocal) {
const headers = {
webpushrKey: process.env.webpushrKey || config.webpushrKey,
webpushrAuthToken: process.env.webpushrAuthToken || config.webpushrAuthToken,
"Content-Type": "application/json"
};
generateActionButtons(newPostLocal);
if (actionButtons.length > 3) {
hexo.log.warn('提示: 不推荐您配置过多按钮');
hexo.log.info('本次已截取前 3 个按钮,并且建议您修改您的配置');
actionButtons = actionButtons.slice(0, 3);
}
const payloadTemplate = {
name: newPostLocal.title,
title: newPostLocal.title,
message: newPostLocal.message,
target_url: newPostLocal.target_url,
image: newPostLocal.image,
icon: config.icon,
auto_hide: newPostLocal.auto_hide,
expire_push: newPostLocal.expire,
action_buttons: actionButtons,
};
let payload = { ...payloadTemplate };
if (endpoint === 'segment') {
payload.segment = topic;
}
if (config.sid) {
payload.sid = config.sid;
delete payload.image;
}
if (actionButtons.length === 0) {
delete payload.action_buttons;
}
if (config.delay === '0' && actionButtons.length === 0) {
delete payload.action_buttons;
} else {
payload.send_at = moment(newPostLocal.schedule).format();
}
hexo.log.info('正在推送文章更新,请稍后');
hexo.log.info('以下是推送内容:', payload);
try {
const res = await axios.post(`https://api.webpushr.com/v1/notification/send/${endpoint}`, payload, { headers });
hexo.log.info(`《${newPostLocal.title}》推送更新成功!`);
hexo.log.info('以下是接口返回信息:', res.data);
} catch (err) {
hexo.log.error(`《${newPostLocal.title}》推送更新失败!`);
hexo.log.error('以下是接口返回信息:', err.response ? err.response.data : err.message);
}
}
function generateActionButtons(newPostLocal) {
if (config.action_buttons && Array.isArray(config.action_buttons)) {
config.action_buttons.forEach(button => {
actionButtons.push({
title: button.title || '前往查看',
url: button.url || newPostLocal.target_url
});
});
} else {
actionButtons.push({
title: '前往查看',
url: newPostLocal.target_url
});
}
}