koishi-plugin-bilibili-notify 3.1.1-alpha.0 → 3.1.3-alpha.0

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.
@@ -1,7 +1,7 @@
1
1
  import { type Bot, type Context, type FlatPick, type Logger, Schema } from "koishi";
2
2
  import type { Notifier } from "@koishijs/plugin-notifier";
3
3
  import type { LoginBili } from "./database";
4
- import { LiveType, type MasterInfo, PushType, type SubItem, type SubManager, type Target } from "./type";
4
+ import { LiveType, type MasterInfo, PushType, type Result, type SubItem, type SubManager, type Target } from "./type";
5
5
  declare class ComRegister {
6
6
  static inject: string[];
7
7
  qqRelatedBotList: Array<string>;
@@ -19,11 +19,11 @@ declare class ComRegister {
19
19
  constructor(ctx: Context, config: ComRegister.Config);
20
20
  init(config: ComRegister.Config): Promise<void>;
21
21
  getBot(pf: string): Bot<Context, any>;
22
- test_wordCloud(): Promise<void>;
23
22
  sendPrivateMsg(content: string): Promise<void>;
24
23
  sendPrivateMsgAndRebootService(): Promise<void>;
25
24
  sendPrivateMsgAndStopService(): Promise<void>;
26
25
  sendMessageWithRetry(bot: Bot<Context>, channelId: string, content: any): Promise<void>;
26
+ getGroupsThatMeetCriteria(targets: Target, type: PushType): string[];
27
27
  broadcastToTargets(targets: Target, content: any, type: PushType): Promise<void>;
28
28
  dynamicDetect(): (...args: any[]) => void;
29
29
  debug_dynamicDetect(): (...args: any[]) => void;
@@ -33,11 +33,8 @@ declare class ComRegister {
33
33
  subShow(): string;
34
34
  updateSubNotifier(): void;
35
35
  checkIfLoginInfoIsLoaded(): Promise<unknown>;
36
- subUserInBili(mid: string): Promise<{
37
- code: number;
38
- msg: string;
39
- }>;
40
- loadSubFromConfig(subs: ComRegister.Config["sub"]): Promise<void>;
36
+ subUserInBili(mid: string): Promise<Result>;
37
+ loadSubFromConfig(subs: ComRegister.Config["sub"]): Promise<Result>;
41
38
  checkIfDynamicDetectIsNeeded(): void;
42
39
  enableDynamicDetect(): void;
43
40
  checkIfIsLogin(): Promise<boolean>;
@@ -176,7 +176,10 @@ class ComRegister {
176
176
  // 销毁定时器
177
177
  this.loginTimer();
178
178
  // 订阅手动订阅中的订阅
179
- await this.loadSubFromConfig(config.sub);
179
+ const { code, msg } = await this.loadSubFromConfig(config.sub);
180
+ // 判断是否加载成功
181
+ if (code !== 0)
182
+ this.logger.error(msg);
180
183
  // 清除控制台通知
181
184
  ctx.ba.disposeNotifier();
182
185
  // 发送成功登录推送
@@ -295,7 +298,17 @@ class ComRegister {
295
298
  return;
296
299
  }
297
300
  // 从配置获取订阅
298
- config.sub && (await this.loadSubFromConfig(config.sub));
301
+ if (config.sub) {
302
+ const { code, msg } = await this.loadSubFromConfig(config.sub);
303
+ // 判断是否加载成功
304
+ if (code !== 0) {
305
+ this.logger.error(msg);
306
+ this.logger.error("订阅对象加载失败,插件初始化失败!");
307
+ // 发送私聊消息
308
+ await this.sendPrivateMsg("订阅对象加载失败,插件初始化失败!");
309
+ return;
310
+ }
311
+ }
299
312
  // 检查是否需要动态监测
300
313
  this.checkIfDynamicDetectIsNeeded();
301
314
  // 在控制台中显示订阅对象
@@ -316,42 +329,6 @@ class ComRegister {
316
329
  getBot(pf) {
317
330
  return this.ctx.bots.find((bot) => bot.platform === pf);
318
331
  }
319
- // TODO:WordCloud
320
- async test_wordCloud() {
321
- /* const currentLiveDanmakuArr = []
322
- // 定义获取弹幕权重Record函数
323
- const getDanmakuWeightRecord = (): Record<string, number> => {
324
- // 创建segmentit
325
- const segmentit = useDefault(new Segment());
326
- // 创建Record
327
- const danmakuWeightRecord: Record<string, number> = {};
328
- // 循环遍历currentLiveDanmakuArr
329
- for (const danmaku of currentLiveDanmakuArr) {
330
- // 遍历结果
331
- segmentit.doSegment(danmaku).map((word: { w: string; p: number }) => {
332
- // 定义权重
333
- danmakuWeightRecord[word.w] = (danmakuWeightRecord[word.w] || 0) + 1;
334
- });
335
- }
336
- // 返回Record
337
- return danmakuWeightRecord;
338
- }; */
339
- // Test
340
- const testTarget = [
341
- {
342
- channelArr: [
343
- {
344
- channelId: "635762054",
345
- dynamic: true,
346
- live: false,
347
- liveGuardBuy: false,
348
- atAll: false,
349
- },
350
- ],
351
- platform: "qqguild",
352
- },
353
- ];
354
- }
355
332
  async sendPrivateMsg(content) {
356
333
  if (this.config.master.enable) {
357
334
  if (this.config.master.masterAccountGuildId) {
@@ -422,82 +399,93 @@ class ComRegister {
422
399
  await this.sendPrivateMsg(`发送群组ID:${channelId}消息失败,请查看日志`);
423
400
  });
424
401
  }
425
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
426
- async broadcastToTargets(targets, content, type) {
427
- for (const target of targets) {
428
- // 获取机器人实例
429
- const bot = this.getBot(target.platform);
430
- // 定义需要发送的数组
431
- let channelArr = [];
432
- // 判断是否需要推送所有机器人加入的群
433
- if (target.channelArr[0].channelId === "all") {
434
- // 获取所有guild
435
- for (const guild of (await bot.getGuildList()).data) {
436
- channelArr.push({
437
- channelId: guild.id,
438
- dynamic: target.channelArr[0].dynamic,
439
- live: target.channelArr[0].live,
440
- liveGuardBuy: target.channelArr[0].liveGuardBuy,
441
- atAll: target.channelArr[0].atAll,
442
- });
402
+ getGroupsThatMeetCriteria(targets, type) {
403
+ // 定义数组
404
+ const pushArr = [];
405
+ // 判断类型
406
+ if (type === type_1.PushType.Live || type === type_1.PushType.StartBroadcasting) {
407
+ for (const target of targets) {
408
+ for (const channel of target.channelArr) {
409
+ if (channel.live) {
410
+ pushArr.push(`${target.platform}:${channel.channelId}`);
411
+ }
443
412
  }
444
413
  }
445
- else {
446
- channelArr = target.channelArr;
447
- }
448
- // 模式匹配
449
- const pushTypePatternMatching = {
450
- [type_1.PushType.Live]: async () => {
451
- for (const channel of channelArr) {
452
- // 判断是否需要推送动态消息
453
- if (channel.live) {
454
- await this.sendMessageWithRetry(bot, channel.channelId, content);
455
- }
456
- // 延迟发送
457
- await this.ctx.sleep(500);
458
- }
459
- },
460
- [type_1.PushType.Dynamic]: async () => {
461
- for (const channel of channelArr) {
462
- // 判断是否需要推送动态消息
463
- if (channel.live) {
464
- await this.sendMessageWithRetry(bot, channel.channelId, content);
465
- }
466
- // 延迟发送
467
- await this.ctx.sleep(500);
468
- }
469
- },
470
- [type_1.PushType.StartBroadcasting]: async () => {
471
- // 直播开播推送,判断是否需要艾特全体成员
472
- for (const channel of channelArr) {
473
- // 判断是否需要推送直播消息
474
- if (channel.live) {
475
- await this.sendMessageWithRetry(bot, channel.channelId, content);
476
- }
477
- // 判断是否需要艾特全体成员
478
- if (channel.atAll) {
479
- await this.sendMessageWithRetry(bot, channel.channelId, (0, jsx_runtime_1.jsx)("at", { type: "all" }));
480
- }
481
- // 延迟发送
482
- await this.ctx.sleep(500);
414
+ return pushArr;
415
+ }
416
+ if (type === type_1.PushType.Dynamic) {
417
+ for (const target of targets) {
418
+ for (const channel of target.channelArr) {
419
+ if (channel.dynamic) {
420
+ pushArr.push(`${target.platform}:${channel.channelId}`);
483
421
  }
484
- },
485
- [type_1.PushType.LiveGuardBuy]: async () => {
486
- // 直播守护购买推送,判断是否需要艾特全体成员
487
- for (const channel of channelArr) {
488
- // 判断是否需要推送直播消息
489
- if (channel.liveGuardBuy) {
490
- await this.sendMessageWithRetry(bot, channel.channelId, content);
491
- }
492
- // 延迟发送
493
- await this.ctx.sleep(500);
422
+ }
423
+ }
424
+ return pushArr;
425
+ }
426
+ if (type === type_1.PushType.LiveGuardBuy) {
427
+ for (const target of targets) {
428
+ for (const channel of target.channelArr) {
429
+ if (channel.liveGuardBuy) {
430
+ pushArr.push(`${target.platform}:${channel.channelId}`);
494
431
  }
495
- },
496
- };
497
- // 推送
498
- await pushTypePatternMatching[type]();
432
+ }
433
+ }
434
+ return pushArr;
499
435
  }
500
436
  }
437
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
438
+ async broadcastToTargets(targets, content, type) {
439
+ // 不止一个目标平台或一个目标频道
440
+ if (targets.length !== 1 || targets[0].channelArr.length !== 1) {
441
+ // 直接使用broadcast
442
+ const pushArr = this.getGroupsThatMeetCriteria(targets, type);
443
+ // logger
444
+ this.logger.info(`推送消息到 ${pushArr.length} 个目标频道,目标频道为:${pushArr.join(", ")}`);
445
+ // 推送消息
446
+ await (0, utils_1.withRetry)(async () => {
447
+ await this.ctx.broadcast(pushArr, content);
448
+ }, 1);
449
+ // 结束
450
+ return;
451
+ }
452
+ // 获取目标
453
+ const targetChannel = targets[0].channelArr[0];
454
+ // 获取机器人实例
455
+ const bot = this.getBot(targets[0].platform);
456
+ // 模式匹配
457
+ const pushTypePatternMatching = {
458
+ [type_1.PushType.Live]: async () => {
459
+ if (targetChannel.live) {
460
+ // 直接推送
461
+ await this.sendMessageWithRetry(bot, targetChannel.channelId, content);
462
+ }
463
+ },
464
+ [type_1.PushType.Dynamic]: async () => {
465
+ if (targetChannel.dynamic) {
466
+ await this.sendMessageWithRetry(bot, targetChannel.channelId, content);
467
+ }
468
+ },
469
+ [type_1.PushType.StartBroadcasting]: async () => {
470
+ // 判断是否需要推送直播消息
471
+ if (targetChannel.live) {
472
+ await this.sendMessageWithRetry(bot, targetChannel.channelId, content);
473
+ }
474
+ // 判断是否需要艾特全体成员
475
+ if (targetChannel.atAll) {
476
+ await this.sendMessageWithRetry(bot, targetChannel.channelId, (0, jsx_runtime_1.jsx)("at", { type: "all" }));
477
+ }
478
+ },
479
+ [type_1.PushType.LiveGuardBuy]: async () => {
480
+ // 判断是否需要推送直播消息
481
+ if (targetChannel.liveGuardBuy) {
482
+ await this.sendMessageWithRetry(bot, targetChannel.channelId, content);
483
+ }
484
+ },
485
+ };
486
+ // 推送
487
+ await pushTypePatternMatching[type]();
488
+ }
501
489
  dynamicDetect() {
502
490
  // 检测初始化变量
503
491
  let detectSetup = true;
@@ -637,6 +625,12 @@ class ComRegister {
637
625
  }
638
626
  return;
639
627
  }
628
+ if (e.message === "已屏蔽专栏动态") {
629
+ if (this.config.filter.notify) {
630
+ await this.broadcastToTargets(sub.target, `${upName}投稿了一条专栏,已屏蔽`, type_1.PushType.Dynamic);
631
+ }
632
+ return;
633
+ }
640
634
  // 未知错误
641
635
  this.logger.error(`dynamicDetect generateDynamicImg() 推送卡片发送失败,原因:${e.message}`);
642
636
  // 发送私聊消息并重启服务
@@ -840,10 +834,14 @@ class ComRegister {
840
834
  const upName = item.modules.module_author.name;
841
835
  // logger
842
836
  this.logger.info(`当前动态UP主UID:${upUID},UP主名称:${upName}`);
837
+ // 定义是否是订阅的UP主flag
838
+ let isSubscribed = false;
843
839
  // 寻找关注的UP主的动态
844
840
  for (const sub of this.subManager) {
845
841
  // 判断是否是订阅的UP主
846
842
  if (sub.dynamic && sub.uid === upUID) {
843
+ // 将flag设置为true
844
+ isSubscribed = true;
847
845
  // logger:订阅该UP主,推送该动态
848
846
  this.logger.info("订阅该UP主,开始推送该动态...");
849
847
  // logger
@@ -912,6 +910,8 @@ class ComRegister {
912
910
  // logger
913
911
  this.logger.info("动态推送完毕!");
914
912
  }
913
+ }
914
+ if (!isSubscribed) {
915
915
  // logger
916
916
  this.logger.info("不是关注的UP主,跳过该动态");
917
917
  }
@@ -1305,10 +1305,8 @@ class ComRegister {
1305
1305
  // 判断分组是否准备好
1306
1306
  const resp = await checkGroupIsReady();
1307
1307
  // 判断是否创建成功
1308
- if (resp.code !== 0) {
1309
- // 创建分组失败
1308
+ if (resp.code !== 0)
1310
1309
  return resp;
1311
- }
1312
1310
  // 获取分组详情
1313
1311
  const getGroupDetailData = async () => {
1314
1312
  // 获取分组明细
@@ -1321,10 +1319,8 @@ class ComRegister {
1321
1319
  // 分组不存在
1322
1320
  const resp = await checkGroupIsReady();
1323
1321
  // 判断是否创建成功
1324
- if (resp.code !== 0) {
1325
- // 创建分组失败
1326
- return { ...resp, data: undefined };
1327
- }
1322
+ if (resp.code !== 0)
1323
+ return resp;
1328
1324
  // 再次获取分组明细
1329
1325
  return getGroupDetailData();
1330
1326
  }
@@ -1437,85 +1433,67 @@ class ComRegister {
1437
1433
  return await func();
1438
1434
  }
1439
1435
  async loadSubFromConfig(subs) {
1440
- // 定义一个AbortController
1441
- const controller = new AbortController();
1442
- const { signal } = controller;
1443
- // 设置超时
1444
- signal.addEventListener("abort", () => {
1445
- this.logger.info(`${signal.reason},订阅未完全加载!`);
1446
- });
1447
- await Promise.all(subs.map(async (sub) => {
1448
- let timer;
1449
- // 创建一个定时器
1450
- const timeoutPromise = new Promise((_, reject) => {
1451
- timer = this.ctx.setTimeout(() => {
1452
- // 取消订阅加载
1453
- if (signal.aborted)
1454
- return;
1455
- // 终止
1456
- controller.abort(`加载订阅UID:${sub.uid}超时`);
1457
- }, this.config.subLoadTimeout * 1000);
1436
+ for (const sub of subs) {
1437
+ // logger
1438
+ this.logger.info(`加载订阅UID:${sub.uid}中...`);
1439
+ // 定义Data
1440
+ const { code: userInfoCode, msg: userInfoMsg, data: userInfoData, } = await (0, utils_1.withRetry)(async () => {
1441
+ // 获取用户信息
1442
+ const data = await this.ctx.ba.getUserInfo(sub.uid);
1443
+ // 返回用户信息
1444
+ return { code: 0, data };
1445
+ })
1446
+ .then((content) => content.data)
1447
+ .catch((e) => {
1448
+ this.logger.error(`loadSubFromConfig() getUserInfo() 发生了错误,错误为:${e.message}`);
1449
+ // 返回失败
1450
+ return { code: -1, message: `加载订阅UID:${sub.uid}失败!` };
1458
1451
  });
1459
- await Promise.race([
1460
- (async () => {
1461
- // logger
1462
- this.logger.info(`加载订阅UID:${sub.uid}中...`);
1463
- // 定义Data
1464
- const data = await (0, utils_1.withRetry)(async () => await this.ctx.ba.getUserInfo(sub.uid))
1465
- .then((content) => content.data)
1466
- .catch((e) => {
1467
- this.logger.error(`loadSubFromConfig() getUserInfo() 发生了错误,错误为:${e.message}`);
1468
- // logger
1469
- this.logger.info(`加载订阅UID:${sub.uid}失败!`);
1470
- });
1471
- // 判断是否需要订阅直播
1472
- if (sub.live) {
1473
- // 检查roomid是否存在
1474
- if (!data.live_room) {
1475
- // 用户没有开通直播间,无法订阅直播
1476
- sub.live = false;
1477
- // 发送提示
1478
- this.logger.warn(`UID:${sub.uid} 用户没有开通直播间,无法订阅直播!`);
1479
- }
1480
- // 判断是否订阅直播
1481
- if (sub.live) {
1482
- // 启动直播监测
1483
- await this.liveDetectWithListener(data.live_room.roomid, sub.target, sub.card);
1484
- }
1485
- }
1486
- // 在B站中订阅该对象
1487
- const subInfo = await this.subUserInBili(sub.uid);
1488
- // 判断订阅是否成功
1489
- if (subInfo.code !== 0) {
1490
- // 订阅失败,直接返回
1491
- this.logger.error(`UID:${sub.uid} 订阅失败,错误信息:${subInfo.msg}`);
1492
- return;
1493
- }
1494
- // 判断是否超时
1495
- if (signal.aborted) {
1496
- // 订阅加载超时,取消订阅加载
1497
- return;
1498
- }
1499
- // 清除定时器
1500
- timer();
1501
- // 将该订阅添加到sm中
1502
- this.subManager.push({
1503
- id: +sub.uid,
1504
- uid: sub.uid,
1505
- uname: data.name,
1506
- roomId: sub.live ? data.live_room.roomid : "",
1507
- target: sub.target,
1508
- platform: "",
1509
- live: sub.live,
1510
- dynamic: sub.dynamic,
1511
- card: sub.card,
1512
- });
1513
- // logger
1514
- this.logger.info(`UID:${sub.uid}订阅加载完毕!`);
1515
- })(),
1516
- timeoutPromise,
1517
- ]);
1518
- }));
1452
+ // 判断是否获取成功
1453
+ if (userInfoCode !== 0)
1454
+ return { code: userInfoCode, msg: userInfoMsg };
1455
+ // 判断是否需要订阅直播
1456
+ if (sub.live) {
1457
+ // 检查roomid是否存在
1458
+ if (!userInfoData.live_room) {
1459
+ // 用户没有开通直播间,无法订阅直播
1460
+ sub.live = false;
1461
+ // 发送提示
1462
+ this.logger.warn(`UID:${sub.uid} 用户没有开通直播间,无法订阅直播!`);
1463
+ }
1464
+ // 判断是否订阅直播
1465
+ if (sub.live) {
1466
+ // 启动直播监测
1467
+ await this.liveDetectWithListener(userInfoData.live_room.roomid, sub.target, sub.card);
1468
+ }
1469
+ }
1470
+ // 在B站中订阅该对象
1471
+ const subInfo = await this.subUserInBili(sub.uid);
1472
+ // 判断订阅是否成功
1473
+ if (subInfo.code !== 0)
1474
+ return subInfo;
1475
+ // 将该订阅添加到sm中
1476
+ this.subManager.push({
1477
+ id: +sub.uid,
1478
+ uid: sub.uid,
1479
+ uname: userInfoData.name,
1480
+ roomId: sub.live ? userInfoData.live_room.roomid : "",
1481
+ target: sub.target,
1482
+ platform: "",
1483
+ live: sub.live,
1484
+ dynamic: sub.dynamic,
1485
+ card: sub.card,
1486
+ });
1487
+ // logger
1488
+ this.logger.info(`UID:${sub.uid}订阅加载完毕!`);
1489
+ // 1-3秒随机延迟
1490
+ const randomDelay = Math.floor(Math.random() * 3) + 1;
1491
+ // logger
1492
+ this.logger.info(`随机延迟:${randomDelay}秒`);
1493
+ // delay
1494
+ await this.ctx.sleep(randomDelay * 1000);
1495
+ }
1496
+ return { code: 0, msg: "订阅加载完毕!" };
1519
1497
  }
1520
1498
  checkIfDynamicDetectIsNeeded() {
1521
1499
  // 检查是否有订阅对象需要动态监测
@@ -33,6 +33,7 @@ declare namespace GenerateImg {
33
33
  regex: string;
34
34
  keywords: Array<string>;
35
35
  forward: boolean;
36
+ article: boolean;
36
37
  };
37
38
  removeBorder: boolean;
38
39
  cardColorStart: string;
@@ -534,8 +534,13 @@ class GenerateImg extends koishi_1.Service {
534
534
  `${upName}发布了剧集(番剧、电影、纪录片),我暂时无法渲染,请自行查看`,
535
535
  link,
536
536
  ];
537
- case DYNAMIC_TYPE_ARTICLE:
537
+ case DYNAMIC_TYPE_ARTICLE: {
538
+ //转发动态屏蔽
539
+ if (this.giConfig.filter.enable && this.giConfig.filter.article) {
540
+ throw new Error("已屏蔽专栏动态");
541
+ }
538
542
  return [`${upName}投稿了新专栏,我暂时无法渲染,请自行查看`, link];
543
+ }
539
544
  case DYNAMIC_TYPE_MUSIC:
540
545
  return [`${upName}发行了新歌,我暂时无法渲染,请自行查看`, link];
541
546
  case DYNAMIC_TYPE_COMMON_SQUARE:
@@ -1473,6 +1478,7 @@ class GenerateImg extends koishi_1.Service {
1473
1478
  regex: koishi_1.Schema.string(),
1474
1479
  keywords: koishi_1.Schema.array(String),
1475
1480
  forward: koishi_1.Schema.boolean(),
1481
+ article: koishi_1.Schema.boolean(),
1476
1482
  }),
1477
1483
  removeBorder: koishi_1.Schema.boolean(),
1478
1484
  cardColorStart: koishi_1.Schema.string(),
package/lib/index.js CHANGED
@@ -387,6 +387,7 @@ exports.Config = koishi_1.Schema.object({
387
387
  forward: koishi_1.Schema.boolean()
388
388
  .default(false)
389
389
  .description("是否屏蔽转发动态"),
390
+ article: koishi_1.Schema.boolean().default(false).description("是否屏蔽专栏"),
390
391
  }),
391
392
  koishi_1.Schema.object({}),
392
393
  ]),
@@ -5,13 +5,14 @@ export declare enum LiveType {
5
5
  StopBroadcast = 3,
6
6
  FirstLiveBroadcast = 4
7
7
  }
8
- export type ChannelArr = Array<{
8
+ export type Channel = {
9
9
  channelId: string;
10
10
  dynamic: boolean;
11
11
  live: boolean;
12
12
  liveGuardBuy: boolean;
13
13
  atAll: boolean;
14
- }>;
14
+ };
15
+ export type ChannelArr = Array<Channel>;
15
16
  export type TargetItem = {
16
17
  channelArr: ChannelArr;
17
18
  platform: string;
@@ -95,3 +96,8 @@ export declare enum PushType {
95
96
  StartBroadcasting = 2,
96
97
  LiveGuardBuy = 3
97
98
  }
99
+ export type Result = {
100
+ code: number;
101
+ msg?: string;
102
+ data?: any;
103
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-bilibili-notify",
3
3
  "description": "Koishi bilibili notify plugin",
4
- "version": "3.1.1-alpha.0",
4
+ "version": "3.1.3-alpha.0",
5
5
  "contributors": [
6
6
  "Akokko <admin@akokko.com>"
7
7
  ],
package/readme.md CHANGED
@@ -234,6 +234,8 @@ uid为必填参数,为要推送的UP主的UID,index为可选参数,为要
234
234
  - ver 3.1.0-alpha.1 修复:无法发送 `@全体成员` 消息,将消息发送模式改回
235
235
  - ver 3.1.0 修复:订阅某位UP主直播和动态后,某些群聊只开启推送直播也会推送动态
236
236
  - ver 3.1.1-alpha.0 修复:稿件重投后,会将之前日期的动态一起推送; 优化:加强动态debug输出; 移除:不必要选项 `live.liveDetectMode`
237
+ - ver 3.1.2-alpha.0 重构:对消息发送模块进行小型重构,多群多平台推送将不再支持艾特全体成员,仅单平台单群聊支持; 移除:群聊 `all` 选项
238
+ - ver 3.1.3-alpha.0 移除:订阅超时; 新增:屏蔽专栏动态功能; 优化:改进了加载插件的错误提示;
237
239
 
238
240
  ## 交流群
239
241