yz-yuki-plugin 2.0.6-0 → 2.0.6-2

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/README.md CHANGED
@@ -8,6 +8,28 @@
8
8
 
9
9
  [![访问量](https://profile-counter.glitch.me/yuki-plugin/count.svg)](https://github.com/snowtafir/yuki-plugin)
10
10
 
11
+
12
+ # 🚩运行环境:
13
+ 1. 系统:
14
+ * windows 10/11+,
15
+ * Linux推荐:Ubuntu 24.04.1 LTS+, 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
+
11
33
  # 🌰一、安装插件
12
34
 
13
35
  ## 选择安装方式
@@ -44,6 +44,9 @@ banWords:
44
44
  # 设置B站动态消息模式 0 文字模式 1 图片模式
45
45
  pushMsgMode: 1
46
46
 
47
+ # 文字模式时,文字消息与图片附件是否合并在一起发送,默认 1 合并,0 不合并。如果合并时图片过多导致发送失败,可设置为 0 单独发送图片。
48
+ mergeTextPic: 1
49
+
47
50
  # 是否启用九宫格样式:默认 1 启用,0 不启用。此为最高优先级,九宫格为动态模式,特定大小/长宽比的图片资源将会动态启用九宫格/四宫格/无宫格样式。
48
51
  boxGrid: 1
49
52
 
@@ -34,6 +34,9 @@ banWords:
34
34
  # 设置微博动态消息模式 0 文字模式 1 图片模式
35
35
  pushMsgMode: 1
36
36
 
37
+ # 文字模式时,文字消息与图片附件是否合并在一起发送,默认 1 合并,0 不合并。如果合并时图片过多导致发送失败,可设置为 0 单独发送图片。
38
+ mergeTextPic: 1
39
+
37
40
  # 是否启用九宫格样式:默认 1 启用,0 不启用。此为最高优先级,九宫格为动态模式,特定大小/长宽比的图片资源将会动态启用九宫格/四宫格/无宫格样式。
38
41
  boxGrid: 1
39
42
 
@@ -1,6 +1,6 @@
1
1
  import JSON from 'json5';
2
2
  import lodash from 'lodash';
3
- import { Messages, Bot, Redis } from 'yunzaijs';
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
- let biliLoginCk = await pollLoginQRCode(e, token);
174
- if (lodash.trim(biliLoginCk).length != 0) {
175
- await saveLoginCookie(e, biliLoginCk);
176
- e.reply(`get bilibili LoginCk:成功!`);
177
- const result = await postGateway(biliLoginCk); //激活ck
178
- const { code, data } = await result.data; // 解析校验结果
179
- switch (code) {
180
- case 0:
181
- (logger ?? Bot.logger)?.mark(`优纪插件:获取biliLoginCK,Gateway校验成功:${JSON.stringify(data)}`);
182
- break;
183
- default:
184
- (logger ?? Bot.logger)?.mark(`优纪插件:获取biliLoginCK,Gateway校验失败:${JSON.stringify(data)}`);
185
- break;
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
- (logger ?? Bot.logger)?.info(`yuki-plugin Login bilibili Failed:${Error}`);
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
- (logger ?? Bot.logger)?.mark(`优纪插件:绑定localCK,Gateway校验成功:${JSON.stringify(data)}`);
270
+ global?.logger?.mark(`优纪插件:绑定localCK,Gateway校验成功:${JSON.stringify(data)}`);
267
271
  break;
268
272
  default:
269
- (logger ?? Bot.logger)?.mark(`优纪插件:绑定localCK,Gateway校验失败:${JSON.stringify(data)}`);
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
- (logger ?? Bot.logger)?.mark(`优纪插件:B站临时ck刷新error:${error}`);
343
+ global?.logger?.mark(`优纪插件:B站临时ck刷新error:${error}`);
340
344
  }
341
345
  }, [/^(#|\/)(yuki|优纪)?刷新(b站|B站|bili|bilibili|哔哩|哔哩哔哩)临时(ck|CK|cookie|COOKIE)$/]);
342
346
  /** 订阅的全部b站推送列表 */
package/lib/apps/weibo.js CHANGED
@@ -58,7 +58,7 @@ message.use(async (e) => {
58
58
  }
59
59
  const userInfo = data.userInfo || {};
60
60
  let name = uid;
61
- if (userInfo && userInfo.length !== 0) {
61
+ if (userInfo.length !== 0) {
62
62
  name = userInfo.screen_name || uid;
63
63
  }
64
64
  // 添加新的推送数据
@@ -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, Bot, Redis } from 'yunzaijs';
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.data.qrcode_key;
35
- const qrcodeUrl = res.data.url;
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.data.code === 0) {
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.data.code === 86101) {
96
+ else if (data?.data?.code === 86101) {
97
97
  // 未扫码
98
98
  // 继续轮询
99
99
  await new Promise(resolve => setTimeout(resolve, 2000));
100
- (logger ?? Bot.logger)?.mark(`优纪插件:扫码B站登录:未扫码,轮询中...`);
100
+ global?.logger?.mark(`优纪插件:扫码B站登录:未扫码,轮询中...`);
101
101
  return pollLoginQRCode(e, qrcodeKey);
102
102
  }
103
- else if (data.data.code === 86090) {
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.data.code === 86038) {
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
- Bot?.logger?.debug(`B站验证登录状态:${JSON.stringify(resData)}`);
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
- await Redis.set(BiliJctKey, ticket, { EX: ttl });
459
- return cookie + `;bili_ticket=${ticket};`;
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 { Bot, Segment } from 'yunzaijs';
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 { readInfo, articleType } = await this.getFullArticleContent(this.formatUrl(desc?.jump_url));
104
- // 文章链接类型为 cv(旧类型) 或者 opus(新类型)
105
- if (articleType === 'cv') {
106
- formatData.data.content = this.praseFullOldTypeArticleContent(readInfo?.content);
107
- if (String(formatData.data.content).length < 100) {
108
- formatData.data.content = this.parseRichTextNodes(desc?.summary?.rich_text_nodes || desc?.summary?.text) || '';
109
- formatData.data.pics = pics;
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
- formatData.data.pics = [];
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
- else if (articleType === 'opus') {
116
- const { content, img } = this.praseFullNewTypeArticleContent(readInfo?.paragraphs);
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.text.replace(/\n/g, '<br>');
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
- * @param paragraphs - MODULE_TYPE_CONTENT 类型文章的段落数组
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
- content += item.text.nodes
304
- .map((node) => {
305
- let nodeType = node.type;
306
- if (nodeType === 'TEXT_NODE_TYPE_RICH') {
307
- let richType = node?.rich?.type;
308
- switch (richType) {
309
- case 'RICH_TEXT_NODE_TYPE_TOPIC':
310
- // 确保链接以 https:// 开头
311
- let jumpUrl = node?.rich?.jump_url;
312
- if (jumpUrl && !jumpUrl.startsWith('http://') && !jumpUrl.startsWith('https://')) {
313
- jumpUrl = `https://${jumpUrl}`;
314
- }
315
- return `<span class="bili-rich-text-module topic" href="${jumpUrl}">${node?.rich?.text}</span>`;
316
- case 'RICH_TEXT_NODE_TYPE_TEXT':
317
- // 正文将 \n 替换为 <br> 以实现换行
318
- return node?.rich?.text.replace(/\n/g, '<br>');
319
- case 'RICH_TEXT_NODE_TYPE_AT':
320
- // 处理 @ 类型,使用官方的HTML标签写法
321
- return `<span data-module="desc" data-type="at" data-oid="${node?.rich?.rid}" class="bili-rich-text-module at">${node?.rich?.text}</span>`;
322
- case 'RICH_TEXT_NODE_TYPE_LOTTERY':
323
- // 处理互动抽奖类型,使用官方的HTML标签写法
324
- return `<span data-module="desc" data-type="lottery" data-oid="${node?.rich?.rid}" class="bili-rich-text-module lottery">${node?.rich?.text}</span>`;
325
- case 'RICH_TEXT_NODE_TYPE_WEB':
326
- // 处理 RICH_TEXT_NODE_TYPE_WEB 类型,直接拼接 text 属性
327
- return node?.rich?.text;
328
- case 'RICH_TEXT_NODE_TYPE_EMOJI':
329
- // 处理表情类型,使用 img 标签显示表情
330
- const emoji = node?.rich?.emoji;
331
- return `<img src="${emoji?.icon_url}" alt="${emoji?.text}" title="${emoji?.text}" style="vertical-align: middle; width: ${emoji?.size}em; height: ${emoji?.size}em;">`;
332
- case 'RICH_TEXT_NODE_TYPE_GOODS':
333
- // 处理商品推广类型,使用官方的HTML标签写法
334
- const goods_url = node?.rich?.jump_url;
335
- 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}">&ZeroWidthSpace;${node?.rich?.text}</span>`;
336
- default:
337
- return node;
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}">&ZeroWidthSpace;${node?.rich?.text}</span>`;
354
+ default:
355
+ return node;
356
+ }
338
357
  }
339
- }
340
- else if (nodeType === 'TEXT_NODE_TYPE_WORD') {
341
- return `${node?.word?.words}<br>`;
342
- }
343
- })
344
- .join('');
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
- img = img.concat(item?.pic?.pics.map((item) => {
349
- return { url: item?.url, width: item?.width, height: item?.height };
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
- (Bot.logger ?? logger)?.mark(`未处理的B站推送【${upName}】:${data.type}`);
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, Bot, Segment } from 'yunzaijs';
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
- (logger ?? Bot.logger)?.mark('优纪插件:B站动态执行推送');
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 == 'continue') {
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
- await this.sendMessage(chatId, bot_id, chatType, dynamicMsg.msg);
216
- const pics = dynamicMsg.pics;
217
- if (pics && pics.length > 0) {
218
- for (let i = 0; i < pics.length; i++) {
219
- await this.sendMessage(chatId, bot_id, chatType, pics[i]);
220
- await this.randomDelay(1000, 2000); // 随机延时1-2秒
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
- (logger ?? Bot.logger)?.error(`群组[${chatId}]推送失败:${JSON.stringify(error)}`);
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
- (logger ?? Bot.logger)?.error(`用户[${chatId}]推送失败:${JSON.stringify(error)}`);
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
- (logger ?? Bot.logger)?.mark('微博推送:Error fetching sub list:', error);
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 { Bot, Segment } from 'yunzaijs';
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
- (logger ?? Bot.logger)?.mark(`优纪插件:获取微博动态全文出错:https://m.weibo.cn/detail/${info?.mid}`);
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, Bot, Segment } from 'yunzaijs';
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
- (logger ?? Bot.logger)?.mark('优纪插件:微博动态执行推送');
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 == 'continue') {
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
- await this.sendMessage(chatId, bot_id, chatType, dynamicMsg.msg);
191
- const pics = dynamicMsg.pics;
192
- if (pics && pics.length > 0) {
193
- for (let i = 0; i < pics.length; i++) {
194
- await this.sendMessage(chatId, bot_id, chatType, pics[i]);
195
- await this.randomDelay(1000, 2000); // 随机延时1-2秒
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
- (logger ?? Bot.logger)?.error(`群组[${chatId}]推送失败:${JSON.stringify(error)}`);
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
- (logger ?? Bot.logger)?.error(`用户[${chatId}]推送失败:${JSON.stringify(error)}`);
307
+ global?.logger?.error(`用户[${chatId}]推送失败:${JSON.stringify(error)}`);
299
308
  }); // 发送好友私聊
300
309
  }
301
310
  }
@@ -1,6 +1,6 @@
1
1
  import * as fs from 'fs';
2
2
  import YAML from 'yaml';
3
- import chokidar from 'chokidar';
3
+ import * as chokidar from 'chokidar';
4
4
  import lodash from 'lodash';
5
5
  import path from 'path';
6
6
  import { _paths } from './paths.js';
@@ -43,7 +43,7 @@ class Image extends Picture {
43
43
  }
44
44
  }
45
45
  // 存储单例实例
46
- let instance = null;
46
+ let instance;
47
47
  // 存储任务队列
48
48
  const queue = [];
49
49
  // 标记当前是否有任务正在处理
@@ -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-0",
3
+ "version": "2.0.6-2",
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.0.4",
34
+ "jsxp": "^1.0.8",
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": "^23.10.1",
39
+ "puppeteer": "^23.11.1",
40
40
  "qrcode": "^1.5.4",
41
41
  "react": "^18.3.1",
42
42
  "react-dom": "^18.3.1",
@@ -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",
@@ -61,21 +62,21 @@
61
62
  "husky": "^9.1.6",
62
63
  "jsdom": "^24.1.1",
63
64
  "json5": "^2.2.3",
64
- "jsxp": "^1.0.4",
65
+ "jsxp": "^1.0.8",
65
66
  "lodash": "^4.17.21",
66
- "lvyjs": "^0.1.4",
67
+ "lvyjs": "^0.2.14",
67
68
  "md5": "^2.3.0",
68
69
  "node-fetch": "^3.3.2",
69
70
  "postcss": "^8.4.47",
70
71
  "prettier": "^3.4.2",
71
- "puppeteer": "^23.10.1",
72
+ "puppeteer": "^23.11.1",
72
73
  "qrcode": "^1.5.4",
73
74
  "react": "^18.3.1",
74
75
  "react-dom": "^18.3.1",
75
76
  "redis": "^4.7.0",
76
77
  "tailwindcss": "^3.4.14",
77
78
  "ts-node": "^10.9.2",
78
- "tsx": "^4.19.0",
79
+ "tsx": "^4.19.2",
79
80
  "typescript": "^5.5.4",
80
81
  "yaml": "^2.6.1",
81
82
  "yunzaijs": "^1.0.0-rc.5"