yz-yuki-plugin 2.0.2 → 2.0.3-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.
Files changed (45) hide show
  1. package/CHANGELOG.md +5 -1
  2. package/README.md +6 -5
  3. package/lib/apps/bilibili.js +50 -6
  4. package/lib/apps/help.js +3 -0
  5. package/lib/apps/version.js +3 -0
  6. package/lib/apps/weibo.js +31 -1
  7. package/lib/components/dynamic/Account.js +2 -0
  8. package/lib/components/dynamic/Content.js +2 -0
  9. package/lib/components/dynamic/Footer.js +1 -0
  10. package/lib/components/dynamic/ForwardContent.js +2 -0
  11. package/lib/components/dynamic/LogoText.js +2 -0
  12. package/lib/components/dynamic/MainPage.js +1 -0
  13. package/lib/components/help/Help.js +1 -0
  14. package/lib/components/loginQrcode/Page.js +1 -0
  15. package/lib/index.js +20 -1
  16. package/lib/models/bilibili/bilibili.api.d.ts +3 -0
  17. package/lib/models/bilibili/bilibili.api.js +9 -0
  18. package/lib/models/bilibili/bilibili.get.web.data.d.ts +3 -0
  19. package/lib/models/bilibili/bilibili.get.web.data.js +4 -0
  20. package/lib/models/bilibili/bilibili.models.d.ts +37 -0
  21. package/lib/models/bilibili/bilibili.models.js +71 -19
  22. package/lib/models/bilibili/bilibili.query.d.ts +24 -0
  23. package/lib/models/bilibili/bilibili.query.js +69 -11
  24. package/lib/models/bilibili/bilibili.task.d.ts +41 -0
  25. package/lib/models/bilibili/bilibili.task.js +77 -34
  26. package/lib/models/bilibili/bilibili.wbi.d.ts +6 -0
  27. package/lib/models/bilibili/bilibili.wbi.js +16 -3
  28. package/lib/models/version/version.d.ts +10 -0
  29. package/lib/models/version/version.js +11 -0
  30. package/lib/models/weibo/weibo.api.d.ts +1 -0
  31. package/lib/models/weibo/weibo.api.js +2 -0
  32. package/lib/models/weibo/weibo.get.web.data.d.ts +3 -0
  33. package/lib/models/weibo/weibo.get.web.data.js +3 -0
  34. package/lib/models/weibo/weibo.query.d.ts +20 -0
  35. package/lib/models/weibo/weibo.query.js +63 -6
  36. package/lib/models/weibo/weibo.task.d.ts +49 -0
  37. package/lib/models/weibo/weibo.task.js +84 -34
  38. package/lib/utils/config.d.ts +51 -1
  39. package/lib/utils/config.js +61 -8
  40. package/lib/utils/image.d.ts +11 -0
  41. package/lib/utils/image.js +15 -0
  42. package/lib/utils/paths.js +7 -7
  43. package/lib/utils/puppeteer.render.d.ts +15 -0
  44. package/lib/utils/puppeteer.render.js +37 -15
  45. package/package.json +8 -7
