koishi-plugin-bilibili-notify 3.0.0-alpha.9 → 3.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,24 +4,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const jsx_runtime_1 = require("@satorijs/element/jsx-runtime");
7
- /* eslint-disable @typescript-eslint/ban-types */
8
- /* eslint-disable @typescript-eslint/no-namespace */
9
- /* eslint-disable @typescript-eslint/no-explicit-any */
7
+ // Koishi核心依赖
10
8
  const koishi_1 = require("koishi");
11
- // 导入qrcode
9
+ // 外部依赖:qrcode
12
10
  const qrcode_1 = __importDefault(require("qrcode"));
13
- var LiveType;
14
- (function (LiveType) {
15
- LiveType[LiveType["NotLiveBroadcast"] = 0] = "NotLiveBroadcast";
16
- LiveType[LiveType["StartBroadcasting"] = 1] = "StartBroadcasting";
17
- LiveType[LiveType["LiveBroadcast"] = 2] = "LiveBroadcast";
18
- LiveType[LiveType["StopBroadcast"] = 3] = "StopBroadcast";
19
- })(LiveType || (LiveType = {}));
11
+ // Utils
12
+ const utils_1 = require("./utils");
13
+ // Types
14
+ const type_1 = require("./type");
15
+ // TODO:WorlCloud
16
+ // import { Segment, useDefault } from "segmentit";
20
17
  class ComRegister {
21
18
  // 必须服务
22
- static inject = ['ba', 'gi', 'database', 'bl', 'sm'];
19
+ static inject = ["ba", "gi", "database", "bl", "sm"];
23
20
  // 定义数组:QQ相关bot
24
- qqRelatedBotList = ['qq', 'onebot', 'red', 'satori', 'chronocat'];
21
+ qqRelatedBotList = [
22
+ "qq",
23
+ "onebot",
24
+ "red",
25
+ "satori",
26
+ "chronocat",
27
+ ];
25
28
  // logger
26
29
  logger;
27
30
  // config
@@ -55,76 +58,82 @@ class ComRegister {
55
58
  // 初始化
56
59
  this.init(config);
57
60
  // 注册指令
58
- const statusCom = ctx.command('status', '插件状态相关指令', { permissions: ['authority:5'] });
59
- statusCom.subcommand('.dyn', '查看动态监测运行状态')
60
- .usage('查看动态监测运行状态')
61
- .example('status dyn')
61
+ const statusCom = ctx.command("status", "插件状态相关指令", {
62
+ permissions: ["authority:5"],
63
+ });
64
+ statusCom
65
+ .subcommand(".dyn", "查看动态监测运行状态")
66
+ .usage("查看动态监测运行状态")
67
+ .example("status dyn")
62
68
  .action(() => {
63
69
  if (this.dynamicDispose) {
64
- return '动态监测正在运行';
65
- }
66
- else {
67
- return '动态监测未运行';
70
+ return "动态监测正在运行";
68
71
  }
72
+ return "动态监测未运行";
69
73
  });
70
- statusCom.subcommand('.sm', '查看订阅管理对象')
71
- .usage('查看订阅管理对象')
72
- .example('status sm')
74
+ statusCom
75
+ .subcommand(".sm", "查看订阅管理对象")
76
+ .usage("查看订阅管理对象")
77
+ .example("status sm")
73
78
  .action(async () => {
74
79
  this.logger.info(this.subManager);
75
- return '查看控制台';
80
+ return "查看控制台";
76
81
  });
77
82
  statusCom
78
- .subcommand('.bot', '查询当前拥有的机器人信息', { hidden: true })
79
- .usage('查询当前拥有的机器人信息')
80
- .example('status bot 查询当前拥有的机器人信息')
83
+ .subcommand(".bot", "查询当前拥有的机器人信息", { hidden: true })
84
+ .usage("查询当前拥有的机器人信息")
85
+ .example("status bot 查询当前拥有的机器人信息")
81
86
  .action(() => {
82
- this.logger.info('开始输出BOT信息');
83
- ctx.bots.forEach(bot => {
84
- this.logger.info('--------------------------------');
85
- this.logger.info('平台:' + bot.platform);
86
- this.logger.info('名称:' + bot.user.name);
87
- this.logger.info('--------------------------------');
88
- });
87
+ this.logger.info("开始输出BOT信息");
88
+ for (const bot of ctx.bots) {
89
+ this.logger.info("--------------------------------");
90
+ this.logger.info(`平台:${bot.platform}`);
91
+ this.logger.info(`名称:${bot.user.name}`);
92
+ this.logger.info("--------------------------------");
93
+ }
89
94
  });
90
95
  statusCom
91
- .subcommand('.env', '查询当前环境的信息', { hidden: true })
92
- .usage('查询当前环境的信息')
93
- .example('status env 查询当前环境的信息')
96
+ .subcommand(".env", "查询当前环境的信息", { hidden: true })
97
+ .usage("查询当前环境的信息")
98
+ .example("status env 查询当前环境的信息")
94
99
  .action(async ({ session }) => {
95
100
  await session.send(`Guild ID:${session.event.guild.id}`);
96
101
  await session.send(`Channel ID: ${session.event.channel.id}`);
97
102
  });
98
- const biliCom = ctx.command('bili', 'bili-notify插件相关指令', { permissions: ['authority:3'] });
99
- biliCom.subcommand('.login', '登录B站之后才可以进行之后的操作')
100
- .usage('使用二维码登录,登录B站之后才可以进行之后的操作')
101
- .example('bili login')
103
+ const biliCom = ctx.command("bili", "bili-notify插件相关指令", {
104
+ permissions: ["authority:3"],
105
+ });
106
+ biliCom
107
+ .subcommand(".login", "登录B站之后才可以进行之后的操作")
108
+ .usage("使用二维码登录,登录B站之后才可以进行之后的操作")
109
+ .example("bili login")
102
110
  .action(async ({ session }) => {
103
- this.logger.info('调用bili login指令');
111
+ this.logger.info("调用bili login指令");
104
112
  // 获取二维码
113
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
105
114
  let content;
106
115
  try {
107
116
  content = await ctx.ba.getLoginQRCode();
108
117
  }
109
118
  catch (e) {
110
- return 'bili login getLoginQRCode() 本次网络请求失败';
119
+ return "bili login getLoginQRCode() 本次网络请求失败";
111
120
  }
112
121
  // 判断是否出问题
113
122
  if (content.code !== 0)
114
- return await session.send('出问题咯,请联系管理员解决');
123
+ return await session.send("出问题咯,请联系管理员解决");
115
124
  // 生成二维码
116
125
  qrcode_1.default.toBuffer(content.data.url, {
117
- errorCorrectionLevel: 'H', // 错误更正水平
118
- type: 'png', // 输出类型
126
+ errorCorrectionLevel: "H", // 错误更正水平
127
+ type: "png", // 输出类型
119
128
  margin: 1, // 边距大小
120
129
  color: {
121
- dark: '#000000', // 二维码颜色
122
- light: '#FFFFFF' // 背景颜色
123
- }
130
+ dark: "#000000", // 二维码颜色
131
+ light: "#FFFFFF", // 背景颜色
132
+ },
124
133
  }, async (err, buffer) => {
125
134
  if (err)
126
- return await session.send('二维码生成出错,请重新尝试');
127
- await session.send(koishi_1.h.image(buffer, 'image/png'));
135
+ return await session.send("二维码生成出错,请重新尝试");
136
+ await session.send(koishi_1.h.image(buffer, "image/png"));
128
137
  });
129
138
  // 检查之前是否存在登录定时器
130
139
  if (this.loginTimer)
@@ -139,6 +148,7 @@ class ComRegister {
139
148
  return;
140
149
  flag = false;
141
150
  // 获取登录信息
151
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
142
152
  let loginContent;
143
153
  try {
144
154
  loginContent = await ctx.ba.getLoginStatus(content.data.qrcode_key);
@@ -149,32 +159,33 @@ class ComRegister {
149
159
  }
150
160
  if (loginContent.code !== 0) {
151
161
  this.loginTimer();
152
- return await session.send('登录失败请重试');
162
+ return await session.send("登录失败请重试");
153
163
  }
154
164
  if (loginContent.data.code === 86038) {
155
165
  this.loginTimer();
156
- return await session.send('二维码已失效,请重新登录');
166
+ return await session.send("二维码已失效,请重新登录");
157
167
  }
158
- if (loginContent.data.code === 0) { // 登录成功
168
+ if (loginContent.data.code === 0) {
169
+ // 登录成功
159
170
  const encryptedCookies = ctx.ba.encrypt(ctx.ba.getCookies());
160
171
  const encryptedRefreshToken = ctx.ba.encrypt(loginContent.data.refresh_token);
161
- await ctx.database.upsert('loginBili', [{
172
+ await ctx.database.upsert("loginBili", [
173
+ {
162
174
  id: 1,
163
175
  bili_cookies: encryptedCookies,
164
- bili_refresh_token: encryptedRefreshToken
165
- }]);
176
+ bili_refresh_token: encryptedRefreshToken,
177
+ },
178
+ ]);
166
179
  // 销毁定时器
167
180
  this.loginTimer();
168
181
  // 订阅手动订阅中的订阅
169
182
  await this.loadSubFromConfig(config.sub);
170
- // 订阅之前的订阅
171
- await this.loadSubFromDatabase();
172
183
  // 清除控制台通知
173
184
  ctx.ba.disposeNotifier();
174
185
  // 发送成功登录推送
175
- await session.send('登录成功');
186
+ await session.send("登录成功");
176
187
  // bili show
177
- await session.execute('bili show');
188
+ await session.execute("bili show");
178
189
  // 开启cookies刷新检测
179
190
  ctx.ba.enableRefreshCookiesDetect();
180
191
  }
@@ -185,450 +196,180 @@ class ComRegister {
185
196
  }, 1000);
186
197
  });
187
198
  biliCom
188
- .subcommand('.unsub <uid:string>', '取消订阅UP主动态、直播或全部')
189
- .usage('取消订阅,加-l为取消直播订阅,加-d为取消动态订阅,什么都不加则为全部取消')
190
- .option('live', '-l')
191
- .option('dynamic', '-d')
192
- .example('bili unsub 用户UID -ld')
193
- .action(async ({ session, options }, uid) => {
194
- this.logger.info('调用bili.unsub指令');
195
- // 若用户UID为空则直接返回
196
- if (!uid)
197
- return '用户UID不能为空';
198
- // -d -l两个选项不能同时存在
199
- if (options.dynamic && options.live)
200
- return '需要取消订阅该UP主请直接使用指令bili unsub 用户UID';
201
- // 定义是否存在
202
- let exist;
203
- await Promise.all(this.subManager.map(async (sub, i) => {
204
- if (sub.uid === uid) {
205
- // 取消单个订阅
206
- if (options.live || options.dynamic) {
207
- if (options.live)
208
- await session.send(this.unsubSingle(sub.roomId, 0)); /* 0为取消订阅Live */
209
- if (options.dynamic)
210
- await session.send(this.unsubSingle(sub.uid, 1)); /* 1为取消订阅Dynamic */
211
- // 将存在flag设置为true
212
- exist = true;
213
- // 结束循环
214
- return;
215
- }
216
- // 从数据库中删除订阅
217
- await ctx.database.remove('bilibili', { uid: this.subManager[i].uid });
218
- // 将该订阅对象从订阅管理对象中移除
219
- this.subManager.splice(i, 1);
220
- // 将订阅对象移出订阅关注组
221
- const removeUserFromGroupData = await ctx.ba.removeUserFromGroup(sub.uid);
222
- // 判断是否移出成功 22105关注对象为自己
223
- if (removeUserFromGroupData.code !== 0 && removeUserFromGroupData.code !== 22105) {
224
- // 移出失败
225
- await session.send('取消订阅对象失败,请稍后重试');
226
- // 将存在flag设置为true
227
- exist = true;
228
- // 结束循环
229
- return;
230
- }
231
- // id--
232
- this.num--;
233
- // 判断是否还有动态订阅
234
- this.checkIfUserIsTheLastOneWhoSubDyn();
235
- // 发送成功通知
236
- await session.send('已取消订阅该用户');
237
- // 更新控制台提示
238
- this.updateSubNotifier();
239
- // 将存在flag设置为true
240
- exist = true;
241
- }
242
- }));
243
- // 未订阅该用户,无需取消订阅
244
- if (!exist)
245
- await session.send('未订阅该用户,无需取消订阅');
246
- });
247
- biliCom
248
- .subcommand('.show', '展示订阅对象')
249
- .usage('展示订阅对象')
250
- .example('bili show')
199
+ .subcommand(".list", "展示订阅对象")
200
+ .usage("展示订阅对象")
201
+ .example("bili list")
251
202
  .action(() => {
252
203
  const subTable = this.subShow();
253
204
  return subTable;
254
205
  });
255
206
  biliCom
256
- .subcommand('.sub <mid:string> [...groupId:string]', '订阅用户动态和直播通知')
257
- .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]+))*$/ })
258
- .option('live', '-l')
259
- .option('dynamic', '-d')
260
- .option('atAll', '-a')
261
- .usage('订阅用户动态和直播通知,若需要订阅直播请加上-l,需要订阅动态则加上-d')
262
- .example('bili sub 1194210119 目标群号或频道号 -l -d 订阅UID为1194210119的UP主的动态和直播')
263
- .action(async ({ session, options }, mid, ...groupId) => {
264
- this.logger.info('调用bili.sub指令');
265
- // 先判断是否订阅直播,再判断是否解锁订阅限制,最后判断直播订阅是否已超三个
266
- if (options.live && !this.config.unlockSubLimits && (this.subManager.reduce((acc, cur) => acc + (cur.live ? 1 : 0), 0) >= 3)) {
267
- return '直播订阅已达上限,请取消部分直播订阅后再进行订阅';
268
- }
269
- // 检查是否登录
270
- if (!(await this.checkIfIsLogin())) {
271
- // 未登录直接返回
272
- return '请使用指令bili login登录后再进行订阅操作';
273
- }
274
- // 检查必选参数是否已填
275
- if (!mid)
276
- return '请输入用户uid';
277
- // 订阅对象
278
- const subUserData = await this.subUserInBili(mid);
279
- // 判断是否订阅对象存在
280
- if (!subUserData.flag)
281
- return '订阅对象失败,请稍后重试!';
282
- // 定义目标变量
283
- let target = [];
284
- // 判断是否使用了多群组推送
285
- if (groupId.length > 0) {
286
- // 定义channelIdArr
287
- const channelIdArr = [];
288
- // 遍历输入的群组
289
- groupId.forEach(group => {
290
- channelIdArr.push({
291
- channelId: group,
292
- dynamic: true,
293
- live: true,
294
- liveDanmaku: false,
295
- atAll: options.atAll
296
- });
297
- });
298
- target.push({
299
- channelIdArr,
300
- platform: session.event.platform
301
- });
302
- }
303
- else {
304
- // 判断是否使用多平台功能
305
- if (options.multiplatform) {
306
- // 分割字符串,赋值给target
307
- target = this.splitMultiPlatformStr(options.multiplatform);
308
- }
309
- // 判断是否使用了多平台
310
- if (target.length > 0) {
311
- for (const [index, { channelIdArr, platform }] of target.entries()) {
312
- if (channelIdArr.length > 0) { // 输入了推送群号或频道号
313
- // 拿到对应的bot
314
- const bot = this.getBot(platform);
315
- // 判断是否配置了对应平台的机器人
316
- if (!ctx.bots.some(bot => bot.platform === platform)) {
317
- // 发送提示消息
318
- await session.send('您未配置对应平台的机器人,不能在该平台进行订阅操作');
319
- // 直接返回
320
- return;
321
- }
322
- // 判断是否需要加入的群全部推送
323
- if (channelIdArr[0].channelId !== 'all') {
324
- // 定义满足条件的群组数组
325
- const targetArr = [];
326
- // 获取机器人加入的群组
327
- const guildList = await bot.getGuildList();
328
- // 遍历target数组
329
- for (const channelId of channelIdArr) {
330
- // 定义是否加入群组标志
331
- let flag = false;
332
- // 遍历群组
333
- for (const guild of guildList.data) {
334
- // 获取频道列表
335
- const channelList = await bot.getChannelList(guild.id);
336
- // 判断机器人是否加入群聊或频道
337
- if (channelList.data.some(channel => channel.id === channelId.channelId)) {
338
- // 加入群聊或频道
339
- targetArr.push(channelId);
340
- // 设置标志位为true
341
- flag = true;
342
- // 结束循环
343
- break;
344
- }
345
- }
346
- if (!flag) {
347
- // 不满足条件发送错误提示
348
- await session.send(`您的机器未加入${channelId.channelId},无法对该群或频道进行推送`);
349
- }
350
- }
351
- // 判断targetArr是否为空
352
- if (target.length === 0) {
353
- // 为空则默认为当前环境
354
- target = [{ channelIdArr: [{ channelId: session.event.channel.id, dynamic: true, live: true, liveDanmaku: false, atAll: options.atAll ? options.atAll : false }], platform: session.event.platform }];
355
- // 没有满足条件的群组或频道
356
- await session.send('没有满足条件的群组或频道,默认订阅到当前聊天环境');
357
- }
358
- // 将符合条件的群组添加到target中
359
- target[index].channelIdArr = targetArr;
360
- }
361
- // 如果为all则全部推送,不需要进行处理
362
- }
363
- else {
364
- // 未填写群号或频道号,默认为当前环境
365
- target = [{ channelIdArr: [{ channelId: session.event.channel.id, dynamic: true, live: true, liveDanmaku: false, atAll: options.atAll ? options.atAll : false }], platform: session.event.platform }];
366
- // 发送提示消息
367
- await session.send('没有填写群号或频道号,默认订阅到当前聊天环境');
207
+ .subcommand(".private", "向主人账号发送一条测试消息", { hidden: true })
208
+ .usage("向主人账号发送一条测试消息")
209
+ .example("bili private 向主人账号发送一条测试消息")
210
+ .action(async ({ session }) => {
211
+ // 发送消息
212
+ await this.sendPrivateMsg("Hello World");
213
+ // 发送提示
214
+ await session.send("已发送消息,如未收到则说明您的机器人不支持发送私聊消息或您的信息填写有误");
215
+ });
216
+ biliCom
217
+ .subcommand(".ll")
218
+ .usage("展示当前正在直播的订阅对象")
219
+ .example("bili ll")
220
+ .action(async () => {
221
+ // 获取liveUsers
222
+ const { data: { live_users }, } = (await ctx.ba.getTheUserWhoIsLiveStreaming());
223
+ // 定义当前正在直播且订阅的UP主列表
224
+ const subLiveUsers = [];
225
+ // 获取当前订阅的UP主
226
+ for (const sub of this.subManager) {
227
+ // 定义开播标志位
228
+ let onLive = false;
229
+ // 判断items是否存在
230
+ if (live_users.items) {
231
+ // 遍历liveUsers
232
+ for (const user of live_users.items) {
233
+ // 判断是否是订阅直播的UP
234
+ if (user.mid.toString() === sub.uid && sub.live) {
235
+ // 设置标志位为true
236
+ onLive = true;
237
+ // break
238
+ break;
368
239
  }
369
240
  }
370
241
  }
371
- else {
372
- // 用户直接订阅,将当前环境赋值给target
373
- target = [{ channelIdArr: [{ channelId: session.event.channel.id, dynamic: true, live: true, liveDanmaku: false, atAll: options.atAll ? options.atAll : false }], platform: session.event.platform }];
374
- }
375
- }
376
- // 定义外围变量
377
- let content;
378
- try {
379
- // 获取用户信息
380
- content = await ctx.ba.getUserInfo(mid);
381
- }
382
- catch (e) {
383
- // 返回错误信息
384
- return 'bili sub getUserInfo() 发生了错误,错误为:' + e.message;
385
- }
386
- // 判断是否成功获取用户信息
387
- if (content.code !== 0) {
388
- // 定义错误消息
389
- let msg;
390
- // 判断错误代码
391
- switch (content.code) {
392
- case -400:
393
- msg = '请求错误';
394
- break;
395
- case -403:
396
- msg = '访问权限不足,请尝试重新登录';
397
- break;
398
- case -404:
399
- msg = '用户不存在';
400
- break;
401
- case -352:
402
- msg = '风控校验失败,请尝试更换UA';
403
- break;
404
- default:
405
- msg = '未知错误,错误信息:' + content.message;
406
- break;
407
- }
408
- // 返回错误信息
409
- return msg;
410
- }
411
- // 获取data
412
- const { data } = content;
413
- // 判断是否需要订阅直播和动态
414
- const [liveMsg, dynamicMsg] = await this.checkIfNeedSub(options.live, options.dynamic, session, data.live_room);
415
- // 判断是否未订阅任何消息
416
- if (!liveMsg && !dynamicMsg)
417
- return '您未订阅该UP的任何消息';
418
- // 获取到对应的订阅对象
419
- const subUser = this.subManager.find(sub => sub.uid === mid);
420
- // 判断要订阅的用户是否已经存在于订阅管理对象中
421
- if (subUser) {
422
- // 已存在,判断是否重复订阅直播通知
423
- if (liveMsg && subUser.live) {
424
- return '已订阅该用户直播通知,请勿重复订阅';
425
- }
426
- // 已存在,判断是否重复订阅动态通知
427
- if (dynamicMsg && subUser.dynamic) {
428
- return '已订阅该用户动态通知,请勿重复订阅';
429
- }
430
- }
431
- // 获取直播房间号
432
- const roomId = data.live_room?.roomid.toString();
433
- // 获取用户信息
434
- let userData;
435
- try {
436
- const { data } = await ctx.ba.getMasterInfo(mid);
437
- userData = data;
438
- }
439
- catch (e) {
440
- this.logger.error('bili sub指令 getMasterInfo() 发生了错误,错误为:' + e.message);
441
- return '订阅出错啦,请重试';
442
- }
443
- const liveDetectModeSelector = {
444
- API: async () => {
445
- // 判断是否已开启直播检测
446
- if (!this.liveDispose) { // 未开启直播检测
447
- // 开启直播检测并保存销毁函数
448
- this.liveDispose = await this.liveDetectWithAPI();
449
- }
450
- },
451
- WS: async () => {
452
- // 连接到服务器
453
- await this.liveDetectWithListener(roomId, target);
454
- }
455
- };
456
- // 订阅直播
457
- if (liveMsg) {
458
- // 判断直播订阅方式
459
- await liveDetectModeSelector[this.config.liveDetectMode]();
460
- // 发送订阅消息通知
461
- await session.send(`订阅${userData.info.uname}直播通知`);
462
- }
463
- // 订阅动态
464
- if (dynamicMsg) {
465
- // 判断是否开启动态监测
466
- if (!this.dynamicDispose) {
467
- // 开启动态监测
468
- this.enableDynamicDetect();
469
- }
470
- // 发送订阅消息通知
471
- await session.send(`订阅${userData.info.uname}动态通知`);
472
- }
473
- // 保存到数据库中
474
- const sub = await ctx.database.create('bilibili', {
475
- uid: mid,
476
- room_id: roomId,
477
- dynamic: dynamicMsg ? 1 : 0,
478
- live: liveMsg ? 1 : 0,
479
- target: JSON.stringify(target),
480
- platform: session.event.platform,
481
- time: new Date()
482
- });
483
- // 订阅数+1
484
- this.num++;
485
- // 保存新订阅对象
486
- this.subManager.push({
487
- id: sub.id,
488
- uid: mid,
489
- roomId,
490
- target,
491
- platform: session.event.platform,
492
- live: liveMsg,
493
- dynamic: dynamicMsg,
494
- });
495
- // 新增订阅展示到控制台
496
- this.updateSubNotifier();
497
- });
498
- biliCom
499
- .subcommand('.status <roomId:string>', '查询主播当前直播状态', { hidden: true })
500
- .usage('查询主播当前直播状态')
501
- .example('bili status 732')
502
- .action(async ({ session }, roomId) => {
503
- this.logger.info('调用bili.status指令');
504
- if (!roomId)
505
- return session.send('请输入房间号!');
506
- let content;
507
- try {
508
- content = await ctx.ba.getLiveRoomInfo(roomId);
509
- }
510
- catch (e) {
511
- return 'bili status指令 getLiveRoomInfo() 发生了错误,错误为:' + e.message;
512
- }
513
- const { data } = content;
514
- let userData;
515
- try {
516
- const { data: userInfo } = await ctx.ba.getMasterInfo(data.uid);
517
- userData = userInfo;
518
- }
519
- catch (e) {
520
- return 'bili status指令 getMasterInfo() 发生了错误,错误为:' + e.message;
242
+ // 判断是否未开播
243
+ subLiveUsers.push({
244
+ uid: Number.parseInt(sub.uid),
245
+ uname: sub.uname,
246
+ onLive,
247
+ });
521
248
  }
522
- // B站出问题了
523
- if (content.code !== 0) {
524
- if (content.msg === '未找到该房间') {
525
- session.send('未找到该房间');
526
- }
527
- else {
528
- session.send('未知错误,错误信息为:' + content.message);
529
- }
530
- return;
249
+ // 定义table字符串
250
+ let table = "";
251
+ // 遍历liveUsers
252
+ for (const user of subLiveUsers) {
253
+ table += `[UID:${user.uid}] 「${user.uname}」 ${user.onLive ? "正在直播" : "未开播"}\n`;
531
254
  }
532
- const { pic, buffer } = await ctx.gi.generateLiveImg(data, userData.info.uname, userData.info.face, data.live_status !== 1 ?
533
- LiveType.NotLiveBroadcast :
534
- LiveType.LiveBroadcast);
535
- // pic 存在,使用的是render模式
536
- if (pic)
537
- return pic;
538
- // pic不存在,说明使用的是page模式
539
- await session.send(koishi_1.h.image(buffer, 'image/png'));
540
- });
541
- biliCom
542
- .subcommand('.private', '向主人账号发送一条测试消息', { hidden: true })
543
- .usage('向主人账号发送一条测试消息')
544
- .example('bili private 向主人账号发送一条测试消息')
545
- .action(async ({ session }) => {
546
- // 发送消息
547
- await this.sendPrivateMsg('Hello World');
548
- // 发送提示
549
- await session.send('已发送消息,如未收到则说明您的机器人不支持发送私聊消息或您的信息填写有误');
255
+ return table;
550
256
  });
551
257
  }
552
258
  async init(config) {
553
259
  // 设置logger
554
- this.logger = this.ctx.logger('cr');
260
+ this.logger = this.ctx.logger("cr");
261
+ // logger
262
+ this.logger.info("初始化插件中...");
555
263
  // 将config设置给类属性
556
264
  this.config = config;
557
265
  // 拿到私人机器人实例
558
- this.privateBot = this.ctx.bots.find(bot => bot.platform === config.master.platform);
266
+ this.privateBot = this.ctx.bots.find((bot) => bot.platform === config.master.platform);
559
267
  if (!this.privateBot) {
560
268
  this.ctx.notifier.create({
561
- content: '您未配置私人机器人,将无法向您推送机器人状态!'
269
+ content: "您未配置私人机器人,将无法向您推送机器人状态!",
562
270
  });
563
- this.logger.error('您未配置私人机器人,将无法向您推送机器人状态!');
564
271
  }
565
272
  // 判断消息发送方式
566
273
  if (config.automaticResend) {
567
- this.sendMsgFunc = async (bot, channelId, content) => {
568
- // 多次尝试发送消息
569
- const attempts = 3;
570
- for (let i = 0; i < attempts; i++) {
571
- try {
572
- // 发送消息
573
- await bot.sendMessage(channelId, content);
574
- // 防止消息发送速度过快被忽略
575
- await this.ctx.sleep(500);
576
- // 成功发送消息,跳出循环
577
- break;
578
- }
579
- catch (e) {
580
- if (i === attempts - 1) { // 已尝试三次
581
- this.logger.error(`发送群组ID:${channelId}消息失败!原因: ` + e.message);
582
- console.log(e);
583
- this.sendPrivateMsg(`发送群组ID:${channelId}消息失败,请查看日志`);
584
- }
274
+ this.sendMsgFunc = async (
275
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
276
+ bot, channelId,
277
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
278
+ content) => {
279
+ (0, utils_1.withRetry)(async () => await bot.sendMessage(channelId, content)).catch(async (e) => {
280
+ if (e.message === "this._request is not a function") {
281
+ // 2S之后重新发送消息
282
+ this.ctx.setTimeout(async () => {
283
+ await this.sendMsgFunc(bot, channelId, content);
284
+ }, 2000);
285
+ // 返回
286
+ return;
585
287
  }
586
- }
288
+ // 打印错误信息
289
+ this.logger.error(`发送群组ID:${channelId}消息失败!原因: ${e.message}`);
290
+ await this.sendPrivateMsg(`发送群组ID:${channelId}消息失败,请查看日志`);
291
+ });
587
292
  };
588
293
  }
589
294
  else {
590
- this.sendMsgFunc = async (bot, guild, content) => {
591
- try {
592
- // 发送消息
593
- await bot.sendMessage(guild, content);
594
- }
595
- catch (e) {
596
- this.logger.error(`发送群组ID:${guild}消息失败!原因: ` + e.message);
597
- await this.sendPrivateMsg(`发送群组ID:${guild}消息失败,请查看日志`);
598
- }
295
+ this.sendMsgFunc = async (
296
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
297
+ bot, channelId,
298
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
299
+ content) => {
300
+ (0, utils_1.withRetry)(async () => await bot.sendMessage(channelId, content), 1).catch(async (e) => {
301
+ if (e.message === "this._request is not a function") {
302
+ // 2S之后重新发送消息
303
+ this.ctx.setTimeout(async () => {
304
+ await this.sendMsgFunc(bot, channelId, content);
305
+ }, 2000);
306
+ // 返回
307
+ return;
308
+ }
309
+ // 打印错误信息
310
+ this.logger.error(`发送群组ID:${channelId}消息失败!原因: ${e.message}`);
311
+ await this.sendPrivateMsg(`发送群组ID:${channelId}消息失败,请查看日志`);
312
+ });
599
313
  };
600
314
  }
601
315
  // 检查登录数据库是否有数据
602
- this.loginDBData = (await this.ctx.database.get('loginBili', 1, ['dynamic_group_id']))[0];
316
+ this.loginDBData = (await this.ctx.database.get("loginBili", 1, ["dynamic_group_id"]))[0];
603
317
  // 判断登录信息是否已加载完毕
604
318
  await this.checkIfLoginInfoIsLoaded();
605
319
  // 如果未登录,则直接返回
606
320
  if (!(await this.checkIfIsLogin())) {
607
321
  // log
608
- this.logger.info(`账号未登录,请登录`);
322
+ this.logger.info("账号未登录,请登录");
609
323
  return;
610
324
  }
611
325
  // 从配置获取订阅
612
- config.sub && await this.loadSubFromConfig(config.sub);
613
- // 从数据库获取订阅
614
- await this.loadSubFromDatabase();
326
+ config.sub && (await this.loadSubFromConfig(config.sub));
615
327
  // 检查是否需要动态监测
616
328
  this.checkIfDynamicDetectIsNeeded();
617
329
  // 在控制台中显示订阅对象
618
330
  this.updateSubNotifier();
331
+ // logger
332
+ this.logger.info("插件初始化完毕!");
619
333
  }
620
- splitMultiPlatformStr(str) {
621
- return str.split(';').map(cv => cv.split('.')).map(([idStr, platform]) => {
622
- const channelIdArr = idStr.split(',').map(id => {
623
- const atAll = /@$/.test(id); // 使用正则表达式检查 id 是否以 @ 结尾
624
- const channelId = atAll ? id.slice(0, -1) : id; // 去除末尾的 @
625
- return { channelId, dynamic: true, live: true, liveDanmaku: false, atAll };
626
- });
627
- return { channelIdArr, platform };
628
- });
629
- }
334
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
630
335
  getBot(pf) {
631
- return this.ctx.bots.find(bot => bot.platform === pf);
336
+ return this.ctx.bots.find((bot) => bot.platform === pf);
337
+ }
338
+ // TODO:WordCloud
339
+ async test_wordCloud() {
340
+ /* const currentLiveDanmakuArr = []
341
+ // 定义获取弹幕权重Record函数
342
+ const getDanmakuWeightRecord = (): Record<string, number> => {
343
+ // 创建segmentit
344
+ const segmentit = useDefault(new Segment());
345
+ // 创建Record
346
+ const danmakuWeightRecord: Record<string, number> = {};
347
+ // 循环遍历currentLiveDanmakuArr
348
+ for (const danmaku of currentLiveDanmakuArr) {
349
+ // 遍历结果
350
+ segmentit.doSegment(danmaku).map((word: { w: string; p: number }) => {
351
+ // 定义权重
352
+ danmakuWeightRecord[word.w] = (danmakuWeightRecord[word.w] || 0) + 1;
353
+ });
354
+ }
355
+ // 返回Record
356
+ return danmakuWeightRecord;
357
+ }; */
358
+ // Test
359
+ const testTarget = [
360
+ {
361
+ channelIdArr: [
362
+ {
363
+ channelId: "635762054",
364
+ dynamic: true,
365
+ live: false,
366
+ liveGuardBuy: false,
367
+ atAll: false,
368
+ },
369
+ ],
370
+ platform: "qqguild",
371
+ },
372
+ ];
632
373
  }
633
374
  async sendPrivateMsg(content) {
634
375
  if (this.config.master.enable) {
@@ -646,9 +387,9 @@ class ComRegister {
646
387
  // 判断重启次数是否超过三次
647
388
  if (this.rebootCount >= 3) {
648
389
  // logger
649
- this.logger.error('已重启插件三次,请检查机器人状态后使用指令 sys start 启动插件');
390
+ this.logger.error("已重启插件三次,请检查机器人状态后使用指令 sys start 启动插件");
650
391
  // 重启失败,发送消息
651
- await this.sendPrivateMsg('已重启插件三次,请检查机器人状态后使用指令 sys start 启动插件');
392
+ await this.sendPrivateMsg("已重启插件三次,请检查机器人状态后使用指令 sys start 启动插件");
652
393
  // 关闭插件
653
394
  await this.ctx.sm.disposePlugin();
654
395
  // 结束
@@ -657,32 +398,33 @@ class ComRegister {
657
398
  // 重启次数+1
658
399
  this.rebootCount++;
659
400
  // logger
660
- this.logger.info('插件出现未知错误,正在重启插件');
401
+ this.logger.info("插件出现未知错误,正在重启插件");
661
402
  // 重启插件
662
403
  const flag = await this.ctx.sm.restartPlugin();
663
404
  // 判断是否重启成功
664
405
  if (flag) {
665
- this.logger.info('重启插件成功');
406
+ this.logger.info("重启插件成功");
666
407
  }
667
408
  else {
668
409
  // logger
669
- this.logger.error('重启插件失败,请检查机器人状态后使用指令 sys start 启动插件');
410
+ this.logger.error("重启插件失败,请检查机器人状态后使用指令 sys start 启动插件");
670
411
  // 重启失败,发送消息
671
- await this.sendPrivateMsg('重启插件失败,请检查机器人状态后使用指令 sys start 启动插件');
412
+ await this.sendPrivateMsg("重启插件失败,请检查机器人状态后使用指令 sys start 启动插件");
672
413
  // 关闭插件
673
414
  await this.ctx.sm.disposePlugin();
674
415
  }
675
416
  }
676
417
  async sendPrivateMsgAndStopService() {
677
418
  // 发送消息
678
- await this.sendPrivateMsg('插件发生未知错误,请检查机器人状态后使用指令 sys start 启动插件');
419
+ await this.sendPrivateMsg("插件发生未知错误,请检查机器人状态后使用指令 sys start 启动插件");
679
420
  // logger
680
- this.logger.error('插件发生未知错误,请检查机器人状态后使用指令 sys start 启动插件');
421
+ this.logger.error("插件发生未知错误,请检查机器人状态后使用指令 sys start 启动插件");
681
422
  // 关闭插件
682
423
  await this.ctx.sm.disposePlugin();
683
424
  // 结束
684
425
  return;
685
426
  }
427
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
686
428
  async sendMsg(targets, content, live) {
687
429
  for (const target of targets) {
688
430
  // 获取机器人实例
@@ -690,15 +432,15 @@ class ComRegister {
690
432
  // 定义需要发送的数组
691
433
  let sendArr = [];
692
434
  // 判断是否需要推送所有机器人加入的群
693
- if (target.channelIdArr[0].channelId === 'all') {
435
+ if (target.channelIdArr[0].channelId === "all") {
694
436
  // 获取所有guild
695
437
  for (const guild of (await bot.getGuildList()).data) {
696
438
  sendArr.push({
697
439
  channelId: guild.id,
698
440
  dynamic: target.channelIdArr[0].dynamic,
699
441
  live: target.channelIdArr[0].live,
700
- liveDanmaku: target.channelIdArr[0].liveDanmaku,
701
- atAll: target.channelIdArr[0].atAll
442
+ liveGuardBuy: target.channelIdArr[0].liveGuardBuy,
443
+ atAll: target.channelIdArr[0].atAll,
702
444
  });
703
445
  }
704
446
  }
@@ -721,7 +463,7 @@ class ComRegister {
721
463
  }
722
464
  else {
723
465
  for (const channel of sendArr) {
724
- // 判断是否需要推送动态消息和直播消息
466
+ // 判断是否需要推送动态消息
725
467
  if (channel.dynamic || channel.live) {
726
468
  await this.sendMsgFunc(bot, channel.channelId, content);
727
469
  }
@@ -736,181 +478,171 @@ class ComRegister {
736
478
  let updateBaseline;
737
479
  // 第一条动态的动态ID
738
480
  let dynamicIdStr;
739
- // 相当于锁的作用,防止上一个循环没处理完
740
- let flag = true;
741
- // 返回一个闭包函数
742
- return async () => {
743
- // 判断上一个循环是否完成
744
- if (!flag)
481
+ // 定义handler
482
+ const handler = async () => {
483
+ // 检测启动初始化
484
+ if (detectSetup) {
485
+ // 获取动态信息
486
+ const data = (await this.ctx.ba.getAllDynamic());
487
+ // 判断获取动态信息是否成功
488
+ if (data.code !== 0)
489
+ return;
490
+ // 设置更新基线
491
+ updateBaseline = data.data.update_baseline;
492
+ // 设置初始化为false
493
+ detectSetup = false;
494
+ // 初始化完成
745
495
  return;
746
- flag = false;
747
- // 无论是否执行成功都要释放锁
496
+ }
497
+ // 获取用户所有动态数据
498
+ let updateNum;
499
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
500
+ let content;
748
501
  try {
749
- // 检测启动初始化
750
- if (detectSetup) {
751
- // 获取动态信息
752
- const data = await this.ctx.ba.getAllDynamic();
753
- // 判断获取动态信息是否成功
754
- if (data.code !== 0)
755
- return;
756
- // 设置更新基线
757
- updateBaseline = data.data.update_baseline;
758
- // 设置初始化为false
759
- detectSetup = false;
760
- // 初始化完成
502
+ // 查询是否有新动态
503
+ const data = await this.ctx.ba.hasNewDynamic(updateBaseline);
504
+ updateNum = data.data.update_num;
505
+ // 没有新动态或获取动态信息失败直接返回
506
+ if (updateNum <= 0 || data.code !== 0)
761
507
  return;
762
- }
763
- // 获取用户所有动态数据
764
- let updateNum;
765
- let content;
766
- try {
767
- // 查询是否有新动态
768
- const data = await this.ctx.ba.hasNewDynamic(updateBaseline);
769
- updateNum = data.data.update_num;
770
- // 没有新动态或获取动态信息失败直接返回
771
- if (updateNum <= 0 || data.code !== 0)
772
- return;
773
- // 获取动态内容
774
- content = await this.ctx.ba.getAllDynamic(updateBaseline);
775
- }
776
- catch (e) {
777
- return this.logger.error('dynamicDetect getUserSpaceDynamic() 发生了错误,错误为:' + e.message);
778
- }
779
- // 判断获取动态内容是否成功
780
- if (content.code !== 0) {
781
- switch (content.code) {
782
- case -101: { // 账号未登录
783
- // 输出日志
784
- this.logger.error('账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件');
785
- // 发送私聊消息
786
- await this.sendPrivateMsg('账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件');
787
- // 停止服务
788
- await this.ctx.sm.disposePlugin();
789
- // 结束循环
790
- break;
791
- }
792
- case -352: { // 风控
793
- // 输出日志
794
- this.logger.error('账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件');
795
- // 发送私聊消息
796
- await this.sendPrivateMsg('账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件');
797
- // 停止服务
798
- await this.ctx.sm.disposePlugin();
799
- // 结束循环
800
- break;
801
- }
802
- case 4101128:
803
- case 4101129: { // 获取动态信息错误
804
- // 输出日志
805
- this.logger.error('获取动态信息错误,错误码为:' + content.code + ',错误为:' + content.message);
806
- // 发送私聊消息
807
- await this.sendPrivateMsg('获取动态信息错误,错误码为:' + content.code + ',错误为:' + content.message); // 未知错误
808
- // 结束循环
809
- break;
810
- }
811
- default: { // 未知错误
812
- // 发送私聊消息
813
- await this.sendPrivateMsg('获取动态信息错误,错误码为:' + content.code + ',错误为:' + content.message); // 未知错误
814
- // 结束循环
815
- break;
816
- }
508
+ // 获取动态内容
509
+ content = (await this.ctx.ba.getAllDynamic(updateBaseline));
510
+ }
511
+ catch (e) {
512
+ return this.logger.error(`dynamicDetect getUserSpaceDynamic() 发生了错误,错误为:${e.message}`);
513
+ }
514
+ // 判断获取动态内容是否成功
515
+ if (content.code !== 0) {
516
+ switch (content.code) {
517
+ case -101: {
518
+ // 账号未登录
519
+ // 输出日志
520
+ this.logger.error("账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件");
521
+ // 发送私聊消息
522
+ await this.sendPrivateMsg("账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件");
523
+ // 停止服务
524
+ await this.ctx.sm.disposePlugin();
525
+ // 结束循环
526
+ break;
527
+ }
528
+ case -352: {
529
+ // 风控
530
+ // 输出日志
531
+ this.logger.error("账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件");
532
+ // 发送私聊消息
533
+ await this.sendPrivateMsg("账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件");
534
+ // 停止服务
535
+ await this.ctx.sm.disposePlugin();
536
+ // 结束循环
537
+ break;
538
+ }
539
+ case 4101128:
540
+ case 4101129: {
541
+ // 获取动态信息错误
542
+ // 输出日志
543
+ this.logger.error(`获取动态信息错误,错误码为:${content.code},错误为:${content.message}`);
544
+ // 发送私聊消息
545
+ await this.sendPrivateMsg(`获取动态信息错误,错误码为:${content.code},错误为:${content.message}`); // 未知错误
546
+ // 结束循环
547
+ break;
548
+ }
549
+ default: {
550
+ // 未知错误
551
+ // 发送私聊消息
552
+ await this.sendPrivateMsg(`获取动态信息错误,错误码为:${content.code},错误为:${content.message}`); // 未知错误
553
+ // 结束循环
554
+ break;
817
555
  }
818
556
  }
819
- // 获取数据内容
820
- const data = content.data;
821
- // 更新基线
822
- updateBaseline = data.update_baseline;
823
- // 有新动态内容
824
- const items = data.items;
825
- // 检查更新的动态
826
- for (let num = updateNum - 1; num >= 0; num--) {
827
- // 没有动态内容则直接跳过
828
- if (!items[num])
829
- continue;
830
- // 从动态数据中取出UP主名称、UID和动态ID
831
- const upUID = items[num].modules.module_author.mid;
832
- // 寻找关注的UP主的动态
833
- this.subManager.forEach(async (sub) => {
834
- // 判断是否是订阅的UP主
835
- if (sub.dynamic && sub.uid == upUID) { // 订阅该UP主,推送该动态
836
- // 判断更新动态是否为1条
837
- if (updateNum === 1) {
838
- // 判断dynamicIdStr是否有值,是否与当前动态ID一致
839
- if (dynamicIdStr && dynamicIdStr === items[num].id_str) {
840
- // 重复动态,不再推送,直接返回
841
- return;
842
- }
843
- // 存储该动态ID
844
- dynamicIdStr = items[num].id_str;
557
+ }
558
+ // 获取数据内容
559
+ const data = content.data;
560
+ // 更新基线
561
+ updateBaseline = data.update_baseline;
562
+ // 有新动态内容
563
+ const items = data.items;
564
+ // 检查更新的动态
565
+ for (let num = updateNum - 1; num >= 0; num--) {
566
+ // 没有动态内容则直接跳过
567
+ if (!items[num])
568
+ continue;
569
+ // 从动态数据中取出UP主名称、UID和动态ID
570
+ const upUID = items[num].modules.module_author.mid;
571
+ // 寻找关注的UP主的动态
572
+ for (const sub of this.subManager) {
573
+ // 判断是否是订阅的UP
574
+ // biome-ignore lint/suspicious/noDoubleEquals: <explanation>
575
+ if (sub.dynamic && sub.uid == upUID) {
576
+ // 订阅该UP主,推送该动态
577
+ // 判断更新动态是否为1条
578
+ if (updateNum === 1) {
579
+ // 判断dynamicIdStr是否有值,是否与当前动态ID一致
580
+ if (dynamicIdStr && dynamicIdStr === items[num].id_str) {
581
+ // 重复动态,不再推送,直接返回
582
+ return;
845
583
  }
846
- // 定义变量
847
- let pic;
848
- let buffer;
849
- // 从动态数据中取出UP主名称和动态ID
850
- const upName = items[num].modules.module_author.name;
851
- const dynamicId = items[num].id_str;
852
- // 推送该条动态
853
- const attempts = 3;
854
- for (let i = 0; i < attempts; i++) {
855
- // 获取动态推送图片
856
- try {
857
- // 渲染图片
858
- const { pic: gimgPic, buffer: gimgBuffer } = await this.ctx.gi.generateDynamicImg(items[num]);
859
- // 赋值
860
- pic = gimgPic;
861
- buffer = gimgBuffer;
862
- // 成功则跳出循环
863
- break;
864
- }
865
- catch (e) {
866
- // 直播开播动态,不做处理
867
- if (e.message === '直播开播动态,不做处理')
868
- return;
869
- if (e.message === '出现关键词,屏蔽该动态') {
870
- // 如果需要发送才发送
871
- if (this.config.filter.notify) {
872
- await this.sendMsg(sub.target, `${upName}发布了一条含有屏蔽关键字的动态`);
873
- }
874
- return;
875
- }
876
- if (e.message === '已屏蔽转发动态') {
877
- if (this.config.filter.notify) {
878
- await this.sendMsg(sub.target, `${upName}发布了一条转发动态,已屏蔽`);
879
- }
880
- return;
881
- }
882
- // 未知错误
883
- if (i === attempts - 1) {
884
- this.logger.error('dynamicDetect generateDynamicImg() 推送卡片发送失败,原因:' + e.message);
885
- // 发送私聊消息并重启服务
886
- return await this.sendPrivateMsgAndStopService();
887
- }
584
+ // 存储该动态ID
585
+ dynamicIdStr = items[num].id_str;
586
+ }
587
+ // 从动态数据中取出UP主名称和动态ID
588
+ const upName = items[num].modules.module_author.name;
589
+ const dynamicId = items[num].id_str;
590
+ // 推送该条动态
591
+ const buffer = await (0, utils_1.withRetry)(async () => {
592
+ // 渲染图片
593
+ return await this.ctx.gi.generateDynamicImg(items[num]);
594
+ }, 1).catch(async (e) => {
595
+ // 直播开播动态,不做处理
596
+ if (e.message === "直播开播动态,不做处理")
597
+ return;
598
+ if (e.message === "出现关键词,屏蔽该动态") {
599
+ // 如果需要发送才发送
600
+ if (this.config.filter.notify) {
601
+ await this.sendMsg(sub.target, `${upName}发布了一条含有屏蔽关键字的动态`);
888
602
  }
603
+ return;
889
604
  }
890
- // 判断是否需要发送URL
891
- const dUrl = this.config.dynamicUrl ? `${upName}发布了一条动态:https://t.bilibili.com/${dynamicId}` : '';
892
- // 如果pic存在,则直接返回pic
893
- if (pic) {
894
- this.logger.info('推送动态中,使用render模式');
895
- // pic存在,使用的是render模式
896
- await this.sendMsg(sub.target, pic + (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: dUrl }));
897
- }
898
- else if (buffer) {
899
- this.logger.info('推送动态中,使用page模式');
900
- // pic不存在,说明使用的是page模式
901
- await this.sendMsg(sub.target, (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, 'image/png'), dUrl] }));
605
+ if (e.message === "已屏蔽转发动态") {
606
+ if (this.config.filter.notify) {
607
+ await this.sendMsg(sub.target, `${upName}转发了一条动态,已屏蔽`);
608
+ }
609
+ return;
902
610
  }
903
- else {
904
- this.logger.info(items[num].modules.module_author.name + '发布了一条动态,但是推送失败');
611
+ // 未知错误
612
+ this.logger.error(`dynamicDetect generateDynamicImg() 推送卡片发送失败,原因:${e.message}`);
613
+ // 发送私聊消息并重启服务
614
+ await this.sendPrivateMsgAndStopService();
615
+ });
616
+ // 判断是否执行成功,未执行成功直接返回
617
+ if (!buffer)
618
+ return;
619
+ // 判断是否需要发送URL
620
+ const dUrl = this.config.dynamicUrl
621
+ ? `${upName}发布了一条动态:https://t.bilibili.com/${dynamicId}`
622
+ : "";
623
+ // logger
624
+ this.logger.info("推送动态中...");
625
+ // 发送推送卡片
626
+ await this.sendMsg(sub.target, (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, "image/png"), dUrl] }));
627
+ // 判断是否需要发送动态中的图片
628
+ if (this.config.pushImgsInDynamic) {
629
+ // 判断是否为图文动态,且存在draw
630
+ if (items[num].type === "DYNAMIC_TYPE_DRAW" &&
631
+ items[num].modules.module_dynamic.major?.draw) {
632
+ for (const img of items[num].modules.module_dynamic.major.draw
633
+ .items) {
634
+ await this.sendMsg(sub.target, (0, jsx_runtime_1.jsx)("img", { src: img.src, alt: "\u52A8\u6001\u56FE\u7247" }));
635
+ }
905
636
  }
906
637
  }
907
- });
638
+ // logger
639
+ this.logger.info("动态推送完毕!");
640
+ }
908
641
  }
909
642
  }
910
- finally {
911
- flag = true;
912
- }
913
643
  };
644
+ // 返回一个闭包函数
645
+ return (0, utils_1.withLock)(handler);
914
646
  }
915
647
  debug_dynamicDetect() {
916
648
  // 检测初始化变量
@@ -919,471 +651,260 @@ class ComRegister {
919
651
  let updateBaseline;
920
652
  // 第一条动态的动态ID
921
653
  let dynamicIdStr;
922
- // 相当于锁的作用,防止上一个循环没处理完
923
- let flag = true;
924
- // 返回一个闭包函数
925
- return async () => {
926
- // 判断上一个循环是否完成
927
- if (!flag)
654
+ // 定义处理逻辑
655
+ const handler = async () => {
656
+ console.log(`初始化状态:${detectSetup}`);
657
+ // 检测启动初始化
658
+ if (detectSetup) {
659
+ // 获取动态信息
660
+ const data = (await this.ctx.ba.getAllDynamic());
661
+ // 判断获取动态信息是否成功
662
+ if (data.code !== 0)
663
+ return;
664
+ console.log(`更新基线:${data.data.update_baseline}`);
665
+ // 设置更新基线
666
+ updateBaseline = data.data.update_baseline;
667
+ // 设置初始化为false
668
+ detectSetup = false;
669
+ // 初始化完成
928
670
  return;
929
- flag = false;
930
- // 无论是否执行成功都要释放锁
671
+ }
672
+ // 获取用户所有动态数据
673
+ let updateNum;
674
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
675
+ let content;
931
676
  try {
932
- console.log(`初始化状态:${detectSetup}`);
933
- // 检测启动初始化
934
- if (detectSetup) {
935
- // 获取动态信息
936
- const data = await this.ctx.ba.getAllDynamic();
937
- // 判断获取动态信息是否成功
938
- if (data.code !== 0)
939
- return;
940
- console.log(`更新基线:${data.data.update_baseline}`);
941
- // 设置更新基线
942
- updateBaseline = data.data.update_baseline;
943
- // 设置初始化为false
944
- detectSetup = false;
945
- // 初始化完成
677
+ // 查询是否有新动态
678
+ const data = await this.ctx.ba.hasNewDynamic(updateBaseline);
679
+ updateNum = data.data.update_num;
680
+ // biome-ignore lint/style/noUnusedTemplateLiteral: <explanation>
681
+ console.log(`获取是否有新动态:`);
682
+ console.log(data);
683
+ // 没有新动态或获取动态信息失败直接返回
684
+ if (updateNum <= 0 || data.code !== 0)
946
685
  return;
947
- }
948
- // 获取用户所有动态数据
949
- let updateNum;
950
- let content;
951
- try {
952
- // 查询是否有新动态
953
- const data = await this.ctx.ba.hasNewDynamic(updateBaseline);
954
- updateNum = data.data.update_num;
955
- console.log(`获取是否有新动态:`);
956
- console.log(data);
957
- // 没有新动态或获取动态信息失败直接返回
958
- if (updateNum <= 0 || data.code !== 0)
959
- return;
960
- // 获取动态内容
961
- content = await this.ctx.ba.getAllDynamic(updateBaseline);
962
- console.log('获取动态内容:');
963
- console.log(content.data.items[0]);
964
- }
965
- catch (e) {
966
- return this.logger.error('dynamicDetect getUserSpaceDynamic() 发生了错误,错误为:' + e.message);
967
- }
968
- // 判断获取动态内容是否成功
969
- if (content.code !== 0) {
970
- switch (content.code) {
971
- case -101: { // 账号未登录
972
- // 输出日志
973
- this.logger.error('账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件');
974
- // 发送私聊消息
975
- await this.sendPrivateMsg('账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件');
976
- // 停止服务
977
- await this.ctx.sm.disposePlugin();
978
- // 结束循环
979
- break;
980
- }
981
- case -352: { // 风控
982
- // 输出日志
983
- this.logger.error('账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件');
984
- // 发送私聊消息
985
- await this.sendPrivateMsg('账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件');
986
- // 停止服务
987
- await this.ctx.sm.disposePlugin();
988
- // 结束循环
989
- break;
990
- }
991
- case 4101128:
992
- case 4101129: { // 获取动态信息错误
993
- // 输出日志
994
- this.logger.error('获取动态信息错误,错误码为:' + content.code + ',错误为:' + content.message);
995
- // 发送私聊消息
996
- await this.sendPrivateMsg('获取动态信息错误,错误码为:' + content.code + ',错误为:' + content.message); // 未知错误
997
- // 结束循环
998
- break;
999
- }
1000
- default: { // 未知错误
1001
- // 发送私聊消息
1002
- await this.sendPrivateMsg('获取动态信息错误,错误码为:' + content.code + ',错误为:' + content.message); // 未知错误
1003
- // 结束循环
1004
- break;
1005
- }
686
+ // 获取动态内容
687
+ content = (await this.ctx.ba.getAllDynamic(updateBaseline));
688
+ console.log("获取动态内容:");
689
+ console.log(content.data.items[0]);
690
+ }
691
+ catch (e) {
692
+ return this.logger.error(`dynamicDetect getUserSpaceDynamic() 发生了错误,错误为:${e.message}`);
693
+ }
694
+ // 判断获取动态内容是否成功
695
+ if (content.code !== 0) {
696
+ switch (content.code) {
697
+ case -101: {
698
+ // 账号未登录
699
+ // 输出日志
700
+ this.logger.error("账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件");
701
+ // 发送私聊消息
702
+ await this.sendPrivateMsg("账号未登录,插件已停止工作,请登录后,输入指令 sys start 启动插件");
703
+ // 停止服务
704
+ await this.ctx.sm.disposePlugin();
705
+ // 结束循环
706
+ break;
707
+ }
708
+ case -352: {
709
+ // 风控
710
+ // 输出日志
711
+ this.logger.error("账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件");
712
+ // 发送私聊消息
713
+ await this.sendPrivateMsg("账号被风控,插件已停止工作,请确认风控解除后,输入指令 sys start 启动插件");
714
+ // 停止服务
715
+ await this.ctx.sm.disposePlugin();
716
+ // 结束循环
717
+ break;
718
+ }
719
+ case 4101128:
720
+ case 4101129: {
721
+ // 获取动态信息错误
722
+ // 输出日志
723
+ this.logger.error(`获取动态信息错误,错误码为:${content.code},错误为:${content.message}`);
724
+ // 发送私聊消息
725
+ await this.sendPrivateMsg(`获取动态信息错误,错误码为:${content.code},错误为:${content.message}`); // 未知错误
726
+ // 结束循环
727
+ break;
728
+ }
729
+ default: {
730
+ // 未知错误
731
+ // 发送私聊消息
732
+ await this.sendPrivateMsg(`获取动态信息错误,错误码为:${content.code},错误为:${content.message}`); // 未知错误
733
+ // 结束循环
734
+ break;
1006
735
  }
1007
736
  }
1008
- // 获取数据内容
1009
- const data = content.data;
1010
- // 更新基线
1011
- updateBaseline = data.update_baseline;
1012
- console.log(`更新基线:${updateBaseline}`);
1013
- // 有新动态内容
1014
- const items = data.items;
1015
- // 检查更新的动态
1016
- for (let num = updateNum - 1; num >= 0; num--) {
1017
- // 有更新动态
1018
- console.log('有更新动态');
1019
- // 没有动态内容则直接跳过
1020
- if (!items[num])
1021
- continue;
1022
- // 从动态数据中取出UP主名称、UID和动态ID
1023
- const upName = content.data.items[num].modules.module_author.name;
1024
- const upUID = items[num].modules.module_author.mid;
1025
- const dynamicId = content.data.items[num].id_str;
1026
- console.log(`寻找关注的UP主,当前动态UP主:${upName},UID:${upUID},动态ID:${dynamicId}`);
1027
- // 寻找关注的UP主的动态
1028
- this.subManager.forEach(async (sub) => {
1029
- console.log(`当前订阅UP主:${sub.uid}`);
1030
- // 判断是否是订阅的UP
1031
- if (sub.dynamic && sub.uid == upUID) { // 订阅该UP主,推送该动态
1032
- // 判断更新动态是否为1条
1033
- if (updateNum === 1) {
1034
- // 判断dynamicIdStr是否有值,是否与当前动态ID一致
1035
- if (dynamicIdStr && dynamicIdStr === items[num].id_str) {
1036
- // 重复动态,不再推送,直接返回
1037
- return;
1038
- }
1039
- // 存储该动态ID
1040
- dynamicIdStr = items[num].id_str;
737
+ }
738
+ // 获取数据内容
739
+ const data = content.data;
740
+ // 更新基线
741
+ updateBaseline = data.update_baseline;
742
+ console.log(`更新基线:${updateBaseline}`);
743
+ // 有新动态内容
744
+ const items = data.items;
745
+ // 检查更新的动态
746
+ for (let num = updateNum - 1; num >= 0; num--) {
747
+ // 有更新动态
748
+ console.log("有更新动态");
749
+ // 没有动态内容则直接跳过
750
+ if (!items[num])
751
+ continue;
752
+ // 从动态数据中取出UP主名称、UID和动态ID
753
+ const upName = content.data.items[num].modules.module_author.name;
754
+ const upUID = items[num].modules.module_author.mid;
755
+ const dynamicId = content.data.items[num].id_str;
756
+ console.log(`寻找关注的UP主,当前动态UP主:${upName},UID:${upUID},动态ID:${dynamicId}`);
757
+ // 寻找关注的UP主的动态
758
+ for (const sub of this.subManager) {
759
+ console.log(`当前订阅UP主:${sub.uid}`);
760
+ // 判断是否是订阅的UP
761
+ // biome-ignore lint/suspicious/noDoubleEquals: <explanation>
762
+ if (sub.dynamic && sub.uid == upUID) {
763
+ // 订阅该UP主,推送该动态
764
+ // 判断更新动态是否为1条
765
+ if (updateNum === 1) {
766
+ // 判断dynamicIdStr是否有值,是否与当前动态ID一致
767
+ if (dynamicIdStr && dynamicIdStr === items[num].id_str) {
768
+ // 重复动态,不再推送,直接返回
769
+ return;
1041
770
  }
1042
- // 定义变量
1043
- let pic;
1044
- let buffer;
1045
- // 从动态数据中取出UP主名称和动态ID
1046
- const upName = items[num].modules.module_author.name;
1047
- const dynamicId = items[num].id_str;
1048
- console.log(`UP主名称:${upName},动态ID:${dynamicId}`);
1049
- // 推送该条动态
1050
- const attempts = 3;
1051
- for (let i = 0; i < attempts; i++) {
1052
- // 获取动态推送图片
1053
- try {
1054
- // 渲染图片
1055
- const { pic: gimgPic, buffer: gimgBuffer } = await this.ctx.gi.generateDynamicImg(items[num]);
1056
- // 赋值
1057
- pic = gimgPic;
1058
- buffer = gimgBuffer;
1059
- // 成功则跳出循环
1060
- break;
1061
- }
1062
- catch (e) {
1063
- // 直播开播动态,不做处理
1064
- if (e.message === '直播开播动态,不做处理')
1065
- return;
1066
- if (e.message === '出现关键词,屏蔽该动态') {
1067
- // 如果需要发送才发送
1068
- if (this.config.filter.notify) {
1069
- await this.sendMsg(sub.target, `${upName}发布了一条含有屏蔽关键字的动态`);
1070
- }
1071
- return;
1072
- }
1073
- if (e.message === '已屏蔽转发动态') {
1074
- if (this.config.filter.notify) {
1075
- await this.sendMsg(sub.target, `${upName}发布了一条转发动态,已屏蔽`);
1076
- }
1077
- return;
1078
- }
1079
- // 未知错误
1080
- if (i === attempts - 1) {
1081
- this.logger.error('dynamicDetect generateDynamicImg() 推送卡片发送失败,原因:' + e.message);
1082
- // 发送私聊消息并重启服务
1083
- return await this.sendPrivateMsgAndStopService();
1084
- }
771
+ // 存储该动态ID
772
+ dynamicIdStr = items[num].id_str;
773
+ }
774
+ // 从动态数据中取出UP主名称和动态ID
775
+ const upName = items[num].modules.module_author.name;
776
+ const dynamicId = items[num].id_str;
777
+ console.log(`UP主名称:${upName},动态ID:${dynamicId}`);
778
+ // 推送该条动态
779
+ const buffer = await (0, utils_1.withRetry)(async () => {
780
+ // 渲染图片
781
+ return await this.ctx.gi.generateDynamicImg(items[num]);
782
+ }, 1).catch(async (e) => {
783
+ // 直播开播动态,不做处理
784
+ if (e.message === "直播开播动态,不做处理")
785
+ return;
786
+ if (e.message === "出现关键词,屏蔽该动态") {
787
+ // 如果需要发送才发送
788
+ if (this.config.filter.notify) {
789
+ await this.sendMsg(sub.target, `${upName}发布了一条含有屏蔽关键字的动态`);
1085
790
  }
791
+ return;
1086
792
  }
1087
- // 判断是否需要发送URL
1088
- const dUrl = this.config.dynamicUrl ? `${upName}发布了一条动态:https://t.bilibili.com/${dynamicId}` : '';
1089
- // 如果pic存在,则直接返回pic
1090
- if (pic) {
1091
- this.logger.info('推送动态中,使用render模式');
1092
- // pic存在,使用的是render模式
1093
- await this.sendMsg(sub.target, pic + (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: dUrl }));
1094
- }
1095
- else if (buffer) {
1096
- this.logger.info('推送动态中,使用page模式');
1097
- // pic不存在,说明使用的是page模式
1098
- await this.sendMsg(sub.target, (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, 'image/png'), dUrl] }));
793
+ if (e.message === "已屏蔽转发动态") {
794
+ if (this.config.filter.notify) {
795
+ await this.sendMsg(sub.target, `${upName}发布了一条转发动态,已屏蔽`);
796
+ }
797
+ return;
1099
798
  }
1100
- else {
1101
- this.logger.info(items[num].modules.module_author.name + '发布了一条动态,但是推送失败');
799
+ // 未知错误
800
+ this.logger.error(`dynamicDetect generateDynamicImg() 推送卡片发送失败,原因:${e.message}`);
801
+ // 发送私聊消息并重启服务
802
+ await this.sendPrivateMsgAndStopService();
803
+ });
804
+ // 屏蔽动态直接返回
805
+ if (!buffer)
806
+ return;
807
+ // 判断是否需要发送URL
808
+ const dUrl = this.config.dynamicUrl
809
+ ? `${upName}发布了一条动态:https://t.bilibili.com/${dynamicId}`
810
+ : "";
811
+ // logger
812
+ this.logger.info("推送动态中...");
813
+ // 推送动态卡片
814
+ await this.sendMsg(sub.target, (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, "image/png"), dUrl] }));
815
+ // 判断是否需要发送动态中的图片
816
+ if (this.config.pushImgsInDynamic) {
817
+ // 判断是否为图文动态,且存在draw
818
+ if (items[num].type === "DYNAMIC_TYPE_DRAW" &&
819
+ items[num].modules.module_dynamic.major?.draw) {
820
+ // logger
821
+ this.logger.info("推送动态图片中...");
822
+ // 循环遍历图片
823
+ for (const img of items[num].modules.module_dynamic.major.draw
824
+ .items) {
825
+ await this.sendMsg(sub.target, (0, jsx_runtime_1.jsx)("img", { src: img.src, alt: "\u52A8\u6001\u56FE\u7247" }));
826
+ }
827
+ // logger
828
+ this.logger.info("推送动态图片完毕!");
1102
829
  }
1103
830
  }
1104
- });
831
+ // logger
832
+ this.logger.info("动态推送完毕!");
833
+ }
1105
834
  }
1106
835
  }
1107
- finally {
1108
- flag = true;
1109
- }
1110
836
  };
837
+ // 加工handler并返回
838
+ return (0, utils_1.withLock)(handler);
1111
839
  }
1112
840
  // 定义发送直播通知卡片方法
1113
- async sendLiveNotifyCard(info, liveType, liveNotifyMsg) {
1114
- // 定义变量
1115
- let pic;
1116
- let buffer;
1117
- // 多次尝试生成图片
1118
- const attempts = 3;
1119
- for (let i = 0; i < attempts; i++) {
1120
- try {
1121
- // 获取直播通知卡片
1122
- const { pic: picv, buffer: bufferv } = await this.ctx.gi.generateLiveImg(info.data, info.username, info.userface, liveType);
1123
- // 赋值
1124
- pic = picv;
1125
- buffer = bufferv;
1126
- // 成功则跳出循环
1127
- break;
1128
- }
1129
- catch (e) {
1130
- if (i === attempts - 1) { // 已尝试三次
1131
- this.logger.error('liveDetect generateLiveImg() 推送卡片生成失败,原因:' + e.message);
1132
- // 发送私聊消息并重启服务
1133
- return await this.sendPrivateMsgAndStopService();
1134
- }
1135
- }
1136
- }
841
+ async sendLiveNotifyCard(info, liveType, followerDisplay, liveNotifyMsg) {
842
+ // 生成图片
843
+ const buffer = await (0, utils_1.withRetry)(async () => {
844
+ // 获取直播通知卡片
845
+ return await this.ctx.gi.generateLiveImg(info.data, info.username, info.userface, followerDisplay, liveType);
846
+ }, 1).catch((e) => {
847
+ this.logger.error(`liveDetect generateLiveImg() 推送卡片生成失败,原因:${e.message}`);
848
+ });
849
+ // 发送私聊消息并重启服务
850
+ if (!buffer)
851
+ return await this.sendPrivateMsgAndStopService();
1137
852
  // 推送直播信息
1138
- // pic 存在,使用的是render模式
1139
- if (pic) {
1140
- // 只有在开播时才艾特全体成员
1141
- if (liveType === LiveType.StartBroadcasting) {
1142
- return await this.sendMsg(info.target, pic + (liveNotifyMsg ?? ''), true);
1143
- }
1144
- // 正常不需要艾特全体成员
1145
- return await this.sendMsg(info.target, pic + (liveNotifyMsg ?? ''));
1146
- }
1147
- // pic不存在,说明使用的是page模式
1148
- const msg = (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, 'image/png'), liveNotifyMsg || ''] });
853
+ const msg = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [koishi_1.h.image(buffer, "image/png"), liveNotifyMsg || ""] }));
1149
854
  // 只有在开播时才艾特全体成员
1150
- if (liveType === LiveType.StartBroadcasting) {
1151
- return await this.sendMsg(info.target, msg, true);
1152
- }
1153
- // 正常不需要艾特全体成员
1154
- return await this.sendMsg(info.target, msg);
855
+ return await this.sendMsg(info.target, msg, liveType === type_1.LiveType.StartBroadcasting);
1155
856
  }
1156
857
  // 定义获取主播信息方法
1157
- async useMasterInfo(uid) {
858
+ async useMasterInfo(uid, masterInfo, liveType) {
859
+ // 获取主播信息
1158
860
  const { data } = await this.ctx.ba.getMasterInfo(uid);
1159
- return { username: data.info.uname, userface: data.info.face, roomId: data.room_id };
861
+ // 定义粉丝数变量
862
+ let liveOpenFollowerNum;
863
+ let liveEndFollowerNum;
864
+ let liveFollowerChange;
865
+ // 判断直播状态
866
+ if (liveType === type_1.LiveType.StartBroadcasting ||
867
+ liveType === type_1.LiveType.FirstLiveBroadcast) {
868
+ // 第一次启动或刚开播
869
+ // 将当前粉丝数赋值给liveOpenFollowerNum、liveEndFollowerNum
870
+ liveOpenFollowerNum = data.follower_num;
871
+ liveEndFollowerNum = data.follower_num;
872
+ // 将粉丝数变化赋值为0
873
+ liveFollowerChange = 0;
874
+ }
875
+ if (liveType === type_1.LiveType.StopBroadcast ||
876
+ liveType === type_1.LiveType.LiveBroadcast) {
877
+ // 将上一次的liveOpenFollowerNum赋值给本次的liveOpenFollowerNum
878
+ liveOpenFollowerNum = masterInfo.liveOpenFollowerNum;
879
+ // 将当前粉丝数赋值给liveEndFollowerNum
880
+ liveEndFollowerNum = data.follower_num;
881
+ // 计算粉丝数变化量
882
+ liveFollowerChange = liveEndFollowerNum - masterInfo.liveOpenFollowerNum;
883
+ }
884
+ // 返回值
885
+ return {
886
+ username: data.info.uname,
887
+ userface: data.info.face,
888
+ roomId: data.room_id,
889
+ liveOpenFollowerNum,
890
+ liveEndFollowerNum,
891
+ liveFollowerChange,
892
+ };
1160
893
  }
1161
894
  async useLiveRoomInfo(roomId) {
1162
895
  // 发送请求获取直播间信息
1163
- let content;
1164
- const attempts = 3;
1165
- for (let i = 0; i < attempts; i++) {
1166
- try {
1167
- // 发送请求获取room信息
1168
- content = await this.ctx.ba.getLiveRoomInfo(roomId);
1169
- // 成功则跳出循环
1170
- break;
1171
- }
1172
- catch (e) {
1173
- this.logger.error('liveDetect getLiveRoomInfo 发生了错误,错误为:' + e.message);
1174
- if (i === attempts - 1) { // 已尝试三次
1175
- // 发送私聊消息并重启服务
1176
- return await this.sendPrivateMsgAndStopService();
1177
- }
1178
- }
1179
- }
1180
- return content.data;
1181
- }
1182
- async liveDetectWithAPI() {
1183
- // 定义变量:第一次订阅
1184
- let liveDetectSetup = true;
1185
- // 定义变量:timer计时器
1186
- let timer = 0;
1187
- // 相当于锁的作用,防止上一个循环没处理完
1188
- let flag = true;
1189
- // 定义订阅对象Record 0未开播 1正在直播 2轮播中
1190
- const liveRecord = {};
1191
- // 定义函数: 发送请求获取直播状态
1192
- const useLiveStatus = async (roomId) => {
1193
- let content;
1194
- const attempts = 3;
1195
- for (let i = 0; i < attempts; i++) {
1196
- try {
1197
- // 发送请求获取room信息
1198
- content = await this.ctx.ba.getLiveRoomInfo(roomId);
1199
- // 成功则跳出循环
1200
- break;
1201
- }
1202
- catch (e) {
1203
- this.logger.error('liveDetect getLiveRoomInfo 发生了错误,错误为:' + e.message);
1204
- if (i === attempts - 1) { // 已尝试三次
1205
- // 发送私聊消息并重启服务
1206
- return await this.sendPrivateMsgAndStopService();
1207
- }
1208
- }
1209
- }
1210
- // 返回data
1211
- return content.data;
1212
- };
1213
- return async () => {
1214
- // 如果flag为false则说明前面的代码还未执行完,则直接返回
1215
- if (!flag)
1216
- return;
1217
- // 将标志位置为false
1218
- flag = false;
1219
- try {
1220
- // 获取正在直播对象
1221
- const liveUsers = await this.ctx.ba.getTheUserWhoIsLiveStreaming();
1222
- // 判断是否是初始化直播监测
1223
- if (liveDetectSetup) {
1224
- // 将第一次订阅置为false
1225
- liveDetectSetup = false;
1226
- // 初始化subRecord
1227
- this.subManager.forEach(sub => {
1228
- // 判断是否订阅直播
1229
- if (sub.live) {
1230
- // 将该订阅添加到subRecord中
1231
- liveRecord[sub.uid] = { liveStatus: 0, liveTime: '', target: sub.target };
1232
- }
1233
- });
1234
- // 先判断是否有UP主正在直播
1235
- if (liveUsers.count > 0) {
1236
- // 遍历liveUsers
1237
- liveUsers.items.forEach(async (item) => {
1238
- // 判断是否有订阅对象正在直播
1239
- if (liveRecord[item.mid]) {
1240
- // 获取当前用户直播间信息
1241
- const data = await useLiveStatus(item.room_id.toString());
1242
- // 设置开播时间
1243
- liveRecord[item.mid].liveTime = data.live_time;
1244
- // 改变开播状态
1245
- liveRecord[item.mid].liveStatus = 1;
1246
- // 设置直播中消息
1247
- const liveMsg = this.config.customLive ? this.config.customLive
1248
- .replace('-name', item.uname)
1249
- .replace('-time', await this.ctx.gi.getTimeDifference(liveRecord[item.mid].liveTime))
1250
- .replace('-link', `https://live.bilibili.com/${data.short_id === 0 ? data.room_id : data.short_id}`) : null;
1251
- // 发送直播通知卡片
1252
- if (this.config.restartPush)
1253
- this.sendLiveNotifyCard({
1254
- username: item.uname,
1255
- userface: item.face,
1256
- target: liveRecord[item.mid].target,
1257
- data
1258
- }, LiveType.LiveBroadcast, liveMsg);
1259
- }
1260
- });
1261
- }
1262
- // 没有正在直播的订阅对象,直接返回
1263
- return;
1264
- }
1265
- // 获取当前订阅直播的数量
1266
- const currentLiveSubs = this.subManager.filter(sub => sub.live);
1267
- // 获取当前liveRecord里的订阅数量
1268
- const currentLiveRecordKeys = Object.keys(liveRecord);
1269
- // 判断是否能匹配双方数量
1270
- if (currentLiveRecordKeys.length < currentLiveSubs.length) {
1271
- // 遍历currentLiveSubs
1272
- for (const sub of currentLiveSubs) {
1273
- // 判断liveRecord中缺少了哪些订阅
1274
- if (!liveRecord[sub.uid]) {
1275
- // 获取当前用户直播间信息
1276
- const data = await useLiveStatus(sub.roomId.toString());
1277
- switch (data.live_status) {
1278
- case 0:
1279
- case 2: { // 未开播
1280
- // 添加到liveRecord中
1281
- liveRecord[sub.uid] = { liveStatus: 0, liveTime: '', target: sub.target };
1282
- // break
1283
- break;
1284
- }
1285
- case 1: { //正在直播
1286
- // 添加到liveRecord中
1287
- liveRecord[sub.uid] = { liveStatus: 1, liveTime: data.live_time, target: sub.target };
1288
- }
1289
- }
1290
- }
1291
- }
1292
- }
1293
- if (currentLiveRecordKeys.length > currentLiveSubs.length) {
1294
- // 创建Set
1295
- const setCurrentLiveSubs = new Set(currentLiveSubs.map(sub => sub.uid));
1296
- // 找出 currentLiveRecordKeys中比currentLiveSubs 多的元素
1297
- const extraInCurrentLiveSubs = currentLiveRecordKeys.filter(key => !setCurrentLiveSubs.has(key));
1298
- // 遍历 extraInCurrentLiveSubs
1299
- for (const subUID of extraInCurrentLiveSubs) {
1300
- // 删除记录
1301
- delete liveRecord[subUID];
1302
- }
1303
- }
1304
- // 数量没有差异,则不进行其他操作
1305
- // 遍历liveUsers
1306
- liveUsers.items.forEach(async (item) => {
1307
- // 判断是否有正在直播的订阅对象
1308
- if (liveRecord[item.mid]) { // 有正在直播的订阅对象
1309
- // 获取当前用户直播间信息
1310
- const data = await useLiveStatus(item.room_id.toString());
1311
- // 判断开播状态
1312
- switch (liveRecord[item.mid].liveStatus) {
1313
- case 0: { // 之前未开播,现在开播了
1314
- // 设置开播时间
1315
- liveRecord[item.mid].liveTime = data.live_time;
1316
- // 定义开播通知语
1317
- const liveStartMsg = this.config.customLiveStart ? this.config.customLiveStart
1318
- .replace('-name', item.uname)
1319
- .replace('-time', await this.ctx.gi.getTimeDifference(liveRecord[item.mid].liveTime))
1320
- .replace('-link', `https://live.bilibili.com/${data.short_id === 0 ? data.room_id : data.short_id}`) : null;
1321
- // 发送直播通知卡片
1322
- await this.sendLiveNotifyCard({
1323
- username: item.uname,
1324
- userface: item.face,
1325
- target: liveRecord[item.mid].target,
1326
- data
1327
- }, LiveType.LiveBroadcast, liveStartMsg);
1328
- // 改变开播状态
1329
- liveRecord[item.mid].liveStatus = 1;
1330
- // 结束
1331
- break;
1332
- }
1333
- case 1: { // 仍在直播
1334
- if (this.config.pushTime > 0) {
1335
- timer++;
1336
- // 开始记录时间
1337
- if (timer >= (6 * 60 * this.config.pushTime)) { // 到时间推送直播消息
1338
- // 到时间重新计时
1339
- timer = 0;
1340
- // 定义直播中通知消息
1341
- const liveMsg = this.config.customLive ? this.config.customLive
1342
- .replace('-name', item.uname)
1343
- .replace('-time', await this.ctx.gi.getTimeDifference(liveRecord[item.mid].liveTime))
1344
- .replace('-link', `https://live.bilibili.com/${data.short_id === 0 ? data.room_id : data.short_id}`) : null;
1345
- // 发送直播通知卡片
1346
- this.sendLiveNotifyCard({
1347
- username: item.uname,
1348
- userface: item.face,
1349
- target: liveRecord[item.mid].target,
1350
- data
1351
- }, LiveType.LiveBroadcast, liveMsg);
1352
- }
1353
- }
1354
- }
1355
- }
1356
- }
1357
- });
1358
- // 找出liveRecord中liveStatus为1但liveUsers中没有的元素
1359
- const extraInLiveRecord = currentLiveRecordKeys.filter(key => !liveUsers.items.some(item => item.mid === Number(key)));
1360
- // 遍历 extraInLiveRecord
1361
- for (const subUID of extraInLiveRecord) { // 下播的主播
1362
- // 获取主播信息
1363
- const masterInfo = await this.useMasterInfo(subUID);
1364
- // 获取直播间消息
1365
- const liveRoomInfo = await this.useLiveRoomInfo(masterInfo.roomId.toString());
1366
- // 设置开播时间
1367
- liveRoomInfo.live_time = liveRecord[subUID].liveTime;
1368
- // 定义下播播通知语
1369
- const liveEndMsg = this.config.customLiveEnd ? this.config.customLiveEnd
1370
- .replace('-name', masterInfo.username)
1371
- .replace('-time', await this.ctx.gi.getTimeDifference(liveRecord[subUID].liveTime))
1372
- .replace('-link', `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`) : null;
1373
- // 发送下播通知
1374
- this.sendLiveNotifyCard({
1375
- username: masterInfo.username,
1376
- userface: masterInfo.userface,
1377
- target: liveRecord[subUID].target,
1378
- data: liveRoomInfo
1379
- }, LiveType.StopBroadcast, liveEndMsg);
1380
- }
1381
- }
1382
- finally {
1383
- // 执行完方法体不论如何都把flag设置为true
1384
- flag = true;
1385
- }
1386
- };
896
+ const data = await (0, utils_1.withRetry)(async () => await this.ctx.ba.getLiveRoomInfo(roomId))
897
+ .then((content) => content.data)
898
+ .catch((e) => {
899
+ this.logger.error(`liveDetect getLiveRoomInfo 发生了错误,错误为:${e.message}`);
900
+ // 返回错误
901
+ return false;
902
+ });
903
+ // 发送私聊消息并重启服务
904
+ if (!data)
905
+ return await this.sendPrivateMsgAndStopService();
906
+ // 返回
907
+ return data;
1387
908
  }
1388
909
  async liveDetectWithListener(roomId, target) {
1389
910
  // 定义开播时间
@@ -1392,68 +913,59 @@ class ComRegister {
1392
913
  let pushAtTimeTimer;
1393
914
  // 定义弹幕存放数组
1394
915
  const currentLiveDanmakuArr = [];
1395
- const temporaryLiveDanmakuArr = [];
1396
916
  // 定义开播状态
1397
917
  let liveStatus = false;
1398
918
  // 处理target
1399
919
  // 定义channelIdArr总长度
1400
920
  let channelIdArrLen = 0;
1401
921
  // 定义数据
922
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
1402
923
  let liveRoomInfo;
1403
924
  let masterInfo;
925
+ let watchedNum;
1404
926
  // 找到频道/群组对应的
1405
- const danmakuPushTargetArr = target.map(channel => {
927
+ const liveGuardBuyPushTargetArr = target.map((channel) => {
1406
928
  // 获取符合条件的target
1407
- const liveDanmakuArr = channel.channelIdArr.filter(channelId => channelId.liveDanmaku);
929
+ const liveGuardBuyArr = channel.channelIdArr.filter((channelId) => channelId.liveGuardBuy);
1408
930
  // 将当前liveDanmakuArr的长度+到channelIdArrLen中
1409
- channelIdArrLen += liveDanmakuArr.length;
931
+ channelIdArrLen += liveGuardBuyArr.length;
1410
932
  // 返回符合的target
1411
933
  return {
1412
- channelIdArr: liveDanmakuArr,
1413
- platform: channel.platform
934
+ channelIdArr: liveGuardBuyArr,
935
+ platform: channel.platform,
1414
936
  };
1415
937
  });
1416
938
  // 定义定时推送函数
1417
939
  const pushAtTimeFunc = async () => {
1418
940
  // 判断是否信息是否获取成功
1419
- if (!(await useMasterAndLiveRoomInfo())) {
941
+ if (!(await useMasterAndLiveRoomInfo(type_1.LiveType.LiveBroadcast))) {
1420
942
  // 未获取成功,直接返回
1421
- return this.sendPrivateMsg('获取直播间信息失败,推送直播卡片失败!');
943
+ return this.sendPrivateMsg("获取直播间信息失败,推送直播卡片失败!");
1422
944
  }
1423
945
  // 设置开播时间
1424
946
  liveTime = liveRoomInfo.live_time;
947
+ // 获取watched
948
+ const watched = watchedNum || "暂未获取到";
1425
949
  // 设置直播中消息
1426
- const liveMsg = this.config.customLive ? this.config.customLive
1427
- .replace('-name', masterInfo.username)
1428
- .replace('-time', await this.ctx.gi.getTimeDifference(liveTime))
1429
- .replace('-link', `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`) : null;
950
+ const liveMsg = this.config.customLive
951
+ ? this.config.customLive
952
+ .replace("-name", masterInfo.username)
953
+ .replace("-time", await this.ctx.gi.getTimeDifference(liveTime))
954
+ .replace("-watched", watched)
955
+ .replace("-link", `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`)
956
+ : null;
1430
957
  // 发送直播通知卡片
1431
958
  await this.sendLiveNotifyCard({
1432
959
  username: masterInfo.username,
1433
960
  userface: masterInfo.userface,
1434
961
  target,
1435
- data: liveRoomInfo
1436
- }, LiveType.LiveBroadcast, liveMsg);
1437
- };
1438
- // 定义弹幕推送函数
1439
- const danmakuPushFunc = () => {
1440
- // 判断数组是否有内容
1441
- if (channelIdArrLen > 0 && temporaryLiveDanmakuArr.length > 0) {
1442
- // 发送消息
1443
- this.sendMsg(danmakuPushTargetArr, temporaryLiveDanmakuArr.join('\n'));
1444
- // 将临时消息数组清空
1445
- temporaryLiveDanmakuArr.length = 0;
1446
- }
962
+ data: liveRoomInfo,
963
+ }, type_1.LiveType.LiveBroadcast, watched, liveMsg);
1447
964
  };
1448
965
  // 定义直播间信息获取函数
1449
- const useMasterAndLiveRoomInfo = async () => {
1450
- // 定义flag
966
+ const useMasterAndLiveRoomInfo = async (liveType) => {
967
+ // 定义函数是否执行成功flag
1451
968
  let flag = true;
1452
- // 判断是否已存在值
1453
- if (liveRoomInfo && masterInfo && liveTime) {
1454
- // 所有值均已存在,不需要再获取信息
1455
- return flag;
1456
- }
1457
969
  // 获取直播间信息
1458
970
  liveRoomInfo = await this.useLiveRoomInfo(roomId).catch(() => {
1459
971
  // 设置flag为false
@@ -1469,7 +981,7 @@ class ComRegister {
1469
981
  return flag;
1470
982
  }
1471
983
  // 获取主播信息(需要满足flag为true,liveRoomInfo.uid有值)
1472
- masterInfo = await this.useMasterInfo(liveRoomInfo.uid).catch(() => {
984
+ masterInfo = await this.useMasterInfo(liveRoomInfo.uid, masterInfo, liveType).catch(() => {
1473
985
  // 设置flag为false
1474
986
  flag = false;
1475
987
  // 返回空
@@ -1478,119 +990,143 @@ class ComRegister {
1478
990
  // 返回信息
1479
991
  return flag;
1480
992
  };
1481
- // 判断是否信息是否获取成功
1482
- if (!(await useMasterAndLiveRoomInfo())) {
1483
- // 未获取成功,直接返回
1484
- return this.sendPrivateMsg('获取直播间信息失败,启动直播间弹幕检测失败!');
1485
- }
1486
993
  // 构建消息处理函数
1487
994
  const handler = {
1488
- onOpen: () => {
1489
- this.logger.info('直播间连接成功');
1490
- },
1491
- onClose: () => {
1492
- this.logger.info('直播间连接已断开');
1493
- },
1494
995
  onIncomeDanmu: ({ body }) => {
1495
- // 处理消息,只需要UP主名字和消息内容
1496
- const content = `【${masterInfo.username}的直播间】${body.user.uname}:${body.content}`;
1497
996
  // 保存消息到数组
1498
997
  currentLiveDanmakuArr.push(body.content);
1499
- temporaryLiveDanmakuArr.push(content);
1500
998
  },
1501
999
  onIncomeSuperChat: ({ body }) => {
1502
- // 处理SC消息
1503
- const content = `【${masterInfo.username}的直播间】${body.user.uname}发送了一条SC:${body.content}`;
1504
1000
  // 保存消息到数组
1505
1001
  currentLiveDanmakuArr.push(body.content);
1506
- temporaryLiveDanmakuArr.push(content);
1002
+ },
1003
+ onWatchedChange: ({ body }) => {
1004
+ // 保存观看人数到变量
1005
+ watchedNum = body.text_small;
1507
1006
  },
1508
1007
  onGuardBuy: ({ body }) => {
1509
- const content = `【${masterInfo.username}的直播间】${body.user.uname}加入了大航海(${body.gift_name})`;
1510
- // 保存消息到数组
1511
- currentLiveDanmakuArr.push(content);
1512
- temporaryLiveDanmakuArr.push(content);
1008
+ // 定义消息
1009
+ const content = `[${masterInfo.username}的直播间]「${body.user.uname}」加入了大航海(${body.gift_name})`;
1010
+ // 直接发送消息
1011
+ channelIdArrLen > 0 && this.sendMsg(liveGuardBuyPushTargetArr, content);
1513
1012
  },
1514
1013
  onLiveStart: async () => {
1515
1014
  // 判断是否已经开播
1516
1015
  if (liveStatus)
1517
1016
  return;
1017
+ // 设置开播状态为true
1018
+ liveStatus = true;
1518
1019
  // 判断是否信息是否获取成功
1519
- if (!(await useMasterAndLiveRoomInfo())) {
1020
+ if (!(await useMasterAndLiveRoomInfo(type_1.LiveType.StartBroadcasting))) {
1021
+ // 设置开播状态为false
1022
+ liveStatus = false;
1520
1023
  // 未获取成功,直接返回
1521
- return this.sendPrivateMsg('获取直播间信息失败,推送直播开播卡片失败!');
1024
+ return await this.sendPrivateMsg("获取直播间信息失败,推送直播开播卡片失败!");
1522
1025
  }
1523
1026
  // 设置开播时间
1524
1027
  liveTime = liveRoomInfo.live_time;
1525
- // 定义开播通知语
1526
- const liveStartMsg = this.config.customLiveStart ? this.config.customLiveStart
1527
- .replace('-name', masterInfo.username)
1528
- .replace('-time', await this.ctx.gi.getTimeDifference(liveTime))
1529
- .replace('-link', `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`) : null;
1028
+ // 获取当前粉丝数
1029
+ const follower = masterInfo.liveOpenFollowerNum >= 10_000
1030
+ ? `${(masterInfo.liveOpenFollowerNum / 10000).toFixed(1)}万`
1031
+ : masterInfo.liveOpenFollowerNum.toString();
1032
+ // 定义开播通知语
1033
+ const liveStartMsg = this.config.customLiveStart
1034
+ ? this.config.customLiveStart
1035
+ .replace("-name", masterInfo.username)
1036
+ .replace("-time", await this.ctx.gi.getTimeDifference(liveTime))
1037
+ .replace("-follower", follower)
1038
+ .replace("-link", `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`)
1039
+ : null;
1530
1040
  // 推送开播通知
1531
1041
  await this.sendLiveNotifyCard({
1532
1042
  username: masterInfo.username,
1533
1043
  userface: masterInfo.userface,
1534
1044
  target,
1535
- data: liveRoomInfo
1536
- }, LiveType.StartBroadcasting, liveStartMsg);
1045
+ data: liveRoomInfo,
1046
+ }, type_1.LiveType.StartBroadcasting, follower, liveStartMsg);
1537
1047
  // 判断定时器是否已开启
1538
1048
  if (!pushAtTimeTimer) {
1539
1049
  // 开始直播,开启定时器
1540
1050
  pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1000 * 60 * 60);
1541
1051
  }
1542
- // 设置开播状态为true
1543
- liveStatus = true;
1544
1052
  },
1545
1053
  onLiveEnd: async () => {
1054
+ // 将直播状态设置为false
1055
+ liveStatus = false;
1546
1056
  // 判断是否信息是否获取成功
1547
- if (!(await useMasterAndLiveRoomInfo())) {
1057
+ if (!(await useMasterAndLiveRoomInfo(type_1.LiveType.StopBroadcast))) {
1548
1058
  // 未获取成功,直接返回
1549
- return this.sendPrivateMsg('获取直播间信息失败,推送直播下播卡片失败!');
1059
+ return this.sendPrivateMsg("获取直播间信息失败,推送直播下播卡片失败!");
1550
1060
  }
1551
1061
  // 更改直播时长
1552
1062
  liveRoomInfo.live_time = liveTime;
1553
- // 定义下播播通知语
1554
- const liveEndMsg = this.config.customLiveEnd ? this.config.customLiveEnd
1555
- .replace('-name', masterInfo.username)
1556
- .replace('-time', await this.ctx.gi.getTimeDifference(liveTime)) : null;
1063
+ // 获取粉丝数变化
1064
+ const followerChange = (() => {
1065
+ // 获取直播关注变化值
1066
+ const liveFollowerChangeNum = masterInfo.liveFollowerChange;
1067
+ // 判断是否大于0
1068
+ if (liveFollowerChangeNum > 0) {
1069
+ // 大于0则加+
1070
+ return liveFollowerChangeNum >= 10_000
1071
+ ? `+${liveFollowerChangeNum.toFixed(1)}万`
1072
+ : `+${liveFollowerChangeNum}`;
1073
+ }
1074
+ // 小于0
1075
+ return liveFollowerChangeNum <= -10_000
1076
+ ? `${liveFollowerChangeNum.toFixed(1)}万`
1077
+ : liveFollowerChangeNum.toString();
1078
+ })();
1079
+ // 定义下播播通知语
1080
+ const liveEndMsg = this.config.customLiveEnd
1081
+ ? this.config.customLiveEnd
1082
+ .replace("-name", masterInfo.username)
1083
+ .replace("-time", await this.ctx.gi.getTimeDifference(liveTime))
1084
+ .replace("-follower_change", followerChange)
1085
+ : null;
1557
1086
  // 推送通知卡片
1558
1087
  await this.sendLiveNotifyCard({
1559
1088
  username: masterInfo.username,
1560
1089
  userface: masterInfo.userface,
1561
1090
  target,
1562
- data: liveRoomInfo
1563
- }, LiveType.StopBroadcast, liveEndMsg);
1091
+ data: liveRoomInfo,
1092
+ }, type_1.LiveType.StopBroadcast, followerChange, liveEndMsg);
1564
1093
  // 关闭定时推送定时器
1565
1094
  pushAtTimeTimer();
1566
1095
  // 将推送定时器变量置空
1567
1096
  pushAtTimeTimer = null;
1568
- // 将直播状态设置为false
1569
- liveStatus = false;
1570
- }
1097
+ },
1571
1098
  };
1572
1099
  // 启动直播间弹幕监测
1573
- await this.ctx.bl.startLiveRoomListener(roomId, handler, danmakuPushFunc);
1100
+ await this.ctx.bl.startLiveRoomListener(roomId, handler);
1101
+ // 第一次启动获取信息并判信息是否获取成功
1102
+ if (!(await useMasterAndLiveRoomInfo(type_1.LiveType.FirstLiveBroadcast))) {
1103
+ // 未获取成功,直接返回
1104
+ return this.sendPrivateMsg("获取直播间信息失败,启动直播间弹幕检测失败!");
1105
+ }
1574
1106
  // 判断直播状态
1575
1107
  if (liveRoomInfo.live_status === 1) {
1576
1108
  // 设置开播时间
1577
1109
  liveTime = liveRoomInfo.live_time;
1110
+ // 获取当前累计观看人数
1111
+ const watched = watchedNum || "暂未获取到";
1578
1112
  // 定义直播中通知消息
1579
- const liveMsg = this.config.customLive ? this.config.customLive
1580
- .replace('-name', masterInfo.username)
1581
- .replace('-time', await this.ctx.gi.getTimeDifference(liveTime))
1582
- .replace('-link', `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`) : null;
1113
+ const liveMsg = this.config.customLive
1114
+ ? this.config.customLive
1115
+ .replace("-name", masterInfo.username)
1116
+ .replace("-time", await this.ctx.gi.getTimeDifference(liveTime))
1117
+ .replace("-watched", watched)
1118
+ .replace("-link", `https://live.bilibili.com/${liveRoomInfo.short_id === 0 ? liveRoomInfo.room_id : liveRoomInfo.short_id}`)
1119
+ : null;
1583
1120
  // 发送直播通知卡片
1584
1121
  if (this.config.restartPush) {
1585
1122
  await this.sendLiveNotifyCard({
1586
1123
  username: masterInfo.username,
1587
1124
  userface: masterInfo.userface,
1588
1125
  target,
1589
- data: liveRoomInfo
1590
- }, LiveType.LiveBroadcast, liveMsg);
1126
+ data: liveRoomInfo,
1127
+ }, type_1.LiveType.LiveBroadcast, watched, liveMsg);
1591
1128
  }
1592
- // 正在直播,开启定时器
1593
- // 判断定时器是否已开启
1129
+ // 正在直播,开启定时器,判断定时器是否已开启
1594
1130
  if (!pushAtTimeTimer) {
1595
1131
  // 开始直播,开启定时器
1596
1132
  pushAtTimeTimer = this.ctx.setInterval(pushAtTimeFunc, this.config.pushTime * 1000 * 60 * 60);
@@ -1601,41 +1137,11 @@ class ComRegister {
1601
1137
  }
1602
1138
  subShow() {
1603
1139
  // 在控制台中显示订阅对象
1604
- let table = ``;
1605
- this.subManager.forEach(sub => {
1606
- table += `UID:${sub.uid} ${sub.dynamic ? '已订阅动态' : ''} ${sub.live ? '已订阅直播' : ''}` + '\n';
1607
- });
1608
- return table ? table : '没有订阅任何UP';
1609
- }
1610
- async checkIfNeedSub(liveSub, dynamicSub, session, liveRoomData) {
1611
- // 定义方法:用户直播间是否存在
1612
- const liveRoom = async () => {
1613
- if (!liveRoomData) {
1614
- // 未开通直播间
1615
- await session.send('该用户未开通直播间,无法订阅直播');
1616
- // 返回false
1617
- return true;
1618
- }
1619
- return false;
1620
- };
1621
- // 如果两者都为true或者都为false则直接返回
1622
- if ((liveSub && dynamicSub) || (!liveSub && !dynamicSub)) {
1623
- // 判断是否存在直播间
1624
- if (await liveRoom())
1625
- return [false, true];
1626
- // 返回
1627
- return [true, true];
1628
- }
1629
- // 如果只订阅直播
1630
- if (liveSub) {
1631
- // 判断是否存在直播间
1632
- if (await liveRoom())
1633
- return [false, false];
1634
- // 返回
1635
- return [true, false];
1140
+ let table = "";
1141
+ for (const sub of this.subManager) {
1142
+ table += `UID:${sub.uid} ${sub.dynamic ? "已订阅动态" : ""} ${sub.live ? "已订阅直播" : ""}\n`;
1636
1143
  }
1637
- // 只订阅动态
1638
- return [false, true];
1144
+ return table ? table : "没有订阅任何UP";
1639
1145
  }
1640
1146
  updateSubNotifier() {
1641
1147
  // 更新控制台提示
@@ -1644,28 +1150,30 @@ class ComRegister {
1644
1150
  // 获取订阅信息
1645
1151
  const subInfo = this.subShow();
1646
1152
  // 定义table
1647
- let table = '';
1648
- if (subInfo === '没有订阅任何UP') {
1153
+ let table = "";
1154
+ if (subInfo === "没有订阅任何UP") {
1649
1155
  table = subInfo;
1650
1156
  }
1651
1157
  else {
1652
1158
  // 获取subTable
1653
- const subTableArray = subInfo.split('\n');
1159
+ const subTableArray = subInfo.split("\n");
1654
1160
  subTableArray.splice(subTableArray.length - 1, 1);
1655
1161
  // 定义Table
1656
- 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 }))) })] });
1162
+ 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) => (
1163
+ // biome-ignore lint/correctness/useJsxKeyInIterable: <explanation>
1164
+ (0, jsx_runtime_1.jsx)("li", { children: str }))) })] }));
1657
1165
  }
1658
1166
  // 设置更新后的提示
1659
1167
  this.subNotifier = this.ctx.notifier.create(table);
1660
1168
  }
1661
1169
  async checkIfLoginInfoIsLoaded() {
1662
- return new Promise(resolve => {
1170
+ return new Promise((resolve) => {
1663
1171
  const check = () => {
1664
1172
  if (!this.ctx.ba.getLoginInfoIsLoaded()) {
1665
1173
  this.ctx.setTimeout(check, 500);
1666
1174
  }
1667
1175
  else {
1668
- resolve('success');
1176
+ resolve("success");
1669
1177
  }
1670
1178
  };
1671
1179
  check();
@@ -1675,7 +1183,8 @@ class ComRegister {
1675
1183
  // 获取关注分组信息
1676
1184
  const checkGroupIsReady = async () => {
1677
1185
  // 判断是否有数据
1678
- if (this.loginDBData.dynamic_group_id === '' || this.loginDBData.dynamic_group_id === null) {
1186
+ if (this.loginDBData.dynamic_group_id === "" ||
1187
+ this.loginDBData.dynamic_group_id === null) {
1679
1188
  // 没有数据,没有创建分组,尝试创建分组
1680
1189
  const createGroupData = await this.ctx.ba.createGroup("订阅");
1681
1190
  // 如果分组已创建,则获取分组id
@@ -1685,7 +1194,7 @@ class ComRegister {
1685
1194
  // 遍历所有分组
1686
1195
  for (const group of allGroupData.data) {
1687
1196
  // 找到订阅分组
1688
- if (group.name === '订阅') {
1197
+ if (group.name === "订阅") {
1689
1198
  // 拿到分组id
1690
1199
  this.loginDBData.dynamic_group_id = group.tagid;
1691
1200
  // 结束循环
@@ -1699,7 +1208,9 @@ class ComRegister {
1699
1208
  return false;
1700
1209
  }
1701
1210
  // 创建成功,保存到数据库
1702
- this.ctx.database.set('loginBili', 1, { dynamic_group_id: this.loginDBData.dynamic_group_id });
1211
+ this.ctx.database.set("loginBili", 1, {
1212
+ dynamic_group_id: this.loginDBData.dynamic_group_id,
1213
+ });
1703
1214
  // 创建成功
1704
1215
  return true;
1705
1216
  }
@@ -1710,7 +1221,7 @@ class ComRegister {
1710
1221
  // 判断是否创建成功
1711
1222
  if (!flag) {
1712
1223
  // 创建分组失败
1713
- return { flag: false, msg: '创建分组失败,请尝试重启插件' };
1224
+ return { flag: false, msg: "创建分组失败,请尝试重启插件" };
1714
1225
  }
1715
1226
  // 获取分组明细
1716
1227
  const relationGroupDetailData = await this.ctx.ba.getRelationGroupDetail(this.loginDBData.dynamic_group_id);
@@ -1724,71 +1235,72 @@ class ComRegister {
1724
1235
  // 判断是否创建成功
1725
1236
  if (!flag) {
1726
1237
  // 创建分组失败
1727
- return { flag: false, msg: '创建分组失败,请尝试重启插件' };
1238
+ return { flag: false, msg: "创建分组失败,请尝试重启插件" };
1728
1239
  }
1729
- return { flag: true, msg: '分组不存在,已重新创建分组' };
1240
+ return { flag: true, msg: "分组不存在,已重新创建分组" };
1730
1241
  }
1731
1242
  // 获取分组明细失败
1732
- return { flag: false, msg: '获取分组明细失败' };
1243
+ return { flag: false, msg: "获取分组明细失败" };
1733
1244
  }
1734
- relationGroupDetailData.data.forEach(user => {
1245
+ for (const user of relationGroupDetailData.data) {
1735
1246
  if (user.mid === mid) {
1736
1247
  // 已关注订阅对象
1737
- return { flag: true, msg: '订阅对象已存在于分组中' };
1248
+ return { flag: true, msg: "订阅对象已存在于分组中" };
1738
1249
  }
1739
- });
1250
+ }
1740
1251
  // 订阅对象
1741
1252
  const subUserData = await this.ctx.ba.follow(mid);
1742
1253
  // 判断是否订阅成功
1743
1254
  switch (subUserData.code) {
1744
- case -101: return { flag: false, msg: '账号未登录,请使用指令bili login登录后再进行订阅操作' };
1745
- case -102: return { flag: false, msg: '账号被封停,无法进行订阅操作' };
1746
- case 22002: return { flag: false, msg: '因对方隐私设置,无法进行订阅操作' };
1747
- case 22003: return { flag: false, msg: '你已将对方拉黑,无法进行订阅操作' };
1748
- case 22013: return { flag: false, msg: '账号已注销,无法进行订阅操作' };
1749
- case 40061: return { flag: false, msg: '账号不存在,请检查uid输入是否正确或用户是否存在' };
1750
- case 22001: break; // 订阅对象为自己 无需添加到分组
1255
+ case -101:
1256
+ return {
1257
+ flag: false,
1258
+ msg: "账号未登录,请使用指令bili login登录后再进行订阅操作",
1259
+ };
1260
+ case -102:
1261
+ return { flag: false, msg: "账号被封停,无法进行订阅操作" };
1262
+ case 22002:
1263
+ return { flag: false, msg: "因对方隐私设置,无法进行订阅操作" };
1264
+ case 22003:
1265
+ return { flag: false, msg: "你已将对方拉黑,无法进行订阅操作" };
1266
+ case 22013:
1267
+ return { flag: false, msg: "账号已注销,无法进行订阅操作" };
1268
+ case 40061:
1269
+ return {
1270
+ flag: false,
1271
+ msg: "账号不存在,请检查uid输入是否正确或用户是否存在",
1272
+ };
1273
+ case 22001:
1274
+ break; // 订阅对象为自己 无需添加到分组
1751
1275
  case 22014: // 已关注订阅对象 无需再次关注
1752
- case 0: { // 执行订阅成功
1276
+ case 0: {
1277
+ // 执行订阅成功
1753
1278
  // 把订阅对象添加到分组中
1754
1279
  const copyUserToGroupData = await this.ctx.ba.copyUserToGroup(mid, this.loginDBData.dynamic_group_id);
1755
1280
  // 判断是否添加成功
1756
1281
  if (copyUserToGroupData.code !== 0) {
1757
1282
  // 添加失败
1758
- return { flag: false, msg: '添加订阅对象到分组失败,请稍后重试' };
1283
+ return { flag: false, msg: "添加订阅对象到分组失败,请稍后重试" };
1759
1284
  }
1760
1285
  }
1761
1286
  }
1762
1287
  // 订阅成功
1763
- return { flag: true, msg: '用户订阅成功' };
1288
+ return { flag: true, msg: "用户订阅成功" };
1764
1289
  }
1765
1290
  async loadSubFromConfig(subs) {
1766
1291
  for (const sub of subs) {
1292
+ // logger
1293
+ this.logger.info(`加载订阅UID:${sub.uid}中...`);
1767
1294
  // 定义Data
1768
- let data;
1295
+ const data = await (0, utils_1.withRetry)(async () => await this.ctx.ba.getUserInfo(sub.uid))
1296
+ .then((content) => content.data)
1297
+ .catch((e) => {
1298
+ this.logger.error(`loadSubFromConfig() getUserInfo() 发生了错误,错误为:${e.message}`);
1299
+ // logger
1300
+ this.logger.info(`加载订阅UID:${sub.uid}失败!`);
1301
+ });
1769
1302
  // 判断是否需要订阅直播
1770
1303
  if (sub.live) {
1771
- // 获取用户信息
1772
- let content;
1773
- // 设置重试次数
1774
- const attempts = 3;
1775
- for (let i = 0; i < attempts; i++) {
1776
- try {
1777
- // 获取用户信息
1778
- content = await this.ctx.ba.getUserInfo(sub.uid);
1779
- // 成功则跳出循环
1780
- break;
1781
- }
1782
- catch (e) {
1783
- this.logger.error('loadSubFromConfig() getUserInfo() 发生了错误,错误为:' + e.message);
1784
- if (i === attempts - 1) { // 已尝试三次
1785
- // 发送私聊消息并重启服务
1786
- return await this.sendPrivateMsgAndStopService();
1787
- }
1788
- }
1789
- }
1790
- // 获取data
1791
- data = content.data;
1792
1304
  // 检查roomid是否存在
1793
1305
  if (!data.live_room) {
1794
1306
  // 用户没有开通直播间,无法订阅直播
@@ -1796,24 +1308,10 @@ class ComRegister {
1796
1308
  // 发送提示
1797
1309
  this.logger.warn(`UID:${sub.uid} 用户没有开通直播间,无法订阅直播!`);
1798
1310
  }
1799
- //
1800
- const liveDetectModeSelector = {
1801
- API: async () => {
1802
- // 判断是否已开启直播检测
1803
- if (!this.liveDispose) { // 未开启直播检测
1804
- // 开启直播检测并保存销毁函数
1805
- this.liveDispose = await this.liveDetectWithAPI();
1806
- }
1807
- },
1808
- WS: async () => {
1809
- // 连接到服务器
1810
- await this.liveDetectWithListener(data.live_room.roomid, sub.target);
1811
- }
1812
- };
1813
1311
  // 判断是否订阅直播
1814
1312
  if (sub.live) {
1815
1313
  // 启动直播监测
1816
- await liveDetectModeSelector[this.config.liveDetectMode]();
1314
+ await this.liveDetectWithListener(data.live_room.roomid, sub.target);
1817
1315
  }
1818
1316
  }
1819
1317
  // 在B站中订阅该对象
@@ -1825,154 +1323,19 @@ class ComRegister {
1825
1323
  this.subManager.push({
1826
1324
  id: +sub.uid,
1827
1325
  uid: sub.uid,
1828
- roomId: sub.live ? data.live_room.roomid : '',
1326
+ uname: data.name,
1327
+ roomId: sub.live ? data.live_room.roomid : "",
1829
1328
  target: sub.target,
1830
- platform: '',
1329
+ platform: "",
1831
1330
  live: sub.live,
1832
- dynamic: sub.dynamic
1331
+ dynamic: sub.dynamic,
1833
1332
  });
1834
- }
1835
- }
1836
- async loadSubFromDatabase() {
1837
- // 从数据库中获取数据
1838
- const subData = await this.ctx.database.get('bilibili', { id: { $gt: 0 } });
1839
- // 定义变量:订阅直播数
1840
- let liveSubNum = 0;
1841
- // 循环遍历
1842
- for (const sub of subData) {
1843
- // 判断是否存在没有任何订阅的数据
1844
- if (!sub.dynamic && !sub.live) { // 存在未订阅任何项目的数据
1845
- // 删除该条数据
1846
- this.ctx.database.remove('bilibili', { id: sub.id });
1847
- // log
1848
- this.logger.warn(`UID:${sub.uid} 该条数据没有任何订阅数据,自动取消订阅`);
1849
- // 跳过下面的步骤
1850
- continue;
1851
- }
1852
- // 判断用户是否在B站中订阅了
1853
- const subUserData = await this.subUserInBili(sub.uid);
1854
- // 判断是否订阅
1855
- if (!subUserData.flag) {
1856
- // log
1857
- this.logger.warn(`UID:${sub.uid} ${subUserData.msg},自动取消订阅`);
1858
- // 发送私聊消息
1859
- await this.sendPrivateMsg(`UID:${sub.uid} ${subUserData.msg},自动取消订阅`);
1860
- // 删除该条数据
1861
- await this.ctx.database.remove('bilibili', { id: sub.id });
1862
- // 跳过下面的步骤
1863
- continue;
1864
- }
1865
- // 获取推送目标数组
1866
- const target = JSON.parse(sub.target);
1867
- /* 判断数据库是否被篡改 */
1868
- // 获取用户信息
1869
- let content;
1870
- const attempts = 3;
1871
- for (let i = 0; i < attempts; i++) {
1872
- try {
1873
- // 获取用户信息
1874
- content = await this.ctx.ba.getUserInfo(sub.uid);
1875
- // 成功则跳出循环
1876
- break;
1877
- }
1878
- catch (e) {
1879
- this.logger.error('getSubFromDatabase() getUserInfo() 发生了错误,错误为:' + e.message);
1880
- if (i === attempts - 1) { // 已尝试三次
1881
- // 发送私聊消息并重启服务
1882
- return await this.sendPrivateMsgAndStopService();
1883
- }
1884
- }
1885
- }
1886
- // 获取data
1887
- const { data } = content;
1888
- // 定义函数删除数据和发送提示
1889
- const deleteSub = async () => {
1890
- // 从数据库删除该条数据
1891
- await this.ctx.database.remove('bilibili', { id: sub.id });
1892
- // 给用户发送提示
1893
- await this.sendPrivateMsg(`UID:${sub.uid} 数据库内容被篡改,已取消对该UP主的订阅`);
1894
- };
1895
- // 判断是否有其他问题
1896
- if (content.code !== 0) {
1897
- switch (content.code) {
1898
- case -352:
1899
- case -403: {
1900
- await this.sendPrivateMsg('你的登录信息已过期,请重新登录Bilibili');
1901
- return;
1902
- }
1903
- case -400:
1904
- case -404:
1905
- default: {
1906
- await deleteSub();
1907
- // PrivateMsg
1908
- await this.sendPrivateMsg(`UID:${sub.uid} 数据出现问题,自动取消订阅`);
1909
- // log
1910
- this.logger.info(`UID:${sub.uid} 数据出现问题,自动取消订阅`);
1911
- return;
1912
- }
1913
- }
1914
- }
1915
- // 检测房间号是否被篡改
1916
- if (sub.live && (!data.live_room || data.live_room.roomid != sub.room_id)) {
1917
- // 房间号被篡改,删除该订阅
1918
- await deleteSub();
1919
- // log
1920
- this.logger.info(`UID:${sub.uid} 房间号被篡改,自动取消订阅`);
1921
- // Send msg
1922
- await this.sendPrivateMsg(`UID:${sub.uid} 房间号被篡改,自动取消订阅`);
1923
- // 直接返回
1924
- return;
1925
- }
1926
- // 构建订阅对象
1927
- const subManagerItem = {
1928
- id: sub.id,
1929
- uid: sub.uid,
1930
- roomId: sub.room_id,
1931
- target,
1932
- platform: sub.platform,
1933
- live: sub.live === 1 ? true : false,
1934
- dynamic: sub.dynamic === 1 ? true : false,
1935
- liveDispose: null
1936
- };
1937
- // 定义直播模式监测器
1938
- const liveDetectModeSelector = {
1939
- API: async () => {
1940
- // 判断是否已开启直播检测
1941
- if (!this.liveDispose) { // 未开启直播检测
1942
- // 开启直播检测并保存销毁函数
1943
- this.liveDispose = await this.liveDetectWithAPI();
1944
- }
1945
- },
1946
- WS: async () => {
1947
- // 判断订阅直播数是否超过限制
1948
- if (!this.config.unlockSubLimits && liveSubNum >= 3) {
1949
- // 将live改为false
1950
- subManagerItem.live = false;
1951
- // log
1952
- this.logger.warn(`UID:${sub.uid} 订阅直播数超过限制,自动取消订阅`);
1953
- // 发送错误消息
1954
- await this.sendPrivateMsg(`UID:${sub.uid} 订阅直播数超过限制,自动取消订阅`);
1955
- }
1956
- else {
1957
- // 直播订阅数+1
1958
- liveSubNum++;
1959
- // 订阅直播,开始循环检测
1960
- await this.liveDetectWithListener(sub.room_id, target);
1961
- }
1962
- }
1963
- };
1964
- // 判断是否订阅直播
1965
- if (sub.live) {
1966
- // 启动直播监测
1967
- await liveDetectModeSelector[this.config.liveDetectMode]();
1968
- }
1969
- // 保存新订阅对象
1970
- this.subManager.push(subManagerItem);
1333
+ this.logger.info(`UID:${sub.uid}订阅加载完毕!`);
1971
1334
  }
1972
1335
  }
1973
1336
  checkIfDynamicDetectIsNeeded() {
1974
1337
  // 检查是否有订阅对象需要动态监测
1975
- if (this.subManager.some(sub => sub.dynamic))
1338
+ if (this.subManager.some((sub) => sub.dynamic))
1976
1339
  this.enableDynamicDetect();
1977
1340
  }
1978
1341
  enableDynamicDetect() {
@@ -1984,130 +1347,12 @@ class ComRegister {
1984
1347
  this.dynamicDispose = this.ctx.setInterval(this.dynamicDetect(), this.config.dynamicLoopTime * 1000);
1985
1348
  }
1986
1349
  }
1987
- unsubSingle(id /* UID或RoomId */, type /* 0取消Live订阅,1取消Dynamic订阅 */) {
1988
- // 定义返回消息
1989
- let msg;
1990
- // 定义方法:检查是否没有任何订阅
1991
- const checkIfNoSubExist = (sub) => !sub.dynamic && !sub.live;
1992
- // 定义方法:将订阅对象从订阅管理对象中移除
1993
- const removeSub = (index) => {
1994
- // 从管理对象中移除
1995
- this.subManager.splice(index, 1);
1996
- // 从数据库中删除
1997
- this.ctx.database.remove('bilibili', [this.subManager[index].id]);
1998
- // num--
1999
- this.num--;
2000
- // 判断是否还存在订阅了动态的对象,不存在则停止动态监测
2001
- this.checkIfUserIsTheLastOneWhoSubDyn();
2002
- };
2003
- try {
2004
- switch (type) {
2005
- case 0: { // 取消Live订阅
2006
- // 获取订阅对象所在的索引
2007
- const index = this.subManager.findIndex(sub => sub.roomId === id);
2008
- // 获取订阅对象
2009
- const sub = this.subManager.find(sub => sub.roomId === id);
2010
- // 判断是否存在订阅对象
2011
- if (!sub) {
2012
- msg = '未订阅该用户,无需取消订阅';
2013
- return msg;
2014
- }
2015
- // 取消订阅
2016
- sub.live = false;
2017
- // 判断直播检测方式
2018
- switch (this.config.liveDetectMode) {
2019
- case 'API': {
2020
- msg = '请手动删除订阅,并重启插件';
2021
- break;
2022
- }
2023
- case 'WS': {
2024
- // 取消直播监听
2025
- this.ctx.bl.closeListener(sub.roomId);
2026
- }
2027
- }
2028
- // 如果没有对这个UP的任何订阅,则移除
2029
- if (checkIfNoSubExist(sub)) {
2030
- // 从管理对象中移除
2031
- removeSub(index);
2032
- return '已取消订阅该用户';
2033
- }
2034
- // 更新数据库
2035
- this.ctx.database.upsert('bilibili', [{
2036
- id: +`${sub.id}`,
2037
- live: 0
2038
- }]);
2039
- return '已取消订阅Live';
2040
- }
2041
- case 1: { // 取消Dynamic订阅
2042
- // 获取订阅对象所在的索引
2043
- const index = this.subManager.findIndex(sub => sub.uid === id);
2044
- // 获取订阅对象
2045
- const sub = this.subManager.find(sub => sub.uid === id);
2046
- // 判断是否存在订阅对象
2047
- if (!sub) {
2048
- msg = '未订阅该用户,无需取消订阅';
2049
- return msg;
2050
- }
2051
- // 取消订阅
2052
- this.subManager[index].dynamic = false;
2053
- // 判断是否还存在订阅了动态的对象,不存在则停止动态监测
2054
- this.checkIfUserIsTheLastOneWhoSubDyn();
2055
- // 如果没有对这个UP的任何订阅,则移除
2056
- if (checkIfNoSubExist(sub)) {
2057
- // 从管理对象中移除
2058
- removeSub(index);
2059
- return '已取消订阅该用户';
2060
- }
2061
- // 更新数据库
2062
- this.ctx.database.upsert('bilibili', [{
2063
- id: sub.id,
2064
- dynamic: 0
2065
- }]);
2066
- return '已取消订阅Dynamic';
2067
- }
2068
- }
2069
- }
2070
- finally {
2071
- // 执行完该方法后,保证执行一次updateSubNotifier()
2072
- this.updateSubNotifier();
2073
- }
2074
- }
2075
- checkIfUserIsTheLastOneWhoSubDyn() {
2076
- if (this.dynamicDispose && !this.subManager.some(sub => sub.dynamic)) {
2077
- // 停止动态监测
2078
- this.dynamicDispose();
2079
- this.dynamicDispose = null;
2080
- }
2081
- }
2082
- unsubAll(uid) {
2083
- this.subManager.filter(sub => sub.uid === uid).map(async (sub, i) => {
2084
- // 判断是否还存在订阅了动态的对象,不存在则停止动态监测
2085
- this.checkIfUserIsTheLastOneWhoSubDyn();
2086
- switch (this.config.liveDetectMode) {
2087
- case "API": {
2088
- break;
2089
- }
2090
- case "WS": {
2091
- // 停止直播检测
2092
- this.ctx.bl.closeListener(sub.roomId);
2093
- }
2094
- }
2095
- // 从数据库中删除订阅
2096
- await this.ctx.database.remove('bilibili', { uid: this.subManager[i].uid });
2097
- // 将该订阅对象从订阅管理对象中移除
2098
- this.subManager.splice(i, 1);
2099
- // id--
2100
- this.num--;
2101
- // 发送成功通知
2102
- this.sendPrivateMsg(`UID:${uid},已取消订阅该用户`);
2103
- // 更新控制台提示
2104
- this.updateSubNotifier();
2105
- });
2106
- }
2107
1350
  async checkIfIsLogin() {
2108
- if ((await this.ctx.database.get('loginBili', 1)).length !== 0) { // 数据库中有数据
1351
+ if ((await this.ctx.database.get("loginBili", 1)).length !== 0) {
1352
+ // 数据库中有数据
2109
1353
  // 检查cookie中是否有值
2110
- if (this.ctx.ba.getCookies() !== '[]') { // 有值说明已登录
1354
+ if (this.ctx.ba.getCookies() !== "[]") {
1355
+ // 有值说明已登录
2111
1356
  return true;
2112
1357
  }
2113
1358
  }
@@ -2117,48 +1362,49 @@ class ComRegister {
2117
1362
  (function (ComRegister) {
2118
1363
  ComRegister.Config = koishi_1.Schema.object({
2119
1364
  sub: koishi_1.Schema.array(koishi_1.Schema.object({
2120
- uid: koishi_1.Schema.string().description('订阅用户UID'),
2121
- dynamic: koishi_1.Schema.boolean().description('是否订阅用户动态'),
2122
- live: koishi_1.Schema.boolean().description('是否订阅用户直播'),
1365
+ uid: koishi_1.Schema.string().description("订阅用户UID"),
1366
+ dynamic: koishi_1.Schema.boolean().description("是否订阅用户动态"),
1367
+ live: koishi_1.Schema.boolean().description("是否订阅用户直播"),
2123
1368
  target: koishi_1.Schema.array(koishi_1.Schema.object({
2124
1369
  channelIdArr: koishi_1.Schema.array(koishi_1.Schema.object({
2125
- channelId: koishi_1.Schema.string().description('频道/群组号'),
2126
- dynamic: koishi_1.Schema.boolean().description('该频道/群组是否推送动态信息'),
2127
- live: koishi_1.Schema.boolean().description('该频道/群组是否推送直播通知'),
2128
- liveDanmaku: koishi_1.Schema.boolean().description('该频道/群组是否推送弹幕消息'),
2129
- atAll: koishi_1.Schema.boolean().description('推送开播通知时是否艾特全体成员')
2130
- })).description('频道/群组信息'),
2131
- platform: koishi_1.Schema.string().description('推送平台')
2132
- })).description('订阅用户需要发送的频道/群组信息')
2133
- })).role('table').description('手动输入订阅信息,方便自定义订阅内容,这里的订阅内容不会存入数据库。uid: 订阅用户UID,dynamic: 是否需要订阅动态,live: 是否需要订阅直播'),
1370
+ channelId: koishi_1.Schema.string().description("频道/群组号"),
1371
+ dynamic: koishi_1.Schema.boolean().description("该频道/群组是否推送动态信息"),
1372
+ live: koishi_1.Schema.boolean().description("该频道/群组是否推送直播通知"),
1373
+ liveGuardBuy: koishi_1.Schema.boolean().description("该频道/群组是否推送弹幕消息"),
1374
+ atAll: koishi_1.Schema.boolean().description("推送开播通知时是否艾特全体成员"),
1375
+ })).description("频道/群组信息"),
1376
+ platform: koishi_1.Schema.string().description("推送平台"),
1377
+ })).description("订阅用户需要发送的频道/群组信息"),
1378
+ }))
1379
+ .role("table")
1380
+ .description("手动输入订阅信息,方便自定义订阅内容,这里的订阅内容不会存入数据库。uid: 订阅用户UID,dynamic: 是否需要订阅动态,live: 是否需要订阅直播"),
2134
1381
  master: koishi_1.Schema.object({
2135
1382
  enable: koishi_1.Schema.boolean(),
2136
1383
  platform: koishi_1.Schema.string(),
2137
1384
  masterAccount: koishi_1.Schema.string(),
2138
- masterAccountGuildId: koishi_1.Schema.string()
1385
+ masterAccountGuildId: koishi_1.Schema.string(),
2139
1386
  }),
2140
- unlockSubLimits: koishi_1.Schema.boolean().required(),
2141
1387
  automaticResend: koishi_1.Schema.boolean().required(),
2142
1388
  liveDetectMode: koishi_1.Schema.union([
2143
- koishi_1.Schema.const('API'),
2144
- koishi_1.Schema.const('WS')
1389
+ koishi_1.Schema.const("API"),
1390
+ koishi_1.Schema.const("WS"),
2145
1391
  ]).required(),
2146
1392
  restartPush: koishi_1.Schema.boolean().required(),
2147
1393
  pushTime: koishi_1.Schema.number().required(),
1394
+ pushImgsInDynamic: koishi_1.Schema.boolean().required(),
2148
1395
  liveLoopTime: koishi_1.Schema.number().default(10),
2149
1396
  customLiveStart: koishi_1.Schema.string().required(),
2150
1397
  customLive: koishi_1.Schema.string(),
2151
1398
  customLiveEnd: koishi_1.Schema.string().required(),
2152
1399
  dynamicUrl: koishi_1.Schema.boolean().required(),
2153
1400
  dynamicLoopTime: koishi_1.Schema.number().default(60),
2154
- dynamicCheckNumber: koishi_1.Schema.number().required(),
2155
1401
  filter: koishi_1.Schema.object({
2156
1402
  enable: koishi_1.Schema.boolean(),
2157
1403
  notify: koishi_1.Schema.boolean(),
2158
1404
  regex: koishi_1.Schema.string(),
2159
1405
  keywords: koishi_1.Schema.array(String),
2160
1406
  }),
2161
- dynamicDebugMode: koishi_1.Schema.boolean().required()
1407
+ dynamicDebugMode: koishi_1.Schema.boolean().required(),
2162
1408
  });
2163
1409
  })(ComRegister || (ComRegister = {}));
2164
1410
  exports.default = ComRegister;