koishi-plugin-bilibili-notify 1.0.13 → 1.0.14

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/biliAPI.d.ts CHANGED
@@ -12,6 +12,7 @@ declare class BiliAPI extends Service {
12
12
  client: any;
13
13
  loginData: any;
14
14
  loginNotifier: Notifier;
15
+ refreshCookieTimer: Function;
15
16
  constructor(ctx: Context);
16
17
  protected start(): void | Promise<void>;
17
18
  getServerUTCTime(): Promise<number>;
package/lib/biliAPI.js CHANGED
@@ -25,6 +25,7 @@ class BiliAPI extends koishi_1.Service {
25
25
  client;
26
26
  loginData;
27
27
  loginNotifier;
28
+ refreshCookieTimer;
28
29
  constructor(ctx) {
29
30
  super(ctx, 'biliAPI');
30
31
  }
@@ -35,6 +36,52 @@ class BiliAPI extends koishi_1.Service {
35
36
  this.loadCookiesFromDatabase();
36
37
  // this.logger.info('BiliAPI已被注册到Context中')
37
38
  }
39
+ /* async test_refresh_token() {
40
+ const publicKey = await crypto.subtle.importKey(
41
+ "jwk",
42
+ {
43
+ kty: "RSA",
44
+ n: "y4HdjgJHBlbaBN04VERG4qNBIFHP6a3GozCl75AihQloSWCXC5HDNgyinEnhaQ_4-gaMud_GF50elYXLlCToR9se9Z8z433U3KjM-3Yx7ptKkmQNAMggQwAVKgq3zYAoidNEWuxpkY_mAitTSRLnsJW-NCTa0bqBFF6Wm1MxgfE",
45
+ e: "AQAB",
46
+ },
47
+ { name: "RSA-OAEP", hash: "SHA-256" },
48
+ true,
49
+ ["encrypt"],
50
+ )
51
+
52
+ async function getCorrespondPath(timestamp) {
53
+ const data = new TextEncoder().encode(`refresh_${timestamp}`);
54
+ const encrypted = new Uint8Array(await crypto.subtle.encrypt({ name: "RSA-OAEP" }, publicKey, data))
55
+ return encrypted.reduce((str, c) => str + c.toString(16).padStart(2, "0"), "")
56
+ }
57
+
58
+ const ts = Date.now()
59
+ const correspondPath = await getCorrespondPath(ts)
60
+ const { data } = await this.client.get(`https://www.bilibili.com/correspond/1/${correspondPath}`)
61
+ // 创建一个虚拟的DOM元素
62
+ const { document } = new JSDOM(data).window;
63
+ // 提取标签name为1-name的内容
64
+ const targetElement = document.getElementById('1-name');
65
+ const refresh_csrf = targetElement ? targetElement.textContent : null;
66
+ // 获取csrf
67
+ let csrf: string
68
+ const cookies = JSON.parse(this.getCookies())
69
+ cookies.forEach(cookie => {
70
+ if (cookie.key === 'bili_jct') csrf = cookie.value
71
+ })
72
+ // 读取数据库获取cookies
73
+ const database = (await this.ctx.database.get('loginBili', 1))[0]
74
+ // 获取refreshToken
75
+ const refresh_token = this.ctx.wbi.decrypt(database.bili_refresh_token)
76
+ // 发送请求
77
+ const { data: refreshData } = await this.client.post('https://passport.bilibili.com/x/passport-login/web/cookie/refresh', {
78
+ csrf,
79
+ refresh_csrf,
80
+ source: 'main_web',
81
+ refresh_token
82
+ })
83
+ console.log(refreshData);
84
+ } */
38
85
  async getServerUTCTime() {
39
86
  try {
40
87
  const { data } = await this.client.get(GET_SERVER_UTC_TIME);
@@ -204,12 +251,28 @@ class BiliAPI extends koishi_1.Service {
204
251
  // restart plugin check
205
252
  this.checkIfTokenNeedRefresh(decryptedRefreshToken, csrf);
206
253
  // Open scheduled tasks and check if token need refresh
207
- this.ctx.setInterval(() => {
254
+ this.refreshCookieTimer = this.ctx.setInterval(() => {
208
255
  this.checkIfTokenNeedRefresh(decryptedRefreshToken, csrf);
209
256
  }, 43200000);
210
257
  }
211
258
  async checkIfTokenNeedRefresh(refreshToken, csrf, times = 0) {
259
+ // 定义数据
212
260
  let data;
261
+ // 定义方法
262
+ const notifyAndError = (info) => {
263
+ // 设置控制台通知
264
+ this.loginNotifier = this.ctx.notifier.create({
265
+ type: 'warning',
266
+ content: info
267
+ });
268
+ // 重置为未登录状态
269
+ this.createNewClient();
270
+ // 关闭定时器
271
+ this.refreshCookieTimer();
272
+ // 抛出错误
273
+ throw new Error(info);
274
+ };
275
+ // 尝试获取Cookieinfo
213
276
  try {
214
277
  const { data: cookieData } = await this.getCookieInfo(refreshToken);
215
278
  data = cookieData;
@@ -227,17 +290,21 @@ class BiliAPI extends koishi_1.Service {
227
290
  // 不需要刷新,直接返回
228
291
  if (!data.refresh)
229
292
  return;
293
+ // 定义Key
230
294
  const publicKey = await crypto.subtle.importKey("jwk", {
231
295
  kty: "RSA",
232
296
  n: "y4HdjgJHBlbaBN04VERG4qNBIFHP6a3GozCl75AihQloSWCXC5HDNgyinEnhaQ_4-gaMud_GF50elYXLlCToR9se9Z8z433U3KjM-3Yx7ptKkmQNAMggQwAVKgq3zYAoidNEWuxpkY_mAitTSRLnsJW-NCTa0bqBFF6Wm1MxgfE",
233
297
  e: "AQAB",
234
298
  }, { name: "RSA-OAEP", hash: "SHA-256" }, true, ["encrypt"]);
299
+ // 定义获取CorrespondPath方法
235
300
  async function getCorrespondPath(timestamp) {
236
301
  const data = new TextEncoder().encode(`refresh_${timestamp}`);
237
302
  const encrypted = new Uint8Array(await crypto.subtle.encrypt({ name: "RSA-OAEP" }, publicKey, data));
238
303
  return encrypted.reduce((str, c) => str + c.toString(16).padStart(2, "0"), "");
239
304
  }
240
- const correspondPath = await getCorrespondPath(data.timestamp);
305
+ // 获取CorrespondPath
306
+ const ts = Date.now();
307
+ const correspondPath = await getCorrespondPath(ts);
241
308
  // 获取refresh_csrf
242
309
  const { data: refreshCsrfHtml } = await this.client.get(`https://www.bilibili.com/correspond/1/${correspondPath}`);
243
310
  // 创建一个虚拟的DOM元素
@@ -247,19 +314,11 @@ class BiliAPI extends koishi_1.Service {
247
314
  const refresh_csrf = targetElement ? targetElement.textContent : null;
248
315
  // 发送刷新请求
249
316
  const { data: refreshData } = await this.client.post('https://passport.bilibili.com/x/passport-login/web/cookie/refresh', {
250
- csrf: csrf.trim(),
317
+ csrf,
251
318
  refresh_csrf,
252
319
  source: 'main_web',
253
320
  refresh_token: refreshToken
254
321
  });
255
- const notifyAndError = (info) => {
256
- // 设置控制台通知
257
- this.loginNotifier = this.ctx.notifier.create({
258
- type: 'warning',
259
- content: info
260
- });
261
- throw new Error(info);
262
- };
263
322
  // 检查是否有其他问题
264
323
  switch (refreshData.code) {
265
324
  // 账号未登录
@@ -283,12 +342,6 @@ class BiliAPI extends koishi_1.Service {
283
342
  }]);
284
343
  // Get new csrf from cookies
285
344
  let newCsrf;
286
- /* this.jar.store.getAllCookies((err, c) => {
287
- if (err) throw err;
288
- c.forEach(cookie => {
289
- if (cookie.key === 'bili_jct') newCsrf = cookie.value
290
- });
291
- }) */
292
345
  this.jar.serializeSync().cookies.forEach(cookie => {
293
346
  if (cookie.key === 'bili_jct')
294
347
  newCsrf = cookie.value;
@@ -20,6 +20,7 @@ declare class ComRegister {
20
20
  qqBot: Bot<Context>;
21
21
  qqguildBot: Bot<Context>;
22
22
  oneBot: Bot<Context>;
23
+ redBot: Bot<Context>;
23
24
  constructor(ctx: Context, config: ComRegister.Config);
24
25
  dynamicDetect(ctx: Context, bot: Bot<Context>, guildId: string, uid: string): () => Promise<void>;
25
26
  liveDetect(ctx: Context, bot: Bot<Context>, guildId: string, roomId: string): () => Promise<string[]>;
@@ -33,6 +34,7 @@ declare class ComRegister {
33
34
  declare namespace ComRegister {
34
35
  interface Config {
35
36
  unlockSubLimits: boolean;
37
+ liveStartAtAll: boolean;
36
38
  pushTime: number;
37
39
  liveLoopTime: number;
38
40
  dynamicLoopTime: number;
@@ -27,15 +27,20 @@ class ComRegister {
27
27
  qqguildBot;
28
28
  // OneBot机器人
29
29
  oneBot;
30
+ // Red机器人
31
+ redBot;
30
32
  constructor(ctx, config) {
31
33
  this.logger = ctx.logger('commandRegister');
32
34
  this.config = config;
33
- // 拿到QQ群机器人
34
- this.qqBot = ctx.bots.find(bot => bot.platform === 'qq');
35
- // 拿到QQ频道机器人
36
- this.qqguildBot = ctx.bots.find(bot => bot.platform === 'qqguild');
37
- // 拿到OneBot机器人
38
- this.oneBot = ctx.bots.find(bot => bot.platform === 'onebot');
35
+ // 拿到各类机器人
36
+ ctx.bots.forEach(bot => {
37
+ switch (bot.platform) {
38
+ case 'qq': this.qqBot = bot;
39
+ case 'qqguild': this.qqguildBot = bot;
40
+ case 'onebot': this.oneBot = bot;
41
+ case ' red': this.redBot = bot;
42
+ }
43
+ });
39
44
  // 从数据库获取订阅
40
45
  this.getSubFromDatabase(ctx);
41
46
  /* const testCom = ctx.command('test', { hidden: true, permissions: ['authority:5'] })
@@ -45,7 +50,7 @@ class ComRegister {
45
50
  .action(async () => {
46
51
  this.logger.info('调用test cookies指令')
47
52
  // await ctx.biliAPI.loadCookiesFromDatabase()
48
- console.log(ctx.biliAPI.getCookies());
53
+ console.log(JSON.parse(ctx.biliAPI.getCookies()));
49
54
  })
50
55
 
51
56
  testCom
@@ -120,6 +125,14 @@ class ComRegister {
120
125
  .example('test utc')
121
126
  .action(async ({ session }) => {
122
127
  session.send((await ctx.biliAPI.getServerUTCTime()).toString())
128
+ })
129
+
130
+ testCom
131
+ .subcommand('.refresh')
132
+ .usage('测试cookie刷新方法')
133
+ .example('test refresh')
134
+ .action(async ({ session }) => {
135
+ ctx.biliAPI.test_refresh_token()
123
136
  }) */
124
137
  const biliCom = ctx.command('bili', 'bili-notify插件相关指令', { permissions: ['authority:3'] });
125
138
  biliCom.subcommand('.login', '登录B站之后才可以进行之后的操作')
@@ -154,43 +167,55 @@ class ComRegister {
154
167
  });
155
168
  // 检查之前是否存在登录定时器
156
169
  this.loginTimer && this.loginTimer();
170
+ // 设置flag
171
+ let flag = true;
157
172
  // 发起登录请求检查登录状态
158
173
  this.loginTimer = ctx.setInterval(async () => {
159
- let loginContent;
160
174
  try {
161
- loginContent = await ctx.biliAPI.getLoginStatus(content.data.qrcode_key);
162
- }
163
- catch (e) {
164
- this.logger.error(e);
165
- return;
166
- }
167
- if (loginContent.code !== 0) {
168
- this.loginTimer();
169
- return await session.send('登录失败请联系管理员解决');
170
- }
171
- if (loginContent.data.code === 86038) {
172
- this.loginTimer();
173
- return await session.send('二维码已失效,请重新登录');
175
+ // 判断上一个循环是否完成
176
+ if (!flag)
177
+ return;
178
+ flag = false;
179
+ // 获取登录信息
180
+ let loginContent;
181
+ try {
182
+ loginContent = await ctx.biliAPI.getLoginStatus(content.data.qrcode_key);
183
+ }
184
+ catch (e) {
185
+ this.logger.error(e);
186
+ return;
187
+ }
188
+ if (loginContent.code !== 0) {
189
+ this.loginTimer();
190
+ return await session.send('登录失败请联系管理员解决');
191
+ }
192
+ if (loginContent.data.code === 86038) {
193
+ this.loginTimer();
194
+ return await session.send('二维码已失效,请重新登录');
195
+ }
196
+ if (loginContent.data.code === 0) { // 登录成功
197
+ const encryptedCookies = ctx.wbi.encrypt(ctx.biliAPI.getCookies());
198
+ const encryptedRefreshToken = ctx.wbi.encrypt(loginContent.data.refresh_token);
199
+ await ctx.database.upsert('loginBili', [{
200
+ id: 1,
201
+ bili_cookies: encryptedCookies,
202
+ bili_refresh_token: encryptedRefreshToken
203
+ }]);
204
+ // 销毁定时器
205
+ this.loginTimer();
206
+ // 订阅之前的订阅
207
+ await this.getSubFromDatabase(ctx);
208
+ // 清除控制台通知
209
+ ctx.biliAPI.disposeNotifier();
210
+ // 发送成功登录推送
211
+ await session.send('登录成功');
212
+ // bili show
213
+ await session.execute('bili show');
214
+ return;
215
+ }
174
216
  }
175
- if (loginContent.data.code === 0) { // 登录成功
176
- const encryptedCookies = ctx.wbi.encrypt(ctx.biliAPI.getCookies());
177
- const encryptedRefreshToken = ctx.wbi.encrypt(loginContent.data.refresh_token);
178
- await ctx.database.upsert('loginBili', [{
179
- id: 1,
180
- bili_cookies: encryptedCookies,
181
- bili_refresh_token: encryptedRefreshToken
182
- }]);
183
- // 销毁定时器
184
- this.loginTimer();
185
- // 订阅之前的订阅
186
- await this.getSubFromDatabase(ctx);
187
- // 清除控制台通知
188
- ctx.biliAPI.disposeNotifier();
189
- // 发送成功登录推送
190
- await session.send('登录成功');
191
- // bili show
192
- await session.execute('bili show');
193
- return;
217
+ finally {
218
+ flag = true;
194
219
  }
195
220
  }, 1000);
196
221
  });
@@ -315,11 +340,12 @@ class ComRegister {
315
340
  if (!liveMsg && !dynamicMsg) {
316
341
  return '您未订阅该UP的任何消息';
317
342
  }
318
- // 设置群号
319
- if (!guildId) { // 没有输入群号,默认当前聊天环境
343
+ // 设置频道号
344
+ if (!guildId) { // 没有输入频道号,默认当前聊天环境
320
345
  switch (session.event.platform) {
321
- case 'qqguild':
346
+ case 'red':
322
347
  case 'onebot':
348
+ case 'qqguild':
323
349
  guildId = session.event.channel.id;
324
350
  break;
325
351
  case 'qq':
@@ -413,6 +439,9 @@ class ComRegister {
413
439
  case 'onebot':
414
440
  bot = this.oneBot;
415
441
  break;
442
+ case 'red':
443
+ bot = this.redBot;
444
+ break;
416
445
  default: return '非法调用';
417
446
  }
418
447
  // 开始循环检测
@@ -451,6 +480,9 @@ class ComRegister {
451
480
  case 'onebot':
452
481
  bot = this.oneBot;
453
482
  break;
483
+ case 'red':
484
+ bot = this.redBot;
485
+ break;
454
486
  default: return '非法调用';
455
487
  }
456
488
  // 开始循环检测
@@ -753,6 +785,11 @@ class ComRegister {
753
785
  uData = userData;
754
786
  // 发送直播通知卡片
755
787
  sendLiveNotifyCard(data, uData, LiveType.StartBroadcasting);
788
+ // 判断是否需要@全体成员
789
+ if (this.config.liveStartAtAll) {
790
+ // 发送@全体成员通知
791
+ bot.sendMessage(guildId, (0, jsx_runtime_1.jsx)("at", { type: "all" }));
792
+ }
756
793
  }
757
794
  else { // 还在直播
758
795
  if (this.config.pushTime > 0) {
@@ -881,6 +918,9 @@ class ComRegister {
881
918
  case 'onebot':
882
919
  bot = this.oneBot;
883
920
  break;
921
+ case 'red':
922
+ bot = this.redBot;
923
+ break;
884
924
  default: {
885
925
  // 本条数据被篡改,删除该条订阅
886
926
  ctx.database.remove('bilibili', { id: sub.id });
@@ -1040,6 +1080,7 @@ class ComRegister {
1040
1080
  (function (ComRegister) {
1041
1081
  ComRegister.Config = koishi_1.Schema.object({
1042
1082
  unlockSubLimits: koishi_1.Schema.boolean().required(),
1083
+ liveStartAtAll: koishi_1.Schema.boolean().required(),
1043
1084
  pushTime: koishi_1.Schema.number().required(),
1044
1085
  liveLoopTime: koishi_1.Schema.number().default(10),
1045
1086
  dynamicLoopTime: koishi_1.Schema.number().default(60),
package/lib/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export interface Config {
6
6
  key: string;
7
7
  basicSettings: {};
8
8
  unlockSubLimits: boolean;
9
+ liveStartAtAll: boolean;
9
10
  pushTime: number;
10
11
  dynamicCheckNumber: number;
11
12
  dynamicLoopTime: '1分钟' | '2分钟' | '3分钟' | '5分钟';
package/lib/index.js CHANGED
@@ -49,6 +49,10 @@ exports.Config = koishi_1.Schema.object({
49
49
  unlockSubLimits: koishi_1.Schema.boolean()
50
50
  .default(false)
51
51
  .description('解锁3个订阅限制,默认只允许订阅3位UP主。订阅过多用户可能有导致IP暂时被封禁的风险'),
52
+ liveStartAtAll: koishi_1.Schema.boolean()
53
+ .default(false)
54
+ .experimental()
55
+ .description('直播开始时艾特全体成员,默认关闭'),
52
56
  pushTime: koishi_1.Schema.number()
53
57
  .min(0)
54
58
  .max(12)
@@ -61,7 +65,7 @@ exports.Config = koishi_1.Schema.object({
61
65
  .role('slider')
62
66
  .step(1)
63
67
  .default(5)
64
- .description('设定每次检查动态的数量。若订阅的UP主经常在短时间内连着发多条动态可以将该值提高,若订阅的UP主有置顶动态,在计算该值时应-1。默认值为5条'),
68
+ .description('设定每次检查动态的数量。若订阅的UP主经常在短时间内连着发多条动态可以将该值提高,若订阅的UP主有置顶动态,在计算该值时应+1。默认值为5条'),
65
69
  dynamicLoopTime: koishi_1.Schema.union(['1分钟', '2分钟', '3分钟', '5分钟'])
66
70
  .role('')
67
71
  .default('2分钟')
@@ -163,6 +167,7 @@ function apply(ctx, config) {
163
167
  // ctx.plugin(Authority)
164
168
  ctx.plugin(comRegister_1.default, {
165
169
  unlockSubLimits: config.unlockSubLimits,
170
+ liveStartAtAll: config.liveStartAtAll,
166
171
  pushTime: config.pushTime,
167
172
  dynamicCheckNumber: config.dynamicCheckNumber,
168
173
  dynamicLoopTime
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": "1.0.13",
4
+ "version": "1.0.14",
5
5
  "contributors": [
6
6
  "Akokko <admin@akokko.com>"
7
7
  ],
package/readme.md CHANGED
@@ -89,6 +89,7 @@
89
89
  - ver 1.0.11 修复了render渲染模式下,动态重复推送的问题,修复了没有订阅时,控制台空白提示的问题。优化了视频动态缩略图显示不全的问题,优化了部分逻辑。增强容错和增加错误提示
90
90
  - ver 1.0.12 提供用户选择动态推送卡片字体增大的选项
91
91
  - ver 1.0.13 修复了直播通知卡片连续发三次的bug,修复了多次调用指令 `bili login` 产生的bug
92
+ - ver 1.0.14 修复了获取二维码,二维码失效后会多次发生提示的bug,新增对red的支持,新增开播艾特全体成员功能,优化了部分逻辑
92
93
 
93
94
  ## 感谢
94
95