koishi-plugin-bilibili-notify 3.5.0 → 3.6.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs CHANGED
@@ -40,6 +40,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
40
40
  //#endregion
41
41
  let koishi = require("koishi");
42
42
  require("@koishijs/plugin-notifier");
43
+ let __koishijs_plugin_console = require("@koishijs/plugin-console");
44
+ let node_path = require("node:path");
43
45
  require("@koishijs/plugin-help");
44
46
  let blive_message_listener = require("blive-message-listener");
45
47
  let qrcode = require("qrcode");
@@ -49,7 +51,6 @@ let luxon = require("luxon");
49
51
  let __node_rs_jieba = require("@node-rs/jieba");
50
52
  let __node_rs_jieba_dict = require("@node-rs/jieba/dict");
51
53
  require("koishi-plugin-puppeteer");
52
- let node_path = require("node:path");
53
54
  let node_url = require("node:url");
54
55
  let md5 = require("md5");
55
56
  md5 = __toESM(md5);
@@ -164,6 +165,67 @@ const BAConfigSchema = koishi.Schema.object({
164
165
  dynamicDebugMode: koishi.Schema.boolean().default(false).description("动态调试模式,开启后会在控制台输出动态推送的详细信息,用于调试")
165
166
  });
166
167
 
168
+ //#endregion
169
+ //#region src/type/index.ts
170
+ let LiveType = /* @__PURE__ */ function(LiveType$1) {
171
+ LiveType$1[LiveType$1["NotLiveBroadcast"] = 0] = "NotLiveBroadcast";
172
+ LiveType$1[LiveType$1["StartBroadcasting"] = 1] = "StartBroadcasting";
173
+ LiveType$1[LiveType$1["LiveBroadcast"] = 2] = "LiveBroadcast";
174
+ LiveType$1[LiveType$1["StopBroadcast"] = 3] = "StopBroadcast";
175
+ LiveType$1[LiveType$1["FirstLiveBroadcast"] = 4] = "FirstLiveBroadcast";
176
+ return LiveType$1;
177
+ }({});
178
+ let PushType = /* @__PURE__ */ function(PushType$1) {
179
+ PushType$1[PushType$1["Live"] = 0] = "Live";
180
+ PushType$1[PushType$1["Dynamic"] = 1] = "Dynamic";
181
+ PushType$1[PushType$1["DynamicAtAll"] = 2] = "DynamicAtAll";
182
+ PushType$1[PushType$1["StartBroadcasting"] = 3] = "StartBroadcasting";
183
+ PushType$1[PushType$1["LiveGuardBuy"] = 4] = "LiveGuardBuy";
184
+ PushType$1[PushType$1["WordCloudAndLiveSummary"] = 5] = "WordCloudAndLiveSummary";
185
+ PushType$1[PushType$1["Superchat"] = 6] = "Superchat";
186
+ return PushType$1;
187
+ }({});
188
+ const PushTypeMsg = {
189
+ [PushType.Live]: "直播推送",
190
+ [PushType.Dynamic]: "动态推送",
191
+ [PushType.DynamicAtAll]: "动态推送+At全体",
192
+ [PushType.StartBroadcasting]: "开播推送",
193
+ [PushType.LiveGuardBuy]: "上舰推送",
194
+ [PushType.WordCloudAndLiveSummary]: "弹幕词云和直播总结推送",
195
+ [PushType.Superchat]: "SC推送"
196
+ };
197
+ let BiliLoginStatus = /* @__PURE__ */ function(BiliLoginStatus$1) {
198
+ BiliLoginStatus$1[BiliLoginStatus$1["NOT_LOGIN"] = 0] = "NOT_LOGIN";
199
+ BiliLoginStatus$1[BiliLoginStatus$1["LOADING_LOGIN_INFO"] = 1] = "LOADING_LOGIN_INFO";
200
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_QR"] = 2] = "LOGIN_QR";
201
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGGING_QR"] = 3] = "LOGGING_QR";
202
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGGING_IN"] = 4] = "LOGGING_IN";
203
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGGED_IN"] = 5] = "LOGGED_IN";
204
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_SUCCESS"] = 6] = "LOGIN_SUCCESS";
205
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_FAILED"] = 7] = "LOGIN_FAILED";
206
+ return BiliLoginStatus$1;
207
+ }({});
208
+
209
+ //#endregion
210
+ //#region src/data_server.ts
211
+ /** biome-ignore-all assist/source/organizeImports: <import> */
212
+ var BilibiliNotifyDataServer = class extends __koishijs_plugin_console.DataService {
213
+ biliData = {
214
+ status: BiliLoginStatus.LOADING_LOGIN_INFO,
215
+ msg: "正在加载登录信息..."
216
+ };
217
+ constructor(ctx) {
218
+ super(ctx, "bilibili-notify");
219
+ ctx.on("bilibili-notify/login-status-report", (data) => {
220
+ this.biliData = data;
221
+ this.refresh();
222
+ });
223
+ }
224
+ async get() {
225
+ return this.biliData;
226
+ }
227
+ };
228
+
167
229
  //#endregion
168
230
  //#region src/utils/index.ts
169
231
  /**
@@ -204,7 +266,7 @@ async function withRetry(fn, maxAttempts = 3, delayMs = 1e3) {
204
266
  } catch (error) {
205
267
  attempt++;
206
268
  if (attempt >= maxAttempts) throw error;
207
- await new Promise((resolve$1) => setTimeout(resolve$1, delayMs * attempt));
269
+ await new Promise((resolve$2) => setTimeout(resolve$2, delayMs * attempt));
208
270
  }
209
271
  }
210
272
  function replaceButKeep(oldObj, newObj, keepKeys) {
@@ -213,36 +275,6 @@ function replaceButKeep(oldObj, newObj, keepKeys) {
213
275
  return result;
214
276
  }
215
277
 
216
- //#endregion
217
- //#region src/type/index.ts
218
- let LiveType = /* @__PURE__ */ function(LiveType$1) {
219
- LiveType$1[LiveType$1["NotLiveBroadcast"] = 0] = "NotLiveBroadcast";
220
- LiveType$1[LiveType$1["StartBroadcasting"] = 1] = "StartBroadcasting";
221
- LiveType$1[LiveType$1["LiveBroadcast"] = 2] = "LiveBroadcast";
222
- LiveType$1[LiveType$1["StopBroadcast"] = 3] = "StopBroadcast";
223
- LiveType$1[LiveType$1["FirstLiveBroadcast"] = 4] = "FirstLiveBroadcast";
224
- return LiveType$1;
225
- }({});
226
- let PushType = /* @__PURE__ */ function(PushType$1) {
227
- PushType$1[PushType$1["Live"] = 0] = "Live";
228
- PushType$1[PushType$1["Dynamic"] = 1] = "Dynamic";
229
- PushType$1[PushType$1["DynamicAtAll"] = 2] = "DynamicAtAll";
230
- PushType$1[PushType$1["StartBroadcasting"] = 3] = "StartBroadcasting";
231
- PushType$1[PushType$1["LiveGuardBuy"] = 4] = "LiveGuardBuy";
232
- PushType$1[PushType$1["WordCloudAndLiveSummary"] = 5] = "WordCloudAndLiveSummary";
233
- PushType$1[PushType$1["Superchat"] = 6] = "Superchat";
234
- return PushType$1;
235
- }({});
236
- const PushTypeMsg = {
237
- [PushType.Live]: "直播推送",
238
- [PushType.Dynamic]: "动态推送",
239
- [PushType.DynamicAtAll]: "动态推送+At全体",
240
- [PushType.StartBroadcasting]: "开播推送",
241
- [PushType.LiveGuardBuy]: "上舰推送",
242
- [PushType.WordCloudAndLiveSummary]: "弹幕词云和直播总结推送",
243
- [PushType.Superchat]: "SC推送"
244
- };
245
-
246
278
  //#endregion
247
279
  //#region src/stop_words.ts
