yz-yuki-plugin 2.0.7-18 → 2.0.7-19

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/CHANGELOG.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # 2.0.7
2
+ * 新增动态内容过多时转发发送功能,默认开启
2
3
  * 优化动态检查日志
3
4
  * 优化文字动态内容及排版,修复微博视频图片混合的动态显示缺失问题
4
5
  * 优化获取B站文章动态内容
@@ -60,6 +60,9 @@ banWords:
60
60
  # 设置B站动态消息模式 0 文字模式 1 图片模式
61
61
  pushMsgMode: 1
62
62
 
63
+ # 动态过长(>300字)或条数过多(>2条)时是否以转发形式发送动态,默认 1 开启,0 关闭。
64
+ forwardSendDynamic: 1
65
+
63
66
  # 文字模式时,文字消息与图片附件是否合并在一起发送,默认 1 合并,0 不合并。
64
67
  # 如果合并时图片过多导致发送失败,可设置为 0 单独发送图片。
65
68
  mergeTextPic: 1
@@ -55,6 +55,9 @@ banWords:
55
55
  # 设置微博动态消息模式 0 文字模式 1 图片模式
56
56
  pushMsgMode: 1
57
57
 
58
+ # 动态过长(>300字)或条数过多(>2条)时是否以转发形式发送动态,默认 1 开启,0 关闭。
59
+ forwardSendDynamic: 1
60
+
58
61
  # 文字模式时,文字消息与图片附件是否合并在一起发送,默认 1 合并,0 不合并。
59
62
  # 如果合并时图片过多导致发送失败,可设置为 0 单独发送图片。
60
63
  mergeTextPic: 1
