yz-yuki-plugin 2.0.4-9 → 2.0.5-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.puppeteerrc.cjs +1 -1
- package/CHANGELOG.md +3 -0
- package/README.md +19 -3
- package/defaultConfig/bilibili/config.yaml +2 -2
- package/defaultConfig/help/help.yaml +51 -51
- package/defaultConfig/weibo/config.yaml +2 -2
- package/lib/apps/bilibili.js +88 -84
- package/lib/apps/help.js +3 -3
- package/lib/apps/version.js +4 -4
- package/lib/apps/weibo.js +47 -47
- package/lib/components/dynamic/Account.js +3 -3
- package/lib/components/dynamic/Content.js +2 -2
- package/lib/components/dynamic/Footer.js +3 -3
- package/lib/components/dynamic/LogoText.js +2 -2
- package/lib/components/dynamic/MainPage.js +2 -2
- package/lib/components/loginQrcode/Page.js +1 -1
- package/lib/index.js +7 -9
- package/lib/models/bilibili/bilibili.api.d.ts +4 -4
- package/lib/models/bilibili/bilibili.api.js +13 -13
- package/lib/models/bilibili/bilibili.get.web.data.js +32 -18
- package/lib/models/bilibili/bilibili.models.d.ts +9 -9
- package/lib/models/bilibili/bilibili.models.js +248 -192
- package/lib/models/bilibili/bilibili.query.d.ts +5 -5
- package/lib/models/bilibili/bilibili.query.js +135 -114
- package/lib/models/bilibili/bilibili.task.d.ts +1 -1
- package/lib/models/bilibili/bilibili.task.js +41 -36
- package/lib/models/bilibili/bilibili.ticket.js +3 -3
- package/lib/models/bilibili/bilibili.wbi.js +10 -12
- package/lib/models/help/help.js +2 -2
- package/lib/models/weibo/weibo.api.js +2 -2
- package/lib/models/weibo/weibo.get.web.data.js +6 -7
- package/lib/models/weibo/weibo.query.d.ts +4 -4
- package/lib/models/weibo/weibo.query.js +66 -69
- package/lib/models/weibo/weibo.task.d.ts +1 -1
- package/lib/models/weibo/weibo.task.js +43 -38
- package/lib/utils/config.d.ts +2 -2
- package/lib/utils/config.js +8 -8
- package/lib/utils/paths.js +1 -1
- package/lib/utils/puppeteer.render.js +20 -22
- package/package.json +8 -4
- package/resources/css/dynamic/Account.css +1 -1
- package/resources/css/dynamic/Content.box.grid.4.css +2 -2
- package/resources/css/dynamic/Content.box.grid.9.css +2 -2
- package/resources/css/dynamic/Content.css +1 -1
- package/resources/css/dynamic/Footer.css +1 -1
- package/resources/css/dynamic/ForwardContent.css +1 -1
- package/resources/css/dynamic/LogoText.css +2 -2
- package/resources/css/dynamic/MainPage.css +4 -5
- package/resources/css/help/help.css +18 -11
- package/resources/css/loginQrcode/Page.css +7 -11
- package/resources/css/version/version.css +8 -6
|
@@ -21,16 +21,16 @@ class WeiboQuery {
|
|
|
21
21
|
/**分类动态,返回标识 */
|
|
22
22
|
static MakeCategory(raw_post) {
|
|
23
23
|
if (raw_post?.mblog?.retweeted_status) {
|
|
24
|
-
return
|
|
24
|
+
return 'DYNAMIC_TYPE_FORWARD';
|
|
25
25
|
}
|
|
26
26
|
else if (raw_post?.mblog?.page_info && raw_post?.mblog?.page_info?.type === 'video') {
|
|
27
|
-
return
|
|
27
|
+
return 'DYNAMIC_TYPE_AV';
|
|
28
28
|
}
|
|
29
29
|
else if (raw_post?.mblog?.pics) {
|
|
30
|
-
return
|
|
30
|
+
return 'DYNAMIC_TYPE_DRAW';
|
|
31
31
|
}
|
|
32
32
|
else {
|
|
33
|
-
return
|
|
33
|
+
return 'DYNAMIC_TYPE_ARTICLE';
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
/**筛选正文 */
|
|
@@ -77,59 +77,64 @@ class WeiboQuery {
|
|
|
77
77
|
formatData.data.name = nick_name;
|
|
78
78
|
/**头像框 */
|
|
79
79
|
formatData.data.pendant = '';
|
|
80
|
-
formatData.data.created = moment().format(
|
|
80
|
+
formatData.data.created = moment().format('YYYY年MM月DD日 HH:mm:ss');
|
|
81
81
|
formatData.data.type = type;
|
|
82
82
|
switch (type) {
|
|
83
|
-
case
|
|
84
|
-
formatData.data.title = info?.page_info?.title ||
|
|
83
|
+
case 'DYNAMIC_TYPE_AV':
|
|
84
|
+
formatData.data.title = info?.page_info?.title || '';
|
|
85
85
|
formatData.data.content = this.parseRichTextNodes(info?.text);
|
|
86
86
|
formatData.data.url = detail_url;
|
|
87
|
-
formatData.data.pubTs = moment(created_time).format(
|
|
88
|
-
formatData.data.category =
|
|
87
|
+
formatData.data.pubTs = moment(created_time).format('YYYY年MM月DD日 HH:mm:ss');
|
|
88
|
+
formatData.data.category = '视频动态';
|
|
89
89
|
formatData.data.pics = info?.page_info?.page_pic?.url ? [{ url: info.page_info.page_pic.url }] : [];
|
|
90
90
|
break;
|
|
91
|
-
case
|
|
91
|
+
case 'DYNAMIC_TYPE_DRAW':
|
|
92
92
|
let raw_pics_list = retweeted ? info?.retweeted_status?.pics || [] : info?.pics || [];
|
|
93
|
-
pics =
|
|
94
|
-
|
|
93
|
+
pics =
|
|
94
|
+
raw_pics_list.map((img) => {
|
|
95
|
+
return { url: img?.large?.url, width: Number(img?.large?.geo?.width), height: Number(img?.large?.geo?.height) };
|
|
96
|
+
}) || [];
|
|
97
|
+
formatData.data.title = '';
|
|
95
98
|
formatData.data.content = this.parseRichTextNodes(info?.text);
|
|
96
99
|
formatData.data.url = detail_url;
|
|
97
|
-
formatData.data.pubTs = moment(created_time).format(
|
|
100
|
+
formatData.data.pubTs = moment(created_time).format('YYYY年MM月DD日 HH:mm:ss');
|
|
98
101
|
formatData.data.pics = pics;
|
|
99
|
-
formatData.data.category =
|
|
102
|
+
formatData.data.category = '图文动态';
|
|
100
103
|
break;
|
|
101
|
-
case
|
|
104
|
+
case 'DYNAMIC_TYPE_ARTICLE':
|
|
102
105
|
let raw_pics_list_article = retweeted ? info?.retweeted_status?.pics || [] : info?.pics || [];
|
|
103
|
-
pics =
|
|
104
|
-
|
|
106
|
+
pics =
|
|
107
|
+
raw_pics_list_article.map((img) => {
|
|
108
|
+
return { url: img?.large?.url, width: Number(img?.large?.geo?.width), height: Number(img?.large?.geo?.height) };
|
|
109
|
+
}) || [];
|
|
110
|
+
formatData.data.title = '';
|
|
105
111
|
formatData.data.content = this.parseRichTextNodes(info?.text);
|
|
106
112
|
formatData.data.url = detail_url;
|
|
107
|
-
formatData.data.pubTs = moment(created_time).format(
|
|
113
|
+
formatData.data.pubTs = moment(created_time).format('YYYY年MM月DD日 HH:mm:ss');
|
|
108
114
|
formatData.data.pics = pics;
|
|
109
|
-
formatData.data.category =
|
|
115
|
+
formatData.data.category = '文章动态';
|
|
110
116
|
break;
|
|
111
|
-
case
|
|
112
|
-
formatData.data.title =
|
|
117
|
+
case 'DYNAMIC_TYPE_FORWARD':
|
|
118
|
+
formatData.data.title = '';
|
|
113
119
|
formatData.data.content = this.parseRichTextNodes(info?.text);
|
|
114
|
-
formatData.data.pubTs = moment(created_time).format(
|
|
120
|
+
formatData.data.pubTs = moment(created_time).format('YYYY年MM月DD日 HH:mm:ss');
|
|
115
121
|
formatData.data.url = detail_url;
|
|
116
122
|
formatData.data.pics = [];
|
|
117
123
|
let origin_post_info = info?.retweeted_status;
|
|
118
124
|
formatData.data.orig = await this.formatDynamicData(origin_post_info);
|
|
119
|
-
formatData.data.category =
|
|
125
|
+
formatData.data.category = '转发动态';
|
|
120
126
|
break;
|
|
121
127
|
}
|
|
122
128
|
return {
|
|
123
129
|
...formatData,
|
|
124
|
-
uid: info?.id
|
|
130
|
+
uid: info?.id
|
|
125
131
|
};
|
|
126
132
|
}
|
|
127
|
-
;
|
|
128
133
|
/**
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
* 动态内容富文本节点解析
|
|
135
|
+
* @param nodes - 动态内容富文本节点
|
|
136
|
+
* @returns 解析后的动态内容富文本
|
|
137
|
+
*/
|
|
133
138
|
static parseRichTextNodes = (nodes) => {
|
|
134
139
|
if (typeof nodes === 'string') {
|
|
135
140
|
// 将 \n 替换为 <br> 以实现换行
|
|
@@ -199,25 +204,23 @@ class WeiboQuery {
|
|
|
199
204
|
let title = `微博【${upName}】动态推送:\n`;
|
|
200
205
|
const dynamicPicCountLimit = setData.pushPicCountLimit || 3;
|
|
201
206
|
switch (type) {
|
|
202
|
-
case
|
|
207
|
+
case 'DYNAMIC_TYPE_AV':
|
|
203
208
|
if (!info)
|
|
204
209
|
return;
|
|
205
210
|
let cover_img_url = info?.page_info?.page_pic?.url;
|
|
206
|
-
let cover_img = Segment.image(cover_img_url, false, 15000, { referer:
|
|
211
|
+
let cover_img = Segment.image(cover_img_url, false, 15000, { referer: 'https://weibo.com' });
|
|
207
212
|
title = `微博【${upName}】视频动态推送:\n`;
|
|
208
213
|
msg = [
|
|
209
214
|
title,
|
|
210
215
|
`-----------------------------\n`,
|
|
211
|
-
`标题:${info?.page_info?.title ||
|
|
216
|
+
`标题:${info?.page_info?.title || ''}\n`,
|
|
212
217
|
`${this.filterText(info?.text)}\n`,
|
|
213
218
|
`链接:${detail_url}\n`,
|
|
214
|
-
`时间:${created_time
|
|
215
|
-
|
|
216
|
-
: ""}\n`,
|
|
217
|
-
cover_img,
|
|
219
|
+
`时间:${created_time ? moment(created_time).format('YYYY年MM月DD日 HH:mm:ss') : ''}\n`,
|
|
220
|
+
cover_img
|
|
218
221
|
];
|
|
219
222
|
return msg;
|
|
220
|
-
case
|
|
223
|
+
case 'DYNAMIC_TYPE_DRAW':
|
|
221
224
|
raw_pics_list = retweeted ? info?.retweeted_status?.pics || [] : info?.pics || [];
|
|
222
225
|
if (!info && !raw_pics_list)
|
|
223
226
|
return;
|
|
@@ -226,7 +229,7 @@ class WeiboQuery {
|
|
|
226
229
|
pic_urls = raw_pics_list.map((img) => img?.large?.url);
|
|
227
230
|
pics = [];
|
|
228
231
|
for (let pic_url of pic_urls) {
|
|
229
|
-
const temp = Segment.image(pic_url, false, 15000, { referer:
|
|
232
|
+
const temp = Segment.image(pic_url, false, 15000, { referer: 'https://weibo.com' });
|
|
230
233
|
pics.push(temp);
|
|
231
234
|
}
|
|
232
235
|
title = `微博【${upName}】图文动态推送:\n`;
|
|
@@ -235,13 +238,11 @@ class WeiboQuery {
|
|
|
235
238
|
`-----------------------------\n`,
|
|
236
239
|
`${this.dynamicContentLimit(this.filterText(info?.text), setData)}\n`,
|
|
237
240
|
`链接:${detail_url}\n`,
|
|
238
|
-
`时间:${created_time
|
|
239
|
-
|
|
240
|
-
: ""}\n`,
|
|
241
|
-
...pics,
|
|
241
|
+
`时间:${created_time ? moment(created_time).format('YYYY年MM月DD日 HH:mm:ss') : ''}\n`,
|
|
242
|
+
...pics
|
|
242
243
|
];
|
|
243
244
|
return msg;
|
|
244
|
-
case
|
|
245
|
+
case 'DYNAMIC_TYPE_ARTICLE':
|
|
245
246
|
if (!info)
|
|
246
247
|
return;
|
|
247
248
|
raw_pics_list = retweeted ? info?.retweeted_status?.pics || [] : info?.pics || [];
|
|
@@ -250,7 +251,7 @@ class WeiboQuery {
|
|
|
250
251
|
pic_urls = raw_pics_list.map(img => img?.large?.url);
|
|
251
252
|
pics = [];
|
|
252
253
|
for (const pic_url of pic_urls) {
|
|
253
|
-
const temp = Segment.image(pic_url, false, 15000, { referer:
|
|
254
|
+
const temp = Segment.image(pic_url, false, 15000, { referer: 'https://weibo.com' });
|
|
254
255
|
pics.push(temp);
|
|
255
256
|
}
|
|
256
257
|
title = `微博【${upName}】文章动态推送:\n`;
|
|
@@ -259,13 +260,11 @@ class WeiboQuery {
|
|
|
259
260
|
`-----------------------------\n`,
|
|
260
261
|
`正文:${this.dynamicContentLimit(this.filterText(info?.text), setData)}\n`,
|
|
261
262
|
`链接:${detail_url}\n`,
|
|
262
|
-
`时间:${created_time
|
|
263
|
-
|
|
264
|
-
: ""}\n`,
|
|
265
|
-
...pics,
|
|
263
|
+
`时间:${created_time ? moment(created_time).format('YYYY年MM月DD日 HH:mm:ss') : ''}\n`,
|
|
264
|
+
...pics
|
|
266
265
|
];
|
|
267
266
|
return msg;
|
|
268
|
-
case
|
|
267
|
+
case 'DYNAMIC_TYPE_FORWARD':
|
|
269
268
|
if (!info)
|
|
270
269
|
return;
|
|
271
270
|
if (!info?.retweeted_status)
|
|
@@ -285,21 +284,19 @@ class WeiboQuery {
|
|
|
285
284
|
`-----------------------------\n`,
|
|
286
285
|
`${this.dynamicContentLimit(this.filterText(info?.text), setData)}\n`,
|
|
287
286
|
`链接:${detail_url}\n`,
|
|
288
|
-
`时间:${created_time
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
"\n---以下为转发内容---\n",
|
|
292
|
-
...orig,
|
|
287
|
+
`时间:${created_time ? moment(created_time).format('YYYY年MM月DD日 HH:mm:ss') : ''}\n`,
|
|
288
|
+
'\n---以下为转发内容---\n',
|
|
289
|
+
...orig
|
|
293
290
|
];
|
|
294
291
|
return msg;
|
|
295
292
|
default:
|
|
296
293
|
logger?.mark(`未处理的微博推送【${upName}】:${type}`);
|
|
297
|
-
return
|
|
294
|
+
return 'continue';
|
|
298
295
|
}
|
|
299
296
|
}
|
|
300
297
|
// 限制文字模式下动态内容的字数和行数
|
|
301
298
|
static dynamicContentLimit(content, setData) {
|
|
302
|
-
const lines = content.split(
|
|
299
|
+
const lines = content.split('\n');
|
|
303
300
|
const lengthLimit = setData.pushContentLenLimit || 100;
|
|
304
301
|
const lineLimit = setData.pushContentLineLimit || 5;
|
|
305
302
|
// 限制行数
|
|
@@ -314,14 +311,14 @@ class WeiboQuery {
|
|
|
314
311
|
continue;
|
|
315
312
|
}
|
|
316
313
|
if (lines[i].length > remainingLength) {
|
|
317
|
-
lines[i] = lines[i].slice(0, remainingLength) +
|
|
314
|
+
lines[i] = lines[i].slice(0, remainingLength) + '...';
|
|
318
315
|
totalLength = lengthLimit;
|
|
319
316
|
}
|
|
320
317
|
else {
|
|
321
318
|
totalLength += lines[i].length;
|
|
322
319
|
}
|
|
323
320
|
}
|
|
324
|
-
return lines.join(
|
|
321
|
+
return lines.join('\n');
|
|
325
322
|
}
|
|
326
323
|
// 处理斜杠开头的url
|
|
327
324
|
static formatUrl(url) {
|
|
@@ -331,11 +328,11 @@ class WeiboQuery {
|
|
|
331
328
|
static typeHandle(up, msg, type) {
|
|
332
329
|
// 定义一个对象映射,将关键字映射到对应的类型
|
|
333
330
|
const typeMap = {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
331
|
+
直播: 'DYNAMIC_TYPE_LIVE_RCMD',
|
|
332
|
+
转发: 'DYNAMIC_TYPE_FORWARD',
|
|
333
|
+
文章: 'DYNAMIC_TYPE_ARTICLE',
|
|
334
|
+
图文: ['DYNAMIC_TYPE_DRAW', 'DYNAMIC_TYPE_WORD'],
|
|
335
|
+
视频: 'DYNAMIC_TYPE_AV'
|
|
339
336
|
};
|
|
340
337
|
// 初始化新的类型集合,如果 up.type 存在则使用它,否则使用空数组
|
|
341
338
|
let newType = new Set(up.type || []);
|
|
@@ -347,11 +344,11 @@ class WeiboQuery {
|
|
|
347
344
|
if (msg.indexOf(key) !== -1) {
|
|
348
345
|
if (Array.isArray(value)) {
|
|
349
346
|
// 如果 value 是数组,则对数组中的每个元素进行操作
|
|
350
|
-
value.forEach(v => action ===
|
|
347
|
+
value.forEach(v => (action === 'add' ? newType.add(v) : newType.delete(v)));
|
|
351
348
|
}
|
|
352
349
|
else {
|
|
353
350
|
// 否则直接对单个值进行操作
|
|
354
|
-
action ===
|
|
351
|
+
action === 'add' ? newType.add(value) : newType.delete(value);
|
|
355
352
|
}
|
|
356
353
|
isHandled = true; // 标记有类型被处理
|
|
357
354
|
}
|
|
@@ -359,16 +356,16 @@ class WeiboQuery {
|
|
|
359
356
|
return isHandled; // 返回是否有类型被处理
|
|
360
357
|
};
|
|
361
358
|
// 根据 type 参数决定是添加还是删除类型
|
|
362
|
-
if (type ===
|
|
363
|
-
handleType(
|
|
359
|
+
if (type === 'add') {
|
|
360
|
+
handleType('add'); // 调用 handleType 函数进行类型添加
|
|
364
361
|
}
|
|
365
|
-
else if (type ===
|
|
362
|
+
else if (type === 'del') {
|
|
366
363
|
if (!newType.size) {
|
|
367
364
|
// 如果 newType 为空,则初始化它为所有可能的类型
|
|
368
365
|
newType = new Set(Object.values(typeMap).flat());
|
|
369
366
|
}
|
|
370
367
|
// 调用 handleType 函数进行类型删除,如果没有类型被删除则清空 newType
|
|
371
|
-
if (!handleType(
|
|
368
|
+
if (!handleType('delete')) {
|
|
372
369
|
newType.clear();
|
|
373
370
|
}
|
|
374
371
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventType } from 'yunzai';
|
|
2
|
-
import { MainProps } from
|
|
2
|
+
import { MainProps } from '@/components/dynamic/MainPage';
|
|
3
3
|
import { ScreenshotOptions } from '@/utils/puppeteer.render';
|
|
4
4
|
export declare class WeiboTask {
|
|
5
5
|
taskName: string;
|
|
@@ -11,13 +11,13 @@ class WeiboTask {
|
|
|
11
11
|
privateKey;
|
|
12
12
|
e;
|
|
13
13
|
constructor(e) {
|
|
14
|
-
this.taskName =
|
|
15
|
-
this.groupKey =
|
|
16
|
-
this.privateKey =
|
|
14
|
+
this.taskName = 'weiboTask';
|
|
15
|
+
this.groupKey = 'Yz:yuki:weibo:upPush:group:';
|
|
16
|
+
this.privateKey = 'Yz:yuki:weibo:upPush:private:';
|
|
17
17
|
}
|
|
18
18
|
async runTask() {
|
|
19
|
-
let weiboConfigData = await Config.getUserConfig(
|
|
20
|
-
let weiboPushData = await Config.getUserConfig(
|
|
19
|
+
let weiboConfigData = await Config.getUserConfig('weibo', 'config');
|
|
20
|
+
let weiboPushData = await Config.getUserConfig('weibo', 'push');
|
|
21
21
|
let interval = weiboConfigData.interval || 7200; // 推送间隔时间,单位为秒,默认2小时
|
|
22
22
|
const uidMap = new Map(); // 存放group 和 private 对应所属 uid 与推送信息的映射
|
|
23
23
|
const dynamicList = {}; // 存放获取的所有动态,键为 uid,值为动态数组
|
|
@@ -33,7 +33,8 @@ class WeiboTask {
|
|
|
33
33
|
*/
|
|
34
34
|
async processWeiboData(weiboPushData, uidMap, dynamicList) {
|
|
35
35
|
const requestedDataOfUids = new Map(); // 存放已请求的 uid 映射
|
|
36
|
-
for (let chatType in weiboPushData) {
|
|
36
|
+
for (let chatType in weiboPushData) {
|
|
37
|
+
// 遍历 group 和 private
|
|
37
38
|
if (!uidMap.has(chatType)) {
|
|
38
39
|
uidMap.set(chatType, new Map());
|
|
39
40
|
}
|
|
@@ -87,11 +88,11 @@ class WeiboTask {
|
|
|
87
88
|
}
|
|
88
89
|
if (!raw_post?.mblog?.created_at)
|
|
89
90
|
continue;
|
|
90
|
-
if (Number(now -
|
|
91
|
+
if (Number(now - WeiboQuery.getDynamicCreatetDate(raw_post) / 1000) > interval) {
|
|
91
92
|
logger.debug(`超过间隔,跳过 [ ${user?.screen_name} : ${user?.id} ] ${raw_post?.mblog?.created_at} 的动态`);
|
|
92
93
|
continue;
|
|
93
94
|
} // 如果超过推送时间间隔,跳过当前循环
|
|
94
|
-
if (dynamicItem.type ===
|
|
95
|
+
if (dynamicItem.type === 'DYNAMIC_TYPE_FORWARD' && !weiboConfigData.pushTransmit)
|
|
95
96
|
continue; // 如果关闭了转发动态的推送,跳过当前循环
|
|
96
97
|
willPushDynamicList.push(dynamicItem);
|
|
97
98
|
}
|
|
@@ -124,11 +125,11 @@ class WeiboTask {
|
|
|
124
125
|
async sendDynamic(chatId, bot_id, upName, pushDynamicData, weiboConfigData, chatType) {
|
|
125
126
|
const id_str = WeiboQuery.getDynamicId(pushDynamicData); // 获取动态 ID
|
|
126
127
|
let sended, markKey;
|
|
127
|
-
if (chatType ===
|
|
128
|
+
if (chatType === 'group') {
|
|
128
129
|
markKey = this.groupKey;
|
|
129
130
|
sended = await Redis.get(`${markKey}${chatId}:${id_str}`);
|
|
130
131
|
}
|
|
131
|
-
else if (chatType ===
|
|
132
|
+
else if (chatType === 'private') {
|
|
132
133
|
markKey = this.privateKey;
|
|
133
134
|
sended = await Redis.get(`${markKey}${chatId}:${id_str}`);
|
|
134
135
|
}
|
|
@@ -137,9 +138,9 @@ class WeiboTask {
|
|
|
137
138
|
if (!!weiboConfigData.pushMsgMode) {
|
|
138
139
|
const { data, uid } = await WeiboQuery.formatDynamicData(pushDynamicData); // 处理动态数据
|
|
139
140
|
const eval2 = eval;
|
|
140
|
-
let banWords = eval2(`/${weiboConfigData.banWords.join(
|
|
141
|
+
let banWords = eval2(`/${weiboConfigData.banWords.join('|')}/g`); // 构建屏蔽关键字正则表达式
|
|
141
142
|
if (new RegExp(banWords).test(`${data?.title}${data?.content}`)) {
|
|
142
|
-
return
|
|
143
|
+
return 'return'; // 如果动态包含屏蔽关键字,则直接返回
|
|
143
144
|
}
|
|
144
145
|
let boxGrid = !!weiboConfigData.boxGrid === false ? false : true; // 是否启用九宫格样式,默认为 true
|
|
145
146
|
let isSplit = !!weiboConfigData.isSplit === false ? false : true; // 是否启用分片截图,默认为 true
|
|
@@ -150,42 +151,42 @@ class WeiboTask {
|
|
|
150
151
|
let renderData = this.buildRenderData(extentData, urlQrcodeData, boxGrid);
|
|
151
152
|
const ScreenshotOptionsData = {
|
|
152
153
|
addStyle: style,
|
|
153
|
-
header: {
|
|
154
|
+
header: { Referer: 'https://weibo.com' },
|
|
154
155
|
isSplit: isSplit,
|
|
155
156
|
modelName: 'weibo',
|
|
156
157
|
SOptions: {
|
|
157
158
|
type: 'webp',
|
|
158
|
-
quality: 98
|
|
159
|
+
quality: 98
|
|
159
160
|
},
|
|
160
161
|
saveHtmlfile: false,
|
|
161
|
-
pageSplitHeight: splitHeight
|
|
162
|
+
pageSplitHeight: splitHeight
|
|
162
163
|
};
|
|
163
164
|
let imgs = await this.renderDynamicCard(uid, renderData, ScreenshotOptionsData);
|
|
164
165
|
if (!imgs)
|
|
165
166
|
return;
|
|
166
|
-
Redis.set(`${markKey}${chatId}:${id_str}`,
|
|
167
|
-
(logger ?? Bot.logger)?.mark(
|
|
167
|
+
Redis.set(`${markKey}${chatId}:${id_str}`, '1', { EX: 3600 * 10 }); // 设置已发送标记
|
|
168
|
+
(logger ?? Bot.logger)?.mark('优纪插件:微博动态执行推送');
|
|
168
169
|
for (let i = 0; i < imgs.length; i++) {
|
|
169
170
|
const image = imgs[i];
|
|
170
171
|
await this.sendMessage(chatId, bot_id, chatType, Segment.image(image));
|
|
171
172
|
await this.randomDelay(1000, 2000); // 随机延时1-2秒
|
|
172
173
|
}
|
|
173
|
-
await new Promise(
|
|
174
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
174
175
|
}
|
|
175
176
|
else {
|
|
176
177
|
const dynamicMsg = await WeiboQuery.formatTextDynamicData(upName, pushDynamicData, false, weiboConfigData); //构建文字动态消息
|
|
177
|
-
Redis.set(`${markKey}${chatId}:${id_str}`,
|
|
178
|
-
if (dynamicMsg ==
|
|
179
|
-
return
|
|
178
|
+
Redis.set(`${markKey}${chatId}:${id_str}`, '1', { EX: 3600 * 10 }); // 设置已发送标记
|
|
179
|
+
if (dynamicMsg == 'continue' || dynamicMsg == false) {
|
|
180
|
+
return 'return'; // 如果动态消息构建失败或内部资源获取失败,则直接返回
|
|
180
181
|
}
|
|
181
182
|
if (weiboConfigData.banWords.length > 0) {
|
|
182
|
-
const banWords = new RegExp(weiboConfigData.banWords.join(
|
|
183
|
-
if (banWords.test(dynamicMsg.join(
|
|
184
|
-
return
|
|
183
|
+
const banWords = new RegExp(weiboConfigData.banWords.join('|'), 'g'); // 构建屏蔽关键字正则表达式
|
|
184
|
+
if (banWords.test(dynamicMsg.join(''))) {
|
|
185
|
+
return 'return'; // 如果动态消息包含屏蔽关键字,则直接返回
|
|
185
186
|
}
|
|
186
187
|
}
|
|
187
188
|
await this.sendMessage(chatId, bot_id, chatType, dynamicMsg);
|
|
188
|
-
await new Promise(
|
|
189
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
189
190
|
}
|
|
190
191
|
}
|
|
191
192
|
/**
|
|
@@ -196,10 +197,10 @@ class WeiboTask {
|
|
|
196
197
|
* @returns 渲染数据
|
|
197
198
|
*/
|
|
198
199
|
buildRenderData(extentData, urlQrcodeData, boxGrid) {
|
|
199
|
-
if (extentData.orig &&
|
|
200
|
+
if (extentData.orig && extentData.orig.length !== 0) {
|
|
200
201
|
return {
|
|
201
202
|
data: {
|
|
202
|
-
appName:
|
|
203
|
+
appName: 'weibo',
|
|
203
204
|
boxGrid: boxGrid,
|
|
204
205
|
type: extentData?.type,
|
|
205
206
|
face: extentData?.face,
|
|
@@ -222,7 +223,7 @@ class WeiboTask {
|
|
|
222
223
|
title: extentData?.orig?.data?.title,
|
|
223
224
|
content: extentData?.orig?.data?.content,
|
|
224
225
|
pics: extentData?.orig?.data?.pics,
|
|
225
|
-
category: extentData?.orig?.data?.category
|
|
226
|
+
category: extentData?.orig?.data?.category
|
|
226
227
|
}
|
|
227
228
|
}
|
|
228
229
|
}
|
|
@@ -231,7 +232,7 @@ class WeiboTask {
|
|
|
231
232
|
else {
|
|
232
233
|
return {
|
|
233
234
|
data: {
|
|
234
|
-
appName:
|
|
235
|
+
appName: 'weibo',
|
|
235
236
|
boxGrid: boxGrid,
|
|
236
237
|
type: extentData?.type,
|
|
237
238
|
face: extentData?.face,
|
|
@@ -243,7 +244,7 @@ class WeiboTask {
|
|
|
243
244
|
urlImgData: urlQrcodeData,
|
|
244
245
|
created: extentData?.created,
|
|
245
246
|
pics: extentData?.pics,
|
|
246
|
-
category: extentData?.category
|
|
247
|
+
category: extentData?.category
|
|
247
248
|
}
|
|
248
249
|
};
|
|
249
250
|
}
|
|
@@ -256,7 +257,7 @@ class WeiboTask {
|
|
|
256
257
|
* @returns 图片数据
|
|
257
258
|
*/
|
|
258
259
|
async renderDynamicCard(uid, renderData, ScreenshotOptionsData) {
|
|
259
|
-
const dynamicMsg = await renderPage(uid,
|
|
260
|
+
const dynamicMsg = await renderPage(uid, 'MainPage', renderData, ScreenshotOptionsData); // 渲染动态卡片
|
|
260
261
|
if (dynamicMsg !== false) {
|
|
261
262
|
return dynamicMsg.img; // 缓存图片数据
|
|
262
263
|
}
|
|
@@ -272,15 +273,19 @@ class WeiboTask {
|
|
|
272
273
|
* @param message 消息内容
|
|
273
274
|
*/
|
|
274
275
|
async sendMessage(chatId, bot_id, chatType, message) {
|
|
275
|
-
if (chatType ===
|
|
276
|
-
await (Bot[bot_id] ?? Bot)
|
|
277
|
-
|
|
276
|
+
if (chatType === 'group') {
|
|
277
|
+
await (Bot[bot_id] ?? Bot)
|
|
278
|
+
?.pickGroup(String(chatId))
|
|
279
|
+
.sendMsg(message) // 发送群聊
|
|
280
|
+
.catch(error => {
|
|
278
281
|
(logger ?? Bot.logger)?.error(`群组[${chatId}]推送失败:${JSON.stringify(error)}`);
|
|
279
282
|
});
|
|
280
283
|
}
|
|
281
|
-
else if (chatType ===
|
|
282
|
-
await (Bot[bot_id] ?? Bot)
|
|
283
|
-
|
|
284
|
+
else if (chatType === 'private') {
|
|
285
|
+
await (Bot[bot_id] ?? Bot)
|
|
286
|
+
?.pickFriend(String(chatId))
|
|
287
|
+
.sendMsg(message)
|
|
288
|
+
.catch(error => {
|
|
284
289
|
(logger ?? Bot.logger)?.error(`用户[${chatId}]推送失败:${JSON.stringify(error)}`);
|
|
285
290
|
}); // 发送好友私聊
|
|
286
291
|
}
|
|
@@ -291,7 +296,7 @@ class WeiboTask {
|
|
|
291
296
|
* @param max 最大延时时间
|
|
292
297
|
*/
|
|
293
298
|
async randomDelay(min, max) {
|
|
294
|
-
await new Promise(
|
|
299
|
+
await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * (max - min + 1) + min)));
|
|
295
300
|
}
|
|
296
301
|
}
|
|
297
302
|
|
package/lib/utils/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import chokidar from
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
2
|
/**
|
|
3
3
|
* Config 类用于管理配置文件的读取和监听
|
|
4
4
|
*/
|
|
@@ -66,7 +66,7 @@ declare class Config {
|
|
|
66
66
|
/** 读取package.json文件,获取指定key的值
|
|
67
67
|
* @param keyName 要获取的key名称
|
|
68
68
|
* @param path package.json文件路径
|
|
69
|
-
|
|
69
|
+
*/
|
|
70
70
|
getPackageJsonKey(keyName: string, path: string): string | null;
|
|
71
71
|
}
|
|
72
72
|
declare const _default: Config;
|
package/lib/utils/config.js
CHANGED
|
@@ -71,7 +71,7 @@ class Config {
|
|
|
71
71
|
const key = `${typeDir}_${appDir}_${functionName}`;
|
|
72
72
|
if (this[key])
|
|
73
73
|
return this[key];
|
|
74
|
-
this[key] = YAML.parse(fs.readFileSync(configFilePath,
|
|
74
|
+
this[key] = YAML.parse(fs.readFileSync(configFilePath, 'utf8'));
|
|
75
75
|
this.watch(configFilePath, typeDir, appDir, functionName);
|
|
76
76
|
return this[key];
|
|
77
77
|
}
|
|
@@ -83,7 +83,7 @@ class Config {
|
|
|
83
83
|
* @returns {string} 配置文件路径
|
|
84
84
|
*/
|
|
85
85
|
getConfigFilePath(typeDir, appDir, functionName) {
|
|
86
|
-
if (typeDir ===
|
|
86
|
+
if (typeDir === 'defaultConfig') {
|
|
87
87
|
return path.join(_paths.pluginPath, `${typeDir}`, `${appDir}`, `${functionName}.yaml`);
|
|
88
88
|
}
|
|
89
89
|
else {
|
|
@@ -102,7 +102,7 @@ class Config {
|
|
|
102
102
|
if (this.watcher[key])
|
|
103
103
|
return;
|
|
104
104
|
const watcher = chokidar.watch(configFilePath);
|
|
105
|
-
watcher.on(
|
|
105
|
+
watcher.on('change', () => {
|
|
106
106
|
delete this[key];
|
|
107
107
|
logger.mark(`[修改配置文件][${typeDir}][${appDir}][${functionName}]`);
|
|
108
108
|
if (this[`change_${appDir}${functionName}`]) {
|
|
@@ -117,7 +117,7 @@ class Config {
|
|
|
117
117
|
* @param functionName 配置文件名称,不包含.yaml后缀
|
|
118
118
|
*/
|
|
119
119
|
getDefaultConfig(appDir, functionName) {
|
|
120
|
-
return this.getConfigData(
|
|
120
|
+
return this.getConfigData('defaultConfig', appDir, functionName);
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
123
|
* 获取用户配置
|
|
@@ -125,7 +125,7 @@ class Config {
|
|
|
125
125
|
* @param functionName 配置文件名称,不包含.yaml后缀
|
|
126
126
|
*/
|
|
127
127
|
getUserConfig(appDir, functionName) {
|
|
128
|
-
const userConfigData = this.getConfigData(
|
|
128
|
+
const userConfigData = this.getConfigData('config', appDir, functionName);
|
|
129
129
|
const defaultConfigData = this.getDefaultConfig(appDir, functionName);
|
|
130
130
|
return lodash.merge({}, defaultConfigData, userConfigData);
|
|
131
131
|
}
|
|
@@ -143,7 +143,7 @@ class Config {
|
|
|
143
143
|
}
|
|
144
144
|
else {
|
|
145
145
|
const yamlContent = YAML.stringify(data);
|
|
146
|
-
fs.writeFileSync(filePath, yamlContent,
|
|
146
|
+
fs.writeFileSync(filePath, yamlContent, 'utf8');
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
/**
|
|
@@ -156,12 +156,12 @@ class Config {
|
|
|
156
156
|
updateConfigItem(appDir, functionName, key, value) {
|
|
157
157
|
const config = this.getUserConfig(appDir, functionName);
|
|
158
158
|
config[key] = value; // 更新配置项
|
|
159
|
-
this.saveConfig(
|
|
159
|
+
this.saveConfig('config', appDir, functionName, config); // 保存更新后的配置
|
|
160
160
|
}
|
|
161
161
|
/** 读取package.json文件,获取指定key的值
|
|
162
162
|
* @param keyName 要获取的key名称
|
|
163
163
|
* @param path package.json文件路径
|
|
164
|
-
|
|
164
|
+
*/
|
|
165
165
|
getPackageJsonKey(keyName, path) {
|
|
166
166
|
try {
|
|
167
167
|
const content = fs.readFileSync(path, 'utf-8');
|
package/lib/utils/paths.js
CHANGED
|
@@ -12,7 +12,7 @@ const _paths = {
|
|
|
12
12
|
botTempPath: join(_path, 'temp'), // Bot缓存目录
|
|
13
13
|
pluginPath, // yuki-plugin根目录
|
|
14
14
|
pluginResources: join(pluginPath, 'resources'), // yuki-plugin资源目录
|
|
15
|
-
pluginName
|
|
15
|
+
pluginName // 插件所在文件夹名称
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
18
|
* 使用import.meta.url得到require
|