248
280
  const stopwords = new Set([
@@ -442,68 +474,6 @@ var ComRegister = class ComRegister {
442
474
  await session.send(`Channel ID: ${session.event.channel.id}`);
443
475
  });
444
476
  const biliCom = ctx.command("bili", "bili-notify插件相关指令", { permissions: ["authority:3"] });
445
- biliCom.subcommand(".login", "登录B站之后才可以进行之后的操作").usage("使用二维码登录,登录B站之后才可以进行之后的操作").example("bili login").action(async ({ session }) => {
446
- this.logger.info("调用bili login指令");
447
- let content;
448
- try {
449
- content = await ctx["bilibili-notify-api"].getLoginQRCode();
450
- } catch (_) {
451
- return "bili login getLoginQRCode() 本次网络请求失败";
452
- }
453
- if (content.code !== 0) return await session.send("出问题咯!");
454
- qrcode.default.toBuffer(content.data.url, {
455
- errorCorrectionLevel: "H",
456
- type: "png",
457
- margin: 1,
458
- color: {
459
- dark: "#000000",
460
- light: "#FFFFFF"
461
- }
462
- }, async (err, buffer) => {
463
- if (err) return await session.send("二维码生成出错,请重新尝试");
464
- await session.send(koishi.h.image(buffer, "image/jpeg"));
465
- });
466
- if (this.loginTimer) this.loginTimer();
467
- let flag = true;
468
- this.loginTimer = ctx.setInterval(async () => {
469
- try {
470
- if (!flag) return;
471
- flag = false;
472
- let loginContent;
473
- try {
474
- loginContent = await ctx["bilibili-notify-api"].getLoginStatus(content.data.qrcode_key);
475
- } catch (e) {
476
- this.logger.error(e);
477
- return;
478
- }
479
- if (loginContent.code !== 0) {
480
- this.loginTimer();
481
- return await session.send("登录失败请重试");
482
- }
483
- if (loginContent.data.code === 86038) {
484
- this.loginTimer();
485
- return await session.send("二维码已失效,请重新登录");
486
- }
487
- if (loginContent.data.code === 0) {
488
- const encryptedCookies = ctx["bilibili-notify-api"].encrypt(ctx["bilibili-notify-api"].getCookies());
489
- const encryptedRefreshToken = ctx["bilibili-notify-api"].encrypt(loginContent.data.refresh_token);
490
- await ctx.database.upsert("loginBili", [{
491
- id: 1,
492
- bili_cookies: encryptedCookies,
493
- bili_refresh_token: encryptedRefreshToken
494
- }]);
495
- this.loginDBData = (await this.ctx.database.get("loginBili", 1))[0];
496
- await this.ctx["bilibili-notify-api"].loadCookiesFromDatabase();
497
- await this.checkIfLoginInfoIsLoaded();
498
- this.loginTimer();
499
- ctx["bilibili-notify-api"].disposeNotifier();
500
- await session.send("登录成功,请重启插件");
501
- }
502
- } finally {
503
- flag = true;
504
- }
505
- }, 1e3);
506
- });
507
477
  biliCom.subcommand(".list", "展示订阅对象").usage("展示订阅对象").example("bili list").action(() => {
508
478
  return this.subShow();
509
479
  });
@@ -521,7 +491,7 @@ var ComRegister = class ComRegister {
521
491
  break;
522
492
  }
523
493
  subLiveUsers.push({
524
- uid: Number.parseInt(uid),
494
+ uid: Number.parseInt(uid, 10),
525
495
  uname: sub.uname,
526
496
  onLive
527
497
  });
@@ -746,6 +716,7 @@ var ComRegister = class ComRegister {
746
716
  this.logger = this.ctx.logger("bilibili-notify-core");
747
717
  this.logger.info("初始化插件中...");
748
718
  this.config = config;
719
+ this.registeringForEvents();
749
720
  this.privateBot = this.ctx.bots.find((bot) => bot.platform === config.master.platform);
750
721
  if (!this.privateBot) this.ctx.notifier.create({ content: "您未配置私人机器人,将无法向您推送机器人状态!" });
751
722
  this.loginDBData = (await this.ctx.database.get("loginBili", 1, ["dynamic_group_id"]))[0];
@@ -754,9 +725,19 @@ var ComRegister = class ComRegister {
754
725
  this.logger.info("账号未登录,请登录");
755
726
  return;
756
727
  }
728
+ const personalInfo = await this.ctx["bilibili-notify-api"].getMyselfInfo();
729
+ if (personalInfo.code !== 0) this.ctx.emit("bilibili-notify/login-status-report", {
730
+ status: BiliLoginStatus.LOGGED_IN,
731
+ msg: "已登录,但获取个人信息失败"
732
+ });
733
+ const myCardInfo = await this.ctx["bilibili-notify-api"].getUserCardInfo(personalInfo.data.mid.toString(), true);
734
+ this.ctx.emit("bilibili-notify/login-status-report", {
735
+ status: BiliLoginStatus.LOGGED_IN,
736
+ msg: "已登录",
737
+ data: myCardInfo.data
738
+ });
757
739
  this.mergeStopWords(config.wordcloudStopWords);
758
740
  this.initAllManager();
759
- this.registeringForEvents();
760
741
  if (config.advancedSub) {
761
742
  this.logger.info("开启高级订阅,等待加载订阅...");
762
743
  this.ctx.emit("bilibili-notify/ready-to-recive");
@@ -766,6 +747,107 @@ var ComRegister = class ComRegister {
766
747
  } else this.logger.info("初始化完毕,未添加任何订阅!");
767
748
  }
768
749
  registeringForEvents() {
750
+ this.ctx.console.addListener("bilibili-notify/start-login", async () => {
751
+ this.logger.info("调用bili login指令");
752
+ let content;
753
+ try {
754
+ content = await this.ctx["bilibili-notify-api"].getLoginQRCode();
755
+ } catch (_) {
756
+ return "bili login getLoginQRCode() 本次网络请求失败";
757
+ }
758
+ if (content.code !== 0) return this.ctx.emit("bilibili-notify/login-status-report", {
759
+ status: BiliLoginStatus.LOGIN_FAILED,
760
+ msg: "获取二维码失败"
761
+ });
762
+ qrcode.default.toBuffer(content.data.url, {
763
+ errorCorrectionLevel: "H",
764
+ type: "png",
765
+ margin: 1,
766
+ color: {
767
+ dark: "#000000",
768
+ light: "#FFFFFF"
769
+ }
770
+ }, async (err, buffer) => {
771
+ if (err) {
772
+ this.logger.error("生成二维码失败", err);
773
+ return this.ctx.emit("bilibili-notify/login-status-report", {
774
+ status: BiliLoginStatus.LOGIN_FAILED,
775
+ msg: "生成二维码失败"
776
+ });
777
+ }
778
+ const url = "data:image/png;base64," + Buffer.from(buffer).toString("base64");
779
+ this.ctx.emit("bilibili-notify/login-status-report", {
780
+ status: BiliLoginStatus.LOGIN_QR,
781
+ msg: "请使用Bilibili App扫码登录",
782
+ data: url
783
+ });
784
+ });
785
+ if (this.loginTimer) this.loginTimer();
786
+ let flag = true;
787
+ this.loginTimer = this.ctx.setInterval(async () => {
788
+ try {
789
+ if (!flag) return;
790
+ flag = false;
791
+ let loginContent;
792
+ try {
793
+ loginContent = await this.ctx["bilibili-notify-api"].getLoginStatus(content.data.qrcode_key);
794
+ } catch (e) {
795
+ this.logger.error(e);
796
+ return;
797
+ }
798
+ if (loginContent.data.code === 86101) return this.ctx.emit("bilibili-notify/login-status-report", {
799
+ status: BiliLoginStatus.LOGGING_QR,
800
+ msg: "未扫码"
801
+ });
802
+ if (loginContent.data.code === 86090) return this.ctx.emit("bilibili-notify/login-status-report", {
803
+ status: BiliLoginStatus.LOGGING_QR,
804
+ msg: "二维码已扫码未确认"
805
+ });
806
+ if (loginContent.data.code === 86038) {
807
+ this.loginTimer();
808
+ return this.ctx.emit("bilibili-notify/login-status-report", {
809
+ status: BiliLoginStatus.LOGIN_FAILED,
810
+ msg: "二维码已失效,请重新登录"
811
+ });
812
+ }
813
+ if (loginContent.data.code === 0) {
814
+ const encryptedCookies = this.ctx["bilibili-notify-api"].encrypt(this.ctx["bilibili-notify-api"].getCookies());
815
+ const encryptedRefreshToken = this.ctx["bilibili-notify-api"].encrypt(loginContent.data.refresh_token);
816
+ await this.ctx.database.upsert("loginBili", [{
817
+ id: 1,
818
+ bili_cookies: encryptedCookies,
819
+ bili_refresh_token: encryptedRefreshToken
820
+ }]);
821
+ this.loginDBData = (await this.ctx.database.get("loginBili", 1))[0];
822
+ await this.ctx["bilibili-notify-api"].loadCookiesFromDatabase();
823
+ await this.checkIfLoginInfoIsLoaded();
824
+ this.loginTimer();
825
+ this.ctx["bilibili-notify-api"].disposeNotifier();
826
+ this.ctx.emit("bilibili-notify/login-status-report", {
827
+ status: BiliLoginStatus.LOGIN_SUCCESS,
828
+ msg: "已登录,请点击按钮重启插件(5s后自动重启)"
829
+ });
830
+ await this.ctx["bilibili-notify"].restartPlugin();
831
+ }
832
+ if (loginContent.code !== 0) {
833
+ this.loginTimer();
834
+ return this.ctx.emit("bilibili-notify/login-status-report", {
835
+ status: BiliLoginStatus.LOGIN_FAILED,
836
+ msg: "登录失败,请重试"
837
+ });
838
+ }
839
+ } finally {
840
+ flag = true;
841
+ }
842
+ }, 1e3);
843
+ });
844
+ this.ctx.console.addListener("bilibili-notify/restart-plugin", async () => {
845
+ await this.ctx["bilibili-notify"].restartPlugin();
846
+ });
847
+ this.ctx.console.addListener("bilibili-notify/request-cors", async (url) => {
848
+ const buffer = await (await fetch(url)).arrayBuffer();
849
+ return "data:image/png;base64," + Buffer.from(buffer).toString("base64");
850
+ });
769
851
  this.ctx.on("dispose", () => {
770
852
  if (this.loginTimer) this.loginTimer();
771
853
  if (this.dynamicJob) this.dynamicJob.stop();
@@ -1336,7 +1418,7 @@ var ComRegister = class ComRegister {
1336
1418
  return await this.broadcastToTargets(uid, msg, liveType === LiveType.StartBroadcasting ? PushType.StartBroadcasting : PushType.Live);
1337
1419
  }
1338
1420
  async segmentDanmaku(danmaku, danmakuWeightRecord) {
1339
- this._jieba.cut(danmaku, true).filter((word) => word.length >= 2 && !this.stopwords.has(word)).map((w) => {
1421
+ this._jieba.cut(danmaku, true).filter((word) => word.length >= 2 && !this.stopwords.has(word)).forEach((w) => {
1340
1422
  danmakuWeightRecord[w] = (danmakuWeightRecord[w] || 0) + 1;
1341
1423
  });
1342
1424
  }
@@ -1416,8 +1498,12 @@ var ComRegister = class ComRegister {
1416
1498
  return customLiveSummary.replace("-dmc", `${danmakuSenderCount}`).replace("-mdn", masterInfo.medalName).replace("-dca", `${danmakuCount}`).replace("-un1", top5DanmakuSender[0][0]).replace("-dc1", `${top5DanmakuSender[0][1]}`).replace("-un2", top5DanmakuSender[1][0]).replace("-dc2", `${top5DanmakuSender[1][1]}`).replace("-un3", top5DanmakuSender[2][0]).replace("-dc3", `${top5DanmakuSender[2][1]}`).replace("-un4", top5DanmakuSender[3][0]).replace("-dc4", `${top5DanmakuSender[3][1]}`).replace("-un5", top5DanmakuSender[4][0]).replace("-dc5", `${top5DanmakuSender[4][1]}`).replaceAll("\\n", "\n");
1417
1499
  })();
1418
1500
  await this.broadcastToTargets(sub.uid, [img, summary], PushType.WordCloudAndLiveSummary);
1419
- Object.keys(danmakuWeightRecord).forEach((key) => delete danmakuWeightRecord[key]);
1420
- Object.keys(danmakuSenderRecord).forEach((key) => delete danmakuSenderRecord[key]);
1501
+ Object.keys(danmakuWeightRecord).forEach((key) => {
1502
+ delete danmakuWeightRecord[key];
1503
+ });
1504
+ Object.keys(danmakuSenderRecord).forEach((key) => {
1505
+ delete danmakuSenderRecord[key];
1506
+ });
1421
1507
  };
1422
1508
  const pushAtTimeFunc = async () => {
1423
1509
  if (!await useLiveRoomInfo(LiveType.LiveBroadcast) && !await useMasterInfo(LiveType.LiveBroadcast)) {
@@ -1635,10 +1721,10 @@ var ComRegister = class ComRegister {
1635
1721
  this.subNotifier = this.ctx.notifier.create(table);
1636
1722
  }
1637
1723
  async checkIfLoginInfoIsLoaded() {
1638
- return new Promise((resolve$1) => {
1724
+ return new Promise((resolve$2) => {
1639
1725
  const check = () => {
1640
1726
  if (!this.ctx["bilibili-notify-api"].getLoginInfoIsLoaded()) this.ctx.setTimeout(check, 500);
1641
- else resolve$1("success");
1727
+ else resolve$2("success");
1642
1728
  };
1643
1729
  check();
1644
1730
  });
@@ -1998,7 +2084,7 @@ var GenerateImg = class GenerateImg extends koishi.Service {
1998
2084
  margin: 0;
1999
2085
  padding: 0;
2000
2086
  box-sizing: border-box;
2001
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2087
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2002
2088
  }
2003
2089
 
2004
2090
  html {
@@ -2161,7 +2247,7 @@ var GenerateImg = class GenerateImg extends koishi.Service {
2161
2247
  margin: 0;
2162
2248
  padding: 0;
2163
2249
  box-sizing: border-box;
2164
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2250
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2165
2251
  }
2166
2252
 
2167
2253
  html {
@@ -2597,7 +2683,7 @@ var GenerateImg = class GenerateImg extends koishi.Service {
2597
2683
  margin: 0;
2598
2684
  padding: 0;
2599
2685
  box-sizing: border-box;
2600
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2686
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2601
2687
  }
2602
2688
 
2603
2689
  html {
@@ -2960,7 +3046,7 @@ var GenerateImg = class GenerateImg extends koishi.Service {
2960
3046
  margin: 0;
2961
3047
  padding: 0;
2962
3048
  box-sizing: border-box;
2963
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
3049
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2964
3050
  }
2965
3051
 
2966
3052
  html {
@@ -3419,7 +3505,7 @@ var GenerateImg = class GenerateImg extends koishi.Service {
3419
3505
  margin: 0;
3420
3506
  padding: 0;
3421
3507
  box-sizing: border-box;
3422
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
3508
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
3423
3509
  }
3424
3510
 
3425
3511
  html {
@@ -3672,6 +3758,7 @@ const GET_LIVE_ROOM_INFO = "https://api.live.bilibili.com/room/v1/Room/get_info"
3672
3758
  const GET_MASTER_INFO = "https://api.live.bilibili.com/live_user/v1/Master/info";
3673
3759
  const GET_TIME_NOW = "https://api.bilibili.com/x/report/click/now";
3674
3760
  const GET_SERVER_UTC_TIME = "https://interface.bilibili.com/serverdate.js";
3761
+ const GET_USER_CARD_INFO = "https://api.bilibili.com/x/web-interface/card";
3675
3762
  const GET_LATEST_UPDATED_UPS = "https://api.bilibili.com/x/polymer/web-dynamic/v1/portal";
3676
3763
  const GET_ONLINE_GOLD_RANK = "https://api.live.bilibili.com//xlive/general-interface/v1/rank/getOnlineGoldRank";
3677
3764
  const GET_USER_INFO_IN_LIVE = "https://api.live.bilibili.com/xlive/app-ucenter/v2/card/user";
@@ -4092,6 +4179,32 @@ var BiliAPI = class extends koishi.Service {
4092
4179
  retries: 3
4093
4180
  });
4094
4181
  }
4182
+ async getUserCardInfo(mid, photo) {
4183
+ const run = async () => {
4184
+ let url = `${GET_USER_CARD_INFO}?mid=${mid}`;
4185
+ if (photo) url += "&photo=true";
4186
+ const { data } = await this.client.get(url);
4187
+ return data;
4188
+ };
4189
+ return await this.pRetry(run, {
4190
+ onFailedAttempt: (error) => {
4191
+ this.logger.error(`getUserInfoInLive() 第${error.attemptNumber}次失败: ${error.message}`);
4192
+ },
4193
+ retries: 3
4194
+ });
4195
+ }
4196
+ async getCORSContent(url) {
4197
+ const run = async () => {
4198
+ const { data } = await this.client.get(url);
4199
+ return data;
4200
+ };
4201
+ return await this.pRetry(run, {
4202
+ onFailedAttempt: (error) => {
4203
+ this.logger.error(`getUserInfoInLive() 第${error.attemptNumber}次失败: ${error.message}`);
4204
+ },
4205
+ retries: 3
4206
+ });
4207
+ }
4095
4208
  async chatWithAI(content) {
4096
4209
  return await this.aiClient.chat.completions.create({
4097
4210
  model: this.apiConfig.ai.model,
@@ -4195,9 +4308,9 @@ var BiliAPI = class extends koishi.Service {
4195
4308
  async getLoginInfoFromDB() {
4196
4309
  const data = (await this.ctx.database.get("loginBili", 1))[0];
4197
4310
  if (data === void 0) {
4198
- this.loginNotifier = this.ctx.notifier.create({
4199
- type: "warning",
4200
- content: "您尚未登录,将无法使用插件提供的指令"
4311
+ this.ctx.emit("bilibili-notify/login-status-report", {
4312
+ status: BiliLoginStatus.NOT_LOGIN,
4313
+ msg: "您尚未登录,请登录后使用插件"
4201
4314
  });
4202
4315
  return {
4203
4316
  cookies: null,
@@ -4212,9 +4325,9 @@ var BiliAPI = class extends koishi.Service {
4212
4325
  refresh_token: decryptedRefreshToken
4213
4326
  };
4214
4327
  } catch (_) {
4215
- this.loginNotifier = this.ctx.notifier.create({
4216
- type: "warning",
4217
- content: "数据库被篡改,请重新登录"
4328
+ this.ctx.emit("bilibili-notify/login-status-report", {
4329
+ status: BiliLoginStatus.NOT_LOGIN,
4330
+ msg: "数据库被篡改,请重新登录"
4218
4331
  });
4219
4332
  await this.ctx.database.remove("loginBili", [1]);
4220
4333
  return {
@@ -4288,16 +4401,13 @@ var BiliAPI = class extends koishi.Service {
4288
4401
  if (!cookies || !refresh_token) return;
4289
4402
  const csrf = cookies.find((cookie) => {
4290
4403
  if (cookie.key === "bili_jct") return true;
4404
+ return false;
4291
4405
  }).value;
4292
4406
  this.checkIfTokenNeedRefresh(refresh_token, csrf);
4293
4407
  }, 36e5);
4294
4408
  }
4295
4409
  async checkIfTokenNeedRefresh(refreshToken, csrf, times = 3) {
4296
4410
  const notifyAndError = async (info) => {
4297
- this.loginNotifier = this.ctx.notifier.create({
4298
- type: "warning",
4299
- content: info
4300
- });
4301
4411
  await this.createNewClient();
4302
4412
  this.refreshCookieTimer();
4303
4413
  throw new Error(info);
@@ -4352,6 +4462,7 @@ var BiliAPI = class extends koishi.Service {
4352
4462
  }]);
4353
4463
  const newCsrf = this.jar.serializeSync().cookies.find((cookie) => {
4354
4464
  if (cookie.key === "bili_jct") return true;
4465
+ return false;
4355
4466
  }).value;
4356
4467
  const { data: aceeptData } = await this.client.post("https://passport.bilibili.com/x/passport-login/web/confirm/refresh", {
4357
4468
  csrf: newCsrf,
@@ -4456,7 +4567,8 @@ var bili_live_default = BLive;
4456
4567
  const inject = [
4457
4568
  "puppeteer",
4458
4569
  "database",
4459
- "notifier"
4570
+ "notifier",
4571
+ "console"
4460
4572
  ];
4461
4573
  const name = "bilibili-notify";
4462
4574
  const usage = `
@@ -4554,10 +4666,10 @@ var ServerManager = class extends koishi.Service {
4554
4666
  };
4555
4667
  disposePlugin = async () => {
4556
4668
  if (this.servers.length === 0) return false;
4557
- await new Promise((resolve$1) => {
4669
+ await new Promise((resolve$2) => {
4558
4670
  for (const fork of this.servers) fork.dispose();
4559
4671
  this.servers = [];
4560
- resolve$1("ok");
4672
+ resolve$2("ok");
4561
4673
  });
4562
4674
  return true;
4563
4675
  };
@@ -4567,15 +4679,15 @@ var ServerManager = class extends koishi.Service {
4567
4679
  return false;
4568
4680
  }
4569
4681
  await this.disposePlugin();
4570
- return new Promise((resolve$1) => {
4682
+ return new Promise((resolve$2) => {
4571
4683
  this.ctx.setTimeout(() => {
4572
4684
  try {
4573
4685
  this.registerPlugin();
4574
4686
  } catch (e) {
4575
4687
  this.logger.error("重启插件失败", e);
4576
- resolve$1(false);
4688
+ resolve$2(false);
4577
4689
  }
4578
- resolve$1(true);
4690
+ resolve$2(true);
4579
4691
  }, 1e3);
4580
4692
  });
4581
4693
  };
@@ -4584,6 +4696,11 @@ function apply(ctx, config) {
4584
4696
  globalConfig = config;
4585
4697
  ctx.plugin(database_exports);
4586
4698
  ctx.plugin(ServerManager);
4699
+ ctx.plugin(BilibiliNotifyDataServer);
4700
+ ctx.console.addEntry({
4701
+ dev: (0, node_path.resolve)(__dirname, "../client/index.ts"),
4702
+ prod: (0, node_path.resolve)(__dirname, "../dist")
4703
+ });
4587
4704
  ctx.middleware((session, next) => {
4588
4705
  if (session.content === "恶魔兔,启动!") return session.send("启动不了一点");
4589
4706
  return next();
package/lib/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Context, ForkScope, Schema, Service } from "koishi";
2
+ import { DataService } from "@koishijs/plugin-console";
2
3
 
3
4
  //#region src/config.d.ts
4
5
  interface BAConfig {
@@ -121,6 +122,28 @@ type Subscription = {
121
122
  customGuardBuy: CustomGuardBuy;
122
123
  };
123
124
  type Subscriptions = Record<string, Subscription>;
125
+ declare enum BiliLoginStatus {
126
+ NOT_LOGIN = 0,
127
+ LOADING_LOGIN_INFO = 1,
128
+ LOGIN_QR = 2,
129
+ LOGGING_QR = 3,
130
+ LOGGING_IN = 4,
131
+ LOGGED_IN = 5,
132
+ LOGIN_SUCCESS = 6,
133
+ LOGIN_FAILED = 7,
134
+ }
135
+ type BiliDataServer = {
136
+ status: BiliLoginStatus;
137
+ msg: string;
138
+ data?: any;
139
+ };
140
+ //#endregion
141
+ //#region src/data_server.d.ts
142
+ declare class BilibiliNotifyDataServer extends DataService<BiliDataServer> {
143
+ private biliData;
144
+ constructor(ctx: Context);
145
+ get(): Promise<BiliDataServer>;
146
+ }
124
147
  //#endregion
125
148
  //#region src/index.d.ts
126
149
  declare const inject: string[];
@@ -133,6 +156,19 @@ declare module "koishi" {
133
156
  interface Events {
134
157
  "bilibili-notify/advanced-sub"(subs: Subscriptions): void;
135
158
  "bilibili-notify/ready-to-recive"(): void;
159
+ "bilibili-notify/login-status-report"(data: BiliDataServer): void;
160
+ }
161
+ }
162
+ declare module "@koishijs/plugin-console" {
163
+ namespace Console {
164
+ interface Services {
165
+ "bilibili-notify": BilibiliNotifyDataServer;
166
+ }
167
+ }
168
+ interface Events {
169
+ "bilibili-notify/start-login"(): void;
170
+ "bilibili-notify/restart-plugin"(): void;
171
+ "bilibili-notify/request-cors"(url: string): any;
136
172
  }
137
173
  }
138
174
  declare class ServerManager extends Service {
package/lib/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Context, ForkScope, Schema, Service } from "koishi";
2
+ import { DataService } from "@koishijs/plugin-console";
2
3
 
3
4
  //#region src/config.d.ts
4
5
  interface BAConfig {
@@ -121,6 +122,28 @@ type Subscription = {
121
122
  customGuardBuy: CustomGuardBuy;
122
123
  };
123
124
  type Subscriptions = Record<string, Subscription>;
125
+ declare enum BiliLoginStatus {
126
+ NOT_LOGIN = 0,
127
+ LOADING_LOGIN_INFO = 1,
128
+ LOGIN_QR = 2,
129
+ LOGGING_QR = 3,
130
+ LOGGING_IN = 4,
131
+ LOGGED_IN = 5,
132
+ LOGIN_SUCCESS = 6,
133
+ LOGIN_FAILED = 7,
134
+ }
135
+ type BiliDataServer = {
136
+ status: BiliLoginStatus;
137
+ msg: string;
138
+ data?: any;
139
+ };
140
+ //#endregion
141
+ //#region src/data_server.d.ts
142
+ declare class BilibiliNotifyDataServer extends DataService<BiliDataServer> {
143
+ private biliData;
144
+ constructor(ctx: Context);
145
+ get(): Promise<BiliDataServer>;
146
+ }
124
147
  //#endregion
125
148
  //#region src/index.d.ts
126
149
  declare const inject: string[];
@@ -133,6 +156,19 @@ declare module "koishi" {
133
156
  interface Events {
134
157
  "bilibili-notify/advanced-sub"(subs: Subscriptions): void;
135
158
  "bilibili-notify/ready-to-recive"(): void;
159
+ "bilibili-notify/login-status-report"(data: BiliDataServer): void;
160
+ }
161
+ }
162
+ declare module "@koishijs/plugin-console" {
163
+ namespace Console {
164
+ interface Services {
165
+ "bilibili-notify": BilibiliNotifyDataServer;
166
+ }
167
+ }
168
+ interface Events {
169
+ "bilibili-notify/start-login"(): void;
170
+ "bilibili-notify/restart-plugin"(): void;
171
+ "bilibili-notify/request-cors"(url: string): any;
136
172
  }
137
173
  }
138
174
  declare class ServerManager extends Service {
package/lib/index.mjs CHANGED
@@ -1,6 +1,8 @@
1
1
  import "node:module";
2
2
  import { Schema, Service, Universal, h } from "koishi";
3
3
  import "@koishijs/plugin-notifier";
4
+ import { DataService } from "@koishijs/plugin-console";
5
+ import { resolve } from "node:path";
4
6
  import "@koishijs/plugin-help";
5
7
  import { GuardLevel, startListen } from "blive-message-listener";
6
8
  import QRCode from "qrcode";
@@ -9,7 +11,6 @@ import { DateTime } from "luxon";
9
11
  import { Jieba } from "@node-rs/jieba";
10
12
  import { dict } from "@node-rs/jieba/dict";
11
13
  import "koishi-plugin-puppeteer";
12
- import { resolve } from "node:path";
13
14
  import { pathToFileURL } from "node:url";
14
15
  import md5 from "md5";
15
16
  import crypto from "node:crypto";
@@ -135,6 +136,67 @@ const BAConfigSchema = Schema.object({
135
136
  dynamicDebugMode: Schema.boolean().default(false).description("动态调试模式,开启后会在控制台输出动态推送的详细信息,用于调试")
136
137
  });
137
138
 
139
+ //#endregion
140
+ //#region src/type/index.ts
141
+ let LiveType = /* @__PURE__ */ function(LiveType$1) {
142
+ LiveType$1[LiveType$1["NotLiveBroadcast"] = 0] = "NotLiveBroadcast";
143
+ LiveType$1[LiveType$1["StartBroadcasting"] = 1] = "StartBroadcasting";
144
+ LiveType$1[LiveType$1["LiveBroadcast"] = 2] = "LiveBroadcast";
145
+ LiveType$1[LiveType$1["StopBroadcast"] = 3] = "StopBroadcast";
146
+ LiveType$1[LiveType$1["FirstLiveBroadcast"] = 4] = "FirstLiveBroadcast";
147
+ return LiveType$1;
148
+ }({});
149
+ let PushType = /* @__PURE__ */ function(PushType$1) {
150
+ PushType$1[PushType$1["Live"] = 0] = "Live";
151
+ PushType$1[PushType$1["Dynamic"] = 1] = "Dynamic";
152
+ PushType$1[PushType$1["DynamicAtAll"] = 2] = "DynamicAtAll";
153
+ PushType$1[PushType$1["StartBroadcasting"] = 3] = "StartBroadcasting";
154
+ PushType$1[PushType$1["LiveGuardBuy"] = 4] = "LiveGuardBuy";
155
+ PushType$1[PushType$1["WordCloudAndLiveSummary"] = 5] = "WordCloudAndLiveSummary";
156
+ PushType$1[PushType$1["Superchat"] = 6] = "Superchat";
157
+ return PushType$1;
158
+ }({});
159
+ const PushTypeMsg = {
160
+ [PushType.Live]: "直播推送",
161
+ [PushType.Dynamic]: "动态推送",
162
+ [PushType.DynamicAtAll]: "动态推送+At全体",
163
+ [PushType.StartBroadcasting]: "开播推送",
164
+ [PushType.LiveGuardBuy]: "上舰推送",
165
+ [PushType.WordCloudAndLiveSummary]: "弹幕词云和直播总结推送",
166
+ [PushType.Superchat]: "SC推送"
167
+ };
168
+ let BiliLoginStatus = /* @__PURE__ */ function(BiliLoginStatus$1) {
169
+ BiliLoginStatus$1[BiliLoginStatus$1["NOT_LOGIN"] = 0] = "NOT_LOGIN";
170
+ BiliLoginStatus$1[BiliLoginStatus$1["LOADING_LOGIN_INFO"] = 1] = "LOADING_LOGIN_INFO";
171
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_QR"] = 2] = "LOGIN_QR";
172
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGGING_QR"] = 3] = "LOGGING_QR";
173
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGGING_IN"] = 4] = "LOGGING_IN";
174
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGGED_IN"] = 5] = "LOGGED_IN";
175
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_SUCCESS"] = 6] = "LOGIN_SUCCESS";
176
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_FAILED"] = 7] = "LOGIN_FAILED";
177
+ return BiliLoginStatus$1;
178
+ }({});
179
+
180
+ //#endregion
181
+ //#region src/data_server.ts
182
+ /** biome-ignore-all assist/source/organizeImports: <import> */
183
+ var BilibiliNotifyDataServer = class extends DataService {
184
+ biliData = {
185
+ status: BiliLoginStatus.LOADING_LOGIN_INFO,
186
+ msg: "正在加载登录信息..."
187
+ };
188
+ constructor(ctx) {
189
+ super(ctx, "bilibili-notify");
190
+ ctx.on("bilibili-notify/login-status-report", (data) => {
191
+ this.biliData = data;
192
+ this.refresh();
193
+ });
194
+ }
195
+ async get() {
196
+ return this.biliData;
197
+ }
198
+ };
199
+
138
200
  //#endregion
139
201
  //#region src/utils/index.ts
140
202
  /**
@@ -184,36 +246,6 @@ function replaceButKeep(oldObj, newObj, keepKeys) {
184
246
  return result;
185
247
  }
186
248
 
187
- //#endregion
188
- //#region src/type/index.ts
189
- let LiveType = /* @__PURE__ */ function(LiveType$1) {
190
- LiveType$1[LiveType$1["NotLiveBroadcast"] = 0] = "NotLiveBroadcast";
191
- LiveType$1[LiveType$1["StartBroadcasting"] = 1] = "StartBroadcasting";
192
- LiveType$1[LiveType$1["LiveBroadcast"] = 2] = "LiveBroadcast";
193
- LiveType$1[LiveType$1["StopBroadcast"] = 3] = "StopBroadcast";
194
- LiveType$1[LiveType$1["FirstLiveBroadcast"] = 4] = "FirstLiveBroadcast";
195
- return LiveType$1;
196
- }({});
197
- let PushType = /* @__PURE__ */ function(PushType$1) {
198
- PushType$1[PushType$1["Live"] = 0] = "Live";
199
- PushType$1[PushType$1["Dynamic"] = 1] = "Dynamic";
200
- PushType$1[PushType$1["DynamicAtAll"] = 2] = "DynamicAtAll";
201
- PushType$1[PushType$1["StartBroadcasting"] = 3] = "StartBroadcasting";
202
- PushType$1[PushType$1["LiveGuardBuy"] = 4] = "LiveGuardBuy";
203
- PushType$1[PushType$1["WordCloudAndLiveSummary"] = 5] = "WordCloudAndLiveSummary";
204
- PushType$1[PushType$1["Superchat"] = 6] = "Superchat";
205
- return PushType$1;
206
- }({});
207
- const PushTypeMsg = {
208
- [PushType.Live]: "直播推送",
209
- [PushType.Dynamic]: "动态推送",
210
- [PushType.DynamicAtAll]: "动态推送+At全体",
211
- [PushType.StartBroadcasting]: "开播推送",
212
- [PushType.LiveGuardBuy]: "上舰推送",
213
- [PushType.WordCloudAndLiveSummary]: "弹幕词云和直播总结推送",
214
- [PushType.Superchat]: "SC推送"
215
- };
216
-
217
249
  //#endregion
218
250
  //#region src/stop_words.ts
219
251
  const stopwords = new Set([
@@ -413,68 +445,6 @@ var ComRegister = class ComRegister {
413
445
  await session.send(`Channel ID: ${session.event.channel.id}`);
414
446
  });
415
447
  const biliCom = ctx.command("bili", "bili-notify插件相关指令", { permissions: ["authority:3"] });
416
- biliCom.subcommand(".login", "登录B站之后才可以进行之后的操作").usage("使用二维码登录,登录B站之后才可以进行之后的操作").example("bili login").action(async ({ session }) => {
417
- this.logger.info("调用bili login指令");
418
- let content;
419
- try {
420
- content = await ctx["bilibili-notify-api"].getLoginQRCode();
421
- } catch (_) {
422
- return "bili login getLoginQRCode() 本次网络请求失败";
423
- }
424
- if (content.code !== 0) return await session.send("出问题咯!");
425
- QRCode.toBuffer(content.data.url, {
426
- errorCorrectionLevel: "H",
427
- type: "png",
428
- margin: 1,
429
- color: {
430
- dark: "#000000",
431
- light: "#FFFFFF"
432
- }
433
- }, async (err, buffer) => {
434
- if (err) return await session.send("二维码生成出错,请重新尝试");
435
- await session.send(h.image(buffer, "image/jpeg"));
436
- });
437
- if (this.loginTimer) this.loginTimer();
438
- let flag = true;
439
- this.loginTimer = ctx.setInterval(async () => {
440
- try {
441
- if (!flag) return;
442
- flag = false;
443
- let loginContent;
444
- try {
445
- loginContent = await ctx["bilibili-notify-api"].getLoginStatus(content.data.qrcode_key);
446
- } catch (e) {
447
- this.logger.error(e);
448
- return;
449
- }
450
- if (loginContent.code !== 0) {
451
- this.loginTimer();
452
- return await session.send("登录失败请重试");
453
- }
454
- if (loginContent.data.code === 86038) {
455
- this.loginTimer();
456
- return await session.send("二维码已失效,请重新登录");
457
- }
458
- if (loginContent.data.code === 0) {
459
- const encryptedCookies = ctx["bilibili-notify-api"].encrypt(ctx["bilibili-notify-api"].getCookies());
460
- const encryptedRefreshToken = ctx["bilibili-notify-api"].encrypt(loginContent.data.refresh_token);
461
- await ctx.database.upsert("loginBili", [{
462
- id: 1,
463
- bili_cookies: encryptedCookies,
464
- bili_refresh_token: encryptedRefreshToken
465
- }]);
466
- this.loginDBData = (await this.ctx.database.get("loginBili", 1))[0];
467
- await this.ctx["bilibili-notify-api"].loadCookiesFromDatabase();
468
- await this.checkIfLoginInfoIsLoaded();
469
- this.loginTimer();
470
- ctx["bilibili-notify-api"].disposeNotifier();
471
- await session.send("登录成功,请重启插件");
472
- }
473
- } finally {
474
- flag = true;
475
- }
476
- }, 1e3);
477
- });
478
448
  biliCom.subcommand(".list", "展示订阅对象").usage("展示订阅对象").example("bili list").action(() => {
479
449
  return this.subShow();
480
450
  });
@@ -492,7 +462,7 @@ var ComRegister = class ComRegister {
492
462
  break;
493
463
  }
494
464
  subLiveUsers.push({
495
- uid: Number.parseInt(uid),
465
+ uid: Number.parseInt(uid, 10),
496
466
  uname: sub.uname,
497
467
  onLive
498
468
  });
@@ -717,6 +687,7 @@ var ComRegister = class ComRegister {
717
687
  this.logger = this.ctx.logger("bilibili-notify-core");
718
688
  this.logger.info("初始化插件中...");
719
689
  this.config = config;
690
+ this.registeringForEvents();
720
691
  this.privateBot = this.ctx.bots.find((bot) => bot.platform === config.master.platform);
721
692
  if (!this.privateBot) this.ctx.notifier.create({ content: "您未配置私人机器人,将无法向您推送机器人状态!" });
722
693
  this.loginDBData = (await this.ctx.database.get("loginBili", 1, ["dynamic_group_id"]))[0];
@@ -725,9 +696,19 @@ var ComRegister = class ComRegister {
725
696
  this.logger.info("账号未登录,请登录");
726
697
  return;
727
698
  }
699
+ const personalInfo = await this.ctx["bilibili-notify-api"].getMyselfInfo();
700
+ if (personalInfo.code !== 0) this.ctx.emit("bilibili-notify/login-status-report", {
701
+ status: BiliLoginStatus.LOGGED_IN,
702
+ msg: "已登录,但获取个人信息失败"
703
+ });
704
+ const myCardInfo = await this.ctx["bilibili-notify-api"].getUserCardInfo(personalInfo.data.mid.toString(), true);
705
+ this.ctx.emit("bilibili-notify/login-status-report", {
706
+ status: BiliLoginStatus.LOGGED_IN,
707
+ msg: "已登录",
708
+ data: myCardInfo.data
709
+ });
728
710
  this.mergeStopWords(config.wordcloudStopWords);
729
711
  this.initAllManager();
730
- this.registeringForEvents();
731
712
  if (config.advancedSub) {
732
713
  this.logger.info("开启高级订阅,等待加载订阅...");
733
714
  this.ctx.emit("bilibili-notify/ready-to-recive");
@@ -737,6 +718,107 @@ var ComRegister = class ComRegister {
737
718
  } else this.logger.info("初始化完毕,未添加任何订阅!");
738
719
  }
739
720
  registeringForEvents() {
721
+ this.ctx.console.addListener("bilibili-notify/start-login", async () => {
722
+ this.logger.info("调用bili login指令");
723
+ let content;
724
+ try {
725
+ content = await this.ctx["bilibili-notify-api"].getLoginQRCode();
726
+ } catch (_) {
727
+ return "bili login getLoginQRCode() 本次网络请求失败";
728
+ }
729
+ if (content.code !== 0) return this.ctx.emit("bilibili-notify/login-status-report", {
730
+ status: BiliLoginStatus.LOGIN_FAILED,
731
+ msg: "获取二维码失败"
732
+ });
733
+ QRCode.toBuffer(content.data.url, {
734
+ errorCorrectionLevel: "H",
735
+ type: "png",
736
+ margin: 1,
737
+ color: {
738
+ dark: "#000000",
739
+ light: "#FFFFFF"
740
+ }
741
+ }, async (err, buffer) => {
742
+ if (err) {
743
+ this.logger.error("生成二维码失败", err);
744
+ return this.ctx.emit("bilibili-notify/login-status-report", {
745
+ status: BiliLoginStatus.LOGIN_FAILED,
746
+ msg: "生成二维码失败"
747
+ });
748
+ }
749
+ const url = "data:image/png;base64," + Buffer.from(buffer).toString("base64");
750
+ this.ctx.emit("bilibili-notify/login-status-report", {
751
+ status: BiliLoginStatus.LOGIN_QR,
752
+ msg: "请使用Bilibili App扫码登录",
753
+ data: url
754
+ });
755
+ });
756
+ if (this.loginTimer) this.loginTimer();
757
+ let flag = true;
758
+ this.loginTimer = this.ctx.setInterval(async () => {
759
+ try {
760
+ if (!flag) return;
761
+ flag = false;
762
+ let loginContent;
763
+ try {
764
+ loginContent = await this.ctx["bilibili-notify-api"].getLoginStatus(content.data.qrcode_key);
765
+ } catch (e) {
766
+ this.logger.error(e);
767
+ return;
768
+ }
769
+ if (loginContent.data.code === 86101) return this.ctx.emit("bilibili-notify/login-status-report", {
770
+ status: BiliLoginStatus.LOGGING_QR,
771
+ msg: "未扫码"
772
+ });
773
+ if (loginContent.data.code === 86090) return this.ctx.emit("bilibili-notify/login-status-report", {
774
+ status: BiliLoginStatus.LOGGING_QR,
775
+ msg: "二维码已扫码未确认"
776
+ });
777
+ if (loginContent.data.code === 86038) {
778
+ this.loginTimer();
779
+ return this.ctx.emit("bilibili-notify/login-status-report", {
780
+ status: BiliLoginStatus.LOGIN_FAILED,
781
+ msg: "二维码已失效,请重新登录"
782
+ });
783
+ }
784
+ if (loginContent.data.code === 0) {
785
+ const encryptedCookies = this.ctx["bilibili-notify-api"].encrypt(this.ctx["bilibili-notify-api"].getCookies());
786
+ const encryptedRefreshToken = this.ctx["bilibili-notify-api"].encrypt(loginContent.data.refresh_token);
787
+ await this.ctx.database.upsert("loginBili", [{
788
+ id: 1,
789
+ bili_cookies: encryptedCookies,
790
+ bili_refresh_token: encryptedRefreshToken
791
+ }]);
792
+ this.loginDBData = (await this.ctx.database.get("loginBili", 1))[0];
793
+ await this.ctx["bilibili-notify-api"].loadCookiesFromDatabase();
794
+ await this.checkIfLoginInfoIsLoaded();
795
+ this.loginTimer();
796
+ this.ctx["bilibili-notify-api"].disposeNotifier();
797
+ this.ctx.emit("bilibili-notify/login-status-report", {
798
+ status: BiliLoginStatus.LOGIN_SUCCESS,
799
+ msg: "已登录,请点击按钮重启插件(5s后自动重启)"
800
+ });
801
+ await this.ctx["bilibili-notify"].restartPlugin();
802
+ }
803
+ if (loginContent.code !== 0) {
804
+ this.loginTimer();
805
+ return this.ctx.emit("bilibili-notify/login-status-report", {
806
+ status: BiliLoginStatus.LOGIN_FAILED,
807
+ msg: "登录失败,请重试"
808
+ });
809
+ }
810
+ } finally {
811
+ flag = true;
812
+ }
813
+ }, 1e3);
814
+ });
815
+ this.ctx.console.addListener("bilibili-notify/restart-plugin", async () => {
816
+ await this.ctx["bilibili-notify"].restartPlugin();
817
+ });
818
+ this.ctx.console.addListener("bilibili-notify/request-cors", async (url) => {
819
+ const buffer = await (await fetch(url)).arrayBuffer();
820
+ return "data:image/png;base64," + Buffer.from(buffer).toString("base64");
821
+ });
740
822
  this.ctx.on("dispose", () => {
741
823
  if (this.loginTimer) this.loginTimer();
742
824
  if (this.dynamicJob) this.dynamicJob.stop();
@@ -1307,7 +1389,7 @@ var ComRegister = class ComRegister {
1307
1389
  return await this.broadcastToTargets(uid, msg, liveType === LiveType.StartBroadcasting ? PushType.StartBroadcasting : PushType.Live);
1308
1390
  }
1309
1391
  async segmentDanmaku(danmaku, danmakuWeightRecord) {
1310
- this._jieba.cut(danmaku, true).filter((word) => word.length >= 2 && !this.stopwords.has(word)).map((w) => {
1392
+ this._jieba.cut(danmaku, true).filter((word) => word.length >= 2 && !this.stopwords.has(word)).forEach((w) => {
1311
1393
  danmakuWeightRecord[w] = (danmakuWeightRecord[w] || 0) + 1;
1312
1394
  });
1313
1395
  }
@@ -1387,8 +1469,12 @@ var ComRegister = class ComRegister {
1387
1469
  return customLiveSummary.replace("-dmc", `${danmakuSenderCount}`).replace("-mdn", masterInfo.medalName).replace("-dca", `${danmakuCount}`).replace("-un1", top5DanmakuSender[0][0]).replace("-dc1", `${top5DanmakuSender[0][1]}`).replace("-un2", top5DanmakuSender[1][0]).replace("-dc2", `${top5DanmakuSender[1][1]}`).replace("-un3", top5DanmakuSender[2][0]).replace("-dc3", `${top5DanmakuSender[2][1]}`).replace("-un4", top5DanmakuSender[3][0]).replace("-dc4", `${top5DanmakuSender[3][1]}`).replace("-un5", top5DanmakuSender[4][0]).replace("-dc5", `${top5DanmakuSender[4][1]}`).replaceAll("\\n", "\n");
1388
1470
  })();
1389
1471
  await this.broadcastToTargets(sub.uid, [img, summary], PushType.WordCloudAndLiveSummary);
1390
- Object.keys(danmakuWeightRecord).forEach((key) => delete danmakuWeightRecord[key]);
1391
- Object.keys(danmakuSenderRecord).forEach((key) => delete danmakuSenderRecord[key]);
1472
+ Object.keys(danmakuWeightRecord).forEach((key) => {
1473
+ delete danmakuWeightRecord[key];
1474
+ });
1475
+ Object.keys(danmakuSenderRecord).forEach((key) => {
1476
+ delete danmakuSenderRecord[key];
1477
+ });
1392
1478
  };
1393
1479
  const pushAtTimeFunc = async () => {
1394
1480
  if (!await useLiveRoomInfo(LiveType.LiveBroadcast) && !await useMasterInfo(LiveType.LiveBroadcast)) {
@@ -1969,7 +2055,7 @@ var GenerateImg = class GenerateImg extends Service {
1969
2055
  margin: 0;
1970
2056
  padding: 0;
1971
2057
  box-sizing: border-box;
1972
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2058
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
1973
2059
  }
1974
2060
 
1975
2061
  html {
@@ -2132,7 +2218,7 @@ var GenerateImg = class GenerateImg extends Service {
2132
2218
  margin: 0;
2133
2219
  padding: 0;
2134
2220
  box-sizing: border-box;
2135
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2221
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2136
2222
  }
2137
2223
 
2138
2224
  html {
@@ -2568,7 +2654,7 @@ var GenerateImg = class GenerateImg extends Service {
2568
2654
  margin: 0;
2569
2655
  padding: 0;
2570
2656
  box-sizing: border-box;
2571
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2657
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2572
2658
  }
2573
2659
 
2574
2660
  html {
@@ -2931,7 +3017,7 @@ var GenerateImg = class GenerateImg extends Service {
2931
3017
  margin: 0;
2932
3018
  padding: 0;
2933
3019
  box-sizing: border-box;
2934
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
3020
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2935
3021
  }
2936
3022
 
2937
3023
  html {
@@ -3390,7 +3476,7 @@ var GenerateImg = class GenerateImg extends Service {
3390
3476
  margin: 0;
3391
3477
  padding: 0;
3392
3478
  box-sizing: border-box;
3393
- font-family: \"${this.giConfig.font}\", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
3479
+ font-family: "${this.giConfig.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
3394
3480
  }
3395
3481
 
3396
3482
  html {
@@ -3643,6 +3729,7 @@ const GET_LIVE_ROOM_INFO = "https://api.live.bilibili.com/room/v1/Room/get_info"
3643
3729
  const GET_MASTER_INFO = "https://api.live.bilibili.com/live_user/v1/Master/info";
3644
3730
  const GET_TIME_NOW = "https://api.bilibili.com/x/report/click/now";
3645
3731
  const GET_SERVER_UTC_TIME = "https://interface.bilibili.com/serverdate.js";
3732
+ const GET_USER_CARD_INFO = "https://api.bilibili.com/x/web-interface/card";
3646
3733
  const GET_LATEST_UPDATED_UPS = "https://api.bilibili.com/x/polymer/web-dynamic/v1/portal";
3647
3734
  const GET_ONLINE_GOLD_RANK = "https://api.live.bilibili.com//xlive/general-interface/v1/rank/getOnlineGoldRank";
3648
3735
  const GET_USER_INFO_IN_LIVE = "https://api.live.bilibili.com/xlive/app-ucenter/v2/card/user";
@@ -4063,6 +4150,32 @@ var BiliAPI = class extends Service {
4063
4150
  retries: 3
4064
4151
  });
4065
4152
  }
4153
+ async getUserCardInfo(mid, photo) {
4154
+ const run = async () => {
4155
+ let url = `${GET_USER_CARD_INFO}?mid=${mid}`;
4156
+ if (photo) url += "&photo=true";
4157
+ const { data } = await this.client.get(url);
4158
+ return data;
4159
+ };
4160
+ return await this.pRetry(run, {
4161
+ onFailedAttempt: (error) => {
4162
+ this.logger.error(`getUserInfoInLive() 第${error.attemptNumber}次失败: ${error.message}`);
4163
+ },
4164
+ retries: 3
4165
+ });
4166
+ }
4167
+ async getCORSContent(url) {
4168
+ const run = async () => {
4169
+ const { data } = await this.client.get(url);
4170
+ return data;
4171
+ };
4172
+ return await this.pRetry(run, {
4173
+ onFailedAttempt: (error) => {
4174
+ this.logger.error(`getUserInfoInLive() 第${error.attemptNumber}次失败: ${error.message}`);
4175
+ },
4176
+ retries: 3
4177
+ });
4178
+ }
4066
4179
  async chatWithAI(content) {
4067
4180
  return await this.aiClient.chat.completions.create({
4068
4181
  model: this.apiConfig.ai.model,
@@ -4166,9 +4279,9 @@ var BiliAPI = class extends Service {
4166
4279
  async getLoginInfoFromDB() {
4167
4280
  const data = (await this.ctx.database.get("loginBili", 1))[0];
4168
4281
  if (data === void 0) {
4169
- this.loginNotifier = this.ctx.notifier.create({
4170
- type: "warning",
4171
- content: "您尚未登录,将无法使用插件提供的指令"
4282
+ this.ctx.emit("bilibili-notify/login-status-report", {
4283
+ status: BiliLoginStatus.NOT_LOGIN,
4284
+ msg: "您尚未登录,请登录后使用插件"
4172
4285
  });
4173
4286
  return {
4174
4287
  cookies: null,
@@ -4183,9 +4296,9 @@ var BiliAPI = class extends Service {
4183
4296
  refresh_token: decryptedRefreshToken
4184
4297
  };
4185
4298
  } catch (_) {
4186
- this.loginNotifier = this.ctx.notifier.create({
4187
- type: "warning",
4188
- content: "数据库被篡改,请重新登录"
4299
+ this.ctx.emit("bilibili-notify/login-status-report", {
4300
+ status: BiliLoginStatus.NOT_LOGIN,
4301
+ msg: "数据库被篡改,请重新登录"
4189
4302
  });
4190
4303
  await this.ctx.database.remove("loginBili", [1]);
4191
4304
  return {
@@ -4259,16 +4372,13 @@ var BiliAPI = class extends Service {
4259
4372
  if (!cookies || !refresh_token) return;
4260
4373
  const csrf = cookies.find((cookie) => {
4261
4374
  if (cookie.key === "bili_jct") return true;
4375
+ return false;
4262
4376
  }).value;
4263
4377
  this.checkIfTokenNeedRefresh(refresh_token, csrf);
4264
4378
  }, 36e5);
4265
4379
  }
4266
4380
  async checkIfTokenNeedRefresh(refreshToken, csrf, times = 3) {
4267
4381
  const notifyAndError = async (info) => {
4268
- this.loginNotifier = this.ctx.notifier.create({
4269
- type: "warning",
4270
- content: info
4271
- });
4272
4382
  await this.createNewClient();
4273
4383
  this.refreshCookieTimer();
4274
4384
  throw new Error(info);
@@ -4323,6 +4433,7 @@ var BiliAPI = class extends Service {
4323
4433
  }]);
4324
4434
  const newCsrf = this.jar.serializeSync().cookies.find((cookie) => {
4325
4435
  if (cookie.key === "bili_jct") return true;
4436
+ return false;
4326
4437
  }).value;
4327
4438
  const { data: aceeptData } = await this.client.post("https://passport.bilibili.com/x/passport-login/web/confirm/refresh", {
4328
4439
  csrf: newCsrf,
@@ -4427,7 +4538,8 @@ var bili_live_default = BLive;
4427
4538
  const inject = [
4428
4539
  "puppeteer",
4429
4540
  "database",
4430
- "notifier"
4541
+ "notifier",
4542
+ "console"
4431
4543
  ];
4432
4544
  const name = "bilibili-notify";
4433
4545
  const usage = `
@@ -4555,6 +4667,11 @@ function apply(ctx, config) {
4555
4667
  globalConfig = config;
4556
4668
  ctx.plugin(database_exports);
4557
4669
  ctx.plugin(ServerManager);
4670
+ ctx.plugin(BilibiliNotifyDataServer);
4671
+ ctx.console.addEntry({
4672
+ dev: resolve(__dirname, "../client/index.ts"),
4673
+ prod: resolve(__dirname, "../dist")
4674
+ });
4558
4675
  ctx.middleware((session, next) => {
4559
4676
  if (session.content === "恶魔兔,启动!") return session.send("启动不了一点");
4560
4677
  return next();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-bilibili-notify",
3
3
  "description": "Koishi bilibili notify plugin",
4
- "version": "3.5.0",
4
+ "version": "3.6.0-alpha.0",
5
5
  "main": "./lib/index.cjs",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -43,6 +43,7 @@
43
43
  "tough-cookie": "^6.0.0"
44
44
  },
45
45
  "devDependencies": {
46
+ "@koishijs/client": "^5.30.11",
46
47
  "@types/jsdom": "^27.0.0",
47
48
  "@types/luxon": "^3.7.1",
48
49
  "@types/md5": "^2.3.6",
@@ -52,6 +53,7 @@
52
53
  "tsdown": "^0.16.6"
53
54
  },
54
55
  "peerDependencies": {
56
+ "@koishijs/plugin-console": "^5.30.11",
55
57
  "koishi": "^4.18.9"
56
58
  },
57
59
  "engines": {