yz-yuki-plugin 2.0.6-0 → 2.0.6-1
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/defaultConfig/bilibili/config.yaml +3 -0
- package/defaultConfig/weibo/config.yaml +3 -0
- package/lib/apps/bilibili.js +27 -23
- package/lib/models/bilibili/bilibili.main.models.js +18 -13
- package/lib/models/bilibili/bilibili.main.query.js +90 -69
- package/lib/models/bilibili/bilibili.main.task.js +31 -14
- package/lib/models/weibo/weibo.get.web.data.js +1 -2
- package/lib/models/weibo/weibo.query.js +2 -2
- package/lib/models/weibo/weibo.task.js +22 -13
- package/lib/utils/config.js +1 -1
- package/lib/utils/image.js +1 -1
- package/lib/utils/puppeteer.render.js +2 -0
- package/package.json +3 -2
package/lib/apps/bilibili.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import JSON from 'json5';
|
|
2
2
|
import lodash from 'lodash';
|
|
3
|
-
import { Messages,
|
|
3
|
+
import { Messages, Redis } from 'yunzaijs';
|
|
4
4
|
import { BiliQuery } from '../models/bilibili/bilibili.main.query.js';
|
|
5
5
|
import { BiliTask } from '../models/bilibili/bilibili.main.task.js';
|
|
6
6
|
import Config from '../utils/config.js';
|
|
@@ -63,7 +63,7 @@ message.use(async (e) => {
|
|
|
63
63
|
logger.mark(`yuki-plugin addDynamicSub Failed:${JSON.stringify(res.data)}`);
|
|
64
64
|
}
|
|
65
65
|
const { has_more, items } = data || {};
|
|
66
|
-
let infoName;
|
|
66
|
+
let infoName = '';
|
|
67
67
|
if (code === 0 && has_more === false) {
|
|
68
68
|
e.reply(`检测到该uid的主页空间动态内容为空,\n执行uid:${uid} 校验...`);
|
|
69
69
|
const resp = await new BiliGetWebData(e).getBilibiUserInfoByUid(uid);
|
|
@@ -87,7 +87,7 @@ message.use(async (e) => {
|
|
|
87
87
|
e.reply(`昵称:${infoName} \nuid:${uid} 校验成功!`);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
let name;
|
|
90
|
+
let name = '';
|
|
91
91
|
if (Array.isArray(items)) {
|
|
92
92
|
if (items.length > 0) {
|
|
93
93
|
name = items[0].modules?.module_author?.name || uid;
|
|
@@ -170,27 +170,31 @@ message.use(async (e) => {
|
|
|
170
170
|
if (e.isMaster) {
|
|
171
171
|
try {
|
|
172
172
|
const token = await applyLoginQRCode(e);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
173
|
+
if (token) {
|
|
174
|
+
let biliLoginCk = await pollLoginQRCode(e, token);
|
|
175
|
+
if (biliLoginCk) {
|
|
176
|
+
if (lodash.trim(biliLoginCk).length != 0) {
|
|
177
|
+
await saveLoginCookie(e, biliLoginCk);
|
|
178
|
+
e.reply(`get bilibili LoginCk:成功!`);
|
|
179
|
+
const result = await postGateway(biliLoginCk); //激活ck
|
|
180
|
+
const { code, data } = await result.data; // 解析校验结果
|
|
181
|
+
switch (code) {
|
|
182
|
+
case 0:
|
|
183
|
+
global?.logger?.mark(`优纪插件:获取biliLoginCK,Gateway校验成功:${JSON.stringify(data)}`);
|
|
184
|
+
break;
|
|
185
|
+
default:
|
|
186
|
+
global?.logger?.mark(`优纪插件:获取biliLoginCK,Gateway校验失败:${JSON.stringify(data)}`);
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
e.reply(`get bilibili LoginCk:失败X﹏X`);
|
|
192
|
+
}
|
|
186
193
|
}
|
|
187
194
|
}
|
|
188
|
-
else {
|
|
189
|
-
e.reply(`get bilibili LoginCk:失败X﹏X`);
|
|
190
|
-
}
|
|
191
195
|
}
|
|
192
196
|
catch (Error) {
|
|
193
|
-
|
|
197
|
+
global?.logger?.info(`yuki-plugin Login bilibili Failed:${Error}`);
|
|
194
198
|
}
|
|
195
199
|
}
|
|
196
200
|
else {
|
|
@@ -263,10 +267,10 @@ message.use(async (e) => {
|
|
|
263
267
|
const { code, data } = await result.data; // 解析校验结果
|
|
264
268
|
switch (code) {
|
|
265
269
|
case 0:
|
|
266
|
-
|
|
270
|
+
global?.logger?.mark(`优纪插件:绑定localCK,Gateway校验成功:${JSON.stringify(data)}`);
|
|
267
271
|
break;
|
|
268
272
|
default:
|
|
269
|
-
|
|
273
|
+
global?.logger?.mark(`优纪插件:绑定localCK,Gateway校验失败:${JSON.stringify(data)}`);
|
|
270
274
|
break;
|
|
271
275
|
}
|
|
272
276
|
}
|
|
@@ -336,7 +340,7 @@ message.use(async (e) => {
|
|
|
336
340
|
}
|
|
337
341
|
catch (error) {
|
|
338
342
|
e.reply(`~yuki-plugin:\n临时b站ck刷新失败X﹏X\n请重启bot(手动或发送指令 #重启)后重试`);
|
|
339
|
-
|
|
343
|
+
global?.logger?.mark(`优纪插件:B站临时ck刷新error:${error}`);
|
|
340
344
|
}
|
|
341
345
|
}, [/^(#|\/)(yuki|优纪)?刷新(b站|B站|bili|bilibili|哔哩|哔哩哔哩)临时(ck|CK|cookie|COOKIE)$/]);
|
|
342
346
|
/** 订阅的全部b站推送列表 */
|
|
@@ -6,7 +6,7 @@ import { promisify } from 'node:util';
|
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import QRCode from 'qrcode';
|
|
8
8
|
import YAML from 'yaml';
|
|
9
|
-
import { Segment,
|
|
9
|
+
import { Segment, Redis } from 'yunzaijs';
|
|
10
10
|
import { renderPage } from '../../utils/image.js';
|
|
11
11
|
import { _paths } from '../../utils/paths.js';
|
|
12
12
|
import BiliApi from './bilibili.main.api.js';
|
|
@@ -29,10 +29,10 @@ async function applyLoginQRCode(e) {
|
|
|
29
29
|
if (!response.ok) {
|
|
30
30
|
throw new Error(`获取B站登录二维码URL网络请求失败,状态码: ${response.status}`);
|
|
31
31
|
}
|
|
32
|
-
const res = await response.json();
|
|
32
|
+
const res = (await response.json());
|
|
33
33
|
if (res?.code === 0) {
|
|
34
|
-
const qrcodeKey = res
|
|
35
|
-
const qrcodeUrl = res
|
|
34
|
+
const qrcodeKey = res?.data?.qrcode_key;
|
|
35
|
+
const qrcodeUrl = res?.data?.url;
|
|
36
36
|
let loginUrlQrcodeData = await QRCode.toDataURL(`${qrcodeUrl}`);
|
|
37
37
|
const LoginPropsData = {
|
|
38
38
|
data: { url: loginUrlQrcodeData }
|
|
@@ -76,9 +76,9 @@ async function pollLoginQRCode(e, qrcodeKey) {
|
|
|
76
76
|
if (!response.ok) {
|
|
77
77
|
throw new Error(`处理B站登录token网络请求失败,状态码: ${response.status}`);
|
|
78
78
|
}
|
|
79
|
-
const data = await response.json();
|
|
79
|
+
const data = (await response.json());
|
|
80
80
|
if (data.code === 0) {
|
|
81
|
-
if (data
|
|
81
|
+
if (data?.data?.code === 0) {
|
|
82
82
|
// 登录成功,获取 cookie
|
|
83
83
|
const LoginCookie = response.headers.get('set-cookie');
|
|
84
84
|
let loginCk = '';
|
|
@@ -93,20 +93,20 @@ async function pollLoginQRCode(e, qrcodeKey) {
|
|
|
93
93
|
e.reply(`~B站登陆成功~`);
|
|
94
94
|
return loginCk;
|
|
95
95
|
}
|
|
96
|
-
else if (data
|
|
96
|
+
else if (data?.data?.code === 86101) {
|
|
97
97
|
// 未扫码
|
|
98
98
|
// 继续轮询
|
|
99
99
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
100
|
-
|
|
100
|
+
global?.logger?.mark(`优纪插件:扫码B站登录:未扫码,轮询中...`);
|
|
101
101
|
return pollLoginQRCode(e, qrcodeKey);
|
|
102
102
|
}
|
|
103
|
-
else if (data
|
|
103
|
+
else if (data?.data?.code === 86090) {
|
|
104
104
|
// 已扫码未确认
|
|
105
105
|
// 继续轮询
|
|
106
106
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
107
107
|
return pollLoginQRCode(e, qrcodeKey);
|
|
108
108
|
}
|
|
109
|
-
else if (data
|
|
109
|
+
else if (data?.data?.code === 86038) {
|
|
110
110
|
// 二维码已失效
|
|
111
111
|
e.reply('B站登陆二维码已失效');
|
|
112
112
|
return null;
|
|
@@ -135,7 +135,7 @@ async function checkBiliLogin(e) {
|
|
|
135
135
|
redirect: 'follow'
|
|
136
136
|
});
|
|
137
137
|
const resData = await res.json();
|
|
138
|
-
|
|
138
|
+
global?.logger?.debug(`B站验证登录状态:${JSON.stringify(resData)}`);
|
|
139
139
|
if (resData.code === 0) {
|
|
140
140
|
let uname = resData.data?.uname;
|
|
141
141
|
let mid = resData.data?.mid;
|
|
@@ -455,8 +455,13 @@ async function cookieWithBiliTicket(cookie) {
|
|
|
455
455
|
try {
|
|
456
456
|
const csrf = await readSavedCookieItems(cookie, ['bili_jct'], false);
|
|
457
457
|
const { ticket, ttl } = await getBiliTicket(csrf);
|
|
458
|
-
|
|
459
|
-
|
|
458
|
+
if (ticket && ttl) {
|
|
459
|
+
await Redis.set(BiliJctKey, ticket, { EX: ttl });
|
|
460
|
+
return cookie + `;bili_ticket=${ticket};`;
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
return cookie;
|
|
464
|
+
}
|
|
460
465
|
}
|
|
461
466
|
catch (error) {
|
|
462
467
|
logger?.error(`${error}`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import moment from 'moment';
|
|
2
|
-
import {
|
|
2
|
+
import { Segment } from 'yunzaijs';
|
|
3
3
|
import { readSyncCookie, cookieWithBiliTicket } from './bilibili.main.models.js';
|
|
4
4
|
import BiliApi from './bilibili.main.api.js';
|
|
5
5
|
import axios from 'axios';
|
|
@@ -100,30 +100,36 @@ class BiliQuery {
|
|
|
100
100
|
formatData.data.title = desc?.title;
|
|
101
101
|
// 文章内容过长,则尝试获取全文
|
|
102
102
|
if (desc?.summary?.text?.length >= 480) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
formatData.data.content = this.
|
|
109
|
-
formatData.data.
|
|
103
|
+
const fullArticleContent = await this.getFullArticleContent(this.formatUrl(desc?.jump_url));
|
|
104
|
+
if (fullArticleContent) {
|
|
105
|
+
const { readInfo, articleType } = fullArticleContent;
|
|
106
|
+
// 文章链接类型为 cv(旧类型) 或者 opus(新类型)
|
|
107
|
+
if (articleType === 'cv') {
|
|
108
|
+
formatData.data.content = this.praseFullOldTypeArticleContent(readInfo?.content);
|
|
109
|
+
if (String(formatData.data.content).length < 100) {
|
|
110
|
+
formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text) || '';
|
|
111
|
+
formatData.data.pics = pics;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
formatData.data.pics = [];
|
|
115
|
+
}
|
|
110
116
|
}
|
|
111
|
-
else {
|
|
112
|
-
|
|
117
|
+
else if (articleType === 'opus') {
|
|
118
|
+
const FullNewTypeArticleContent = this.praseFullNewTypeArticleContent(readInfo?.paragraphs);
|
|
119
|
+
if (FullNewTypeArticleContent) {
|
|
120
|
+
const { content, img } = FullNewTypeArticleContent;
|
|
121
|
+
formatData.data.content = content;
|
|
122
|
+
formatData.data.pics = img && img.length > 0 ? img : pics;
|
|
123
|
+
if (content && content.length < 100) {
|
|
124
|
+
formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
113
127
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
formatData.data.content = content;
|
|
118
|
-
formatData.data.pics = img && img.length > 0 ? img : pics;
|
|
119
|
-
if (content && content.length < 100) {
|
|
120
|
-
formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text);
|
|
128
|
+
else {
|
|
129
|
+
formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text) || '';
|
|
130
|
+
formatData.data.pics = pics;
|
|
121
131
|
}
|
|
122
132
|
}
|
|
123
|
-
else {
|
|
124
|
-
formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text) || '';
|
|
125
|
-
formatData.data.pics = pics;
|
|
126
|
-
}
|
|
127
133
|
}
|
|
128
134
|
else {
|
|
129
135
|
formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text) || '';
|
|
@@ -208,7 +214,7 @@ class BiliQuery {
|
|
|
208
214
|
return `<span class="bili-rich-text-module topic" href="${jumpUrl}">${node?.text}</span>`;
|
|
209
215
|
case 'RICH_TEXT_NODE_TYPE_TEXT':
|
|
210
216
|
// 正文将 \n 替换为 <br> 以实现换行
|
|
211
|
-
return node
|
|
217
|
+
return node?.text?.replace(/\n/g, '<br>') || '';
|
|
212
218
|
case 'RICH_TEXT_NODE_TYPE_AT':
|
|
213
219
|
// 处理 @ 类型,使用官方的HTML标签写法
|
|
214
220
|
return `<span data-module="desc" data-type="at" data-oid="${node?.rid}" class="bili-rich-text-module at">${node?.text}</span>`;
|
|
@@ -287,8 +293,19 @@ class BiliQuery {
|
|
|
287
293
|
});
|
|
288
294
|
return content;
|
|
289
295
|
}
|
|
290
|
-
|
|
291
|
-
*
|
|
296
|
+
/**
|
|
297
|
+
* 解析新版完整文章内容,将其转换为HTML格式的正文和图片数组。
|
|
298
|
+
* 该方法处理的是 MODULE_TYPE_CONTENT 类型的文章,文章内容由多个段落组成。
|
|
299
|
+
* 每个段落可能包含不同类型的内容,如正文、图片、链接、表情等。
|
|
300
|
+
*
|
|
301
|
+
* @param paragraphs - MODULE_TYPE_CONTENT 类型文章的段落数组,每个段落是一个对象。
|
|
302
|
+
* 每个段落对象包含一个 para_type 属性,用于标识段落类型(1表示正文,2表示图片)。
|
|
303
|
+
* 正文段落中可能包含多个 nodes,每个 node 表示一段文本或一个富文本元素。
|
|
304
|
+
* 图片段落中包含一个 pic 对象,其中 pics 是图片信息的数组。
|
|
305
|
+
* @returns 返回一个对象,包含两个属性:
|
|
306
|
+
* - content: string 类型,解析后的HTML格式的正文字符串。
|
|
307
|
+
* - img: array 类型,包含图片信息的对象数组,每个对象有 url、width 和 height 属性。
|
|
308
|
+
* 如果输入的 paragraphs 不是数组,则返回 null。
|
|
292
309
|
*/
|
|
293
310
|
static praseFullNewTypeArticleContent = (paragraphs) => {
|
|
294
311
|
if (Array.isArray(paragraphs)) {
|
|
@@ -300,54 +317,58 @@ class BiliQuery {
|
|
|
300
317
|
switch (item.para_type) {
|
|
301
318
|
case 1:
|
|
302
319
|
// 处理正文
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
jumpUrl
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
320
|
+
if (item.text?.nodes) {
|
|
321
|
+
content += item.text.nodes
|
|
322
|
+
.map((node) => {
|
|
323
|
+
let nodeType = node.type;
|
|
324
|
+
if (nodeType === 'TEXT_NODE_TYPE_RICH') {
|
|
325
|
+
let richType = node?.rich?.type;
|
|
326
|
+
switch (richType) {
|
|
327
|
+
case 'RICH_TEXT_NODE_TYPE_TOPIC':
|
|
328
|
+
// 确保链接以 https:// 开头
|
|
329
|
+
let jumpUrl = node?.rich?.jump_url;
|
|
330
|
+
if (jumpUrl && !jumpUrl.startsWith('http://') && !jumpUrl.startsWith('https://')) {
|
|
331
|
+
jumpUrl = `https://${jumpUrl}`;
|
|
332
|
+
}
|
|
333
|
+
return `<span class="bili-rich-text-module topic" href="${jumpUrl}">${node?.rich?.text}</span>`;
|
|
334
|
+
case 'RICH_TEXT_NODE_TYPE_TEXT':
|
|
335
|
+
// 正文将 \n 替换为 <br> 以实现换行
|
|
336
|
+
return node?.rich?.text.replace(/\n/g, '<br>');
|
|
337
|
+
case 'RICH_TEXT_NODE_TYPE_AT':
|
|
338
|
+
// 处理 @ 类型,使用官方的HTML标签写法
|
|
339
|
+
return `<span data-module="desc" data-type="at" data-oid="${node?.rich?.rid}" class="bili-rich-text-module at">${node?.rich?.text}</span>`;
|
|
340
|
+
case 'RICH_TEXT_NODE_TYPE_LOTTERY':
|
|
341
|
+
// 处理互动抽奖类型,使用官方的HTML标签写法
|
|
342
|
+
return `<span data-module="desc" data-type="lottery" data-oid="${node?.rich?.rid}" class="bili-rich-text-module lottery">${node?.rich?.text}</span>`;
|
|
343
|
+
case 'RICH_TEXT_NODE_TYPE_WEB':
|
|
344
|
+
// 处理 RICH_TEXT_NODE_TYPE_WEB 类型,直接拼接 text 属性
|
|
345
|
+
return node?.rich?.text;
|
|
346
|
+
case 'RICH_TEXT_NODE_TYPE_EMOJI':
|
|
347
|
+
// 处理表情类型,使用 img 标签显示表情
|
|
348
|
+
const emoji = node?.rich?.emoji;
|
|
349
|
+
return `<img src="${emoji?.icon_url}" alt="${emoji?.text}" title="${emoji?.text}" style="vertical-align: middle; width: ${emoji?.size}em; height: ${emoji?.size}em;">`;
|
|
350
|
+
case 'RICH_TEXT_NODE_TYPE_GOODS':
|
|
351
|
+
// 处理商品推广类型,使用官方的HTML标签写法
|
|
352
|
+
const goods_url = node?.rich?.jump_url;
|
|
353
|
+
return `<span data-module="desc" data-type="goods" data-url="${goods_url}" data-oid="${node?.rich?.rid}" class="bili-rich-text-module goods ${node?.rich?.icon_name}">​${node?.rich?.text}</span>`;
|
|
354
|
+
default:
|
|
355
|
+
return node;
|
|
356
|
+
}
|
|
338
357
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
358
|
+
else if (nodeType === 'TEXT_NODE_TYPE_WORD') {
|
|
359
|
+
return `${node?.word?.words}<br>`;
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
.join('');
|
|
363
|
+
}
|
|
345
364
|
break;
|
|
346
365
|
case 2:
|
|
347
366
|
// 处理图片
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
367
|
+
if (item?.pic?.pics) {
|
|
368
|
+
img = img.concat(item?.pic?.pics.map((item) => {
|
|
369
|
+
return { url: item?.url, width: item?.width, height: item?.height };
|
|
370
|
+
}) || []);
|
|
371
|
+
}
|
|
351
372
|
break;
|
|
352
373
|
}
|
|
353
374
|
});
|
|
@@ -556,7 +577,7 @@ class BiliQuery {
|
|
|
556
577
|
return { msg, pics };
|
|
557
578
|
default:
|
|
558
579
|
// 处理未定义的动态类型
|
|
559
|
-
|
|
580
|
+
global?.logger?.mark(`未处理的B站推送【${upName}】:${data.type}`);
|
|
560
581
|
return 'continue';
|
|
561
582
|
}
|
|
562
583
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import QRCode from 'qrcode';
|
|
2
|
-
import { Redis,
|
|
2
|
+
import { Redis, Segment, Bot } from 'yunzaijs';
|
|
3
3
|
import Config from '../../utils/config.js';
|
|
4
4
|
import { renderPage } from '../../utils/image.js';
|
|
5
5
|
import { BiliGetWebData } from './bilibili.main.get.web.data.js';
|
|
@@ -59,6 +59,8 @@ class BiliTask {
|
|
|
59
59
|
uidMap.set(chatType, new Map());
|
|
60
60
|
}
|
|
61
61
|
const chatTypeMap = uidMap.get(chatType); // 建立当前 chatType (group 或 private) 的 uid 映射
|
|
62
|
+
if (chatTypeMap === undefined)
|
|
63
|
+
continue; // 如果 chatTypeMap 未定义,跳过此次循环
|
|
62
64
|
for (let chatId in biliPushData[chatType]) {
|
|
63
65
|
const subUpsOfChat = Array.prototype.slice.call(biliPushData[chatType][chatId] || []);
|
|
64
66
|
for (let subInfoOfup of subUpsOfChat) {
|
|
@@ -148,10 +150,18 @@ class BiliTask {
|
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
}
|
|
151
|
-
|
|
153
|
+
/**
|
|
154
|
+
* 发送动态消息
|
|
155
|
+
* @param chatId 聊天 ID
|
|
156
|
+
* @param bot_id 机器人 ID
|
|
157
|
+
* @param upName 用户名
|
|
158
|
+
* @param pushDynamicData 推送动态数据
|
|
159
|
+
* @param biliConfigData 哔哩配置数据
|
|
160
|
+
* @param chatType 聊天类型
|
|
161
|
+
*/
|
|
152
162
|
async sendDynamic(chatId, bot_id, upName, pushDynamicData, biliConfigData, chatType) {
|
|
153
163
|
const id_str = pushDynamicData.id_str;
|
|
154
|
-
let sended, markKey;
|
|
164
|
+
let sended = null, markKey = '';
|
|
155
165
|
if (chatType === 'group') {
|
|
156
166
|
markKey = this.groupKey;
|
|
157
167
|
sended = await Redis.get(`${markKey}${chatId}:${id_str}`);
|
|
@@ -192,7 +202,7 @@ class BiliTask {
|
|
|
192
202
|
if (!imgs)
|
|
193
203
|
return;
|
|
194
204
|
Redis.set(`${markKey}${chatId}:${id_str}`, '1', { EX: 3600 * 72 }); // 设置已发送标记
|
|
195
|
-
|
|
205
|
+
logger?.mark('优纪插件:B站动态执行推送');
|
|
196
206
|
for (let i = 0; i < imgs.length; i++) {
|
|
197
207
|
const image = imgs[i];
|
|
198
208
|
await this.sendMessage(chatId, bot_id, chatType, Segment.image(image));
|
|
@@ -203,7 +213,7 @@ class BiliTask {
|
|
|
203
213
|
else {
|
|
204
214
|
const dynamicMsg = await BiliQuery.formatTextDynamicData(upName, pushDynamicData, false, biliConfigData); // 构建图文动态消息
|
|
205
215
|
Redis.set(`${markKey}${chatId}:${id_str}`, '1', { EX: 3600 * 72 }); // 设置已发送标记
|
|
206
|
-
if (dynamicMsg
|
|
216
|
+
if (dynamicMsg === undefined || dynamicMsg === 'continue') {
|
|
207
217
|
return 'return'; // 如果动态消息构建失败,则直接返回
|
|
208
218
|
}
|
|
209
219
|
if (biliConfigData.banWords.length > 0) {
|
|
@@ -212,15 +222,22 @@ class BiliTask {
|
|
|
212
222
|
return 'return'; // 如果动态消息包含屏蔽关键字,则直接返回
|
|
213
223
|
}
|
|
214
224
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
225
|
+
let mergeTextPic = !!biliConfigData.mergeTextPic === false ? false : true; // 是否合并文本和图片,默认为 true
|
|
226
|
+
if (mergeTextPic) {
|
|
227
|
+
const mergeMsg = [...dynamicMsg.msg, ...dynamicMsg.pics];
|
|
228
|
+
await this.sendMessage(chatId, bot_id, chatType, mergeMsg);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
await this.sendMessage(chatId, bot_id, chatType, dynamicMsg.msg);
|
|
232
|
+
const pics = dynamicMsg.pics;
|
|
233
|
+
if (pics && pics.length > 0) {
|
|
234
|
+
for (let i = 0; i < pics.length; i++) {
|
|
235
|
+
await this.sendMessage(chatId, bot_id, chatType, pics[i]);
|
|
236
|
+
await this.randomDelay(1000, 2000); // 随机延时1-2秒
|
|
237
|
+
}
|
|
221
238
|
}
|
|
239
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
222
240
|
}
|
|
223
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
224
241
|
}
|
|
225
242
|
}
|
|
226
243
|
/**
|
|
@@ -312,7 +329,7 @@ class BiliTask {
|
|
|
312
329
|
?.pickGroup(String(chatId))
|
|
313
330
|
.sendMsg(message) // 发送群聊
|
|
314
331
|
.catch((error) => {
|
|
315
|
-
|
|
332
|
+
global?.logger?.error(`群组[${chatId}]推送失败:${JSON.stringify(error)}`);
|
|
316
333
|
});
|
|
317
334
|
}
|
|
318
335
|
else if (chatType === 'private') {
|
|
@@ -320,7 +337,7 @@ class BiliTask {
|
|
|
320
337
|
?.pickFriend(String(chatId))
|
|
321
338
|
.sendMsg(message)
|
|
322
339
|
.catch((error) => {
|
|
323
|
-
|
|
340
|
+
global?.logger?.error(`用户[${chatId}]推送失败:${JSON.stringify(error)}`);
|
|
324
341
|
}); // 发送好友私聊
|
|
325
342
|
}
|
|
326
343
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import { Bot } from 'yunzaijs';
|
|
3
2
|
import { WeiboApi } from './weibo.api.js';
|
|
4
3
|
import { WeiboQuery } from './weibo.query.js';
|
|
5
4
|
|
|
@@ -48,7 +47,7 @@ class WeiboGetWebData {
|
|
|
48
47
|
return data.cards.filter(WeiboQuery.filterCardTypeCustom);
|
|
49
48
|
}
|
|
50
49
|
catch (error) {
|
|
51
|
-
|
|
50
|
+
global?.logger?.mark('微博推送:Error fetching sub list:', error);
|
|
52
51
|
return [];
|
|
53
52
|
}
|
|
54
53
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import moment from 'moment';
|
|
2
2
|
import fetch from 'node-fetch';
|
|
3
3
|
import { WeiboApi } from './weibo.api.js';
|
|
4
|
-
import {
|
|
4
|
+
import { Segment } from 'yunzaijs';
|
|
5
5
|
import { JSDOM } from 'jsdom';
|
|
6
6
|
|
|
7
7
|
class WeiboQuery {
|
|
@@ -195,7 +195,7 @@ class WeiboQuery {
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
catch (err) {
|
|
198
|
-
|
|
198
|
+
global?.logger?.mark(`优纪插件:获取微博动态全文出错:https://m.weibo.cn/detail/${info?.mid}`);
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
/**动态发布时间 */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import QRCode from 'qrcode';
|
|
2
|
-
import { Redis,
|
|
2
|
+
import { Redis, Segment, Bot } from 'yunzaijs';
|
|
3
3
|
import Config from '../../utils/config.js';
|
|
4
4
|
import { renderPage } from '../../utils/image.js';
|
|
5
5
|
import { WeiboGetWebData } from './weibo.get.web.data.js';
|
|
@@ -39,6 +39,8 @@ class WeiboTask {
|
|
|
39
39
|
uidMap.set(chatType, new Map());
|
|
40
40
|
}
|
|
41
41
|
const chatTypeMap = uidMap.get(chatType); // 建立当前 chatType (group 或 private) 的 uid 映射
|
|
42
|
+
if (chatTypeMap === undefined)
|
|
43
|
+
continue; // 如果 chatTypeMap 未定义,跳过此次循环
|
|
42
44
|
for (let chatId in weiboPushData[chatType]) {
|
|
43
45
|
const subUpsOfChat = Array.prototype.slice.call(weiboPushData[chatType][chatId] || []);
|
|
44
46
|
for (let subInfoOfup of subUpsOfChat) {
|
|
@@ -126,7 +128,7 @@ class WeiboTask {
|
|
|
126
128
|
*/
|
|
127
129
|
async sendDynamic(chatId, bot_id, upName, pushDynamicData, weiboConfigData, chatType) {
|
|
128
130
|
const id_str = WeiboQuery.getDynamicId(pushDynamicData); // 获取动态 ID
|
|
129
|
-
let sended, markKey;
|
|
131
|
+
let sended = null, markKey = '';
|
|
130
132
|
if (chatType === 'group') {
|
|
131
133
|
markKey = this.groupKey;
|
|
132
134
|
sended = await Redis.get(`${markKey}${chatId}:${id_str}`);
|
|
@@ -167,7 +169,7 @@ class WeiboTask {
|
|
|
167
169
|
if (!imgs)
|
|
168
170
|
return;
|
|
169
171
|
Redis.set(`${markKey}${chatId}:${id_str}`, '1', { EX: 3600 * 72 }); // 设置已发送标记
|
|
170
|
-
|
|
172
|
+
global?.logger?.mark('优纪插件:微博动态执行推送');
|
|
171
173
|
for (let i = 0; i < imgs.length; i++) {
|
|
172
174
|
const image = imgs[i];
|
|
173
175
|
await this.sendMessage(chatId, bot_id, chatType, Segment.image(image));
|
|
@@ -178,7 +180,7 @@ class WeiboTask {
|
|
|
178
180
|
else {
|
|
179
181
|
const dynamicMsg = await WeiboQuery.formatTextDynamicData(upName, pushDynamicData, false, weiboConfigData); //构建文字动态消息
|
|
180
182
|
Redis.set(`${markKey}${chatId}:${id_str}`, '1', { EX: 3600 * 72 }); // 设置已发送标记
|
|
181
|
-
if (dynamicMsg
|
|
183
|
+
if (dynamicMsg === undefined || dynamicMsg === 'continue') {
|
|
182
184
|
return 'return'; // 如果动态消息构建失败或内部资源获取失败,则直接返回
|
|
183
185
|
}
|
|
184
186
|
if (weiboConfigData.banWords.length > 0) {
|
|
@@ -187,15 +189,22 @@ class WeiboTask {
|
|
|
187
189
|
return 'return'; // 如果动态消息包含屏蔽关键字,则直接返回
|
|
188
190
|
}
|
|
189
191
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
let mergeTextPic = !!weiboConfigData.mergeTextPic === false ? false : true; // 是否合并文字和图片,默认为 true
|
|
193
|
+
if (mergeTextPic) {
|
|
194
|
+
const mergeMsg = [...dynamicMsg.msg, ...dynamicMsg.pics];
|
|
195
|
+
await this.sendMessage(chatId, bot_id, chatType, mergeMsg);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
await this.sendMessage(chatId, bot_id, chatType, dynamicMsg.msg);
|
|
199
|
+
const pics = dynamicMsg.pics;
|
|
200
|
+
if (pics && pics.length > 0) {
|
|
201
|
+
for (let i = 0; i < pics.length; i++) {
|
|
202
|
+
await this.sendMessage(chatId, bot_id, chatType, pics[i]);
|
|
203
|
+
await this.randomDelay(1000, 2000); // 随机延时1-2秒
|
|
204
|
+
}
|
|
196
205
|
}
|
|
206
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
197
207
|
}
|
|
198
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
199
208
|
}
|
|
200
209
|
}
|
|
201
210
|
/**
|
|
@@ -287,7 +296,7 @@ class WeiboTask {
|
|
|
287
296
|
?.pickGroup(String(chatId))
|
|
288
297
|
.sendMsg(message) // 发送群聊
|
|
289
298
|
.catch(error => {
|
|
290
|
-
|
|
299
|
+
global?.logger?.error(`群组[${chatId}]推送失败:${JSON.stringify(error)}`);
|
|
291
300
|
});
|
|
292
301
|
}
|
|
293
302
|
else if (chatType === 'private') {
|
|
@@ -295,7 +304,7 @@ class WeiboTask {
|
|
|
295
304
|
?.pickFriend(String(chatId))
|
|
296
305
|
.sendMsg(message)
|
|
297
306
|
.catch(error => {
|
|
298
|
-
|
|
307
|
+
global?.logger?.error(`用户[${chatId}]推送失败:${JSON.stringify(error)}`);
|
|
299
308
|
}); // 发送好友私聊
|
|
300
309
|
}
|
|
301
310
|
}
|
package/lib/utils/config.js
CHANGED
package/lib/utils/image.js
CHANGED
|
@@ -47,6 +47,8 @@ class YukiPuppeteerRender {
|
|
|
47
47
|
await page.addStyleTag({ content: Options.addStyle });
|
|
48
48
|
}
|
|
49
49
|
const boundingBox = await element.boundingBox(); // 获取内容区域的边界框信息
|
|
50
|
+
if (!boundingBox)
|
|
51
|
+
return false;
|
|
50
52
|
const num = Options?.isSplit ? Math.ceil(boundingBox.height / pageHeight) : 1; // 根据是否需要分片,计算分片数量,默认为 1
|
|
51
53
|
pageHeight = Math.round(boundingBox.height / num); //动态调整分片高度,防止过短影响观感。
|
|
52
54
|
await page.setViewport({ width: boundingBox.width + 50, height: pageHeight + 100 });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yz-yuki-plugin",
|
|
3
|
-
"version": "2.0.6-
|
|
3
|
+
"version": "2.0.6-1",
|
|
4
4
|
"description": "优纪插件,yunzaijs 关于 微博推送、B站推送 等功能的拓展插件",
|
|
5
5
|
"author": "snowtafir",
|
|
6
6
|
"type": "module",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/chalk": "2.2.0",
|
|
49
|
+
"@types/chokidar": "2.1.7",
|
|
49
50
|
"@types/jsdom": "^21.1.7",
|
|
50
51
|
"@types/lodash": "^4.17.7",
|
|
51
52
|
"@types/md5": "^2.3.5",
|
|
@@ -63,7 +64,7 @@
|
|
|
63
64
|
"json5": "^2.2.3",
|
|
64
65
|
"jsxp": "^1.0.4",
|
|
65
66
|
"lodash": "^4.17.21",
|
|
66
|
-
"lvyjs": "^0.
|
|
67
|
+
"lvyjs": "^0.2.6",
|
|
67
68
|
"md5": "^2.3.0",
|
|
68
69
|
"node-fetch": "^3.3.2",
|
|
69
70
|
"postcss": "^8.4.47",
|