@@ -1,8 +1,10 @@
1
1
  class WeiboApi {
2
2
  static WEIBO_API = {
3
3
  weiboGetIndex: 'https://m.weibo.cn/api/container/getIndex',
4
+ //通过关键词${upKeyword}搜索博主 parama = { q: 'Keyword'},
4
5
  weiboAjaxSearch: 'https://weibo.com/ajax/side/search',
5
6
  };
7
+ /**统一设置header */
6
8
  static WEIBO_HEADERS = {
7
9
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
8
10
  'Accept-language': 'zh-CN,zh;q=0.9',
@@ -2,7 +2,10 @@ import { EventType } from 'yunzai';
2
2
  export declare class WeiboGetWebData {
3
3
  e?: EventType;
4
4
  constructor(e?: EventType);
5
+ /**通过uid获取博主信息 */
5
6
  getBloggerInfo(target: any): Promise<import("axios").AxiosResponse<any, any>>;
7
+ /**通过关键词搜索微博大v */
6
8
  searchBloggerInfo(keyword: string): Promise<import("axios").AxiosResponse<any, any>>;
9
+ /**获取主页动态资源相关数组 */
7
10
  getBloggerDynamicList(target: any): Promise<any>;
8
11
  }
@@ -7,6 +7,7 @@ class WeiboGetWebData {
7
7
  e;
8
8
  constructor(e) {
9
9
  }
10
+ /**通过uid获取博主信息 */
10
11
  async getBloggerInfo(target) {
11
12
  const param = { containerid: '100505' + target };
12
13
  const url = new URL(WeiboApi.WEIBO_API.weiboGetIndex);
@@ -17,6 +18,7 @@ class WeiboGetWebData {
17
18
  });
18
19
  return resp;
19
20
  }
21
+ /**通过关键词搜索微博大v */
20
22
  async searchBloggerInfo(keyword) {
21
23
  const url = WeiboApi.WEIBO_API.weiboAjaxSearch;
22
24
  const params = {
@@ -29,6 +31,7 @@ class WeiboGetWebData {
29
31
  });
30
32
  return resp;
31
33
  }
34
+ /**获取主页动态资源相关数组 */
32
35
  async getBloggerDynamicList(target) {
33
36
  const params = { containerid: '107603' + target };
34
37
  const url = new URL(WeiboApi.WEIBO_API.weiboGetIndex);
@@ -1,18 +1,38 @@
1
1
  export declare class WeiboQuery {
2
+ /**获取文章id */
2
3
  static getDynamicId(post: any): any;
4
+ /**获取指定动态类型的原始数据 */
3
5
  static filterCardTypeCustom(raw_post: any): boolean;
6
+ /**转换微博动态创建时间:(created_at)转换为 UNIX 时间戳(以毫秒为单位) */
4
7
  static getDynamicCreatetDate(raw_post: any): number;
8
+ /**分类动态,返回标识 */
5
9
  static MakeCategory(raw_post: any): "DYNAMIC_TYPE_AV" | "DYNAMIC_TYPE_DRAW" | "DYNAMIC_TYPE_ARTICLE" | "DYNAMIC_TYPE_FORWARD";
10
+ /**筛选正文 */
6
11
  static filterText(raw_text: string): string;
12
+ /** 获取并生成微博动态渲染数据 */
7
13
  static formatDynamicData(raw_post: any): Promise<{
8
14
  uid: any;
9
15
  data: {
10
16
  [key: string]: any;
11
17
  };
12
18
  }>;
19
+ /**
20
+ * 动态内容富文本节点解析
21
+ * @param nodes - 动态内容富文本节点
22
+ * @returns 解析后的动态内容富文本
23
+ */
13
24
  static parseRichTextNodes: (nodes: any[] | string | any) => any;
25
+ /**
26
+ * 生成动态消息文字内容
27
+ * @param upName - UP主名称
28
+ * @param formatData - 动态数据
29
+ * @param isForward - 是否为转发动态
30
+ * @param setData - 设置数据
31
+ * @returns 生成的动态消息文字内容
32
+ */
14
33
  static formatTextDynamicData(upName: string, raw_post: any, isForward?: boolean, setData?: any): Promise<false | any[] | "continue">;
15
34
  static dynamicContentLimit(content: string, setData: any): string;
16
35
  static formatUrl(url: string): string;
36
+ /**推送类型设置 */
17
37
  static typeHandle(up: any, msg: string, type: string): unknown[];
18
38
  }
@@ -5,16 +5,20 @@ import { Bot, Segment } from 'yunzai';
5
5
  import { JSDOM } from 'jsdom';
6
6
 
7
7
  class WeiboQuery {
8
+ /**获取文章id */
8
9
  static getDynamicId(post) {
9
10
  return post?.mblog?.mid || post?.mblog?.id;
10
11
  }
12
+ /**获取指定动态类型的原始数据 */
11
13
  static filterCardTypeCustom(raw_post) {
12
14
  return raw_post.card_type === 9;
13
15
  }
16
+ /**转换微博动态创建时间:(created_at)转换为 UNIX 时间戳(以毫秒为单位) */
14
17
  static getDynamicCreatetDate(raw_post) {
15
18
  const created_time = Date.parse(raw_post?.mblog?.created_at || raw_post?.created_at);
16
19
  return created_time;
17
20
  }
21
+ /**分类动态,返回标识 */
18
22
  static MakeCategory(raw_post) {
19
23
  if (raw_post?.mblog?.retweeted_status) {
20
24
  return "DYNAMIC_TYPE_FORWARD";
@@ -29,12 +33,15 @@ class WeiboQuery {
29
33
  return "DYNAMIC_TYPE_ARTICLE";
30
34
  }
31
35
  }
36
+ /**筛选正文 */
32
37
  static filterText(raw_text) {
33
38
  const text = raw_text.replace(/<br \/>/g, '\n');
34
39
  const dom = new JSDOM(text);
35
40
  return dom.window.document.body.textContent || '';
36
41
  }
42
+ /** 获取并生成微博动态渲染数据 */
37
43
  static async formatDynamicData(raw_post) {
44
+ /* 初始数据进一步处理 **************** */
38
45
  let info = raw_post?.mblog || raw_post;
39
46
  let retweeted = info && info?.retweeted_status ? true : false;
40
47
  let pic_num = retweeted ? info?.retweeted_status?.pic_num : info?.pic_num;
@@ -53,14 +60,22 @@ class WeiboQuery {
53
60
  logger?.error(`优纪插件:微博 detail message error(https://m.weibo.cn/detail/${info?.mid})`);
54
61
  }
55
62
  }
63
+ /**头像链接 */
56
64
  const face_url = info?.user?.profile_image_url;
65
+ /**昵称 */
57
66
  const nick_name = info?.user?.screen_name;
67
+ /**动态发布时间 */
58
68
  let created_time = this.getDynamicCreatetDate(raw_post);
69
+ /**动态详情链接 */
59
70
  let detail_url = `https://weibo.com/${info?.user?.id}/${info?.bid}`;
71
+ /* 构造动态渲染数据 *************************** */
60
72
  let pics = [];
61
73
  let formatData = { data: {} };
74
+ /**头像 */
62
75
  formatData.data.face = face_url;
76
+ /**昵称 */
63
77
  formatData.data.name = nick_name;
78
+ /**头像框 */
64
79
  formatData.data.pendant = '';
65
80
  formatData.data.created = moment().format("YYYY年MM月DD日 HH:mm:ss");
66
81
  formatData.data.type = type;
@@ -110,33 +125,60 @@ class WeiboQuery {
110
125
  };
111
126
  }
112
127
  ;
128
+ /**
129
+ * 动态内容富文本节点解析
130
+ * @param nodes - 动态内容富文本节点
131
+ * @returns 解析后的动态内容富文本
132
+ */
113
133
  static parseRichTextNodes = (nodes) => {
114
134
  if (typeof nodes === 'string') {
135
+ // 将 \n 替换为 <br> 以实现换行
115
136
  let parsedContent = nodes.replace(/\n/g, '<br>');
137
+ // 使用正则表达式查找所有的 <a> 标签
116
138
  parsedContent = parsedContent.replace(/<a/g, () => {
139
+ // 生成一个随机的 key 值
117
140
  const randomKey = Math.random().toString(36).substring(7);
118
141
  return `<a key="${randomKey}"`;
119
142
  });
120
143
  parsedContent = parsedContent.replace(/class="url-icon"/g, () => {
144
+ // 生成一个随机的 key 值
121
145
  const randomKey = Math.random().toString(36).substring(7);
122
146
  return `class="url-icon ${randomKey}"`;
123
147
  });
148
+ // 使用正则表达式查找所有的 <img> 标签
124
149
  parsedContent = parsedContent.replace(/<img/g, () => {
150
+ // 生成一个随机的 key 值
125
151
  const randomKey = Math.random().toString(36).substring(7);
126
152
  return `<img key="${randomKey}"`;
127
153
  });
128
154
  return parsedContent;
129
155
  }
130
156
  else {
157
+ // 未知类型,直接返回
131
158
  return nodes;
132
159
  }
133
160
  };
161
+ /**
162
+ * 生成动态消息文字内容
163
+ * @param upName - UP主名称
164
+ * @param formatData - 动态数据
165
+ * @param isForward - 是否为转发动态
166
+ * @param setData - 设置数据
167
+ * @returns 生成的动态消息文字内容
168
+ */
134
169
  static async formatTextDynamicData(upName, raw_post, isForward, setData) {
135
- let msg = [], raw_pics_list, pic_urls, pics;
170
+ let msg = [],
171
+ /**全部图片资源链接*/
172
+ raw_pics_list,
173
+ /**图片高清资源链接*/
174
+ pic_urls,
175
+ /**图片*/
176
+ pics;
136
177
  let info = raw_post?.mblog || raw_post;
137
- let retweeted = info && info.retweeted_status ? true : false;
178
+ let retweeted = info && info.retweeted_status ? true : false; //是否为转发动态
138
179
  let pic_num = retweeted ? info?.retweeted_status?.pic_num : info?.pic_num;
139
180
  let type = this.MakeCategory(raw_post);
181
+ /**获取动态全文 */
140
182
  if (info?.isLongText || pic_num > 9) {
141
183
  const res = await fetch(`https://m.weibo.cn/detail/${info.mid}`, { headers: WeiboApi.WEIBO_HEADERS });
142
184
  try {
@@ -151,6 +193,7 @@ class WeiboQuery {
151
193
  (logger ?? Bot.logger)?.mark(`优纪插件:获取微博动态全文出错:https://m.weibo.cn/detail/${info?.mid}`);
152
194
  }
153
195
  }
196
+ /**动态发布时间 */
154
197
  let created_time = this.getDynamicCreatetDate(raw_post);
155
198
  let detail_url = `https://weibo.com/${info?.user?.id}/${info?.bid}`;
156
199
  let title = `微博【${upName}】动态推送:\n`;
@@ -254,10 +297,12 @@ class WeiboQuery {
254
297
  return "continue";
255
298
  }
256
299
  }
300
+ // 限制文字模式下动态内容的字数和行数
257
301
  static dynamicContentLimit(content, setData) {
258
302
  const lines = content.split("\n");
259
303
  const lengthLimit = setData.pushContentLenLimit || 100;
260
304
  const lineLimit = setData.pushContentLineLimit || 5;
305
+ // 限制行数
261
306
  if (lines.length > lineLimit) {
262
307
  lines.length = lineLimit;
263
308
  }
@@ -278,10 +323,13 @@ class WeiboQuery {
278
323
  }
279
324
  return lines.join("\n");
280
325
  }
326
+ // 处理斜杠开头的url
281
327
  static formatUrl(url) {
282
328
  return 0 == url.indexOf('//') ? `https:${url}` : url;
283
329
  }
330
+ /**推送类型设置 */
284
331
  static typeHandle(up, msg, type) {
332
+ // 定义一个对象映射,将关键字映射到对应的类型
285
333
  const typeMap = {
286
334
  "直播": "DYNAMIC_TYPE_LIVE_RCMD",
287
335
  "转发": "DYNAMIC_TYPE_FORWARD",
@@ -289,33 +337,42 @@ class WeiboQuery {
289
337
  "图文": ["DYNAMIC_TYPE_DRAW", "DYNAMIC_TYPE_WORD"],
290
338
  "视频": "DYNAMIC_TYPE_AV"
291
339
  };
340
+ // 初始化新的类型集合,如果 up.type 存在则使用它,否则使用空数组
292
341
  let newType = new Set(up.type || []);
342
+ // 定义一个处理类型的函数,根据传入的 action 参数决定是添加还是删除类型
293
343
  const handleType = (action) => {
294
- let isHandled = false;
344
+ let isHandled = false; // 标记是否有类型被处理
345
+ // 遍历 typeMap 对象,根据 msg 中的关键字进行类型操作
295
346
  for (const [key, value] of Object.entries(typeMap)) {
296
347
  if (msg.indexOf(key) !== -1) {
297
348
  if (Array.isArray(value)) {
349
+ // 如果 value 是数组,则对数组中的每个元素进行操作
298
350
  value.forEach(v => action === "add" ? newType.add(v) : newType.delete(v));
299
351
  }
300
352
  else {
353
+ // 否则直接对单个值进行操作
301
354
  action === "add" ? newType.add(value) : newType.delete(value);
302
355
  }
303
- isHandled = true;
356
+ isHandled = true; // 标记有类型被处理
304
357
  }
305
358
  }
306
- return isHandled;
359
+ return isHandled; // 返回是否有类型被处理
307
360
  };
361
+ // 根据 type 参数决定是添加还是删除类型
308
362
  if (type === "add") {
309
- handleType("add");
363
+ handleType("add"); // 调用 handleType 函数进行类型添加
310
364
  }
311
365
  else if (type === "del") {
312
366
  if (!newType.size) {
367
+ // 如果 newType 为空,则初始化它为所有可能的类型
313
368
  newType = new Set(Object.values(typeMap).flat());
314
369
  }
370
+ // 调用 handleType 函数进行类型删除,如果没有类型被删除则清空 newType
315
371
  if (!handleType("delete")) {
316
372
  newType.clear();
317
373
  }
318
374
  }
375
+ // 将 newType 转换为数组并返回
319
376
  return Array.from(newType);
320
377
  }
321
378
  }
@@ -8,11 +8,60 @@ export declare class WeiboTask {
8
8
  e?: EventType;
9
9
  constructor(e?: any);
10
10
  runTask(): Promise<void>;
11
+ /**
12
+ * 处理微博数据,获取动态列表并构建 uid 映射
13
+ * @param weiboPushData 微博推送数据
14
+ * @param uidMap uid 映射
15
+ * @param dynamicList 动态列表
16
+ */
11
17
  processWeiboData(weiboPushData: any, uidMap: Map<any, Map<string, any>>, dynamicList: any): Promise<void>;
18
+ /**
19
+ * 推送动态消息
20
+ * @param uidMap uid 映射
21
+ * @param dynamicList 动态列表
22
+ * @param now 当前时间戳
23
+ * @param interval 推送间隔时间
24
+ * @param weiboConfigData 微博配置数据
25
+ */
12
26
  pushDynamicMessages(uidMap: Map<any, Map<string, any>>, dynamicList: any, now: number, interval: number, weiboConfigData: any): Promise<void>;
27
+ /**
28
+ * 发送动态消息
29
+ * @param chatId 聊天 ID
30
+ * @param bot_id 机器人 ID
31
+ * @param upName 用户名
32
+ * @param pushDynamicData 推送动态数据
33
+ * @param weiboConfigData 微博配置数据
34
+ * @param chatType 聊天类型
35
+ */
13
36
  sendDynamic(chatId: string | number, bot_id: string | number, upName: string, pushDynamicData: any, weiboConfigData: any, chatType: string): Promise<string>;
37
+ /**
38
+ * 构建渲染数据
39
+ * @param extentData 扩展数据
40
+ * @param urlQrcodeData URL 二维码数据
41
+ * @param boxGrid 是否启用九宫格样式
42
+ * @returns 渲染数据
43
+ */
14
44
  buildRenderData(extentData: any, urlQrcodeData: string, boxGrid: boolean): MainProps;
45
+ /**
46
+ * 渲染动态卡片
47
+ * @param uid 用户 ID
48
+ * @param renderData 渲染数据
49
+ * @param ScreenshotOptionsData 截图选项数据
50
+ * @returns 图片数据
51
+ */
15
52
  renderDynamicCard(uid: string | number, renderData: MainProps, ScreenshotOptionsData: ScreenshotOptions): Promise<Buffer[] | null>;
53
+ /**
54
+ * 发送消息
55
+ * @param chatId 聊天 ID
56
+ * @param bot_id 机器人 ID
57
+ * @param chatType 聊天类型
58
+ * @param message 消息内容
59
+ */
16
60
  sendMessage(chatId: string | number, bot_id: string | number, chatType: string, message: any): Promise<void>;
61
+ /**
62
+ * 随机延时
63
+ * @param min 最小延时时间
64
+ * @param max 最大延时时间
65
+ */
17
66
  randomDelay(min: number, max: number): Promise<void>;
18
67
  }
@@ -18,23 +18,29 @@ class WeiboTask {
18
18
  async runTask() {
19
19
  let weiboConfigData = await Config.getUserConfig("weibo", "config");
20
20
  let weiboPushData = await Config.getUserConfig("weibo", "push");
21
- let interval = weiboConfigData.interval || 7200;
22
- const uidMap = new Map();
23
- const dynamicList = {};
21
+ let interval = weiboConfigData.interval || 7200; // 推送间隔时间,单位为秒,默认2小时
22
+ const uidMap = new Map(); // 存放group 和 private 对应所属 uid 与推送信息的映射
23
+ const dynamicList = {}; // 存放获取的所有动态,键为 uid,值为动态数组
24
24
  await this.processWeiboData(weiboPushData, uidMap, dynamicList);
25
- let now = Date.now() / 1000;
25
+ let now = Date.now() / 1000; // 当前时间戳(秒)
26
26
  await this.pushDynamicMessages(uidMap, dynamicList, now, interval, weiboConfigData);
27
27
  }
28
+ /**
29
+ * 处理微博数据,获取动态列表并构建 uid 映射
30
+ * @param weiboPushData 微博推送数据
31
+ * @param uidMap uid 映射
32
+ * @param dynamicList 动态列表
33
+ */
28
34
  async processWeiboData(weiboPushData, uidMap, dynamicList) {
29
- for (let chatType in weiboPushData) {
35
+ for (let chatType in weiboPushData) { // 遍历 group 和 private
30
36
  if (!uidMap.has(chatType)) {
31
37
  uidMap.set(chatType, new Map());
32
38
  }
33
- const chatTypeMap = uidMap.get(chatType);
39
+ const chatTypeMap = uidMap.get(chatType); // 建立当前 chatType (group 或 private) 的 uid 映射
34
40
  for (let chatId in weiboPushData[chatType]) {
35
41
  const subUpsOfChat = weiboPushData[chatType][chatId] || [];
36
42
  for (let subInfoOfup of subUpsOfChat) {
37
- const resp = await new WeiboGetWebData().getBloggerDynamicList(subInfoOfup.uid);
43
+ const resp = await new WeiboGetWebData().getBloggerDynamicList(subInfoOfup.uid); // 获取指定 uid 的动态列表
38
44
  if (resp) {
39
45
  const dynamicData = resp || [];
40
46
  dynamicList[subInfoOfup.uid] = dynamicData;
@@ -43,17 +49,25 @@ class WeiboTask {
43
49
  const bot_id = subInfoOfup.bot_id || [];
44
50
  const { name, type } = subInfoOfup;
45
51
  chatTypeMap.set(subInfoOfup.uid, { chatIds, bot_id, upName: name, type });
46
- await this.randomDelay(1000, 4000);
52
+ await this.randomDelay(1000, 4000); // 随机延时1-4秒
47
53
  }
48
54
  }
49
55
  }
50
56
  }
57
+ /**
58
+ * 推送动态消息
59
+ * @param uidMap uid 映射
60
+ * @param dynamicList 动态列表
61
+ * @param now 当前时间戳
62
+ * @param interval 推送间隔时间
63
+ * @param weiboConfigData 微博配置数据
64
+ */
51
65
  async pushDynamicMessages(uidMap, dynamicList, now, interval, weiboConfigData) {
52
66
  for (let [chatType, chatTypeMap] of uidMap) {
53
67
  for (let [key, value] of chatTypeMap) {
54
68
  const tempDynamicList = dynamicList[key] || [];
55
69
  const willPushDynamicList = [];
56
- const printedList = new Set();
70
+ const printedList = new Set(); // 已打印的动态列表
57
71
  for (let dynamicItem of tempDynamicList) {
58
72
  let raw_post = dynamicItem || {};
59
73
  let user = raw_post?.mblog?.user || {};
@@ -66,29 +80,39 @@ class WeiboTask {
66
80
  if (Number(now - (WeiboQuery.getDynamicCreatetDate(raw_post) / 1000)) > interval) {
67
81
  logger.debug(`超过间隔,跳过 [ ${user?.screen_name} : ${user?.id} ] ${raw_post?.mblog?.created_at} 的动态`);
68
82
  continue;
69
- }
83
+ } // 如果超过推送时间间隔,跳过当前循环
70
84
  if (dynamicItem.type === "DYNAMIC_TYPE_FORWARD" && !weiboConfigData.pushTransmit)
71
- continue;
85
+ continue; // 如果关闭了转发动态的推送,跳过当前循环
72
86
  willPushDynamicList.push(dynamicItem);
73
87
  }
74
88
  printedList.clear();
75
- const pushMapInfo = value || {};
89
+ const pushMapInfo = value || {}; // 获取当前 uid 对应的推送信息
76
90
  const { chatIds, bot_id, upName, type } = pushMapInfo;
91
+ // 遍历待推送的动态数组,发送动态消息
77
92
  for (let pushDynamicData of willPushDynamicList) {
78
93
  if (chatIds && chatIds.length) {
79
94
  for (let chatId of chatIds) {
80
95
  if (type && type.length && !type.includes(pushDynamicData.type))
81
- continue;
82
- await this.sendDynamic(chatId, bot_id, upName, pushDynamicData, weiboConfigData, chatType);
83
- await this.randomDelay(2000, 10500);
96
+ continue; // 如果禁用了某类型的动态推送,跳过当前循环
97
+ await this.sendDynamic(chatId, bot_id, upName, pushDynamicData, weiboConfigData, chatType); // 发送动态消息
98
+ await this.randomDelay(2000, 10500); // 随机延时2-10.5秒
84
99
  }
85
100
  }
86
101
  }
87
102
  }
88
103
  }
89
104
  }
105
+ /**
106
+ * 发送动态消息
107
+ * @param chatId 聊天 ID
108
+ * @param bot_id 机器人 ID
109
+ * @param upName 用户名
110
+ * @param pushDynamicData 推送动态数据
111
+ * @param weiboConfigData 微博配置数据
112
+ * @param chatType 聊天类型
113
+ */
90
114
  async sendDynamic(chatId, bot_id, upName, pushDynamicData, weiboConfigData, chatType) {
91
- const id_str = WeiboQuery.getDynamicId(pushDynamicData);
115
+ const id_str = WeiboQuery.getDynamicId(pushDynamicData); // 获取动态 ID
92
116
  let sended, markKey;
93
117
  if (chatType === "group") {
94
118
  markKey = this.groupKey;
@@ -99,17 +123,17 @@ class WeiboTask {
99
123
  sended = await Redis.get(`${markKey}${chatId}:${id_str}`);
100
124
  }
101
125
  if (sended)
102
- return;
126
+ return; // 如果已经发送过,则直接返回
103
127
  if (!!weiboConfigData.pushMsgMode) {
104
- const { data, uid } = await WeiboQuery.formatDynamicData(pushDynamicData);
128
+ const { data, uid } = await WeiboQuery.formatDynamicData(pushDynamicData); // 处理动态数据
105
129
  const eval2 = eval;
106
- let banWords = eval2(`/${weiboConfigData.banWords.join("|")}/g`);
130
+ let banWords = eval2(`/${weiboConfigData.banWords.join("|")}/g`); // 构建屏蔽关键字正则表达式
107
131
  if (new RegExp(banWords).test(`${data?.title}${data?.content}`)) {
108
- return "return";
132
+ return "return"; // 如果动态包含屏蔽关键字,则直接返回
109
133
  }
110
- let boxGrid = !!weiboConfigData.boxGrid === false ? false : true;
111
- let isSplit = !!weiboConfigData.isSplit === false ? false : true;
112
- let style = isSplit ? '' : '.unfold { height: 7500px; }';
134
+ let boxGrid = !!weiboConfigData.boxGrid === false ? false : true; // 是否启用九宫格样式,默认为 true
135
+ let isSplit = !!weiboConfigData.isSplit === false ? false : true; // 是否启用分片截图,默认为 true
136
+ let style = isSplit ? '' : '.unfold { height: 7500px; }'; // 不启用分片截图模式的样式
113
137
  const extentData = { ...data };
114
138
  const urlQrcodeData = await QRCode.toDataURL(extentData?.url);
115
139
  let renderData = this.buildRenderData(extentData, urlQrcodeData, boxGrid);
@@ -127,31 +151,38 @@ class WeiboTask {
127
151
  let imgs = await this.renderDynamicCard(uid, renderData, ScreenshotOptionsData);
128
152
  if (!imgs)
129
153
  return;
130
- Redis.set(`${markKey}${chatId}:${id_str}`, "1", { EX: 3600 * 10 });
154
+ Redis.set(`${markKey}${chatId}:${id_str}`, "1", { EX: 3600 * 10 }); // 设置已发送标记
131
155
  (logger ?? Bot.logger)?.mark("优纪插件:B站动态执行推送");
132
156
  for (let i = 0; i < imgs.length; i++) {
133
157
  const image = imgs[i];
134
158
  await this.sendMessage(chatId, bot_id, chatType, Segment.image(image));
135
- await this.randomDelay(2000, 6500);
159
+ await this.randomDelay(2000, 6500); // 随机延时2-6.5秒
136
160
  }
137
161
  await this.randomDelay(1000, 2000);
138
162
  }
139
163
  else {
140
- const dynamicMsg = await WeiboQuery.formatTextDynamicData(upName, pushDynamicData, false, weiboConfigData);
141
- Redis.set(`${markKey}${chatId}:${id_str}`, "1", { EX: 3600 * 10 });
164
+ const dynamicMsg = await WeiboQuery.formatTextDynamicData(upName, pushDynamicData, false, weiboConfigData); //构建文字动态消息
165
+ Redis.set(`${markKey}${chatId}:${id_str}`, "1", { EX: 3600 * 10 }); // 设置已发送标记
142
166
  if (dynamicMsg == "continue" || dynamicMsg == false) {
143
- return "return";
167
+ return "return"; // 如果动态消息构建失败或内部资源获取失败,则直接返回
144
168
  }
145
169
  if (weiboConfigData.banWords.length > 0) {
146
- const banWords = new RegExp(weiboConfigData.banWords.join("|"), "g");
170
+ const banWords = new RegExp(weiboConfigData.banWords.join("|"), "g"); // 构建屏蔽关键字正则表达式
147
171
  if (banWords.test(dynamicMsg.join(""))) {
148
- return "return";
172
+ return "return"; // 如果动态消息包含屏蔽关键字,则直接返回
149
173
  }
150
174
  }
151
175
  await this.sendMessage(chatId, bot_id, chatType, dynamicMsg);
152
176
  await this.randomDelay(1000, 2000);
153
177
  }
154
178
  }
179
+ /**
180
+ * 构建渲染数据
181
+ * @param extentData 扩展数据
182
+ * @param urlQrcodeData URL 二维码数据
183
+ * @param boxGrid 是否启用九宫格样式
184
+ * @returns 渲染数据
185
+ */
155
186
  buildRenderData(extentData, urlQrcodeData, boxGrid) {
156
187
  if (extentData.orig && (extentData.orig).length !== 0) {
157
188
  return {
@@ -205,18 +236,32 @@ class WeiboTask {
205
236
  };
206
237
  }
207
238
  }
239
+ /**
240
+ * 渲染动态卡片
241
+ * @param uid 用户 ID
242
+ * @param renderData 渲染数据
243
+ * @param ScreenshotOptionsData 截图选项数据
244
+ * @returns 图片数据
245
+ */
208
246
  async renderDynamicCard(uid, renderData, ScreenshotOptionsData) {
209
- const dynamicMsg = await Image.renderPage(uid, "MainPage", renderData, ScreenshotOptionsData);
247
+ const dynamicMsg = await Image.renderPage(uid, "MainPage", renderData, ScreenshotOptionsData); // 渲染动态卡片
210
248
  if (dynamicMsg !== false) {
211
- return dynamicMsg.img;
249
+ return dynamicMsg.img; // 缓存图片数据
212
250
  }
213
251
  else {
214
252
  return null;
215
253
  }
216
254
  }
255
+ /**
256
+ * 发送消息
257
+ * @param chatId 聊天 ID
258
+ * @param bot_id 机器人 ID
259
+ * @param chatType 聊天类型
260
+ * @param message 消息内容
261
+ */
217
262
  async sendMessage(chatId, bot_id, chatType, message) {
218
263
  if (chatType === "group") {
219
- await (Bot[bot_id] ?? Bot)?.pickGroup(String(chatId)).sendMsg(message)
264
+ await (Bot[bot_id] ?? Bot)?.pickGroup(String(chatId)).sendMsg(message) // 发送群聊
220
265
  .catch((error) => {
221
266
  (logger ?? Bot.logger)?.error(`群组[${chatId}]推送失败:${JSON.stringify(error)}`);
222
267
  });
@@ -225,9 +270,14 @@ class WeiboTask {
225
270
  await (Bot[bot_id] ?? Bot)?.pickFriend(String(chatId)).sendMsg(message)
226
271
  .catch((error) => {
227
272
  (logger ?? Bot.logger)?.error(`用户[${chatId}]推送失败:${JSON.stringify(error)}`);
228
- });
273
+ }); // 发送好友私聊
229
274
  }
230
275
  }
276
+ /**
277
+ * 随机延时
278
+ * @param min 最小延时时间
279
+ * @param max 最大延时时间
280
+ */
231
281
  async randomDelay(min, max) {
232
282
  await new Promise((resolve) => setTimeout(resolve, Math.floor(Math.random() * (max - min + 1) + min)));
233
283
  }
@@ -1,20 +1,70 @@
1
1
  import chokidar from "chokidar";
2
+ /**
3
+ * Config 类用于管理配置文件的读取和监听
4
+ */
2
5
  declare class Config {
3
- readonly versionPath: string;
6
+ readonly packageJsonPath: string;
4
7
  readonly defaultConfigPath: string;
5
8
  readonly userConfigPath: string;
6
9
  defaultConfig: Record<string, any>;
7
10
  userConfig: Record<string, any>;
8
11
  watcher: Record<string, chokidar.FSWatcher>;
9
12
  constructor();
13
+ /** 操作并创建配置文件到指定目录 */
10
14
  initConfigFiles(): void;
15
+ /**
16
+ * 通用获取配置文件数据方法
17
+ * @param typeDir 配置文件目录类型对应路径 defaultConfig: defaultConfig 或 config: yunzai/data/yuki-plugin/config
18
+ * @param appDir 配置app目录
19
+ * @param functionName 配置文件名称,不包含.yaml后缀
20
+ * @returns {object} 配置数据
21
+ */
11
22
  getConfigData(typeDir: string, appDir: string, functionName: string): any;
23
+ /**
24
+ * 获取配置文件路径
25
+ * @param typeDir 配置文件目录类型对应路径 defaultConfig: defaultConfig 或 config: yunzai/data/yuki-plugin/config
26
+ * @param appDir 配置app目录
27
+ * @param functionName 配置文件名称,不包含.yaml后缀
28
+ * @returns {string} 配置文件路径
29
+ */
12
30
  getConfigFilePath(typeDir: string, appDir: string, functionName: string): string;
31
+ /**
32
+ * 监听配置文件的变化
33
+ * @param configFilePath 文件路径
34
+ * @param typeDir 配置文件目录类型对应路径 defaultConfig: defaultConfig 或 config: yunzai/data/yuki-plugin/config
35
+ * @param appDir 配置app目录
36
+ * @param functionName 配置文件名称,不包含.yaml后缀
37
+ */
13
38
  watch(configFilePath: string, typeDir: string, appDir: string, functionName: string): void;
39
+ /**
40
+ * 获取默认配置
41
+ * @param appDir 配置app目录
42
+ * @param functionName 配置文件名称,不包含.yaml后缀
43
+ */
14
44
  getDefaultConfig(appDir: string, functionName: string): any;
45
+ /**
46
+ * 获取用户配置
47
+ * @param appDir 配置app目录
48
+ * @param functionName 配置文件名称,不包含.yaml后缀
49
+ */
15
50
  getUserConfig(appDir: string, functionName: string): any;
51
+ /**
52
+ * 保存配置文件
53
+ * @param typeDir 插件为起始的配置文件目录
54
+ * @param appDir 配置app目录
55
+ * @param functionName 配置文件名称,不包含.yaml后缀
56
+ * @param data 配置数据
57
+ */
16
58
  saveConfig(typeDir: string, appDir: string, functionName: string, data: any): void;
59
+ /**
60
+ * 更新并保存配置项
61
+ * @param appDir 配置app目录
62
+ * @param functionName 配置文件名称,不包含.yaml后缀
63
+ * @param key 配置项的键
64
+ * @param value 配置项的值
65
+ */
17
66
  updateConfigItem(appDir: string, functionName: string, key: string, value: any): void;
67
+ /** 读取package.json文件,获取最新版本号*/
18
68
  getLatestVersion(): string | null;
19
69
  }
20
70
  declare const _default: Config;