koishi-plugin-bilibili-notify 2.0.0-alpha.9 → 3.0.0-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.
@@ -18,14 +18,25 @@ var LiveType;
18
18
  LiveType[LiveType["StopBroadcast"] = 3] = "StopBroadcast";
19
19
  })(LiveType || (LiveType = {}));
20
20
  class ComRegister {
21
- static inject = ['ba', 'gi', 'database', 'sm'];
21
+ // 必须服务
22
+ static inject = ['ba', 'gi', 'database', 'bl', 'sm'];
23
+ // 定义数组:QQ相关bot
22
24
  qqRelatedBotList = ['qq', 'onebot', 'red', 'satori', 'chronocat'];
25
+ // logger
23
26
  logger;
27
+ // config
24
28
  config;
29
+ // 登录定时器
25
30
  loginTimer;
31
+ // 订阅数量
26
32
  num = 0;
33
+ // 重启次数
27
34
  rebootCount = 0;
35
+ // 订阅通知
28
36
  subNotifier;
37
+ // Context
38
+ ctx;
39
+ // 订阅管理器
29
40
  subManager = [];
30
41
  // 检查登录数据库是否有数据
31
42
  loginDBData;
@@ -37,56 +48,11 @@ class ComRegister {
37
48
  sendMsgFunc;
38
49
  // 构造函数
39
50
  constructor(ctx, config) {
40
- this.logger = ctx.logger('cr');
41
- this.config = config;
42
- // 拿到私人机器人实例
43
- this.privateBot = ctx.bots.find(bot => bot.platform === config.master.platform);
44
- if (!this.privateBot) {
45
- ctx.notifier.create({
46
- content: '您未配置私人机器人,将无法向您推送机器人状态!'
47
- });
48
- this.logger.error('您未配置私人机器人,将无法向您推送机器人状态!');
49
- }
50
- // 检查登录数据库是否有数据
51
- ctx.database.get('loginBili', 1, ['dynamic_group_id']).then(data => this.loginDBData = data[0]);
52
- // 从数据库获取订阅
53
- this.getSubFromDatabase(ctx);
54
- // 判断消息发送方式
55
- if (config.automaticResend) {
56
- this.sendMsgFunc = async (bot, guild, content) => {
57
- // 多次尝试发送消息
58
- const attempts = 3;
59
- for (let i = 0; i < attempts; i++) {
60
- try {
61
- // 发送消息
62
- await bot.sendMessage(guild, content);
63
- // 防止消息发送速度过快被忽略
64
- await ctx.sleep(500);
65
- // 成功发送消息,跳出循环
66
- break;
67
- }
68
- catch (e) {
69
- if (i === attempts - 1) { // 已尝试三次
70
- this.logger.error(`发送群组ID:${guild}消息失败!原因: ` + e.message);
71
- console.log(e);
72
- this.sendPrivateMsg(`发送群组ID:${guild}消息失败,请查看日志`);
73
- }
74
- }
75
- }
76
- };
77
- }
78
- else {
79
- this.sendMsgFunc = async (bot, guild, content) => {
80
- try {
81
- // 发送消息
82
- await bot.sendMessage(guild, content);
83
- }
84
- catch (e) {
85
- this.logger.error(`发送群组ID:${guild}消息失败!原因: ` + e.message);
86
- await this.sendPrivateMsg(`发送群组ID:${guild}消息失败,请查看日志`);
87
- }
88
- };
89
- }
51
+ // ctx赋值给类属性
52
+ this.ctx = ctx;
53
+ // 初始化
54
+ this.init(config);
55
+ // 注册指令
90
56
  const statusCom = ctx.command('status', '插件状态相关指令', { permissions: ['authority:5'] });
91
57
  statusCom.subcommand('.dyn', '查看动态监测运行状态')
92
58
  .usage('查看动态监测运行状态')
@@ -198,7 +164,7 @@ class ComRegister {
198
164
  // 销毁定时器
199
165
  this.loginTimer();
200
166
  // 订阅之前的订阅
201
- await this.getSubFromDatabase(ctx);
167
+ await this.loadSubFromDatabase();
202
168
  // 清除控制台通知
203
169
  ctx.ba.disposeNotifier();
204
170
  // 发送成功登录推送
@@ -236,17 +202,14 @@ class ComRegister {
236
202
  // 取消单个订阅
237
203
  if (options.live || options.dynamic) {
238
204
  if (options.live)
239
- await session.send(this.unsubSingle(ctx, sub.roomId, 0)); /* 0为取消订阅Live */
205
+ await session.send(this.unsubSingle(sub.roomId, 0)); /* 0为取消订阅Live */
240
206
  if (options.dynamic)
241
- await session.send(this.unsubSingle(ctx, sub.uid, 1)); /* 1为取消订阅Dynamic */
207
+ await session.send(this.unsubSingle(sub.uid, 1)); /* 1为取消订阅Dynamic */
242
208
  // 将存在flag设置为true
243
209
  exist = true;
244
210
  // 结束循环
245
211
  return;
246
212
  }
247
- // 取消全部订阅 执行dispose方法,销毁定时器
248
- if (sub.live)
249
- this.subManager[i].liveDispose();
250
213
  // 从数据库中删除订阅
251
214
  await ctx.database.remove('bilibili', { uid: this.subManager[i].uid });
252
215
  // 将该订阅对象从订阅管理对象中移除
@@ -265,16 +228,11 @@ class ComRegister {
265
228
  // id--
266
229
  this.num--;
267
230
  // 判断是否还有动态订阅
268
- if (this.dynamicDispose && !this.subManager.find((sub) => sub.dynamic === true)) { // 没有动态订阅
269
- // 将动态检测关闭
270
- this.dynamicDispose();
271
- // 将动态监测置为空
272
- this.dynamicDispose = null;
273
- }
231
+ this.checkIfUserIsTheLastOneWhoSubDyn();
274
232
  // 发送成功通知
275
233
  await session.send('已取消订阅该用户');
276
234
  // 更新控制台提示
277
- this.updateSubNotifier(ctx);
235
+ this.updateSubNotifier();
278
236
  // 将存在flag设置为true
279
237
  exist = true;
280
238
  }
@@ -292,20 +250,21 @@ class ComRegister {
292
250
  return subTable;
293
251
  });
294
252
  biliCom
295
- .subcommand('.sub <mid:string>', '订阅用户动态和直播通知')
296
- .option('multiplatform', '-m <value:string>', { type: /^[A-Za-z0-9]+(?:,[A-Za-z0-9]+)*\.[A-Za-z0-9]+(?:,[A-Za-z0-9]+)*(?:;[A-Za-z0-9]+(?:,[A-Za-z0-9]+)*\.[A-Za-z0-9]+(?:,[A-Za-z0-9]+)*)*$/ })
253
+ .subcommand('.sub <mid:string> [...groupId:string]', '订阅用户动态和直播通知')
254
+ .option('multiplatform', '-m <value:string>', { type: /^(?:-?[A-Za-z0-9]+@?(?:,-?[A-Za-z0-9]+@?)*\.[A-Za-z0-9]+)(?:;(?:-?[A-Za-z0-9]+@?(?:,-?[A-Za-z0-9]+@?)*\.[A-Za-z0-9]+))*$/ })
297
255
  .option('live', '-l')
298
256
  .option('dynamic', '-d')
299
- .usage('订阅用户动态和直播通知,若需要订阅直播请加上-l,需要订阅动态则加上-d。若没有加任何参数,之后会向你单独询问,尖括号中为必选参数,中括号为可选参数,目标群号若不填,则默认为当前群聊')
300
- .example('bili sub 1194210119 目标QQ群号(实验性) -l -d 订阅UID为1194210119的UP主的动态和直播')
301
- .action(async ({ session, options }, mid) => {
257
+ .option('atAll', '-a')
258
+ .usage('订阅用户动态和直播通知,若需要订阅直播请加上-l,需要订阅动态则加上-d')
259
+ .example('bili sub 1194210119 目标群号或频道号 -l -d 订阅UID为1194210119的UP主的动态和直播')
260
+ .action(async ({ session, options }, mid, ...groupId) => {
302
261
  this.logger.info('调用bili.sub指令');
303
262
  // 先判断是否订阅直播,再判断是否解锁订阅限制,最后判断直播订阅是否已超三个
304
263
  if (options.live && !this.config.unlockSubLimits && (this.subManager.reduce((acc, cur) => acc + (cur.live ? 1 : 0), 0) >= 3)) {
305
264
  return '直播订阅已达上限,请取消部分直播订阅后再进行订阅';
306
265
  }
307
266
  // 检查是否登录
308
- if (!(await this.checkIfIsLogin(ctx))) {
267
+ if (!(await this.checkIfIsLogin())) {
309
268
  // 未登录直接返回
310
269
  return '请使用指令bili login登录后再进行订阅操作';
311
270
  }
@@ -313,77 +272,103 @@ class ComRegister {
313
272
  if (!mid)
314
273
  return '请输入用户uid';
315
274
  // 订阅对象
316
- const subUserData = await this.subUserInBili(ctx, mid);
275
+ const subUserData = await this.subUserInBili(mid);
317
276
  // 判断是否订阅对象存在
318
277
  if (!subUserData.flag)
319
278
  return '订阅对象失败,请稍后重试!';
320
- let target;
321
- // 判断是否使用多平台功能
322
- if (options.multiplatform) {
323
- // 分割字符串,赋值给target
324
- target = this.splitMultiPlatformStr(options.multiplatform);
279
+ // 定义目标变量
280
+ let target = [];
281
+ // 判断是否使用了多群组推送
282
+ if (groupId.length > 0) {
283
+ // 定义channelIdArr
284
+ const channelIdArr = [];
285
+ // 遍历输入的群组
286
+ groupId.forEach(group => {
287
+ channelIdArr.push({
288
+ channelId: group,
289
+ dynamic: true,
290
+ live: true,
291
+ liveDanmaku: false,
292
+ atAll: options.atAll
293
+ });
294
+ });
295
+ target.push({
296
+ channelIdArr,
297
+ platform: session.event.platform
298
+ });
325
299
  }
326
- if (target) {
327
- target.forEach(async ({ idArr, platform }, index) => {
328
- if (idArr.length > 0) { // 输入了推送群号或频道号
329
- // 拿到对应的bot
330
- const bot = this.getBot(ctx, platform);
331
- // 判断是否配置了对应平台的机器人
332
- if (!ctx.bots.some(bot => bot.platform === platform)) {
333
- await session.send('您未配置对应平台的机器人,不能在该平台进行订阅操作');
334
- }
335
- // 判断是否需要加入的群全部推送
336
- if (idArr[0] !== 'all') {
337
- // 定义满足条件的群组数组
338
- const targetArr = [];
339
- // 获取机器人加入的群组
340
- const guildList = await bot.getGuildList();
341
- // 遍历target数组
342
- for (const id of idArr) {
343
- // 定义是否加入群组标志
344
- let flag = false;
345
- // 遍历群组
346
- for (const guild of guildList.data) {
347
- // 获取频道列表
348
- const channelList = await bot.getChannelList(guild.id);
349
- // 判断机器人是否加入群聊或频道
350
- if (channelList.data.some(channel => channel.id === id)) {
351
- // 加入群聊或频道
352
- targetArr.push(id);
353
- // 设置标志位为true
354
- flag = true;
355
- // 结束循环
356
- break;
300
+ else {
301
+ // 判断是否使用多平台功能
302
+ if (options.multiplatform) {
303
+ // 分割字符串,赋值给target
304
+ target = this.splitMultiPlatformStr(options.multiplatform);
305
+ }
306
+ // 判断是否使用了多平台
307
+ if (target.length > 0) {
308
+ for (const [index, { channelIdArr, platform }] of target.entries()) {
309
+ if (channelIdArr.length > 0) { // 输入了推送群号或频道号
310
+ // 拿到对应的bot
311
+ const bot = this.getBot(platform);
312
+ // 判断是否配置了对应平台的机器人
313
+ if (!ctx.bots.some(bot => bot.platform === platform)) {
314
+ // 发送提示消息
315
+ await session.send('您未配置对应平台的机器人,不能在该平台进行订阅操作');
316
+ // 直接返回
317
+ return;
318
+ }
319
+ // 判断是否需要加入的群全部推送
320
+ if (channelIdArr[0].channelId !== 'all') {
321
+ // 定义满足条件的群组数组
322
+ const targetArr = [];
323
+ // 获取机器人加入的群组
324
+ const guildList = await bot.getGuildList();
325
+ // 遍历target数组
326
+ for (const channelId of channelIdArr) {
327
+ // 定义是否加入群组标志
328
+ let flag = false;
329
+ // 遍历群组
330
+ for (const guild of guildList.data) {
331
+ // 获取频道列表
332
+ const channelList = await bot.getChannelList(guild.id);
333
+ // 判断机器人是否加入群聊或频道
334
+ if (channelList.data.some(channel => channel.id === channelId.channelId)) {
335
+ // 加入群聊或频道
336
+ targetArr.push(channelId);
337
+ // 设置标志位为true
338
+ flag = true;
339
+ // 结束循环
340
+ break;
341
+ }
342
+ }
343
+ if (!flag) {
344
+ // 不满足条件发送错误提示
345
+ await session.send(`您的机器未加入${channelId.channelId},无法对该群或频道进行推送`);
357
346
  }
358
347
  }
359
- if (!flag) {
360
- // 不满足条件发送错误提示
361
- await session.send(`您的机器未加入${id},无法对该群或频道进行推送`);
348
+ // 判断targetArr是否为空
349
+ if (target.length === 0) {
350
+ // 为空则默认为当前环境
351
+ target = [{ channelIdArr: [{ channelId: session.event.channel.id, dynamic: true, live: true, liveDanmaku: false, atAll: options.atAll ? options.atAll : false }], platform: session.event.platform }];
352
+ // 没有满足条件的群组或频道
353
+ await session.send('没有满足条件的群组或频道,默认订阅到当前聊天环境');
362
354
  }
355
+ // 将符合条件的群组添加到target中
356
+ target[index].channelIdArr = targetArr;
363
357
  }
364
- // 判断targetArr是否为空
365
- if (target.length === 0) {
366
- // 为空则默认为当前环境
367
- target = [{ idArr: [session.event.channel.id], platform: session.event.platform }];
368
- // 没有满足条件的群组或频道
369
- await session.send('没有满足条件的群组或频道,默认订阅到当前聊天环境');
370
- }
371
- // 将符合条件的群组添加到target中
372
- target[index].idArr = targetArr;
358
+ // 如果为all则全部推送,不需要进行处理
359
+ }
360
+ else {
361
+ // 未填写群号或频道号,默认为当前环境
362
+ target = [{ channelIdArr: [{ channelId: session.event.channel.id, dynamic: true, live: true, liveDanmaku: false, atAll: options.atAll ? options.atAll : false }], platform: session.event.platform }];
363
+ // 发送提示消息
364
+ await session.send('没有填写群号或频道号,默认订阅到当前聊天环境');
373
365
  }
374
- // 如果为all则全部推送,不需要进行修改
375
- }
376
- else {
377
- // 未填写群号或频道号,默认为当前环境
378
- target = [{ idArr: [session.event.channel.id], platform: session.event.platform }];
379
- // 发送提示消息
380
- await session.send('没有填写群号或频道号,默认订阅到当前聊天环境');
381
366
  }
382
- });
383
- }
384
- else {
385
- // 用户直接订阅,将当前环境赋值给target
386
- target = [{ idArr: [session.event.channel.id], platform: session.event.platform }];
367
+ }
368
+ else {
369
+ // 用户直接订阅,将当前环境赋值给target
370
+ target = [{ channelIdArr: [{ channelId: session.event.channel.id, dynamic: true, live: true, liveDanmaku: false, atAll: options.atAll ? options.atAll : false }], platform: session.event.platform }];
371
+ }
387
372
  }
388
373
  // 定义外围变量
389
374
  let content;
@@ -452,12 +437,10 @@ class ComRegister {
452
437
  this.logger.error('bili sub指令 getMasterInfo() 发生了错误,错误为:' + e.message);
453
438
  return '订阅出错啦,请重试';
454
439
  }
455
- // 定义live销毁函数
456
- let liveDispose;
457
440
  // 订阅直播
458
441
  if (liveMsg) {
459
- // 开始循环检测
460
- liveDispose = ctx.setInterval(this.liveDetect(ctx, roomId, target), config.liveLoopTime * 1000);
442
+ // 连接到服务器
443
+ this.liveDetectWithListener(roomId, target);
461
444
  // 发送订阅消息通知
462
445
  await session.send(`订阅${userData.info.uname}直播通知`);
463
446
  }
@@ -465,13 +448,7 @@ class ComRegister {
465
448
  if (dynamicMsg) {
466
449
  // 判断是否开启动态监测
467
450
  if (!this.dynamicDispose) {
468
- // 开启动态监测
469
- if (this.config.dynamicDebugMode) {
470
- this.dynamicDispose = ctx.setInterval(this.debug_dynamicDetect(ctx), config.dynamicLoopTime * 1000);
471
- }
472
- else {
473
- this.dynamicDispose = ctx.setInterval(this.dynamicDetect(ctx), config.dynamicLoopTime * 1000);
474
- }
451
+ this.enableDynamicDetect();
475
452
  }
476
453
  // 发送订阅消息通知
477
454
  await session.send(`订阅${userData.info.uname}动态通知`);
@@ -481,7 +458,6 @@ class ComRegister {
481
458
  uid: mid,
482
459
  room_id: roomId,
483
460
  dynamic: dynamicMsg ? 1 : 0,
484
- video: 1,
485
461
  live: liveMsg ? 1 : 0,
486
462
  target: JSON.stringify(target),
487
463
  platform: session.event.platform,
@@ -498,28 +474,10 @@ class ComRegister {
498
474
  platform: session.event.platform,
499
475
  live: liveMsg,
500
476
  dynamic: dynamicMsg,
501
- liveDispose
502
477
  });
503
478
  // 新增订阅展示到控制台
504
- this.updateSubNotifier(ctx);
479
+ this.updateSubNotifier();
505
480
  });
506
- /* biliCom
507
- .subcommand('.live <roomId:string> <...guildId:string>', '订阅主播开播通知', { hidden: true })
508
- .usage('订阅主播开播通知')
509
- .example('bili live 26316137 订阅房间号为26316137的直播间')
510
- .action(async (_, roomId, ...guildId) => {
511
- this.logger.info('调用bili.live指令')
512
- // 如果room_id为空则返回
513
- if (!roomId) return `${roomId}非法调用 dynamic 指令` // 订阅主播房间号不能为空
514
- if (!guildId) return `${roomId}非法调用 dynamic 指令` // 目标群组或频道不能为空
515
- // 要订阅的对象不在订阅管理对象中,直接返回
516
- const index = this.subManager.findIndex(sub => sub.roomId === roomId)
517
- if (index === -1) return '请勿直接调用该指令'
518
- // 开始循环检测
519
- const dispose = ctx.setInterval(this.liveDetect(ctx, roomId, guildId, this.subManager[index].platform), config.liveLoopTime * 1000)
520
- // 保存销毁函数
521
- this.subManager[index].liveDispose = dispose
522
- }) */
523
481
  biliCom
524
482
  .subcommand('.status <roomId:string>', '查询主播当前直播状态', { hidden: true })
525
483
  .usage('查询主播当前直播状态')
@@ -574,14 +532,78 @@ class ComRegister {
574
532
  await session.send('已发送消息,如未收到则说明您的机器人不支持发送私聊消息或您的信息填写有误');
575
533
  });
576
534
  }
535
+ async init(config) {
536
+ // 设置logger
537
+ this.logger = this.ctx.logger('cr');
538
+ // 将config设置给类属性
539
+ this.config = config;
540
+ // 拿到私人机器人实例
541
+ this.privateBot = this.ctx.bots.find(bot => bot.platform === config.master.platform);
542
+ if (!this.privateBot) {
543
+ this.ctx.notifier.create({
544
+ content: '您未配置私人机器人,将无法向您推送机器人状态!'
545
+ });
546
+ this.logger.error('您未配置私人机器人,将无法向您推送机器人状态!');
547
+ }
548
+ // 判断消息发送方式
549
+ if (config.automaticResend) {
550
+ this.sendMsgFunc = async (bot, channelId, content) => {
551
+ // 多次尝试发送消息
552
+ const attempts = 3;
553
+ for (let i = 0; i < attempts; i++) {
554
+ try {
555
+ // 发送消息
556
+ await bot.sendMessage(channelId, content);
557
+ // 防止消息发送速度过快被忽略
558
+ await this.ctx.sleep(500);
559
+ // 成功发送消息,跳出循环
560
+ break;
561
+ }
562
+ catch (e) {
563
+ if (i === attempts - 1) { // 已尝试三次
564
+ this.logger.error(`发送群组ID:${channelId}消息失败!原因: ` + e.message);
565
+ console.log(e);
566
+ this.sendPrivateMsg(`发送群组ID:${channelId}消息失败,请查看日志`);
567
+ }
568
+ }
569
+ }
570
+ };
571
+ }
572
+ else {
573
+ this.sendMsgFunc = async (bot, guild, content) => {
574
+ try {
575
+ // 发送消息
576
+ await bot.sendMessage(guild, content);
577
+ }
578
+ catch (e) {
579
+ this.logger.error(`发送群组ID:${guild}消息失败!原因: ` + e.message);
580
+ await this.sendPrivateMsg(`发送群组ID:${guild}消息失败,请查看日志`);
581
+ }
582
+ };
583
+ }
584
+ // 检查登录数据库是否有数据
585
+ this.loginDBData = (await this.ctx.database.get('loginBili', 1, ['dynamic_group_id']))[0];
586
+ // 从配置获取订阅
587
+ config.sub && await this.loadSubFromConfig(config.sub);
588
+ // 从数据库获取订阅
589
+ await this.loadSubFromDatabase();
590
+ // 检查是否需要动态监测
591
+ this.checkIfDynamicDetectIsNeeded();
592
+ // 在控制台中显示订阅对象
593
+ this.updateSubNotifier();
594
+ }
577
595
  splitMultiPlatformStr(str) {
578
596
  return str.split(';').map(cv => cv.split('.')).map(([idStr, platform]) => {
579
- const idArr = idStr.split(',');
580
- return { idArr, platform };
597
+ const channelIdArr = idStr.split(',').map(id => {
598
+ const atAll = /@$/.test(id); // 使用正则表达式检查 id 是否以 @ 结尾
599
+ const channelId = atAll ? id.slice(0, -1) : id; // 去除末尾的 @
600
+ return { channelId, dynamic: true, live: true, liveDanmaku: false, atAll };
601
+ });
602
+ return { channelIdArr, platform };
581
603
  });
582
604
  }
583
- getBot(ctx, pf) {
584
- return ctx.bots.find(bot => bot.platform === pf);
605
+ getBot(pf) {
606
+ return this.ctx.bots.find(bot => bot.platform === pf);
585
607
  }
586
608
  async sendPrivateMsg(content) {
587
609
  if (this.config.master.enable) {
@@ -595,7 +617,7 @@ class ComRegister {
595
617
  }
596
618
  }
597
619
  }
598
- async sendPrivateMsgAndRebootService(ctx) {
620
+ async sendPrivateMsgAndRebootService() {
599
621
  // 判断重启次数是否超过三次
600
622
  if (this.rebootCount >= 3) {
601
623
  // logger
@@ -603,7 +625,7 @@ class ComRegister {
603
625
  // 重启失败,发送消息
604
626
  await this.sendPrivateMsg('已重启插件三次,请检查机器人状态后使用指令 sys start 启动插件');
605
627
  // 关闭插件
606
- await ctx.sm.disposePlugin();
628
+ await this.ctx.sm.disposePlugin();
607
629
  // 结束
608
630
  return;
609
631
  }
@@ -612,7 +634,7 @@ class ComRegister {
612
634
  // logger
613
635
  this.logger.info('插件出现未知错误,正在重启插件');
614
636
  // 重启插件
615
- const flag = await ctx.sm.restartPlugin();
637
+ const flag = await this.ctx.sm.restartPlugin();
616
638
  // 判断是否重启成功
617
639
  if (flag) {
618
640
  this.logger.info('重启插件成功');
@@ -623,42 +645,66 @@ class ComRegister {
623
645
  // 重启失败,发送消息
624
646
  await this.sendPrivateMsg('重启插件失败,请检查机器人状态后使用指令 sys start 启动插件');
625
647
  // 关闭插件
626
- await ctx.sm.disposePlugin();
648
+ await this.ctx.sm.disposePlugin();
627
649
  }
628
650
  }
629
- async sendPrivateMsgAndStopService(ctx) {
651
+ async sendPrivateMsgAndStopService() {
630
652
  // 发送消息
631
653
  await this.sendPrivateMsg('插件发生未知错误,请检查机器人状态后使用指令 sys start 启动插件');
632
654
  // logger
633
655
  this.logger.error('插件发生未知错误,请检查机器人状态后使用指令 sys start 启动插件');
634
656
  // 关闭插件
635
- await ctx.sm.disposePlugin();
657
+ await this.ctx.sm.disposePlugin();
636
658
  // 结束
637
659
  return;
638
660
  }
639
- async sendMsg(ctx, targets, content) {
661
+ async sendMsg(targets, content, live) {
640
662
  for (const target of targets) {
641
663
  // 获取机器人实例
642
- const bot = this.getBot(ctx, target.platform);
664
+ const bot = this.getBot(target.platform);
643
665
  // 定义需要发送的数组
644
666
  let sendArr = [];
645
667
  // 判断是否需要推送所有机器人加入的群
646
- if (target.idArr[0] === 'all') {
668
+ if (target.channelIdArr[0].channelId === 'all') {
647
669
  // 获取所有guild
648
670
  for (const guild of (await bot.getGuildList()).data) {
649
- sendArr.push(guild.id);
671
+ sendArr.push({
672
+ channelId: guild.id,
673
+ dynamic: target.channelIdArr[0].dynamic,
674
+ live: target.channelIdArr[0].live,
675
+ liveDanmaku: target.channelIdArr[0].liveDanmaku,
676
+ atAll: target.channelIdArr[0].atAll
677
+ });
650
678
  }
651
679
  }
652
680
  else {
653
- sendArr = target.idArr;
681
+ sendArr = target.channelIdArr;
682
+ }
683
+ // 判断是否是直播开播推送,如果是则需要进一步判断是否需要艾特群体成员
684
+ if (live) {
685
+ // 直播开播推送,判断是否需要艾特全体成员
686
+ for (const channel of sendArr) {
687
+ // 判断是否需要推送直播消息
688
+ if (channel.live) {
689
+ await this.sendMsgFunc(bot, channel.channelId, content);
690
+ }
691
+ // 判断是否需要艾特全体成员
692
+ if (channel.atAll) {
693
+ await this.sendMsgFunc(bot, channel.channelId, (0, jsx_runtime_1.jsx)("at", { type: "all" }));
694
+ }
695
+ }
654
696
  }
655
- // 循环给每个群组发送
656
- for (const guild of sendArr) {
657
- await this.sendMsgFunc(bot, guild, content);
697
+ else {
698
+ for (const channel of sendArr) {
699
+ // 判断是否需要推送动态消息和直播消息
700
+ if (channel.dynamic || channel.live) {
701
+ await this.sendMsgFunc(bot, channel.channelId, content);
702
+ }
703
+ }
658
704
  }
659
705
  }
660
706
  }
661
- dynamicDetect(ctx) {
707
+ dynamicDetect() {
662
708
  let detectSetup = true;
663
709
  let updateBaseline;
664
710
  // 相当于锁的作用,防止上一个循环没处理完
@@ -674,7 +720,7 @@ class ComRegister {
674
720
  // 检测启动初始化
675
721
  if (detectSetup) {
676
722
  // 获取动态信息
677
- const data = await ctx.ba.getAllDynamic();
723
+ const data = await this.ctx.ba.getAllDynamic();
678
724
  // 判断获取动态信息是否成功
679
725
  if (data.code !== 0)
680
726
  return;
@@ -690,13 +736,13 @@ class ComRegister {
690
736
  let content;
691
737
  try {
692
738
  // 查询是否有新动态
693
- const data = await ctx.ba.hasNewDynamic(updateBaseline);
739
+ const data = await this.ctx.ba.hasNewDynamic(updateBaseline);
694
740
  updateNum = data.data.update_num;
695
741
  // 没有新动态或获取动态信息失败直接返回
696
742
  if (updateNum <= 0 || data.code !== 0)
697
743
  return;
698
744
  // 获取动态内容
699
- content = await ctx.ba.getAllDynamic(updateBaseline);
745
+ content = await this.ctx.ba.getAllDynamic(updateBaseline);
700
746
  }
701
747
  catch (e) {
702
748
  return this.logger.error('dynamicDetect getUserSpaceDynamic() 发生了错误,错误为:' + e.message);
@@ -710,7 +756,7 @@ class ComRegister {
710
756
  // 发送私聊消息
711
757
  await this.sendPrivateMsg('账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件');
712
758
  // 停止服务
713
- await ctx.sm.disposePlugin();
759
+ await this.ctx.sm.disposePlugin();
714
760
  // 结束循环
715
761
  break;
716
762
  }
@@ -720,7 +766,7 @@ class ComRegister {
720
766
  // 发送私聊消息
721
767
  await this.sendPrivateMsg('账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件');
722
768
  // 停止服务
723
- await ctx.sm.disposePlugin();
769
+ await this.ctx.sm.disposePlugin();
724
770
  // 结束循环
725
771
  break;
726
772
  }
@@ -771,7 +817,7 @@ class ComRegister {
771
817
  // 获取动态推送图片
772
818
  try {
773
819
  // 渲染图片
774
- const { pic: gimgPic, buffer: gimgBuffer } = await ctx.gi.generateDynamicImg(items[num]);
820
+ const { pic: gimgPic, buffer: gimgBuffer } = await this.ctx.gi.generateDynamicImg(items[num]);
775
821
  // 赋值
776
822
  pic = gimgPic;
777
823
  buffer = gimgBuffer;
@@ -785,13 +831,13 @@ class ComRegister {
785
831
  if (e.message === '出现关键词,屏蔽该动态') {
786
832
  // 如果需要发送才发送
787
833
  if (this.config.filter.notify) {
788
- await this.sendMsg(ctx, sub.target, `${upName}发布了一条含有屏蔽关键字的动态`);
834
+ await this.sendMsg(sub.target, `${upName}发布了一条含有屏蔽关键字的动态`);
789
835
  }
790
836
  return;
791
837
  }
792
838
  if (e.message === '已屏蔽转发动态') {
793
839
  if (this.config.filter.notify) {
794
- await this.sendMsg(ctx, sub.target, `${upName}发布了一条转发动态,已屏蔽`);
840
+ await this.sendMsg(sub.target, `${upName}发布了一条转发动态,已屏蔽`);
795
841
  }
796
842
  return;
797
843
  }
@@ -799,7 +845,7 @@ class ComRegister {
799
845
  if (i === attempts - 1) {
800
846
  this.logger.error('dynamicDetect generateDynamicImg() 推送卡片发送失败,原因:' + e.message);
801
847
  // 发送私聊消息并重启服务
802
- return await this.sendPrivateMsgAndStopService(ctx);
848
+ return await this.sendPrivateMsgAndStopService();
803
849
  }
804
850
  }
805
851
  }
@@ -809,12 +855,12 @@ class ComRegister {
809
855
  if (pic) {
810
856
  this.logger.info('推送动态中,使用render模式');
811
857
  // pic存在,使用的是render模式
812
- await this.sendMsg(ctx, sub.target, pic + (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: dUrl }));
858
+ await this.sendMsg(sub.target, pic + (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: dUrl }));
813
859
  }
814
860
  else if (buffer) {
815
861
  this.logger.info('推送动态中,使用page模式');
816
862
  // pic不存在,说明使用的是page模式
817
- await this.sendMsg(ctx, sub.target, (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, 'image/png'), dUrl] }));
863
+ await this.sendMsg(sub.target, (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, 'image/png'), dUrl] }));
818
864
  }
819
865
  else {
820
866
  this.logger.info(items[num].modules.module_author.name + '发布了一条动态,但是推送失败');
@@ -828,7 +874,7 @@ class ComRegister {
828
874
  }
829
875
  };
830
876
  }
831
- debug_dynamicDetect(ctx) {
877
+ debug_dynamicDetect() {
832
878
  let detectSetup = true;
833
879
  let updateBaseline;
834
880
  // 相当于锁的作用,防止上一个循环没处理完
@@ -845,7 +891,7 @@ class ComRegister {
845
891
  // 检测启动初始化
846
892
  if (detectSetup) {
847
893
  // 获取动态信息
848
- const data = await ctx.ba.getAllDynamic();
894
+ const data = await this.ctx.ba.getAllDynamic();
849
895
  // 判断获取动态信息是否成功
850
896
  if (data.code !== 0)
851
897
  return;
@@ -862,7 +908,7 @@ class ComRegister {
862
908
  let content;
863
909
  try {
864
910
  // 查询是否有新动态
865
- const data = await ctx.ba.hasNewDynamic(updateBaseline);
911
+ const data = await this.ctx.ba.hasNewDynamic(updateBaseline);
866
912
  updateNum = data.data.update_num;
867
913
  console.log(`获取是否有新动态:`);
868
914
  console.log(data);
@@ -870,7 +916,7 @@ class ComRegister {
870
916
  if (updateNum <= 0 || data.code !== 0)
871
917
  return;
872
918
  // 获取动态内容
873
- content = await ctx.ba.getAllDynamic(updateBaseline);
919
+ content = await this.ctx.ba.getAllDynamic(updateBaseline);
874
920
  console.log('获取动态内容:');
875
921
  console.log(content.data.items[0]);
876
922
  }
@@ -886,7 +932,7 @@ class ComRegister {
886
932
  // 发送私聊消息
887
933
  await this.sendPrivateMsg('账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件');
888
934
  // 停止服务
889
- await ctx.sm.disposePlugin();
935
+ await this.ctx.sm.disposePlugin();
890
936
  // 结束循环
891
937
  break;
892
938
  }
@@ -896,7 +942,7 @@ class ComRegister {
896
942
  // 发送私聊消息
897
943
  await this.sendPrivateMsg('账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件');
898
944
  // 停止服务
899
- await ctx.sm.disposePlugin();
945
+ await this.ctx.sm.disposePlugin();
900
946
  // 结束循环
901
947
  break;
902
948
  }
@@ -955,7 +1001,7 @@ class ComRegister {
955
1001
  // 获取动态推送图片
956
1002
  try {
957
1003
  // 渲染图片
958
- const { pic: gimgPic, buffer: gimgBuffer } = await ctx.gi.generateDynamicImg(items[num]);
1004
+ const { pic: gimgPic, buffer: gimgBuffer } = await this.ctx.gi.generateDynamicImg(items[num]);
959
1005
  // 赋值
960
1006
  pic = gimgPic;
961
1007
  buffer = gimgBuffer;
@@ -969,13 +1015,13 @@ class ComRegister {
969
1015
  if (e.message === '出现关键词,屏蔽该动态') {
970
1016
  // 如果需要发送才发送
971
1017
  if (this.config.filter.notify) {
972
- await this.sendMsg(ctx, sub.target, `${upName}发布了一条含有屏蔽关键字的动态`);
1018
+ await this.sendMsg(sub.target, `${upName}发布了一条含有屏蔽关键字的动态`);
973
1019
  }
974
1020
  return;
975
1021
  }
976
1022
  if (e.message === '已屏蔽转发动态') {
977
1023
  if (this.config.filter.notify) {
978
- await this.sendMsg(ctx, sub.target, `${upName}发布了一条转发动态,已屏蔽`);
1024
+ await this.sendMsg(sub.target, `${upName}发布了一条转发动态,已屏蔽`);
979
1025
  }
980
1026
  return;
981
1027
  }
@@ -983,7 +1029,7 @@ class ComRegister {
983
1029
  if (i === attempts - 1) {
984
1030
  this.logger.error('dynamicDetect generateDynamicImg() 推送卡片发送失败,原因:' + e.message);
985
1031
  // 发送私聊消息并重启服务
986
- return await this.sendPrivateMsgAndStopService(ctx);
1032
+ return await this.sendPrivateMsgAndStopService();
987
1033
  }
988
1034
  }
989
1035
  }
@@ -993,12 +1039,12 @@ class ComRegister {
993
1039
  if (pic) {
994
1040
  this.logger.info('推送动态中,使用render模式');
995
1041
  // pic存在,使用的是render模式
996
- await this.sendMsg(ctx, sub.target, pic + (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: dUrl }));
1042
+ await this.sendMsg(sub.target, pic + (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: dUrl }));
997
1043
  }
998
1044
  else if (buffer) {
999
1045
  this.logger.info('推送动态中,使用page模式');
1000
1046
  // pic不存在,说明使用的是page模式
1001
- await this.sendMsg(ctx, sub.target, (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, 'image/png'), dUrl] }));
1047
+ await this.sendMsg(sub.target, (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, 'image/png'), dUrl] }));
1002
1048
  }
1003
1049
  else {
1004
1050
  this.logger.info(items[num].modules.module_author.name + '发布了一条动态,但是推送失败');
@@ -1012,203 +1058,272 @@ class ComRegister {
1012
1058
  }
1013
1059
  };
1014
1060
  }
1015
- liveDetect(ctx, roomId, target) {
1061
+ // 定义发送直播通知卡片方法
1062
+ async sendLiveNotifyCard(info, liveType, liveNotifyMsg) {
1063
+ // 定义变量
1064
+ let pic;
1065
+ let buffer;
1066
+ // 多次尝试生成图片
1067
+ const attempts = 3;
1068
+ for (let i = 0; i < attempts; i++) {
1069
+ try {
1070
+ // 获取直播通知卡片
1071
+ const { pic: picv, buffer: bufferv } = await this.ctx.gi.generateLiveImg(info.data, info.username, info.userface, liveType);
1072
+ // 赋值
1073
+ pic = picv;
1074
+ buffer = bufferv;
1075
+ // 成功则跳出循环
1076
+ break;
1077
+ }
1078
+ catch (e) {
1079
+ if (i === attempts - 1) { // 已尝试三次
1080
+ this.logger.error('liveDetect generateLiveImg() 推送卡片生成失败,原因:' + e.message);
1081
+ // 发送私聊消息并重启服务
1082
+ return await this.sendPrivateMsgAndStopService();
1083
+ }
1084
+ }
1085
+ }
1086
+ // 推送直播信息
1087
+ // pic 存在,使用的是render模式
1088
+ if (pic) {
1089
+ // 只有在开播时才艾特全体成员
1090
+ if (liveType === LiveType.StartBroadcasting) {
1091
+ return await this.sendMsg(info.target, pic + (liveNotifyMsg ?? ''), true);
1092
+ }
1093
+ // 正常不需要艾特全体成员
1094
+ return await this.sendMsg(info.target, pic + (liveNotifyMsg ?? ''));
1095
+ }
1096
+ // pic不存在,说明使用的是page模式
1097
+ const msg = (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, 'image/png'), liveNotifyMsg || ''] });
1098
+ // 只有在开播时才艾特全体成员
1099
+ if (liveType === LiveType.StartBroadcasting) {
1100
+ return await this.sendMsg(info.target, msg, true);
1101
+ }
1102
+ // 正常不需要艾特全体成员
1103
+ return await this.sendMsg(info.target, msg);
1104
+ }
1105
+ // 定义获取主播信息方法
1106
+ async useMasterInfo(uid) {
1107
+ const { data } = await this.ctx.ba.getMasterInfo(uid);
1108
+ return { username: data.info.uname, userface: data.info.face, roomId: data.room_id };
1109
+ }
1110
+ async useLiveRoomInfo(roomId) {
1111
+ // 发送请求获取直播间信息
1112
+ let content;
1113
+ const attempts = 3;
1114
+ for (let i = 0; i < attempts; i++) {
1115
+ try {
1116
+ // 发送请求获取room信息
1117
+ content = await this.ctx.ba.getLiveRoomInfo(roomId);
1118
+ // 成功则跳出循环
1119
+ break;
1120
+ }
1121
+ catch (e) {
1122
+ this.logger.error('liveDetect getLiveRoomInfo 发生了错误,错误为:' + e.message);
1123
+ if (i === attempts - 1) { // 已尝试三次
1124
+ // 发送私聊消息并重启服务
1125
+ return await this.sendPrivateMsgAndStopService();
1126
+ }
1127
+ }
1128
+ }
1129
+ return content.data;
1130
+ }
1131
+ async liveDetectWithAPI() {
1132
+ // 定义变量:第一次订阅
1016
1133
  let firstSubscription = true;
1134
+ // 定义变量:timer计时器
1017
1135
  let timer = 0;
1018
- let open = false;
1019
- let liveTime;
1020
- let username;
1021
- let userface;
1022
1136
  // 相当于锁的作用,防止上一个循环没处理完
1023
1137
  let flag = true;
1024
- // 定义发送直播通知卡片方法
1025
- const sendLiveNotifyCard = async (data, liveType, liveNotifyMsg, atAll) => {
1026
- // 定义变量
1027
- let pic;
1028
- let buffer;
1029
- // 多次尝试生成图片
1138
+ // 定义订阅对象Record 0未开播 1正在直播 2轮播中
1139
+ const liveRecord = {};
1140
+ // 初始化subRecord
1141
+ this.subManager.forEach(sub => {
1142
+ // 判断是否订阅直播
1143
+ if (sub.live) {
1144
+ // 将该订阅添加到subRecord中
1145
+ liveRecord[sub.uid] = { liveStatus: 0, liveTime: '', target: sub.target };
1146
+ }
1147
+ });
1148
+ // 定义函数: 发送请求获取直播状态
1149
+ const useLiveStatus = async (roomId) => {
1150
+ let content;
1030
1151
  const attempts = 3;
1031
1152
  for (let i = 0; i < attempts; i++) {
1032
1153
  try {
1033
- // 获取直播通知卡片
1034
- const { pic: picv, buffer: bufferv } = await ctx.gi.generateLiveImg(data, username, userface, liveType);
1035
- // 赋值
1036
- pic = picv;
1037
- buffer = bufferv;
1154
+ // 发送请求获取room信息
1155
+ content = await this.ctx.ba.getLiveRoomInfo(roomId);
1038
1156
  // 成功则跳出循环
1039
1157
  break;
1040
1158
  }
1041
1159
  catch (e) {
1160
+ this.logger.error('liveDetect getLiveRoomInfo 发生了错误,错误为:' + e.message);
1042
1161
  if (i === attempts - 1) { // 已尝试三次
1043
- this.logger.error('liveDetect generateLiveImg() 推送卡片生成失败,原因:' + e.message);
1044
1162
  // 发送私聊消息并重启服务
1045
- return await this.sendPrivateMsgAndStopService(ctx);
1163
+ return await this.sendPrivateMsgAndStopService();
1046
1164
  }
1047
1165
  }
1048
1166
  }
1049
- // 推送直播信息
1050
- // pic 存在,使用的是render模式
1051
- if (pic) {
1052
- const msg = (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [atAll && (0, jsx_runtime_1.jsx)("at", { type: "all" }), liveNotifyMsg && liveNotifyMsg] });
1053
- return await this.sendMsg(ctx, target, pic + msg);
1054
- }
1055
- // pic不存在,说明使用的是page模式
1056
- const msg = (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, 'image/png'), atAll && (0, jsx_runtime_1.jsx)("at", { type: "all" }), liveNotifyMsg && liveNotifyMsg] });
1057
- await this.sendMsg(ctx, target, pic + msg);
1167
+ // 返回data
1168
+ return content.data;
1058
1169
  };
1059
- // 定义获取主播信息方法
1060
- let useMasterInfo;
1061
- if (this.config.changeMasterInfoApi) {
1062
- useMasterInfo = async (uid) => {
1063
- const { data } = await ctx.ba.getUserInfo(uid);
1064
- username = data.name;
1065
- userface = data.face;
1066
- };
1067
- }
1068
- else {
1069
- useMasterInfo = async (uid) => {
1070
- const { data: { info } } = await ctx.ba.getMasterInfo(uid);
1071
- username = info.uname;
1072
- userface = info.face;
1073
- };
1074
- }
1075
1170
  return async () => {
1076
1171
  // 如果flag为false则说明前面的代码还未执行完,则直接返回
1077
1172
  if (!flag)
1078
1173
  return;
1174
+ // 将标志位置为false
1079
1175
  flag = false;
1080
- // 无论是否执行成功都要释放锁
1081
1176
  try {
1082
- // 发送请求检测直播状态
1083
- let content;
1084
- const attempts = 3;
1085
- for (let i = 0; i < attempts; i++) {
1086
- try {
1087
- // 发送请求获取room信息
1088
- content = await ctx.ba.getLiveRoomInfo(roomId);
1089
- // 成功则跳出循环
1090
- break;
1091
- }
1092
- catch (e) {
1093
- this.logger.error('liveDetect getLiveRoomInfo 发生了错误,错误为:' + e.message);
1094
- if (i === attempts - 1) { // 已尝试三次
1095
- // 发送私聊消息并重启服务
1096
- return await this.sendPrivateMsgAndStopService(ctx);
1097
- }
1098
- }
1099
- }
1100
- const { data } = content;
1177
+ // 获取正在直播对象
1178
+ const liveUsers = await this.ctx.ba.getTheUserWhoIsLiveStreaming();
1101
1179
  // 判断是否是第一次订阅
1102
1180
  if (firstSubscription) {
1181
+ // 将第一次订阅置为false
1103
1182
  firstSubscription = false;
1104
- // 获取主播信息
1105
- const attempts = 3;
1106
- for (let i = 0; i < attempts; i++) {
1107
- try {
1108
- // 发送请求获取主播信息
1109
- await useMasterInfo(data.uid);
1110
- // 成功则跳出循环
1111
- break;
1112
- }
1113
- catch (e) {
1114
- this.logger.error('liveDetect getMasterInfo() 发生了错误,错误为:' + e.message);
1115
- if (i === attempts - 1) { // 已尝试三次
1116
- // 发送私聊消息并重启服务
1117
- return await this.sendPrivateMsgAndStopService(ctx);
1183
+ // 先判断是否有UP主正在直播
1184
+ if (liveUsers.count > 0) {
1185
+ // 遍历liveUsers
1186
+ liveUsers.items.forEach(async (item) => {
1187
+ // 判断是否有订阅对象正在直播
1188
+ if (liveRecord[item.mid]) {
1189
+ // 获取当前用户直播间信息
1190
+ const data = await useLiveStatus(item.room_id.toString());
1191
+ // 设置开播时间
1192
+ liveRecord[item.mid].liveTime = data.live_time;
1193
+ // 设置直播中消息
1194
+ const liveMsg = this.config.customLive ? this.config.customLive
1195
+ .replace('-name', item.uname)
1196
+ .replace('-time', await this.ctx.gi.getTimeDifference(liveRecord[item.mid].liveTime))
1197
+ .replace('-link', `https://live.bilibili.com/${data.short_id === 0 ? data.room_id : data.short_id}`) : null;
1198
+ // 发送直播通知卡片
1199
+ if (this.config.restartPush)
1200
+ this.sendLiveNotifyCard({
1201
+ username: item.uname,
1202
+ userface: item.face,
1203
+ target: liveRecord[item.mid].target,
1204
+ data
1205
+ }, LiveType.LiveBroadcast, liveMsg);
1206
+ // 改变开播状态
1207
+ liveRecord[item.mid].liveStatus = 1;
1118
1208
  }
1119
- }
1209
+ });
1120
1210
  }
1121
- // 判断直播状态
1122
- if (data.live_status === 1) { // 当前正在直播
1123
- // 设置开播时间
1124
- liveTime = data.live_time;
1125
- // 发送直播通知卡片
1126
- if (this.config.restartPush)
1127
- sendLiveNotifyCard(data, LiveType.LiveBroadcast);
1128
- // 改变开播状态
1129
- open = true;
1130
- } // 未开播,直接返回
1211
+ // 没有正在直播的订阅对象,直接返回
1131
1212
  return;
1132
1213
  }
1133
- // 检查直播状态
1134
- switch (data.live_status) {
1135
- case 0:
1136
- case 2: { // 状态 0 和 2 说明未开播
1137
- if (open) { // 之前开播,现在下播了
1138
- // 更改直播状态
1139
- open = false;
1140
- // 下播了将定时器清零
1141
- timer = 0;
1142
- // 定义下播通知消息
1143
- const liveEndMsg = this.config.customLiveEnd
1144
- .replace('-name', username)
1145
- .replace('-time', await ctx.gi.getTimeDifference(liveTime));
1146
- // 更改直播时长
1147
- data.live_time = liveTime;
1148
- // 发送@全体成员通知
1149
- await sendLiveNotifyCard(data, LiveType.StopBroadcast, liveEndMsg);
1150
- }
1151
- // 未进循环,还未开播,继续循环
1152
- break;
1153
- }
1154
- case 1: {
1155
- if (!open) { // 之前未开播,现在开播了
1156
- // 更改直播状态
1157
- open = true;
1158
- // 设置开播时间
1159
- liveTime = data.live_time;
1160
- // 获取主播信息
1161
- const attempts = 3;
1162
- for (let i = 0; i < attempts; i++) {
1163
- try {
1164
- // 主播信息不会变,开播时刷新一次即可
1165
- // 发送请求获取主播信息
1166
- await useMasterInfo(data.uid);
1167
- // 成功则跳出循环
1214
+ // 获取当前订阅直播的数量
1215
+ const currentLiveSubs = this.subManager.filter(sub => sub.live);
1216
+ // 获取当前liveRecord里的订阅数量
1217
+ const currentLiveRecordKeys = Object.keys(liveRecord);
1218
+ // 判断是否能匹配双方数量
1219
+ if (currentLiveRecordKeys.length < currentLiveSubs.length) {
1220
+ // 遍历currentLiveSubs
1221
+ for (const sub of currentLiveSubs) {
1222
+ // 判断liveRecord中缺少了哪些订阅
1223
+ if (!liveRecord[sub.uid]) {
1224
+ // 获取当前用户直播间信息
1225
+ const data = await useLiveStatus(sub.roomId.toString());
1226
+ switch (data.live_status) {
1227
+ case 0:
1228
+ case 2: { // 未开播
1229
+ // 添加到liveRecord中
1230
+ liveRecord[sub.uid] = { liveStatus: 0, liveTime: '', target: sub.target };
1231
+ // break
1168
1232
  break;
1169
1233
  }
1170
- catch (e) {
1171
- this.logger.error('liveDetect open getMasterInfo() 发生了错误,错误为:' + e.message);
1172
- if (i === attempts - 1) { // 已尝试三次
1173
- // 发送私聊消息并重启服务
1174
- return await this.sendPrivateMsgAndStopService(ctx);
1175
- }
1234
+ case 1: { //正在直播
1235
+ // 添加到liveRecord中
1236
+ liveRecord[sub.uid] = { liveStatus: 1, liveTime: data.live_time, target: sub.target };
1176
1237
  }
1177
1238
  }
1178
- // 定义开播通知语
1179
- const liveStartMsg = this.config.customLiveStart
1180
- .replace('-name', username)
1181
- .replace('-time', await ctx.gi.getTimeDifference(liveTime))
1182
- .replace('-link', `https://live.bilibili.com/${data.short_id === 0 ? data.room_id : data.short_id}`);
1183
- // 判断是否需要@全体成员
1184
- if (this.config.liveStartAtAll) {
1185
- // 发送@全体成员通知
1186
- await sendLiveNotifyCard(data, LiveType.StartBroadcasting, liveStartMsg, true);
1187
- }
1188
- else {
1239
+ }
1240
+ }
1241
+ }
1242
+ if (currentLiveRecordKeys.length > currentLiveSubs.length) {
1243
+ // 创建Set
1244
+ const setCurrentLiveSubs = new Set(currentLiveSubs.map(sub => sub.uid));
1245
+ // 找出 currentLiveRecordKeys中比currentLiveSubs 多的元素
1246
+ const extraInCurrentLiveSubs = currentLiveRecordKeys.filter(key => !setCurrentLiveSubs.has(key));
1247
+ // 遍历 extraInCurrentLiveSubs
1248
+ for (const subUID of extraInCurrentLiveSubs) {
1249
+ // 删除记录
1250
+ delete liveRecord[subUID];
1251
+ }
1252
+ }
1253
+ // 数量没有差异,则不进行其他操作
1254
+ // 遍历liveUsers
1255
+ liveUsers.items.forEach(async (item) => {
1256
+ // 判断是否有正在直播的订阅对象
1257
+ if (liveRecord[item.mid]) { // 有正在直播的订阅对象
1258
+ // 获取当前用户直播间信息
1259
+ const data = await useLiveStatus(item.room_id.toString());
1260
+ // 判断开播状态
1261
+ switch (liveRecord[item.mid].liveStatus) {
1262
+ case 0: { // 之前未开播,现在开播了
1263
+ // 设置开播时间
1264
+ liveRecord[item.mid].liveTime = data.live_time;
1265
+ // 定义开播通知语
1266
+ const liveStartMsg = this.config.customLiveStart ? this.config.customLiveStart
1267
+ .replace('-name', item.uname)
1268
+ .replace('-time', await this.ctx.gi.getTimeDifference(liveRecord[item.mid].liveTime))
1269
+ .replace('-link', `https://live.bilibili.com/${data.short_id === 0 ? data.room_id : data.short_id}`) : null;
1189
1270
  // 发送直播通知卡片
1190
- await sendLiveNotifyCard(data, LiveType.StartBroadcasting, liveStartMsg);
1271
+ await this.sendLiveNotifyCard({
1272
+ username: item.uname,
1273
+ userface: item.face,
1274
+ target: liveRecord[item.mid].target,
1275
+ data
1276
+ }, LiveType.LiveBroadcast, liveStartMsg);
1277
+ // 改变开播状态
1278
+ liveRecord[item.mid].liveStatus = 1;
1279
+ // 结束
1280
+ break;
1191
1281
  }
1192
- }
1193
- else { // 还在直播
1194
- if (this.config.pushTime > 0) {
1195
- timer++;
1196
- // 开始记录时间
1197
- if (timer >= (6 * 60 * this.config.pushTime)) { // 到时间推送直播消息
1198
- // 到时间重新计时
1199
- timer = 0;
1200
- // 定义直播中通知消息
1201
- const liveMsg = this.config.customLive ? this.config.customLive
1202
- .replace('-name', username)
1203
- .replace('-time', await ctx.gi.getTimeDifference(liveTime))
1204
- .replace('-link', `https://live.bilibili.com/${data.short_id === 0 ? data.room_id : data.short_id}`) : '';
1205
- // 发送直播通知卡片
1206
- sendLiveNotifyCard(data, LiveType.LiveBroadcast, liveMsg);
1282
+ case 1: { // 仍在直播
1283
+ if (this.config.pushTime > 0) {
1284
+ timer++;
1285
+ // 开始记录时间
1286
+ if (timer >= (6 * 60 * this.config.pushTime)) { // 到时间推送直播消息
1287
+ // 到时间重新计时
1288
+ timer = 0;
1289
+ // 定义直播中通知消息
1290
+ const liveMsg = this.config.customLive ? this.config.customLive
1291
+ .replace('-name', item.uname)
1292
+ .replace('-time', await this.ctx.gi.getTimeDifference(liveRecord[item.mid].liveTime))
1293
+ .replace('-link', `https://live.bilibili.com/${data.short_id === 0 ? data.room_id : data.short_id}`) : null;
1294
+ // 发送直播通知卡片
1295
+ this.sendLiveNotifyCard({
1296
+ username: item.uname,
1297
+ userface: item.face,
1298
+ target: liveRecord[item.mid].target,
1299
+ data
1300
+ }, LiveType.LiveBroadcast, liveMsg);
1301
+ }
1207
1302
  }
1208
1303
  }
1209
- // 否则继续循环
1210
1304
  }
1211
1305
  }
1306
+ });
1307
+ // 找出liveRecord中liveStatus为1但liveUsers中没有的元素
1308
+ const extraInLiveRecord = currentLiveRecordKeys.filter(key => !liveUsers.items.some(item => item.mid === Number(key)));
1309
+ // 遍历 extraInLiveRecord
1310
+ for (const subUID of extraInLiveRecord) { // 下播的主播
1311
+ // 获取主播信息
1312
+ const masterInfo = await this.useMasterInfo(subUID);
1313
+ // 获取直播间消息
1314
+ const liveRoomInfo = await this.useLiveRoomInfo(masterInfo.roomId.toString());
1315
+ // 定义下播播通知语
1316
+ const liveEndMsg = this.config.customLiveEnd ? this.config.customLiveEnd
1317
+ .replace('-name', masterInfo.username)
1318
+ .replace('-time', await this.ctx.gi.getTimeDifference(liveRecord[subUID].liveTime))
1319
+ .replace('-link', `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`) : null;
1320
+ // 发送下播通知
1321
+ this.sendLiveNotifyCard({
1322
+ username: masterInfo.username,
1323
+ userface: masterInfo.userface,
1324
+ target: liveRecord[subUID].target,
1325
+ data: liveRoomInfo
1326
+ }, LiveType.StopBroadcast, liveEndMsg);
1212
1327
  }
1213
1328
  }
1214
1329
  finally {
@@ -1217,6 +1332,150 @@ class ComRegister {
1217
1332
  }
1218
1333
  };
1219
1334
  }
1335
+ async liveDetectWithListener(roomId, target) {
1336
+ // 定义开播时间
1337
+ let liveTime;
1338
+ // 定义定时推送定时器
1339
+ let pushAtTimeTimer;
1340
+ // 定义弹幕存放数组
1341
+ const currentLiveDanmakuArr = [];
1342
+ const temporaryLiveDanmakuArr = [];
1343
+ // 处理target
1344
+ // 找到频道/群组对应的
1345
+ const newTarget = target.map(channel => {
1346
+ const liveDanmakuArr = channel.channelIdArr.filter(channelId => channelId.liveDanmaku);
1347
+ return {
1348
+ channelIdArr: liveDanmakuArr,
1349
+ platform: channel.platform
1350
+ };
1351
+ });
1352
+ // 定义定时推送函数
1353
+ const pushAtTimeFunc = async () => {
1354
+ // 获取直播间信息
1355
+ const liveRoomInfo = await this.useLiveRoomInfo(roomId);
1356
+ // 获取主播信息
1357
+ const masterInfo = await this.useMasterInfo(liveRoomInfo.uid);
1358
+ // 定义直播中通知消息
1359
+ const liveMsg = this.config.customLive ? this.config.customLive
1360
+ .replace('-name', masterInfo.username)
1361
+ .replace('-time', await this.ctx.gi.getTimeDifference(liveTime))
1362
+ .replace('-link', `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`) : null;
1363
+ // 发送直播通知卡片
1364
+ await this.sendLiveNotifyCard({
1365
+ username: masterInfo.username,
1366
+ userface: masterInfo.userface,
1367
+ target: newTarget,
1368
+ data: liveRoomInfo
1369
+ }, LiveType.LiveBroadcast, liveMsg);
1370
+ };
1371
+ // 定义弹幕推送函数
1372
+ const danmakuPushFunc = () => {
1373
+ // 判断数组是否有内容
1374
+ if (temporaryLiveDanmakuArr.length > 0) {
1375
+ // 发送消息
1376
+ this.sendMsg(newTarget, temporaryLiveDanmakuArr.join('\n'));
1377
+ // 将临时消息数组清空
1378
+ temporaryLiveDanmakuArr.length = 0;
1379
+ }
1380
+ };
1381
+ // 获取直播间信息
1382
+ const liveRoomInfo = await this.useLiveRoomInfo(roomId);
1383
+ // 获取主播信息
1384
+ const masterInfo = await this.useMasterInfo(liveRoomInfo.uid);
1385
+ // 构建消息处理函数
1386
+ const handler = {
1387
+ onOpen: () => {
1388
+ this.logger.info('直播间连接成功');
1389
+ },
1390
+ onClose: () => {
1391
+ this.logger.info('直播间连接已断开');
1392
+ },
1393
+ onIncomeDanmu: ({ body }) => {
1394
+ // 处理消息,只需要UP主名字和消息内容
1395
+ const content = `【${masterInfo.username}的直播间】${body.user.uname}:${body.content}`;
1396
+ // 保存消息到数组
1397
+ currentLiveDanmakuArr.push(body.content);
1398
+ temporaryLiveDanmakuArr.push(content);
1399
+ },
1400
+ onIncomeSuperChat: ({ body }) => {
1401
+ // 处理SC消息
1402
+ const content = `【${masterInfo.username}的直播间】${body.user.uname}发送了一条SC:${body.content}`;
1403
+ // 保存消息到数组
1404
+ currentLiveDanmakuArr.push(body.content);
1405
+ temporaryLiveDanmakuArr.push(content);
1406
+ },
1407
+ onGuardBuy: ({ body }) => {
1408
+ const content = `【${masterInfo.username}的直播间】${body.user.uname}加入了大航海(${body.gift_name})`;
1409
+ // 保存消息到数组
1410
+ currentLiveDanmakuArr.push(content);
1411
+ temporaryLiveDanmakuArr.push(content);
1412
+ },
1413
+ onLiveStart: async () => {
1414
+ // 获取直播间信息
1415
+ const liveRoomInfo = await this.useLiveRoomInfo(roomId);
1416
+ // 获取主播信息
1417
+ const masterInfo = await this.useMasterInfo(liveRoomInfo.uid);
1418
+ // 定义下播通知消息
1419
+ const liveEndMsg = this.config.customLiveEnd ? this.config.customLiveEnd
1420
+ .replace('-name', masterInfo.username)
1421
+ .replace('-time', await this.ctx.gi.getTimeDifference(liveTime)) : null;
1422
+ // 更改直播时长
1423
+ liveRoomInfo.live_time = liveTime;
1424
+ // 推送下播通知
1425
+ await this.sendLiveNotifyCard({
1426
+ username: masterInfo.username,
1427
+ userface: masterInfo.userface,
1428
+ target: newTarget,
1429
+ data: liveRoomInfo
1430
+ }, LiveType.StopBroadcast, liveEndMsg);
1431
+ },
1432
+ onLiveEnd: async () => {
1433
+ // 获取直播间消息
1434
+ const liveRoomInfo = await this.useLiveRoomInfo(roomId);
1435
+ // 获取主播信息
1436
+ const masterInfo = await this.useMasterInfo(liveRoomInfo.uid);
1437
+ // 关闭定时推送定时器
1438
+ pushAtTimeTimer();
1439
+ // 将推送定时器变量置空
1440
+ pushAtTimeTimer = null;
1441
+ // 定义下播播通知语
1442
+ const liveEndMsg = this.config.customLiveEnd ? this.config.customLiveEnd
1443
+ .replace('-name', masterInfo.username)
1444
+ .replace('-time', await this.ctx.gi.getTimeDifference(liveTime))
1445
+ .replace('-link', `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`) : null;
1446
+ // 推送通知卡片
1447
+ await this.sendLiveNotifyCard({
1448
+ username: masterInfo.username,
1449
+ userface: masterInfo.userface,
1450
+ target: newTarget,
1451
+ data: liveRoomInfo
1452
+ }, LiveType.StartBroadcasting, liveEndMsg);
1453
+ }
1454
+ };
1455
+ // 启动直播间弹幕监测
1456
+ this.ctx.bl.startLiveRoomListener(roomId, handler, danmakuPushFunc);
1457
+ // 判断直播状态
1458
+ if (liveRoomInfo.live_status === 1) {
1459
+ // 设置开播时间
1460
+ liveTime = liveRoomInfo.live_time;
1461
+ // 定义直播中通知消息
1462
+ const liveMsg = this.config.customLive ? this.config.customLive
1463
+ .replace('-name', masterInfo.username)
1464
+ .replace('-time', await this.ctx.gi.getTimeDifference(liveTime))
1465
+ .replace('-link', `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`) : null;
1466
+ // 发送直播通知卡片
1467
+ if (this.config.restartPush) {
1468
+ await this.sendLiveNotifyCard({
1469
+ username: masterInfo.username,
1470
+ userface: masterInfo.userface,
1471
+ target: newTarget,
1472
+ data: liveRoomInfo
1473
+ }, LiveType.LiveBroadcast, liveMsg);
1474
+ }
1475
+ // 正在直播,开启定时器
1476
+ pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1000 * 60 * 60);
1477
+ }
1478
+ }
1220
1479
  subShow() {
1221
1480
  // 在控制台中显示订阅对象
1222
1481
  let table = ``;
@@ -1255,7 +1514,7 @@ class ComRegister {
1255
1514
  // 只订阅动态
1256
1515
  return [false, true];
1257
1516
  }
1258
- updateSubNotifier(ctx) {
1517
+ updateSubNotifier() {
1259
1518
  // 更新控制台提示
1260
1519
  if (this.subNotifier)
1261
1520
  this.subNotifier.dispose();
@@ -1274,13 +1533,13 @@ class ComRegister {
1274
1533
  table = (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("p", { children: "\u5F53\u524D\u8BA2\u9605\u5BF9\u8C61\uFF1A" }), (0, jsx_runtime_1.jsx)("ul", { children: subTableArray.map(str => ((0, jsx_runtime_1.jsx)("li", { children: str }))) })] });
1275
1534
  }
1276
1535
  // 设置更新后的提示
1277
- this.subNotifier = ctx.notifier.create(table);
1536
+ this.subNotifier = this.ctx.notifier.create(table);
1278
1537
  }
1279
- async checkIfLoginInfoIsLoaded(ctx) {
1538
+ async checkIfLoginInfoIsLoaded() {
1280
1539
  return new Promise(resolve => {
1281
1540
  const check = () => {
1282
- if (!ctx.ba.getLoginInfoIsLoaded()) {
1283
- ctx.setTimeout(check, 500);
1541
+ if (!this.ctx.ba.getLoginInfoIsLoaded()) {
1542
+ this.ctx.setTimeout(check, 500);
1284
1543
  }
1285
1544
  else {
1286
1545
  resolve('success');
@@ -1289,17 +1548,17 @@ class ComRegister {
1289
1548
  check();
1290
1549
  });
1291
1550
  }
1292
- async subUserInBili(ctx, mid) {
1551
+ async subUserInBili(mid) {
1293
1552
  // 获取关注分组信息
1294
1553
  const checkGroupIsReady = async () => {
1295
1554
  // 判断是否有数据
1296
1555
  if (this.loginDBData.dynamic_group_id === '' || this.loginDBData.dynamic_group_id === null) {
1297
1556
  // 没有数据,没有创建分组,尝试创建分组
1298
- const createGroupData = await ctx.ba.createGroup("订阅");
1557
+ const createGroupData = await this.ctx.ba.createGroup("订阅");
1299
1558
  // 如果分组已创建,则获取分组id
1300
1559
  if (createGroupData.code === 22106) {
1301
1560
  // 分组已存在,拿到之前的分组id
1302
- const allGroupData = await ctx.ba.getAllGroup();
1561
+ const allGroupData = await this.ctx.ba.getAllGroup();
1303
1562
  // 遍历所有分组
1304
1563
  for (const group of allGroupData.data) {
1305
1564
  // 找到订阅分组
@@ -1317,7 +1576,7 @@ class ComRegister {
1317
1576
  return false;
1318
1577
  }
1319
1578
  // 创建成功,保存到数据库
1320
- ctx.database.set('loginBili', 1, { dynamic_group_id: this.loginDBData.dynamic_group_id });
1579
+ this.ctx.database.set('loginBili', 1, { dynamic_group_id: this.loginDBData.dynamic_group_id });
1321
1580
  // 创建成功
1322
1581
  return true;
1323
1582
  }
@@ -1331,7 +1590,7 @@ class ComRegister {
1331
1590
  return { flag: false, msg: '创建分组失败,请尝试重启插件' };
1332
1591
  }
1333
1592
  // 获取分组明细
1334
- const relationGroupDetailData = await ctx.ba.getRelationGroupDetail(this.loginDBData.dynamic_group_id);
1593
+ const relationGroupDetailData = await this.ctx.ba.getRelationGroupDetail(this.loginDBData.dynamic_group_id);
1335
1594
  // 判断分组信息是否获取成功
1336
1595
  if (relationGroupDetailData.code !== 0) {
1337
1596
  if (relationGroupDetailData.code === 22104) {
@@ -1356,7 +1615,7 @@ class ComRegister {
1356
1615
  }
1357
1616
  });
1358
1617
  // 订阅对象
1359
- const subUserData = await ctx.ba.follow(mid);
1618
+ const subUserData = await this.ctx.ba.follow(mid);
1360
1619
  // 判断是否订阅成功
1361
1620
  switch (subUserData.code) {
1362
1621
  case -101: return { flag: false, msg: '账号未登录,请使用指令bili login登录后再进行订阅操作' };
@@ -1369,7 +1628,7 @@ class ComRegister {
1369
1628
  case 22014: // 已关注订阅对象 无需再次关注
1370
1629
  case 0: { // 执行订阅成功
1371
1630
  // 把订阅对象添加到分组中
1372
- const copyUserToGroupData = await ctx.ba.copyUserToGroup(mid, this.loginDBData.dynamic_group_id);
1631
+ const copyUserToGroupData = await this.ctx.ba.copyUserToGroup(mid, this.loginDBData.dynamic_group_id);
1373
1632
  // 判断是否添加成功
1374
1633
  if (copyUserToGroupData.code !== 0) {
1375
1634
  // 添加失败
@@ -1380,11 +1639,68 @@ class ComRegister {
1380
1639
  // 订阅成功
1381
1640
  return { flag: true, msg: '用户订阅成功' };
1382
1641
  }
1383
- async getSubFromDatabase(ctx) {
1642
+ async loadSubFromConfig(subs) {
1643
+ for (const sub of subs) {
1644
+ // 定义Data
1645
+ let data;
1646
+ // 判断是否需要订阅直播
1647
+ if (sub.live) {
1648
+ // 获取用户信息
1649
+ let content;
1650
+ // 设置重试次数
1651
+ const attempts = 3;
1652
+ for (let i = 0; i < attempts; i++) {
1653
+ try {
1654
+ // 获取用户信息
1655
+ content = await this.ctx.ba.getUserInfo(sub.uid);
1656
+ // 成功则跳出循环
1657
+ break;
1658
+ }
1659
+ catch (e) {
1660
+ this.logger.error('getSubFromDatabase() getUserInfo() 发生了错误,错误为:' + e.message);
1661
+ if (i === attempts - 1) { // 已尝试三次
1662
+ // 发送私聊消息并重启服务
1663
+ return await this.sendPrivateMsgAndStopService();
1664
+ }
1665
+ }
1666
+ }
1667
+ // 获取data
1668
+ data = content.data;
1669
+ // 检查roomid是否存在
1670
+ if (!data.live_room) {
1671
+ // 用户没有开通直播间,无法订阅直播
1672
+ sub.live = false;
1673
+ // 发送提示
1674
+ this.logger.warn(`UID:${sub.uid} 用户没有开通直播间,无法订阅直播!`);
1675
+ }
1676
+ // 判断是否订阅直播
1677
+ if (sub.live) {
1678
+ // 订阅直播
1679
+ this.liveDetectWithListener(data.live_room.roomid, sub.target);
1680
+ }
1681
+ }
1682
+ // 在B站中订阅该对象
1683
+ const subInfo = await this.subUserInBili(sub.uid);
1684
+ // 判断订阅是否成功
1685
+ if (!subInfo.flag)
1686
+ this.logger.warn(subInfo.msg);
1687
+ // 将该订阅添加到sm中
1688
+ this.subManager.push({
1689
+ id: +sub.uid,
1690
+ uid: sub.uid,
1691
+ roomId: sub.live ? data.live_room.roomid : '',
1692
+ target: sub.target,
1693
+ platform: '',
1694
+ live: sub.live,
1695
+ dynamic: sub.dynamic
1696
+ });
1697
+ }
1698
+ }
1699
+ async loadSubFromDatabase() {
1384
1700
  // 判断登录信息是否已加载完毕
1385
- await this.checkIfLoginInfoIsLoaded(ctx);
1701
+ await this.checkIfLoginInfoIsLoaded();
1386
1702
  // 如果未登录,则直接返回
1387
- if (!(await this.checkIfIsLogin(ctx))) {
1703
+ if (!(await this.checkIfIsLogin())) {
1388
1704
  // log
1389
1705
  this.logger.info(`账号未登录,请登录`);
1390
1706
  return;
@@ -1393,7 +1709,7 @@ class ComRegister {
1393
1709
  if (this.subManager.length !== 0)
1394
1710
  return;
1395
1711
  // 从数据库中获取数据
1396
- const subData = await ctx.database.get('bilibili', { id: { $gt: 0 } });
1712
+ const subData = await this.ctx.database.get('bilibili', { id: { $gt: 0 } });
1397
1713
  // 定义变量:订阅直播数
1398
1714
  let liveSubNum = 0;
1399
1715
  // 循环遍历
@@ -1401,14 +1717,14 @@ class ComRegister {
1401
1717
  // 判断是否存在没有任何订阅的数据
1402
1718
  if (!sub.dynamic && !sub.live) { // 存在未订阅任何项目的数据
1403
1719
  // 删除该条数据
1404
- ctx.database.remove('bilibili', { id: sub.id });
1720
+ this.ctx.database.remove('bilibili', { id: sub.id });
1405
1721
  // log
1406
1722
  this.logger.warn(`UID:${sub.uid} 该条数据没有任何订阅数据,自动取消订阅`);
1407
1723
  // 跳过下面的步骤
1408
1724
  continue;
1409
1725
  }
1410
1726
  // 判断用户是否在B站中订阅了
1411
- const subUserData = await this.subUserInBili(ctx, sub.uid);
1727
+ const subUserData = await this.subUserInBili(sub.uid);
1412
1728
  // 判断是否订阅
1413
1729
  if (!subUserData.flag) {
1414
1730
  // log
@@ -1416,7 +1732,7 @@ class ComRegister {
1416
1732
  // 发送私聊消息
1417
1733
  await this.sendPrivateMsg(`UID:${sub.uid} ${subUserData.msg},自动取消订阅`);
1418
1734
  // 删除该条数据
1419
- await ctx.database.remove('bilibili', { id: sub.id });
1735
+ await this.ctx.database.remove('bilibili', { id: sub.id });
1420
1736
  // 跳过下面的步骤
1421
1737
  continue;
1422
1738
  }
@@ -1429,7 +1745,7 @@ class ComRegister {
1429
1745
  for (let i = 0; i < attempts; i++) {
1430
1746
  try {
1431
1747
  // 获取用户信息
1432
- content = await ctx.ba.getUserInfo(sub.uid);
1748
+ content = await this.ctx.ba.getUserInfo(sub.uid);
1433
1749
  // 成功则跳出循环
1434
1750
  break;
1435
1751
  }
@@ -1437,7 +1753,7 @@ class ComRegister {
1437
1753
  this.logger.error('getSubFromDatabase() getUserInfo() 发生了错误,错误为:' + e.message);
1438
1754
  if (i === attempts - 1) { // 已尝试三次
1439
1755
  // 发送私聊消息并重启服务
1440
- return await this.sendPrivateMsgAndStopService(ctx);
1756
+ return await this.sendPrivateMsgAndStopService();
1441
1757
  }
1442
1758
  }
1443
1759
  }
@@ -1446,7 +1762,7 @@ class ComRegister {
1446
1762
  // 定义函数删除数据和发送提示
1447
1763
  const deleteSub = async () => {
1448
1764
  // 从数据库删除该条数据
1449
- await ctx.database.remove('bilibili', { id: sub.id });
1765
+ await this.ctx.database.remove('bilibili', { id: sub.id });
1450
1766
  // 给用户发送提示
1451
1767
  await this.sendPrivateMsg(`UID:${sub.uid} 数据库内容被篡改,已取消对该UP主的订阅`);
1452
1768
  };
@@ -1478,6 +1794,7 @@ class ComRegister {
1478
1794
  this.logger.info(`UID:${sub.uid} 房间号被篡改,自动取消订阅`);
1479
1795
  // Send msg
1480
1796
  await this.sendPrivateMsg(`UID:${sub.uid} 房间号被篡改,自动取消订阅`);
1797
+ // 直接返回
1481
1798
  return;
1482
1799
  }
1483
1800
  // 构建订阅对象
@@ -1487,46 +1804,47 @@ class ComRegister {
1487
1804
  roomId: sub.room_id,
1488
1805
  target,
1489
1806
  platform: sub.platform,
1490
- live: +sub.live === 1 ? true : false,
1491
- dynamic: +sub.dynamic === 1 ? true : false,
1807
+ live: sub.live === 1 ? true : false,
1808
+ dynamic: sub.dynamic === 1 ? true : false,
1492
1809
  liveDispose: null
1493
1810
  };
1494
1811
  // 判断是否订阅直播
1495
1812
  if (sub.live) {
1496
1813
  // 判断订阅直播数是否超过限制
1497
1814
  if (!this.config.unlockSubLimits && liveSubNum >= 3) {
1815
+ // 将live改为false
1498
1816
  subManagerItem.live = false;
1499
1817
  // log
1500
1818
  this.logger.warn(`UID:${sub.uid} 订阅直播数超过限制,自动取消订阅`);
1501
1819
  // 发送错误消息
1502
- this.sendPrivateMsg(`UID:${sub.uid} 订阅直播数超过限制,自动取消订阅`);
1820
+ await this.sendPrivateMsg(`UID:${sub.uid} 订阅直播数超过限制,自动取消订阅`);
1503
1821
  }
1504
1822
  else {
1505
1823
  // 直播订阅数+1
1506
1824
  liveSubNum++;
1507
1825
  // 订阅直播,开始循环检测
1508
- const dispose = ctx.setInterval(this.liveDetect(ctx, sub.room_id, target), this.config.liveLoopTime * 1000);
1509
- // 保存销毁函数
1510
- subManagerItem.liveDispose = dispose;
1826
+ this.liveDetectWithListener(sub.room_id, target);
1511
1827
  }
1512
1828
  }
1513
1829
  // 保存新订阅对象
1514
1830
  this.subManager.push(subManagerItem);
1515
1831
  }
1832
+ }
1833
+ checkIfDynamicDetectIsNeeded() {
1516
1834
  // 检查是否有订阅对象需要动态监测
1517
- if (this.subManager.some(sub => sub.dynamic)) {
1518
- // 开始动态监测
1519
- if (this.config.dynamicDebugMode) {
1520
- this.dynamicDispose = ctx.setInterval(this.debug_dynamicDetect(ctx), 10000);
1521
- }
1522
- else {
1523
- this.dynamicDispose = ctx.setInterval(this.dynamicDetect(ctx), 10000 /* this.config.dynamicLoopTime * 1000 */);
1524
- }
1835
+ if (this.subManager.some(sub => sub.dynamic))
1836
+ this.enableDynamicDetect();
1837
+ }
1838
+ enableDynamicDetect() {
1839
+ // 开始动态监测
1840
+ if (this.config.dynamicDebugMode) {
1841
+ this.dynamicDispose = this.ctx.setInterval(this.debug_dynamicDetect(), this.config.dynamicLoopTime * 1000);
1842
+ }
1843
+ else {
1844
+ this.dynamicDispose = this.ctx.setInterval(this.dynamicDetect(), this.config.dynamicLoopTime * 1000);
1525
1845
  }
1526
- // 在控制台中显示订阅对象
1527
- this.updateSubNotifier(ctx);
1528
1846
  }
1529
- unsubSingle(ctx, id /* UID或RoomId */, type /* 0取消Live订阅,1取消Dynamic订阅 */) {
1847
+ unsubSingle(id /* UID或RoomId */, type /* 0取消Live订阅,1取消Dynamic订阅 */) {
1530
1848
  // 定义返回消息
1531
1849
  let msg;
1532
1850
  // 定义方法:检查是否没有任何订阅
@@ -1536,7 +1854,7 @@ class ComRegister {
1536
1854
  // 从管理对象中移除
1537
1855
  this.subManager.splice(index, 1);
1538
1856
  // 从数据库中删除
1539
- ctx.database.remove('bilibili', [this.subManager[index].id]);
1857
+ this.ctx.database.remove('bilibili', [this.subManager[index].id]);
1540
1858
  // num--
1541
1859
  this.num--;
1542
1860
  // 判断是否还存在订阅了动态的对象,不存在则停止动态监测
@@ -1555,9 +1873,6 @@ class ComRegister {
1555
1873
  return msg;
1556
1874
  }
1557
1875
  // 取消订阅
1558
- if (sub.live)
1559
- sub.liveDispose();
1560
- sub.liveDispose = null;
1561
1876
  sub.live = false;
1562
1877
  // 如果没有对这个UP的任何订阅,则移除
1563
1878
  if (checkIfNoSubExist(sub)) {
@@ -1566,7 +1881,7 @@ class ComRegister {
1566
1881
  return '已取消订阅该用户';
1567
1882
  }
1568
1883
  // 更新数据库
1569
- ctx.database.upsert('bilibili', [{
1884
+ this.ctx.database.upsert('bilibili', [{
1570
1885
  id: +`${sub.id}`,
1571
1886
  live: 0
1572
1887
  }]);
@@ -1593,7 +1908,7 @@ class ComRegister {
1593
1908
  return '已取消订阅该用户';
1594
1909
  }
1595
1910
  // 更新数据库
1596
- ctx.database.upsert('bilibili', [{
1911
+ this.ctx.database.upsert('bilibili', [{
1597
1912
  id: sub.id,
1598
1913
  dynamic: 0
1599
1914
  }]);
@@ -1603,25 +1918,22 @@ class ComRegister {
1603
1918
  }
1604
1919
  finally {
1605
1920
  // 执行完该方法后,保证执行一次updateSubNotifier()
1606
- this.updateSubNotifier(ctx);
1921
+ this.updateSubNotifier();
1607
1922
  }
1608
1923
  }
1609
1924
  checkIfUserIsTheLastOneWhoSubDyn() {
1610
- if (this.subManager.some(sub => sub.dynamic)) {
1925
+ if (this.dynamicDispose && !this.subManager.some(sub => sub.dynamic)) {
1611
1926
  // 停止动态监测
1612
1927
  this.dynamicDispose();
1613
1928
  this.dynamicDispose = null;
1614
1929
  }
1615
1930
  }
1616
- unsubAll(ctx, uid) {
1931
+ unsubAll(uid) {
1617
1932
  this.subManager.filter(sub => sub.uid === uid).map(async (sub, i) => {
1618
- // 取消全部订阅 执行dispose方法,销毁定时器
1619
- if (sub.live)
1620
- await this.subManager[i].liveDispose();
1621
1933
  // 判断是否还存在订阅了动态的对象,不存在则停止动态监测
1622
1934
  this.checkIfUserIsTheLastOneWhoSubDyn();
1623
1935
  // 从数据库中删除订阅
1624
- await ctx.database.remove('bilibili', { uid: this.subManager[i].uid });
1936
+ await this.ctx.database.remove('bilibili', { uid: this.subManager[i].uid });
1625
1937
  // 将该订阅对象从订阅管理对象中移除
1626
1938
  this.subManager.splice(i, 1);
1627
1939
  // id--
@@ -1629,13 +1941,13 @@ class ComRegister {
1629
1941
  // 发送成功通知
1630
1942
  this.sendPrivateMsg(`UID:${uid},已取消订阅该用户`);
1631
1943
  // 更新控制台提示
1632
- this.updateSubNotifier(ctx);
1944
+ this.updateSubNotifier();
1633
1945
  });
1634
1946
  }
1635
- async checkIfIsLogin(ctx) {
1636
- if ((await ctx.database.get('loginBili', 1)).length !== 0) { // 数据库中有数据
1947
+ async checkIfIsLogin() {
1948
+ if ((await this.ctx.database.get('loginBili', 1)).length !== 0) { // 数据库中有数据
1637
1949
  // 检查cookie中是否有值
1638
- if (ctx.ba.getCookies() !== '[]') { // 有值说明已登录
1950
+ if (this.ctx.ba.getCookies() !== '[]') { // 有值说明已登录
1639
1951
  return true;
1640
1952
  }
1641
1953
  }
@@ -1644,6 +1956,21 @@ class ComRegister {
1644
1956
  }
1645
1957
  (function (ComRegister) {
1646
1958
  ComRegister.Config = koishi_1.Schema.object({
1959
+ sub: koishi_1.Schema.array(koishi_1.Schema.object({
1960
+ uid: koishi_1.Schema.string().description('订阅用户UID'),
1961
+ dynamic: koishi_1.Schema.boolean().description('是否订阅用户动态'),
1962
+ live: koishi_1.Schema.boolean().description('是否订阅用户直播'),
1963
+ target: koishi_1.Schema.array(koishi_1.Schema.object({
1964
+ channelIdArr: koishi_1.Schema.array(koishi_1.Schema.object({
1965
+ channelId: koishi_1.Schema.string().description('频道/群组号'),
1966
+ dynamic: koishi_1.Schema.boolean().description('该频道/群组是否推送动态信息'),
1967
+ live: koishi_1.Schema.boolean().description('该频道/群组是否推送直播通知'),
1968
+ liveDanmaku: koishi_1.Schema.boolean().description('该频道/群组是否推送弹幕消息'),
1969
+ atAll: koishi_1.Schema.boolean().description('推送开播通知时是否艾特全体成员')
1970
+ })).description('频道/群组信息'),
1971
+ platform: koishi_1.Schema.string().description('推送平台')
1972
+ })).description('订阅用户需要发送的频道/群组信息')
1973
+ })).role('table').description('手动输入订阅信息,方便自定义订阅内容,这里的订阅内容不会存入数据库。uid: 订阅用户UID,dynamic: 是否需要订阅动态,live: 是否需要订阅直播'),
1647
1974
  master: koishi_1.Schema.object({
1648
1975
  enable: koishi_1.Schema.boolean(),
1649
1976
  platform: koishi_1.Schema.string(),
@@ -1652,8 +1979,6 @@ class ComRegister {
1652
1979
  }),
1653
1980
  unlockSubLimits: koishi_1.Schema.boolean().required(),
1654
1981
  automaticResend: koishi_1.Schema.boolean().required(),
1655
- changeMasterInfoApi: koishi_1.Schema.boolean().required(),
1656
- liveStartAtAll: koishi_1.Schema.boolean().required(),
1657
1982
  restartPush: koishi_1.Schema.boolean().required(),
1658
1983
  pushTime: koishi_1.Schema.number().required(),
1659
1984
  liveLoopTime: koishi_1.Schema.number().default(10),