yz-yuki-plugin 2.0.6-1 → 2.0.6-11
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 +41 -1
- package/CHANGELOG.md +2 -0
- package/README.md +23 -0
- package/defaultConfig/bilibili/config.yaml +14 -1
- package/defaultConfig/weibo/config.yaml +1 -1
- package/lib/apps/weibo.js +4 -4
- package/lib/index.js +1 -1
- package/lib/models/bilibili/bilibili.main.query.js +8 -7
- package/lib/models/bilibili/bilibili.main.task.js +123 -34
- package/lib/models/bilibili/bilibili.risk.w_webid.js +6 -3
- package/lib/models/weibo/{weibo.get.web.data.js → weibo.main.get.web.data.js} +2 -2
- package/lib/models/weibo/{weibo.query.js → weibo.main.query.js} +13 -9
- package/lib/models/weibo/{weibo.task.js → weibo.main.task.js} +103 -34
- package/lib/utils/image.js +4 -4
- package/package.json +9 -8
- /package/lib/models/weibo/{weibo.api.js → weibo.main.api.js} +0 -0
package/.puppeteerrc.cjs
CHANGED
|
@@ -1,4 +1,44 @@
|
|
|
1
|
+
const os = require('os');
|
|
2
|
+
const { existsSync } = require('fs');
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const arch = os.arch();
|
|
5
|
+
|
|
6
|
+
let skipDownload = false;
|
|
7
|
+
let executablePath;
|
|
8
|
+
|
|
9
|
+
if (['linux', 'android'].includes(process.platform))
|
|
10
|
+
for (const item of ['chromium', 'chromium-browser', 'chrome', 'google-chrome'])
|
|
11
|
+
try {
|
|
12
|
+
const chromiumPath = execSync(`command -v ${item}`).toString().trim();
|
|
13
|
+
if (chromiumPath && existsSync(chromiumPath)) {
|
|
14
|
+
executablePath = chromiumPath;
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
} catch (err) {}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @type {string} 浏览器 "可执行文件路径" 列表,可根据需要自行修改或添加
|
|
21
|
+
*/
|
|
22
|
+
if (!executablePath)
|
|
23
|
+
for (const item of [
|
|
24
|
+
// Windows
|
|
25
|
+
'C:/Program Files/Google/Chrome/Application/chrome.exe',
|
|
26
|
+
'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe',
|
|
27
|
+
// macOS
|
|
28
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
29
|
+
'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge'
|
|
30
|
+
])
|
|
31
|
+
if (existsSync(item)) {
|
|
32
|
+
executablePath = item;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (executablePath || arch == 'arm64' || arch == 'aarch64') {
|
|
37
|
+
(typeof logger != 'undefined' ? logger : console).info(`[Chromium] ${executablePath}`);
|
|
38
|
+
skipDownload = true;
|
|
39
|
+
}
|
|
40
|
+
|
|
1
41
|
/**
|
|
2
42
|
* @type {import("puppeteer").Configuration}
|
|
3
43
|
*/
|
|
4
|
-
module.exports =
|
|
44
|
+
module.exports = { skipDownload, executablePath };
|
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -8,6 +8,29 @@
|
|
|
8
8
|
|
|
9
9
|
[](https://github.com/snowtafir/yuki-plugin)
|
|
10
10
|
|
|
11
|
+
|
|
12
|
+
# 🚩运行环境:
|
|
13
|
+
1. 系统:
|
|
14
|
+
* windows 10/11+,
|
|
15
|
+
* Linux推荐:CentOS Stream 8 +, Debian 12+, Fedora 35+
|
|
16
|
+
|
|
17
|
+
2. node v22+ 下载地址:https://nodejs.org/zh-cn/download/
|
|
18
|
+
|
|
19
|
+
3. 推荐使用chrome或chromium浏览器,其他浏览器可能存在兼容性问题。
|
|
20
|
+
* chrome 浏览器 v131+ win_x64下载地址:https://www.google.cn/chrome/
|
|
21
|
+
* chromium 浏览器 v128+ Linux/win手动下载安装:https://download-chromium.appspot.com
|
|
22
|
+
|
|
23
|
+
> linux命令行安装chromiun浏览器:
|
|
24
|
+
```sh
|
|
25
|
+
sudo apt-get install chromium-browser # Ubuntu/Debian
|
|
26
|
+
sudo dnf install chromium # Fedora
|
|
27
|
+
sudo yum install chromium # CentOS Stream 8
|
|
28
|
+
|
|
29
|
+
#查看版本
|
|
30
|
+
chromium-browser --version
|
|
31
|
+
```
|
|
32
|
+
> 注意,如果windows下手动安装chromium浏览器,或安装了其他修改版chrome浏览器,出现找不到浏览器,需要手动将`可执行文件路径`添加到 [./.puppeteerrc.cjs](./.puppeteerrc.cjs) 的路径列表中。
|
|
33
|
+
|
|
11
34
|
# 🌰一、安装插件
|
|
12
35
|
|
|
13
36
|
## 选择安装方式
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# b站推送,1 开启 0 关闭,保留添加的相关数据,但是不再推送
|
|
2
2
|
pushStatus: 1
|
|
3
3
|
|
|
4
|
-
# 检测b
|
|
4
|
+
# 检测b站动态的冷却时间 CD,Cron表达式,作用域共6位,具体方法浏览器搜索 “node-schedule cron表达式”,示例:
|
|
5
5
|
# "*/15 * * * *" #每15min检测一次
|
|
6
6
|
# "*/31 * * * *" #每31min检测一次
|
|
7
7
|
# "0 5,35 * * * *" #每小时固定第5分0秒、第35分0秒检测一次,共2次/h
|
|
@@ -58,3 +58,16 @@ noSplitHeight: 7500
|
|
|
58
58
|
|
|
59
59
|
# 动态卡片分页截图高度,默认8000px(仅填数字,无需填入单位),请勿设置过大或过小。启用分片截图时生效。
|
|
60
60
|
splitHeight: 8000
|
|
61
|
+
|
|
62
|
+
# 直播动态是否@全体成员,默认 0 关闭,1 开启。开启前请检查 <机器人> 是否有 [管理员权限] 或 [聊天平台是否支持],某些聊天平台或类型不支持@全体成员,如qq官方机器人等。
|
|
63
|
+
liveAtAll: 0
|
|
64
|
+
|
|
65
|
+
# 直播动态@全体成员的群组/聊天/私聊列表,默认为空即不在任何群于推送直播动态中执行@全体成员。开启liveAtAll后才会生效。
|
|
66
|
+
liveAtAllGroupList:
|
|
67
|
+
- 1234567890 # 示例群号
|
|
68
|
+
|
|
69
|
+
# 直播动态@全体成员的共享冷却时间CD,单位秒,默认 1800 秒(30分钟),即每个群聊30分钟内不论多少条直播动态,只会@一次。注意,qq群有 @全体成员 10次/日 的限制,所以请合理设置。
|
|
70
|
+
liveAtAllCD: 1800
|
|
71
|
+
|
|
72
|
+
# 直播动态@全体成员失败时是否发送错误消息,默认 1 发送,0 不发送。开启liveAtAll后才会生效。
|
|
73
|
+
liveAtAllErrMsg: 1
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 微博推送,1 开启 0 关闭,保留添加的相关数据,但是不再推送
|
|
2
2
|
pushStatus: 1
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
# 检测微博动态的冷却时间 CD,Cron表达式,作用域共6位,具体方法浏览器搜索 “node-schedule cron表达式”,示例:
|
|
5
5
|
# "*/15 * * * *" #每15min检测一次
|
|
6
6
|
# "*/31 * * * *" #每31min检测一次
|
|
7
7
|
# "0 5,35 * * * *" #每小时固定第5分0秒、第35分0秒检测一次,共2次/h
|
package/lib/apps/weibo.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Messages } from 'yunzaijs';
|
|
2
|
-
import { WeiboQuery } from '../models/weibo/weibo.query.js';
|
|
3
|
-
import { WeiboTask } from '../models/weibo/weibo.task.js';
|
|
2
|
+
import { WeiboQuery } from '../models/weibo/weibo.main.query.js';
|
|
3
|
+
import { WeiboTask } from '../models/weibo/weibo.main.task.js';
|
|
4
4
|
import Config from '../utils/config.js';
|
|
5
|
-
import { WeiboGetWebData } from '../models/weibo/weibo.get.web.data.js';
|
|
5
|
+
import { WeiboGetWebData } from '../models/weibo/weibo.main.get.web.data.js';
|
|
6
6
|
|
|
7
7
|
const message = new Messages('message');
|
|
8
8
|
let weiboPushData = Config.getConfigData('config', 'weibo', 'push');
|
|
@@ -58,7 +58,7 @@ message.use(async (e) => {
|
|
|
58
58
|
}
|
|
59
59
|
const userInfo = data.userInfo || {};
|
|
60
60
|
let name = uid;
|
|
61
|
-
if (userInfo
|
|
61
|
+
if (userInfo.length !== 0) {
|
|
62
62
|
name = userInfo.screen_name || uid;
|
|
63
63
|
}
|
|
64
64
|
// 添加新的推送数据
|
package/lib/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import path from 'path';
|
|
|
5
5
|
import { _paths } from './utils/paths.js';
|
|
6
6
|
import * as index$1 from './apps/index.js';
|
|
7
7
|
import { BiliTask } from './models/bilibili/bilibili.main.task.js';
|
|
8
|
-
import { WeiboTask } from './models/weibo/weibo.task.js';
|
|
8
|
+
import { WeiboTask } from './models/weibo/weibo.main.task.js';
|
|
9
9
|
|
|
10
10
|
const yukiPluginVersion = Config.getPackageJsonKey('version', path.join(_paths.pluginPath, 'package.json'));
|
|
11
11
|
let biliConfigData = Config.getConfigData('config', 'bilibili', 'config');
|
|
@@ -395,7 +395,8 @@ class BiliQuery {
|
|
|
395
395
|
const BiliDrawDynamicLinkUrl = 'https://m.bilibili.com/dynamic/';
|
|
396
396
|
let desc, msg = [], pics = [], author, majorType, content, dynamicTitle;
|
|
397
397
|
let title = `B站【${upName}】动态推送:\n`;
|
|
398
|
-
|
|
398
|
+
let dynamicType = data.type;
|
|
399
|
+
switch (dynamicType) {
|
|
399
400
|
case 'DYNAMIC_TYPE_AV':
|
|
400
401
|
// 处理视频动态
|
|
401
402
|
desc = data?.modules?.module_dynamic?.major?.archive;
|
|
@@ -412,7 +413,7 @@ class BiliQuery {
|
|
|
412
413
|
`时间:${author ? moment(author.pub_ts * 1000).format('YYYY年MM月DD日 HH:mm:ss') : ''}`
|
|
413
414
|
];
|
|
414
415
|
pics = [Segment.image(desc?.cover)];
|
|
415
|
-
return { msg, pics };
|
|
416
|
+
return { msg, pics, dynamicType };
|
|
416
417
|
case 'DYNAMIC_TYPE_WORD':
|
|
417
418
|
// 处理文字动态
|
|
418
419
|
author = data?.modules?.module_author;
|
|
@@ -442,7 +443,7 @@ class BiliQuery {
|
|
|
442
443
|
`链接:${BiliDrawDynamicLinkUrl}${data.id_str}\n`,
|
|
443
444
|
`时间:${author ? moment(author.pub_ts * 1000).format('YYYY年MM月DD日 HH:mm:ss') : ''}`
|
|
444
445
|
];
|
|
445
|
-
return { msg, pics };
|
|
446
|
+
return { msg, pics, dynamicType };
|
|
446
447
|
case 'DYNAMIC_TYPE_DRAW':
|
|
447
448
|
// 处理图文动态
|
|
448
449
|
author = data?.modules?.module_author;
|
|
@@ -488,7 +489,7 @@ class BiliQuery {
|
|
|
488
489
|
`链接:${BiliDrawDynamicLinkUrl}${data.id_str}\n`,
|
|
489
490
|
`时间:${author ? moment(author.pub_ts * 1000).format('YYYY年MM月DD日 HH:mm:ss') : ''}`
|
|
490
491
|
];
|
|
491
|
-
return { msg, pics };
|
|
492
|
+
return { msg, pics, dynamicType };
|
|
492
493
|
case 'DYNAMIC_TYPE_ARTICLE':
|
|
493
494
|
// 处理文章动态
|
|
494
495
|
author = data?.modules?.module_author;
|
|
@@ -531,7 +532,7 @@ class BiliQuery {
|
|
|
531
532
|
`链接:${this.formatUrl(desc.jump_url)}\n`,
|
|
532
533
|
`时间:${author ? moment(author.pub_ts * 1000).format('YYYY年MM月DD日 HH:mm:ss') : ''}`
|
|
533
534
|
];
|
|
534
|
-
return { msg, pics };
|
|
535
|
+
return { msg, pics, dynamicType };
|
|
535
536
|
case 'DYNAMIC_TYPE_FORWARD':
|
|
536
537
|
// 处理转发动态
|
|
537
538
|
author = data?.modules?.module_author;
|
|
@@ -561,7 +562,7 @@ class BiliQuery {
|
|
|
561
562
|
'\n---以下为转发内容---\n',
|
|
562
563
|
...origContent
|
|
563
564
|
];
|
|
564
|
-
return { msg, pics };
|
|
565
|
+
return { msg, pics, dynamicType };
|
|
565
566
|
case 'DYNAMIC_TYPE_LIVE_RCMD':
|
|
566
567
|
// 处理直播动态
|
|
567
568
|
desc = data?.modules?.module_dynamic?.major?.live_rcmd?.content;
|
|
@@ -574,7 +575,7 @@ class BiliQuery {
|
|
|
574
575
|
title = `B站【${upName}】直播动态推送:\n`;
|
|
575
576
|
msg = [title, `-----------------------------\n`, `标题:${desc.title}\n`, `链接:https:${desc.link}`];
|
|
576
577
|
pics = [Segment.image(desc.cover)];
|
|
577
|
-
return { msg, pics };
|
|
578
|
+
return { msg, pics, dynamicType };
|
|
578
579
|
default:
|
|
579
580
|
// 处理未定义的动态类型
|
|
580
581
|
global?.logger?.mark(`未处理的B站推送【${upName}】:${data.type}`);
|
|
@@ -33,15 +33,22 @@ class BiliTask {
|
|
|
33
33
|
}
|
|
34
34
|
return resjson;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* 执行动态推送任务
|
|
38
|
+
*/
|
|
36
39
|
async runTask() {
|
|
37
40
|
let biliConfigData = await Config.getUserConfig('bilibili', 'config');
|
|
38
41
|
let biliPushData = await Config.getUserConfig('bilibili', 'push');
|
|
39
42
|
let interval = biliConfigData?.interval || 7200;
|
|
43
|
+
logger.debug(`当前B站功能配置:${JSON.stringify(biliConfigData)}`);
|
|
40
44
|
const uidMap = new Map(); // 存放group 和 private 对应所属 uid 与推送信息的映射
|
|
41
45
|
const dynamicList = {}; // 存放获取的所有动态,键为 uid,值为动态数组
|
|
42
46
|
await this.processBiliData(biliPushData, biliConfigData, uidMap, dynamicList);
|
|
43
47
|
let now = Date.now() / 1000; // 时间戳(秒)
|
|
44
|
-
|
|
48
|
+
// 定义待推送动态消息映射
|
|
49
|
+
const messageMap = new Map();
|
|
50
|
+
await this.makeUidDynamicDataMap(uidMap, dynamicList, now, interval, biliConfigData, messageMap);
|
|
51
|
+
await this.sendDynamicMessage(messageMap, biliConfigData);
|
|
45
52
|
}
|
|
46
53
|
/**
|
|
47
54
|
* 处理Bilibili数据,获取动态列表并构建 uid 映射
|
|
@@ -101,17 +108,17 @@ class BiliTask {
|
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
}
|
|
104
|
-
requestedDataOfUids.clear(); //
|
|
111
|
+
requestedDataOfUids.clear(); // 清空已请求的 uid 映射
|
|
105
112
|
}
|
|
106
113
|
/**
|
|
107
|
-
*
|
|
114
|
+
* 构建uid对应动态数据映射
|
|
108
115
|
* @param uidMap uid 映射
|
|
109
116
|
* @param dynamicList 动态列表
|
|
110
117
|
* @param now 当前时间戳
|
|
111
118
|
* @param interval 推送间隔时间
|
|
112
119
|
* @param biliConfigData Bilibili配置数据
|
|
113
120
|
*/
|
|
114
|
-
async
|
|
121
|
+
async makeUidDynamicDataMap(uidMap, dynamicList, now, interval, biliConfigData, messageMap) {
|
|
115
122
|
for (let [chatType, chatTypeMap] of uidMap) {
|
|
116
123
|
for (let [key, value] of chatTypeMap) {
|
|
117
124
|
const tempDynamicList = dynamicList[key] || [];
|
|
@@ -142,7 +149,7 @@ class BiliTask {
|
|
|
142
149
|
for (let chatId of chatIds) {
|
|
143
150
|
if (type && type.length && !type.includes(pushDynamicData.type))
|
|
144
151
|
continue; // 如果禁用了某类型的动态推送,跳过当前循环
|
|
145
|
-
await this.
|
|
152
|
+
await this.makeDynamicMessageMap(chatId, bot_id, upName, pushDynamicData, biliConfigData, chatType, messageMap); // 发送动态消息
|
|
146
153
|
await this.randomDelay(1000, 2000); // 随机延时1-2秒
|
|
147
154
|
}
|
|
148
155
|
}
|
|
@@ -151,15 +158,15 @@ class BiliTask {
|
|
|
151
158
|
}
|
|
152
159
|
}
|
|
153
160
|
/**
|
|
154
|
-
*
|
|
161
|
+
* 渲染构建待发送的动态消息数据的映射数组
|
|
155
162
|
* @param chatId 聊天 ID
|
|
156
163
|
* @param bot_id 机器人 ID
|
|
157
|
-
* @param upName
|
|
164
|
+
* @param upName up主用户名
|
|
158
165
|
* @param pushDynamicData 推送动态数据
|
|
159
166
|
* @param biliConfigData 哔哩配置数据
|
|
160
167
|
* @param chatType 聊天类型
|
|
161
168
|
*/
|
|
162
|
-
async
|
|
169
|
+
async makeDynamicMessageMap(chatId, bot_id, upName, pushDynamicData, biliConfigData, chatType, messageMap) {
|
|
163
170
|
const id_str = pushDynamicData.id_str;
|
|
164
171
|
let sended = null, markKey = '';
|
|
165
172
|
if (chatType === 'group') {
|
|
@@ -172,7 +179,9 @@ class BiliTask {
|
|
|
172
179
|
}
|
|
173
180
|
if (sended)
|
|
174
181
|
return; // 如果已经发送过,则直接返回
|
|
175
|
-
|
|
182
|
+
// 判断推送内容模式
|
|
183
|
+
let pushMsgMode = !!biliConfigData.pushMsgMode === false ? 'TEXT' : 'PIC'; // 是否启用图文模式,默认为 PIC 截图模式
|
|
184
|
+
if (pushMsgMode === 'PIC') {
|
|
176
185
|
const { data, uid } = await BiliQuery.formatDynamicData(pushDynamicData); // 处理动态数据
|
|
177
186
|
const extentData = { ...data };
|
|
178
187
|
const eval2 = eval;
|
|
@@ -200,43 +209,31 @@ class BiliTask {
|
|
|
200
209
|
};
|
|
201
210
|
let imgs = await this.renderDynamicCard(uid, renderData, ScreenshotOptionsData);
|
|
202
211
|
if (!imgs)
|
|
203
|
-
return;
|
|
204
|
-
|
|
205
|
-
logger?.mark('优纪插件:B站动态执行推送');
|
|
206
|
-
for (let i = 0; i < imgs.length; i++) {
|
|
207
|
-
const image = imgs[i];
|
|
208
|
-
await this.sendMessage(chatId, bot_id, chatType, Segment.image(image));
|
|
209
|
-
await this.randomDelay(1000, 2000); // 随机延时1-2秒
|
|
210
|
-
}
|
|
211
|
-
await new Promise(resolve => setTimeout(resolve, 1000)); // 休眠1秒
|
|
212
|
+
return; // 如果渲染失败,则直接返回
|
|
213
|
+
await this.addMessageToMap(messageMap, chatType, bot_id, chatId, 'SINGLE', id_str, extentData?.type, imgs.map(img => Segment.image(img)));
|
|
212
214
|
}
|
|
213
215
|
else {
|
|
214
216
|
const dynamicMsg = await BiliQuery.formatTextDynamicData(upName, pushDynamicData, false, biliConfigData); // 构建图文动态消息
|
|
215
|
-
Redis.set(`${markKey}${chatId}:${id_str}`, '1', { EX: 3600 * 72 }); // 设置已发送标记
|
|
216
217
|
if (dynamicMsg === undefined || dynamicMsg === 'continue') {
|
|
217
218
|
return 'return'; // 如果动态消息构建失败,则直接返回
|
|
218
219
|
}
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
const getBanWords = biliConfigData?.banWords;
|
|
221
|
+
if (getBanWords && Array.isArray(getBanWords) && getBanWords.length > 0) {
|
|
222
|
+
const banWords = new RegExp(getBanWords.join('|'), 'g'); // 构建屏蔽关键字正则表达式
|
|
221
223
|
if (banWords.test(dynamicMsg.msg.join(''))) {
|
|
222
224
|
return 'return'; // 如果动态消息包含屏蔽关键字,则直接返回
|
|
223
225
|
}
|
|
224
226
|
}
|
|
225
227
|
let mergeTextPic = !!biliConfigData.mergeTextPic === false ? false : true; // 是否合并文本和图片,默认为 true
|
|
226
|
-
|
|
228
|
+
//开启了合并文本和图片
|
|
229
|
+
if (mergeTextPic === true) {
|
|
227
230
|
const mergeMsg = [...dynamicMsg.msg, ...dynamicMsg.pics];
|
|
228
|
-
await this.
|
|
231
|
+
await this.addMessageToMap(messageMap, chatType, bot_id, chatId, 'MERGE', id_str, dynamicMsg.dynamicType, mergeMsg);
|
|
229
232
|
}
|
|
230
233
|
else {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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
|
-
}
|
|
238
|
-
}
|
|
239
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
234
|
+
//不合并文本和图片
|
|
235
|
+
await this.addMessageToMap(messageMap, chatType, bot_id, chatId, 'MERGE', id_str, dynamicMsg.dynamicType, dynamicMsg.msg);
|
|
236
|
+
await this.addMessageToMap(messageMap, chatType, bot_id, chatId, 'SINGLE', id_str, dynamicMsg.dynamicType, dynamicMsg.pics);
|
|
240
237
|
}
|
|
241
238
|
}
|
|
242
239
|
}
|
|
@@ -317,13 +314,105 @@ class BiliTask {
|
|
|
317
314
|
}
|
|
318
315
|
}
|
|
319
316
|
/**
|
|
320
|
-
*
|
|
317
|
+
* 收集消息映射
|
|
318
|
+
* @param messageMap 消息映射
|
|
319
|
+
* @param chatType 聊天类型
|
|
320
|
+
* @param bot_id 机器人 ID
|
|
321
|
+
* @param chatId 聊天 ID
|
|
322
|
+
* @param sendMode 发送模式: SINGLE 逐条发送,MERGE 合并发送
|
|
323
|
+
* @param dynamicUUid_str 动态 UUID
|
|
324
|
+
* @param dynamicType 动态类型
|
|
325
|
+
* @param message 消息内容
|
|
326
|
+
*/
|
|
327
|
+
async addMessageToMap(messageMap, chatType, bot_id, chatId, sendMode, dynamicUUid_str, dynamicType, messages) {
|
|
328
|
+
if (!messageMap.has(chatType)) {
|
|
329
|
+
messageMap.set(chatType, new Map());
|
|
330
|
+
}
|
|
331
|
+
const botMap = messageMap.get(chatType);
|
|
332
|
+
if (!botMap?.has(bot_id)) {
|
|
333
|
+
botMap?.set(bot_id, new Map());
|
|
334
|
+
}
|
|
335
|
+
const chatMap = botMap?.get(bot_id);
|
|
336
|
+
if (!chatMap?.has(chatId)) {
|
|
337
|
+
chatMap?.set(chatId, []);
|
|
338
|
+
}
|
|
339
|
+
chatMap?.get(chatId)?.push({ sendMode, dynamicUUid_str, dynamicType, messages });
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* 推送动态消息
|
|
343
|
+
* @param messageMap 消息映射
|
|
344
|
+
* @param biliConfigData 哔哩配置数据
|
|
345
|
+
*/
|
|
346
|
+
async sendDynamicMessage(messageMap, biliConfigData) {
|
|
347
|
+
let liveAtAll = !!biliConfigData.liveAtAll === true ? true : false; // 直播动态是否@全体成员,默认false
|
|
348
|
+
let liveAtAllCD = biliConfigData.liveAtAllCD || 1800; // 直播动态@全体成员 冷却时间CD,默认 30 分钟
|
|
349
|
+
// 直播动态@全体成员的群组/好友列表,默认空数组,为空则不进行@全体成员操作
|
|
350
|
+
let liveAtAllGroupList = new Set(Array.isArray(biliConfigData?.liveAtAllGroupList) ? Array.from(biliConfigData.liveAtAllGroupList).map(item => String(item)) : []);
|
|
351
|
+
const LogMark = new Set(); // 日志mark
|
|
352
|
+
for (const [chatType, botMap] of messageMap) {
|
|
353
|
+
for (const [bot_id, chatMap] of botMap) {
|
|
354
|
+
for (const [chatId, messageCombinationList] of chatMap) {
|
|
355
|
+
// 遍历组合消息
|
|
356
|
+
for (const messageCombination of messageCombinationList) {
|
|
357
|
+
const { sendMode, dynamicUUid_str, dynamicType, messages } = messageCombination;
|
|
358
|
+
let sended = null;
|
|
359
|
+
let markKey = '';
|
|
360
|
+
if (chatType === 'group') {
|
|
361
|
+
markKey = this.groupKey;
|
|
362
|
+
sended = await Redis.get(`${markKey}${chatId}:${dynamicUUid_str}`);
|
|
363
|
+
}
|
|
364
|
+
else if (chatType === 'private') {
|
|
365
|
+
markKey = this.privateKey;
|
|
366
|
+
sended = await Redis.get(`${markKey}${chatId}:${dynamicUUid_str}`);
|
|
367
|
+
}
|
|
368
|
+
const sendMarkKey = `${markKey}${chatId}:${dynamicUUid_str}`;
|
|
369
|
+
if (sended) {
|
|
370
|
+
continue; // 如果已经发送过,则直接跳过
|
|
371
|
+
}
|
|
372
|
+
if (!LogMark.has('1')) {
|
|
373
|
+
global?.logger?.mark('优纪插件: B站动态执行推送');
|
|
374
|
+
LogMark.add('1');
|
|
375
|
+
}
|
|
376
|
+
let liveAtAllMark = await Redis.get(`${markKey}${chatId}:liveAtAllMark`); // 直播动态@全体成员标记,默认 0
|
|
377
|
+
// 如果开启了直播动态@全体成员
|
|
378
|
+
if (liveAtAll && !liveAtAllMark && dynamicType === 'DYNAMIC_TYPE_LIVE_RCMD' && liveAtAllGroupList.has(String(chatId))) {
|
|
379
|
+
try {
|
|
380
|
+
await this.sendMessageApi(chatId, bot_id, chatType, [Segment.at('all')]);
|
|
381
|
+
await Redis.set(`${markKey}${chatId}:liveAtAllMark`, 1, { EX: liveAtAllCD }); // 设置直播动态@全体成员标记为 1
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
logger.error(`直播动态发送@全体成员失败,请检查 <机器人> 是否有 [管理员权限] 或 [聊天平台是否支持] :${error}`);
|
|
385
|
+
let liveAtAllErrMsg = !!biliConfigData.liveAtAllErrMsg === false ? false : true; // 直播动态@全体成员失败是否发送错误提示消息,默认 false
|
|
386
|
+
if (liveAtAllErrMsg) {
|
|
387
|
+
await this.sendMessageApi(chatId, bot_id, chatType, ['直播动态发送@全体成员失败,请检查权限或平台是否支持']);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (sendMode === 'SINGLE') {
|
|
392
|
+
for (let i = 0; i < messages.length; i++) {
|
|
393
|
+
await this.sendMessageApi(chatId, bot_id, chatType, messages[i]);
|
|
394
|
+
}
|
|
395
|
+
await Redis.set(sendMarkKey, '1', { EX: 3600 * 72 }); // 发送成功后设置标记
|
|
396
|
+
await this.randomDelay(1000, 2000); // 随机延时1-2秒
|
|
397
|
+
}
|
|
398
|
+
else if (sendMode === 'MERGE') {
|
|
399
|
+
await this.sendMessageApi(chatId, bot_id, chatType, messages);
|
|
400
|
+
await Redis.set(sendMarkKey, '1', { EX: 3600 * 72 }); // 发送成功后设置标记
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
LogMark.clear(); // 清空日志mark
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* 发送消息api
|
|
321
410
|
* @param chatId 聊天 ID
|
|
322
411
|
* @param bot_id 机器人 ID
|
|
323
412
|
* @param chatType 聊天类型
|
|
324
413
|
* @param message 消息内容
|
|
325
414
|
*/
|
|
326
|
-
async
|
|
415
|
+
async sendMessageApi(chatId, bot_id, chatType, message) {
|
|
327
416
|
if (chatType === 'group') {
|
|
328
417
|
await (Bot[bot_id] ?? Bot)
|
|
329
418
|
?.pickGroup(String(chatId))
|
|
@@ -7,7 +7,8 @@ import { readSyncCookie, cookieWithBiliTicket } from './bilibili.main.models.js'
|
|
|
7
7
|
async function getWebId(uid) {
|
|
8
8
|
const w_webid_key = 'Yz:yuki:bili:w_webid';
|
|
9
9
|
const w_webid = await Redis.get(w_webid_key);
|
|
10
|
-
|
|
10
|
+
const keyTTL = await Redis.ttl(w_webid_key);
|
|
11
|
+
if (w_webid && keyTTL < 259200) {
|
|
11
12
|
return String(w_webid);
|
|
12
13
|
}
|
|
13
14
|
else {
|
|
@@ -28,8 +29,10 @@ async function getWebId(uid) {
|
|
|
28
29
|
const decoded__RENDER_DATA__JsonString = decodeURIComponent(__RENDER_DATA__[1]);
|
|
29
30
|
const accessIdRegex = /"access_id":"(.*?)"/;
|
|
30
31
|
const access_id = decoded__RENDER_DATA__JsonString.match(accessIdRegex);
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
const ExpirationTimeRegex = /document.getElementById\("__RENDER_DATA__"\).*?setTimeout\(function\(\)\s*{window.location.reload\(true\);},\s*(\d+)\s*\*\s*(\d+)\);<\/script>/;
|
|
33
|
+
const ExpirationTime = htmlContent.match(ExpirationTimeRegex);
|
|
34
|
+
if (access_id && access_id[1] && ExpirationTime && ExpirationTime[1]) {
|
|
35
|
+
await Redis.set(w_webid_key, access_id[1], { EX: Number(ExpirationTime[1]) });
|
|
33
36
|
return String(access_id[1]);
|
|
34
37
|
}
|
|
35
38
|
else {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import moment from 'moment';
|
|
2
2
|
import fetch from 'node-fetch';
|
|
3
|
-
import { WeiboApi } from './weibo.api.js';
|
|
3
|
+
import { WeiboApi } from './weibo.main.api.js';
|
|
4
4
|
import { Segment } from 'yunzaijs';
|
|
5
5
|
import { JSDOM } from 'jsdom';
|
|
6
6
|
|
|
@@ -29,9 +29,12 @@ class WeiboQuery {
|
|
|
29
29
|
else if (raw_post?.mblog?.pics) {
|
|
30
30
|
return 'DYNAMIC_TYPE_DRAW';
|
|
31
31
|
}
|
|
32
|
-
else {
|
|
32
|
+
else if (!raw_post?.mblog?.pics && String(raw_post?.mblog?.text).trim().length > 0) {
|
|
33
33
|
return 'DYNAMIC_TYPE_ARTICLE';
|
|
34
34
|
}
|
|
35
|
+
else {
|
|
36
|
+
return 'DYNAMIC_TYPE_UNKNOWN';
|
|
37
|
+
}
|
|
35
38
|
}
|
|
36
39
|
/**筛选正文 */
|
|
37
40
|
static filterText(raw_text) {
|
|
@@ -77,6 +80,7 @@ class WeiboQuery {
|
|
|
77
80
|
formatData.data.name = nick_name;
|
|
78
81
|
/**头像框 */
|
|
79
82
|
formatData.data.pendant = '';
|
|
83
|
+
/**生成日期 */
|
|
80
84
|
formatData.data.created = moment().format('YYYY年MM月DD日 HH:mm:ss');
|
|
81
85
|
formatData.data.type = type;
|
|
82
86
|
switch (type) {
|
|
@@ -182,7 +186,7 @@ class WeiboQuery {
|
|
|
182
186
|
let info = raw_post?.mblog || raw_post;
|
|
183
187
|
let retweeted = info && info.retweeted_status ? true : false; //是否为转发动态
|
|
184
188
|
let pic_num = retweeted ? info?.retweeted_status?.pic_num : info?.pic_num;
|
|
185
|
-
let
|
|
189
|
+
let dynamicType = this.MakeCategory(raw_post);
|
|
186
190
|
/**获取动态全文 */
|
|
187
191
|
if (info?.isLongText || pic_num > 9) {
|
|
188
192
|
const res = await fetch(`https://m.weibo.cn/detail/${info.mid}`, { headers: WeiboApi.WEIBO_HEADERS });
|
|
@@ -203,7 +207,7 @@ class WeiboQuery {
|
|
|
203
207
|
let detail_url = `https://weibo.com/${info?.user?.id}/${info?.bid}`;
|
|
204
208
|
let title = `微博【${upName}】动态推送:\n`;
|
|
205
209
|
const dynamicPicCountLimit = setData.pushPicCountLimit || 3;
|
|
206
|
-
switch (
|
|
210
|
+
switch (dynamicType) {
|
|
207
211
|
case 'DYNAMIC_TYPE_AV':
|
|
208
212
|
if (!info)
|
|
209
213
|
return;
|
|
@@ -219,7 +223,7 @@ class WeiboQuery {
|
|
|
219
223
|
`时间:${created_time ? moment(created_time).format('YYYY年MM月DD日 HH:mm:ss') : ''}`
|
|
220
224
|
];
|
|
221
225
|
pics = [cover_img];
|
|
222
|
-
return { msg, pics };
|
|
226
|
+
return { msg, pics, dynamicType };
|
|
223
227
|
case 'DYNAMIC_TYPE_DRAW':
|
|
224
228
|
raw_pics_list = retweeted ? info?.retweeted_status?.pics || [] : info?.pics || [];
|
|
225
229
|
if (!info && !raw_pics_list)
|
|
@@ -239,7 +243,7 @@ class WeiboQuery {
|
|
|
239
243
|
`链接:${detail_url}\n`,
|
|
240
244
|
`时间:${created_time ? moment(created_time).format('YYYY年MM月DD日 HH:mm:ss') : ''}`
|
|
241
245
|
];
|
|
242
|
-
return { msg, pics };
|
|
246
|
+
return { msg, pics, dynamicType };
|
|
243
247
|
case 'DYNAMIC_TYPE_ARTICLE':
|
|
244
248
|
if (!info)
|
|
245
249
|
return;
|
|
@@ -259,7 +263,7 @@ class WeiboQuery {
|
|
|
259
263
|
`链接:${detail_url}\n`,
|
|
260
264
|
`时间:${created_time ? moment(created_time).format('YYYY年MM月DD日 HH:mm:ss') : ''}`
|
|
261
265
|
];
|
|
262
|
-
return { msg, pics };
|
|
266
|
+
return { msg, pics, dynamicType };
|
|
263
267
|
case 'DYNAMIC_TYPE_FORWARD':
|
|
264
268
|
if (!info)
|
|
265
269
|
return;
|
|
@@ -286,9 +290,9 @@ class WeiboQuery {
|
|
|
286
290
|
'\n---以下为转发内容---\n',
|
|
287
291
|
...origContent
|
|
288
292
|
];
|
|
289
|
-
return { msg, pics };
|
|
293
|
+
return { msg, pics, dynamicType };
|
|
290
294
|
default:
|
|
291
|
-
logger?.mark(`未处理的微博推送【${upName}】:${
|
|
295
|
+
logger?.mark(`未处理的微博推送【${upName}】:${dynamicType}`);
|
|
292
296
|
return 'continue';
|
|
293
297
|
}
|
|
294
298
|
}
|
|
@@ -2,8 +2,8 @@ import QRCode from 'qrcode';
|
|
|
2
2
|
import { Redis, Segment, Bot } from 'yunzaijs';
|
|
3
3
|
import Config from '../../utils/config.js';
|
|
4
4
|
import { renderPage } from '../../utils/image.js';
|
|
5
|
-
import { WeiboGetWebData } from './weibo.get.web.data.js';
|
|
6
|
-
import { WeiboQuery } from './weibo.query.js';
|
|
5
|
+
import { WeiboGetWebData } from './weibo.main.get.web.data.js';
|
|
6
|
+
import { WeiboQuery } from './weibo.main.query.js';
|
|
7
7
|
|
|
8
8
|
class WeiboTask {
|
|
9
9
|
taskName;
|
|
@@ -15,15 +15,22 @@ class WeiboTask {
|
|
|
15
15
|
this.groupKey = 'Yz:yuki:weibo:upPush:group:';
|
|
16
16
|
this.privateKey = 'Yz:yuki:weibo:upPush:private:';
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* 执行动态推送任务
|
|
20
|
+
*/
|
|
18
21
|
async runTask() {
|
|
19
22
|
let weiboConfigData = await Config.getUserConfig('weibo', 'config');
|
|
20
23
|
let weiboPushData = await Config.getUserConfig('weibo', 'push');
|
|
21
24
|
let interval = weiboConfigData.interval || 7200; // 推送间隔时间,单位为秒,默认2小时
|
|
25
|
+
logger.debug(`当前微博功能配置:${JSON.stringify(weiboConfigData)}`);
|
|
22
26
|
const uidMap = new Map(); // 存放group 和 private 对应所属 uid 与推送信息的映射
|
|
23
27
|
const dynamicList = {}; // 存放获取的所有动态,键为 uid,值为动态数组
|
|
24
28
|
await this.processWeiboData(weiboPushData, uidMap, dynamicList);
|
|
25
29
|
let now = Date.now() / 1000; // 当前时间戳(秒)
|
|
26
|
-
|
|
30
|
+
// 定义待推送动态消息映射
|
|
31
|
+
const messageMap = new Map();
|
|
32
|
+
await this.makeUidDynamicDataMap(uidMap, dynamicList, now, interval, weiboConfigData, messageMap);
|
|
33
|
+
await this.sendDynamicMessage(messageMap, weiboConfigData);
|
|
27
34
|
}
|
|
28
35
|
/**
|
|
29
36
|
* 处理微博数据,获取动态列表并构建 uid 映射
|
|
@@ -70,14 +77,14 @@ class WeiboTask {
|
|
|
70
77
|
requestedDataOfUids.clear(); // 清空已请求的映射
|
|
71
78
|
}
|
|
72
79
|
/**
|
|
73
|
-
*
|
|
80
|
+
* 构建uid对应动态数据映射
|
|
74
81
|
* @param uidMap uid 映射
|
|
75
82
|
* @param dynamicList 动态列表
|
|
76
83
|
* @param now 当前时间戳
|
|
77
84
|
* @param interval 推送间隔时间
|
|
78
85
|
* @param weiboConfigData 微博配置数据
|
|
79
86
|
*/
|
|
80
|
-
async
|
|
87
|
+
async makeUidDynamicDataMap(uidMap, dynamicList, now, interval, weiboConfigData, messageMap) {
|
|
81
88
|
for (let [chatType, chatTypeMap] of uidMap) {
|
|
82
89
|
for (let [key, value] of chatTypeMap) {
|
|
83
90
|
const tempDynamicList = dynamicList[key] || [];
|
|
@@ -109,7 +116,7 @@ class WeiboTask {
|
|
|
109
116
|
for (let chatId of chatIds) {
|
|
110
117
|
if (type && type.length && !type.includes(pushDynamicData.type))
|
|
111
118
|
continue; // 如果禁用了某类型的动态推送,跳过当前循环
|
|
112
|
-
await this.
|
|
119
|
+
await this.makeDynamicMessageMap(chatId, bot_id, upName, pushDynamicData, weiboConfigData, chatType, messageMap); // 发送动态消息
|
|
113
120
|
await this.randomDelay(1000, 2000); // 随机延时1-2秒
|
|
114
121
|
}
|
|
115
122
|
}
|
|
@@ -118,15 +125,16 @@ class WeiboTask {
|
|
|
118
125
|
}
|
|
119
126
|
}
|
|
120
127
|
/**
|
|
121
|
-
*
|
|
128
|
+
* 渲染构建待发送的动态消息数据的映射数组
|
|
122
129
|
* @param chatId 聊天 ID
|
|
123
130
|
* @param bot_id 机器人 ID
|
|
124
|
-
* @param upName
|
|
131
|
+
* @param upName 博主用户名
|
|
125
132
|
* @param pushDynamicData 推送动态数据
|
|
126
133
|
* @param weiboConfigData 微博配置数据
|
|
127
134
|
* @param chatType 聊天类型
|
|
135
|
+
* @param messageMap 待发送的动态消息映射
|
|
128
136
|
*/
|
|
129
|
-
async
|
|
137
|
+
async makeDynamicMessageMap(chatId, bot_id, upName, pushDynamicData, weiboConfigData, chatType, messageMap) {
|
|
130
138
|
const id_str = WeiboQuery.getDynamicId(pushDynamicData); // 获取动态 ID
|
|
131
139
|
let sended = null, markKey = '';
|
|
132
140
|
if (chatType === 'group') {
|
|
@@ -167,43 +175,31 @@ class WeiboTask {
|
|
|
167
175
|
};
|
|
168
176
|
let imgs = await this.renderDynamicCard(uid, renderData, ScreenshotOptionsData);
|
|
169
177
|
if (!imgs)
|
|
170
|
-
return;
|
|
171
|
-
|
|
172
|
-
global?.logger?.mark('优纪插件:微博动态执行推送');
|
|
173
|
-
for (let i = 0; i < imgs.length; i++) {
|
|
174
|
-
const image = imgs[i];
|
|
175
|
-
await this.sendMessage(chatId, bot_id, chatType, Segment.image(image));
|
|
176
|
-
await this.randomDelay(1000, 2000); // 随机延时1-2秒
|
|
177
|
-
}
|
|
178
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
178
|
+
return; // 如果渲染失败,则直接返回
|
|
179
|
+
await this.addMessageToMap(messageMap, chatType, bot_id, chatId, 'SINGLE', id_str, extentData?.type, imgs.map(img => Segment.image(img)));
|
|
179
180
|
}
|
|
180
181
|
else {
|
|
181
182
|
const dynamicMsg = await WeiboQuery.formatTextDynamicData(upName, pushDynamicData, false, weiboConfigData); //构建文字动态消息
|
|
182
|
-
Redis.set(`${markKey}${chatId}:${id_str}`, '1', { EX: 3600 * 72 }); // 设置已发送标记
|
|
183
183
|
if (dynamicMsg === undefined || dynamicMsg === 'continue') {
|
|
184
184
|
return 'return'; // 如果动态消息构建失败或内部资源获取失败,则直接返回
|
|
185
185
|
}
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
const getBanWords = weiboConfigData?.banWords;
|
|
187
|
+
if (getBanWords && Array.isArray(getBanWords) && getBanWords.length > 0) {
|
|
188
|
+
const banWords = new RegExp(getBanWords.join('|'), 'g'); // 构建屏蔽关键字正则表达式
|
|
188
189
|
if (banWords.test(dynamicMsg.msg.join(''))) {
|
|
189
190
|
return 'return'; // 如果动态消息包含屏蔽关键字,则直接返回
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
let mergeTextPic = !!weiboConfigData.mergeTextPic === false ? false : true; // 是否合并文字和图片,默认为 true
|
|
193
|
-
|
|
194
|
+
//开启了合并文本和图片
|
|
195
|
+
if (mergeTextPic === true) {
|
|
194
196
|
const mergeMsg = [...dynamicMsg.msg, ...dynamicMsg.pics];
|
|
195
|
-
await this.
|
|
197
|
+
await this.addMessageToMap(messageMap, chatType, bot_id, chatId, 'MERGE', id_str, dynamicMsg.dynamicType, mergeMsg);
|
|
196
198
|
}
|
|
197
199
|
else {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
}
|
|
205
|
-
}
|
|
206
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
200
|
+
//不合并文本和图片
|
|
201
|
+
await this.addMessageToMap(messageMap, chatType, bot_id, chatId, 'MERGE', id_str, dynamicMsg.dynamicType, dynamicMsg.msg);
|
|
202
|
+
await this.addMessageToMap(messageMap, chatType, bot_id, chatId, 'SINGLE', id_str, dynamicMsg.dynamicType, dynamicMsg.pics);
|
|
207
203
|
}
|
|
208
204
|
}
|
|
209
205
|
}
|
|
@@ -284,13 +280,86 @@ class WeiboTask {
|
|
|
284
280
|
}
|
|
285
281
|
}
|
|
286
282
|
/**
|
|
287
|
-
*
|
|
283
|
+
* 收集消息映射
|
|
284
|
+
* @param messageMap 消息映射
|
|
285
|
+
* @param chatType 聊天类型
|
|
286
|
+
* @param bot_id 机器人 ID
|
|
287
|
+
* @param chatId 聊天 ID
|
|
288
|
+
* @param sendMode 发送模式: SINGLE 逐条发送,MERGE 合并发送
|
|
289
|
+
* @param dynamicUUid_str 动态 UUID
|
|
290
|
+
* @param dynamicType 动态类型
|
|
291
|
+
* @param message 消息内容
|
|
292
|
+
*/
|
|
293
|
+
async addMessageToMap(messageMap, chatType, bot_id, chatId, sendMode, dynamicUUid_str, dynamicType, messages) {
|
|
294
|
+
if (!messageMap.has(chatType)) {
|
|
295
|
+
messageMap.set(chatType, new Map());
|
|
296
|
+
}
|
|
297
|
+
const botMap = messageMap.get(chatType);
|
|
298
|
+
if (!botMap?.has(bot_id)) {
|
|
299
|
+
botMap?.set(bot_id, new Map());
|
|
300
|
+
}
|
|
301
|
+
const chatMap = botMap?.get(bot_id);
|
|
302
|
+
if (!chatMap?.has(chatId)) {
|
|
303
|
+
chatMap?.set(chatId, []);
|
|
304
|
+
}
|
|
305
|
+
chatMap?.get(chatId)?.push({ sendMode, dynamicUUid_str, dynamicType, messages });
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* 推送动态消息
|
|
309
|
+
* @param messageMap 消息映射
|
|
310
|
+
* @param biliConfigData 微博配置数据
|
|
311
|
+
*/
|
|
312
|
+
async sendDynamicMessage(messageMap, weiboConfigData) {
|
|
313
|
+
const LogMark = new Set(); // 日志mark
|
|
314
|
+
for (const [chatType, botMap] of messageMap) {
|
|
315
|
+
for (const [bot_id, chatMap] of botMap) {
|
|
316
|
+
for (const [chatId, messageCombinationList] of chatMap) {
|
|
317
|
+
// 遍历组合消息
|
|
318
|
+
for (const messageCombination of messageCombinationList) {
|
|
319
|
+
const { sendMode, dynamicUUid_str, dynamicType, messages } = messageCombination;
|
|
320
|
+
let sended = null;
|
|
321
|
+
let markKey = '';
|
|
322
|
+
if (chatType === 'group') {
|
|
323
|
+
markKey = this.groupKey;
|
|
324
|
+
sended = await Redis.get(`${markKey}${chatId}:${dynamicUUid_str}`);
|
|
325
|
+
}
|
|
326
|
+
else if (chatType === 'private') {
|
|
327
|
+
markKey = this.privateKey;
|
|
328
|
+
sended = await Redis.get(`${markKey}${chatId}:${dynamicUUid_str}`);
|
|
329
|
+
}
|
|
330
|
+
const sendMarkKey = `${markKey}${chatId}:${dynamicUUid_str}`;
|
|
331
|
+
if (sended) {
|
|
332
|
+
continue; // 如果已经发送过,则直接跳过
|
|
333
|
+
}
|
|
334
|
+
if (!LogMark.has('1')) {
|
|
335
|
+
global?.logger?.mark('优纪插件: B站动态执行推送');
|
|
336
|
+
LogMark.add('1');
|
|
337
|
+
}
|
|
338
|
+
if (sendMode === 'SINGLE') {
|
|
339
|
+
for (let i = 0; i < messages.length; i++) {
|
|
340
|
+
await this.sendMessageApi(chatId, bot_id, chatType, messages[i]);
|
|
341
|
+
}
|
|
342
|
+
await Redis.set(sendMarkKey, '1', { EX: 3600 * 72 }); // 发送成功后设置标记
|
|
343
|
+
await this.randomDelay(1000, 2000); // 随机延时1-2秒
|
|
344
|
+
}
|
|
345
|
+
else if (sendMode === 'MERGE') {
|
|
346
|
+
await this.sendMessageApi(chatId, bot_id, chatType, messages);
|
|
347
|
+
await Redis.set(sendMarkKey, '1', { EX: 3600 * 72 }); // 发送成功后设置标记
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
LogMark.clear(); // 清空日志mark
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* 发送消息api
|
|
288
357
|
* @param chatId 聊天 ID
|
|
289
358
|
* @param bot_id 机器人 ID
|
|
290
359
|
* @param chatType 聊天类型
|
|
291
360
|
* @param message 消息内容
|
|
292
361
|
*/
|
|
293
|
-
async
|
|
362
|
+
async sendMessageApi(chatId, bot_id, chatType, message) {
|
|
294
363
|
if (chatType === 'group') {
|
|
295
364
|
await (Bot[bot_id] ?? Bot)
|
|
296
365
|
?.pickGroup(String(chatId))
|
package/lib/utils/image.js
CHANGED
|
@@ -15,11 +15,11 @@ class Image extends Picture {
|
|
|
15
15
|
// 继承父类实例
|
|
16
16
|
super();
|
|
17
17
|
// 父类已经实例化组件渲染对象
|
|
18
|
-
//this.
|
|
18
|
+
//this.component;
|
|
19
19
|
// 父类已经实例化启动 Puppeteer
|
|
20
|
-
//this.
|
|
20
|
+
//this.puppeteer.start();
|
|
21
21
|
// 初始化 YukiPuppeteerRender 实例
|
|
22
|
-
this.yukiPuppeteerRender = new YukiPuppeteerRender(this.
|
|
22
|
+
this.yukiPuppeteerRender = new YukiPuppeteerRender(this.puppeteer);
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* 实例方法,用于执行实际的渲染和截图操作
|
|
@@ -34,7 +34,7 @@ class Image extends Picture {
|
|
|
34
34
|
// 根据组件名称获取对应的 React 组件
|
|
35
35
|
const Page = index[page];
|
|
36
36
|
// 调用 yukiPuppeteerRender 进行截图操作
|
|
37
|
-
return this.yukiPuppeteerRender.yukiScreenshot(this.
|
|
37
|
+
return this.yukiPuppeteerRender.yukiScreenshot(this.component.compile({
|
|
38
38
|
path: page,
|
|
39
39
|
name: `${uid}.html`,
|
|
40
40
|
component: React.createElement(Page, { ...props }),
|
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-11",
|
|
4
4
|
"description": "优纪插件,yunzaijs 关于 微博推送、B站推送 等功能的拓展插件",
|
|
5
5
|
"author": "snowtafir",
|
|
6
6
|
"type": "module",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"debug": "^4.3.6",
|
|
32
32
|
"jsdom": "^25.0.1",
|
|
33
33
|
"json5": "^2.2.3",
|
|
34
|
-
"jsxp": "^1.
|
|
34
|
+
"jsxp": "^1.1.2",
|
|
35
35
|
"lodash": "^4.17.21",
|
|
36
36
|
"md5": "^2.3.0",
|
|
37
37
|
"moment": "^2.30.1",
|
|
38
38
|
"node-fetch": "^3.3.2",
|
|
39
|
-
"puppeteer": "^
|
|
39
|
+
"puppeteer": "^24.1.0",
|
|
40
40
|
"qrcode": "^1.5.4",
|
|
41
41
|
"react": "^18.3.1",
|
|
42
42
|
"react-dom": "^18.3.1",
|
|
@@ -60,23 +60,24 @@
|
|
|
60
60
|
"axios": "^1.7.9",
|
|
61
61
|
"chokidar": "^4.0.1",
|
|
62
62
|
"husky": "^9.1.6",
|
|
63
|
+
"icqq": "^0.6.10",
|
|
63
64
|
"jsdom": "^24.1.1",
|
|
64
65
|
"json5": "^2.2.3",
|
|
65
|
-
"jsxp": "^1.
|
|
66
|
+
"jsxp": "^1.1.2",
|
|
66
67
|
"lodash": "^4.17.21",
|
|
67
|
-
"lvyjs": "^0.2.
|
|
68
|
+
"lvyjs": "^0.2.14",
|
|
68
69
|
"md5": "^2.3.0",
|
|
69
70
|
"node-fetch": "^3.3.2",
|
|
70
71
|
"postcss": "^8.4.47",
|
|
71
72
|
"prettier": "^3.4.2",
|
|
72
|
-
"puppeteer": "^
|
|
73
|
+
"puppeteer": "^24.1.0",
|
|
73
74
|
"qrcode": "^1.5.4",
|
|
74
75
|
"react": "^18.3.1",
|
|
75
76
|
"react-dom": "^18.3.1",
|
|
76
77
|
"redis": "^4.7.0",
|
|
77
78
|
"tailwindcss": "^3.4.14",
|
|
78
79
|
"ts-node": "^10.9.2",
|
|
79
|
-
"tsx": "^4.19.
|
|
80
|
+
"tsx": "^4.19.2",
|
|
80
81
|
"typescript": "^5.5.4",
|
|
81
82
|
"yaml": "^2.6.1",
|
|
82
83
|
"yunzaijs": "^1.0.0-rc.5"
|
|
@@ -106,6 +107,6 @@
|
|
|
106
107
|
"registry": "https://registry.npmjs.org"
|
|
107
108
|
},
|
|
108
109
|
"engines": {
|
|
109
|
-
"node": ">=
|
|
110
|
+
"node": ">=20"
|
|
110
111
|
}
|
|
111
112
|
}
|
|
File without changes
|