@@ -380,51 +380,103 @@ class BiliTask {
380
380
  async sendDynamicMessage(messageMap, biliConfigData) {
381
381
  let liveAtAll = !!biliConfigData.liveAtAll === true ? true : false; // 直播动态是否@全体成员,默认false
382
382
  let liveAtAllCD = biliConfigData.liveAtAllCD || 1800; // 直播动态@全体成员 冷却时间CD,默认 30 分钟
383
+ let forwardSendDynamic = biliConfigData.forwardSendDynamic === 0 || biliConfigData.forwardSendDynamic === false ? false : true; // 转发动态是否合并发送,默认 true
383
384
  // 直播动态@全体成员的群组/好友列表,默认空数组,为空则不进行@全体成员操作
384
385
  let liveAtAllGroupList = new Set(Array.isArray(biliConfigData?.liveAtAllGroupList) ? Array.from(biliConfigData.liveAtAllGroupList).map(item => String(item)) : []);
385
386
  const LogMark = new Set(); // 日志mark
386
387
  for (const [chatType, botMap] of messageMap) {
387
388
  for (const [bot_id, chatMap] of botMap) {
388
389
  for (const [chatId, messageCombinationList] of chatMap) {
389
- // 遍历组合消息
390
+ // 区分群聊和私聊
391
+ let markKey = chatType === 'group' ? this.groupKey : this.privateKey;
392
+ if (!LogMark.has('1')) {
393
+ global?.logger?.mark('优纪插件: B站动态执行推送');
394
+ LogMark.add('1');
395
+ }
396
+ let liveAtAllMark = await Redis.get(`${markKey}${chatId}:liveAtAllMark`); // 直播动态@全体成员标记,默认 0
397
+ const hasLiveDynamic = messageCombinationList.some(m => m.dynamicType === 'DYNAMIC_TYPE_LIVE_RCMD');
398
+ // 如果开启了直播动态@全体成员
399
+ if (liveAtAll && !liveAtAllMark && hasLiveDynamic && liveAtAllGroupList.has(String(chatId))) {
400
+ try {
401
+ await this.sendMsgApi(chatId, bot_id, chatType, [Segment.at('all')]);
402
+ await Redis.set(`${markKey}${chatId}:liveAtAllMark`, 1, { EX: liveAtAllCD }); // 设置直播动态@全体成员标记为 1
403
+ }
404
+ catch (error) {
405
+ logger.error(`直播动态发送@全体成员失败,请检查 <机器人> 是否有 [管理员权限] 或 [聊天平台是否支持] :${error}`);
406
+ let liveAtAllErrMsg = !!biliConfigData.liveAtAllErrMsg === false ? false : true; // 直播动态@全体成员失败是否发送错误提示消息,默认 false
407
+ if (liveAtAllErrMsg) {
408
+ await this.sendMsgApi(chatId, bot_id, chatType, ['直播动态发送@全体成员失败,请检查权限或平台是否支持']);
409
+ }
410
+ }
411
+ }
412
+ // 统计图片数量和文字长度
413
+ let imageCount = 0;
414
+ let textLength = 0;
390
415
  for (const messageCombination of messageCombinationList) {
391
- const { sendMode, dynamicUUid_str, dynamicType, messages } = messageCombination;
392
- let markKey = '';
393
- if (chatType === 'group') {
394
- markKey = this.groupKey;
416
+ const { messages } = messageCombination;
417
+ for (const msg of messages) {
418
+ if (typeof msg === 'object' && msg.type === 'image') {
419
+ imageCount++;
420
+ }
421
+ else if (typeof msg === 'string') {
422
+ textLength += msg.length;
423
+ }
424
+ }
425
+ }
426
+ // 满足条件才使用合并转发
427
+ const useForward = imageCount > 2 || textLength > 300;
428
+ if (forwardSendDynamic && useForward) {
429
+ const forwardNodes = [];
430
+ // 合并所有消息
431
+ const forwardSendMardKeyList = [];
432
+ forwardNodes.push({
433
+ name: '优纪酱通知',
434
+ uin: String(80000000),
435
+ message: ['有新的B站动态了~'],
436
+ time: Date.now()
437
+ });
438
+ for (const messageCombination of messageCombinationList) {
439
+ const { sendMode, dynamicUUid_str, dynamicType, messages } = messageCombination;
440
+ const sendMarkKey = `${markKey}${chatId}:${dynamicUUid_str}`;
441
+ // 原子性设置标记,防止并发重复
442
+ const setResult = await Redis.set(sendMarkKey, '1', { NX: true, EX: 3600 * 72 });
443
+ if (!setResult) {
444
+ continue; // 已有标记,跳过
445
+ }
446
+ forwardSendMardKeyList.push(sendMarkKey); // 收集合并转发的标记键
447
+ // 每条动态一个 node
448
+ forwardNodes.push({
449
+ name: '匿名消息',
450
+ uin: String(80000000),
451
+ message: messages,
452
+ time: Date.now()
453
+ });
454
+ }
455
+ // 尝试合并转发动态
456
+ if ((await this.sendMsgApi(chatId, bot_id, chatType, '优纪酱B站动态通知~')) &&
457
+ (await this.sendForwardMsgApi(chatId, bot_id, chatType, forwardNodes))) {
458
+ await this.randomDelay(1000, 2000);
459
+ continue; // 合并转发成功,跳过后续单条发送逻辑
395
460
  }
396
- else if (chatType === 'private') {
397
- markKey = this.privateKey;
461
+ else {
462
+ for (const sendMarkKey of forwardSendMardKeyList) {
463
+ await Redis.del(sendMarkKey); // 发送消息失败,删除合并转发成功标记
464
+ }
398
465
  }
466
+ }
467
+ // 合并转发失败,回退为原有方式
468
+ for (const messageCombination of messageCombinationList) {
469
+ const { sendMode, dynamicUUid_str, dynamicType, messages } = messageCombination;
399
470
  const sendMarkKey = `${markKey}${chatId}:${dynamicUUid_str}`;
400
471
  // 原子性设置标记,防止并发重复
401
472
  const setResult = await Redis.set(sendMarkKey, '1', { NX: true, EX: 3600 * 72 });
402
473
  if (!setResult) {
403
474
  continue; // 已有标记,跳过
404
475
  }
405
- if (!LogMark.has('1')) {
406
- global?.logger?.mark('优纪插件: B站动态执行推送');
407
- LogMark.add('1');
408
- }
409
- let liveAtAllMark = await Redis.get(`${markKey}${chatId}:liveAtAllMark`); // 直播动态@全体成员标记,默认 0
410
- // 如果开启了直播动态@全体成员
411
- if (liveAtAll && !liveAtAllMark && dynamicType === 'DYNAMIC_TYPE_LIVE_RCMD' && liveAtAllGroupList.has(String(chatId))) {
412
- try {
413
- await this.sendMessageApi(chatId, bot_id, chatType, [Segment.at('all')]);
414
- await Redis.set(`${markKey}${chatId}:liveAtAllMark`, 1, { EX: liveAtAllCD }); // 设置直播动态@全体成员标记为 1
415
- }
416
- catch (error) {
417
- logger.error(`直播动态发送@全体成员失败,请检查 <机器人> 是否有 [管理员权限] 或 [聊天平台是否支持] :${error}`);
418
- let liveAtAllErrMsg = !!biliConfigData.liveAtAllErrMsg === false ? false : true; // 直播动态@全体成员失败是否发送错误提示消息,默认 false
419
- if (liveAtAllErrMsg) {
420
- await this.sendMessageApi(chatId, bot_id, chatType, ['直播动态发送@全体成员失败,请检查权限或平台是否支持']);
421
- }
422
- }
423
- }
424
476
  let sendSuccess = true;
425
477
  if (sendMode === 'SINGLE') {
426
478
  for (let i = 0; i < messages.length; i++) {
427
- if (!(await this.sendMessageApi(chatId, bot_id, chatType, messages[i]))) {
479
+ if (!(await this.sendMsgApi(chatId, bot_id, chatType, messages[i]))) {
428
480
  sendSuccess = false;
429
481
  break;
430
482
  }
@@ -437,7 +489,7 @@ class BiliTask {
437
489
  }
438
490
  }
439
491
  else if (sendMode === 'MERGE') {
440
- if (!(await this.sendMessageApi(chatId, bot_id, chatType, messages))) {
492
+ if (!(await this.sendMsgApi(chatId, bot_id, chatType, messages))) {
441
493
  await Redis.del(sendMarkKey); // 失败删除标记
442
494
  }
443
495
  await this.randomDelay(1000, 2000);
@@ -455,7 +507,7 @@ class BiliTask {
455
507
  * @param chatType 聊天类型
456
508
  * @param message 消息内容
457
509
  */
458
- async sendMessageApi(chatId, bot_id, chatType, message) {
510
+ async sendMsgApi(chatId, bot_id, chatType, message) {
459
511
  try {
460
512
  if (chatType === 'group') {
461
513
  await (Bot[bot_id] ?? Bot)?.pickGroup(String(chatId)).sendMsg(message); // 发送群聊
@@ -470,6 +522,30 @@ class BiliTask {
470
522
  return false; // 发送失败
471
523
  }
472
524
  }
525
+ /**
526
+ * 发送合并转发消息
527
+ * @param chatId 聊天 ID
528
+ * @param bot_id 机器人 ID
529
+ * @param chatType 聊天类型
530
+ * @param message 消息内容
531
+ * @returns 是否发送成功
532
+ */
533
+ async sendForwardMsgApi(chatId, bot_id, chatType, forwardNodes) {
534
+ const forwardMsg = await Bot.makeForwardMsg(forwardNodes);
535
+ try {
536
+ if (chatType === 'group') {
537
+ await (Bot[bot_id] ?? Bot)?.pickGroup(String(chatId)).sendMsg(forwardMsg); // 发送群聊合并转发
538
+ }
539
+ else if (chatType === 'private') {
540
+ await (Bot[bot_id] ?? Bot)?.pickFriend(String(chatId)).sendMsg(forwardMsg); // 发送好友私聊合并转发
541
+ }
542
+ return true; // 发送成功
543
+ }
544
+ catch (error) {
545
+ global?.logger?.error(`${chatType === 'group' ? '群聊' : '私聊'} ${chatId} 合并转发消息发送失败:${JSON.stringify(error)}`);
546
+ return false; // 发送失败
547
+ }
548
+ }
473
549
  /**
474
550
  * 随机延时
475
551
  * @param min 最小延时时间
@@ -344,34 +344,85 @@ class WeiboTask {
344
344
  * @param biliConfigData 微博配置数据
345
345
  */
346
346
  async sendDynamicMessage(messageMap, weiboConfigData) {
347
+ let forwardSendDynamic = weiboConfigData.forwardSendDynamic === 0 || weiboConfigData.forwardSendDynamic === false ? false : true; // 转发动态是否合并发送,默认 true
347
348
  const LogMark = new Set(); // 日志mark
348
349
  for (const [chatType, botMap] of messageMap) {
349
350
  for (const [bot_id, chatMap] of botMap) {
350
351
  for (const [chatId, messageCombinationList] of chatMap) {
351
- // 遍历组合消息
352
+ // 区分群聊和私聊
353
+ let markKey = chatType === 'group' ? this.groupKey : this.privateKey;
354
+ if (!LogMark.has('1')) {
355
+ global?.logger?.mark('优纪插件: B站动态执行推送');
356
+ LogMark.add('1');
357
+ }
358
+ // 统计图片数量和文字长度
359
+ let imageCount = 0;
360
+ let textLength = 0;
352
361
  for (const messageCombination of messageCombinationList) {
353
- const { sendMode, dynamicUUid_str, dynamicType, messages } = messageCombination;
354
- let markKey = '';
355
- if (chatType === 'group') {
356
- markKey = this.groupKey;
362
+ const { messages } = messageCombination;
363
+ for (const msg of messages) {
364
+ if (typeof msg === 'object' && msg.type === 'image') {
365
+ imageCount++;
366
+ }
367
+ else if (typeof msg === 'string') {
368
+ textLength += msg.length;
369
+ }
370
+ }
371
+ }
372
+ // 满足条件才使用合并转发
373
+ const useForward = imageCount > 2 || textLength > 300;
374
+ if (forwardSendDynamic && useForward) {
375
+ const forwardNodes = [];
376
+ // 合并所有消息
377
+ const forwardSendMardKeyList = [];
378
+ forwardNodes.push({
379
+ name: '优纪酱通知',
380
+ uin: String(80000000),
381
+ message: ['有新的微博动态了~'],
382
+ time: Date.now()
383
+ });
384
+ for (const messageCombination of messageCombinationList) {
385
+ const { sendMode, dynamicUUid_str, dynamicType, messages } = messageCombination;
386
+ const sendMarkKey = `${markKey}${chatId}:${dynamicUUid_str}`;
387
+ // 原子性设置标记,防止并发重复
388
+ const setResult = await Redis.set(sendMarkKey, '1', { NX: true, EX: 3600 * 72 });
389
+ if (!setResult) {
390
+ continue; // 已有标记,跳过
391
+ }
392
+ forwardSendMardKeyList.push(sendMarkKey); // 收集合并转发的标记键
393
+ // 每条动态一个 node
394
+ forwardNodes.push({
395
+ name: '匿名消息',
396
+ uin: String(80000000),
397
+ message: messages,
398
+ time: Date.now()
399
+ });
400
+ }
401
+ // 尝试合并转发动态
402
+ if ((await this.sendMsgApi(chatId, bot_id, chatType, '优纪酱微博动态通知~')) &&
403
+ (await this.sendForwardMsgApi(chatId, bot_id, chatType, forwardNodes))) {
404
+ await this.randomDelay(1000, 2000);
405
+ continue; // 合并转发成功,跳过后续单条发送逻辑
357
406
  }
358
- else if (chatType === 'private') {
359
- markKey = this.privateKey;
407
+ else {
408
+ for (const sendMarkKey of forwardSendMardKeyList) {
409
+ await Redis.del(sendMarkKey); // 发送消息失败,删除合并转发成功标记
410
+ }
360
411
  }
412
+ }
413
+ // 合并转发失败,回退为原有方式
414
+ for (const messageCombination of messageCombinationList) {
415
+ const { sendMode, dynamicUUid_str, dynamicType, messages } = messageCombination;
361
416
  const sendMarkKey = `${markKey}${chatId}:${dynamicUUid_str}`;
362
417
  // 原子性设置标记,防止并发重复
363
418
  const setResult = await Redis.set(sendMarkKey, '1', { NX: true, EX: 3600 * 72 });
364
419
  if (!setResult) {
365
420
  continue; // 已有标记,跳过
366
421
  }
367
- if (!LogMark.has('1')) {
368
- global?.logger?.mark('优纪插件: B站动态执行推送');
369
- LogMark.add('1');
370
- }
371
422
  let sendSuccess = true;
372
423
  if (sendMode === 'SINGLE') {
373
424
  for (let i = 0; i < messages.length; i++) {
374
- if (!(await this.sendMessageApi(chatId, bot_id, chatType, messages[i]))) {
425
+ if (!(await this.sendMsgApi(chatId, bot_id, chatType, messages[i]))) {
375
426
  sendSuccess = false;
376
427
  break;
377
428
  }
@@ -384,7 +435,7 @@ class WeiboTask {
384
435
  }
385
436
  }
386
437
  else if (sendMode === 'MERGE') {
387
- if (!(await this.sendMessageApi(chatId, bot_id, chatType, messages))) {
438
+ if (!(await this.sendMsgApi(chatId, bot_id, chatType, messages))) {
388
439
  await Redis.del(sendMarkKey); // 失败删除标记
389
440
  }
390
441
  await this.randomDelay(1000, 2000);
@@ -402,7 +453,7 @@ class WeiboTask {
402
453
  * @param chatType 聊天类型
403
454
  * @param message 消息内容
404
455
  */
405
- async sendMessageApi(chatId, bot_id, chatType, message) {
456
+ async sendMsgApi(chatId, bot_id, chatType, message) {
406
457
  try {
407
458
  if (chatType === 'group') {
408
459
  await (Bot[bot_id] ?? Bot)?.pickGroup(String(chatId)).sendMsg(message); // 发送群聊
@@ -417,6 +468,30 @@ class WeiboTask {
417
468
  return false; // 发送失败
418
469
  }
419
470
  }
471
+ /**
472
+ * 发送合并转发消息
473
+ * @param chatId 聊天 ID
474
+ * @param bot_id 机器人 ID
475
+ * @param chatType 聊天类型
476
+ * @param message 消息内容
477
+ * @returns 是否发送成功
478
+ */
479
+ async sendForwardMsgApi(chatId, bot_id, chatType, forwardNodes) {
480
+ const forwardMsg = await Bot.makeForwardMsg(forwardNodes);
481
+ try {
482
+ if (chatType === 'group') {
483
+ await (Bot[bot_id] ?? Bot)?.pickGroup(String(chatId)).sendMsg(forwardMsg); // 发送群聊合并转发
484
+ }
485
+ else if (chatType === 'private') {
486
+ await (Bot[bot_id] ?? Bot)?.pickFriend(String(chatId)).sendMsg(forwardMsg); // 发送好友私聊合并转发
487
+ }
488
+ return true; // 发送成功
489
+ }
490
+ catch (error) {
491
+ global?.logger?.error(`${chatType === 'group' ? '群聊' : '私聊'} ${chatId} 合并转发消息发送失败:${JSON.stringify(error)}`);
492
+ return false; // 发送失败
493
+ }
494
+ }
420
495
  /**
421
496
  * 随机延时
422
497
  * @param min 最小延时时间
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yz-yuki-plugin",
3
- "version": "2.0.7-18",
3
+ "version": "2.0.7-19",
4
4
  "description": "优纪插件,yunzaijs 关于 微博推送、B站推送 等功能的拓展插件",
5
5
  "author": "snowtafir",
6
6
  "type": "module",