koishi-plugin-bilibili-notify 3.0.0-alpha.2 → 3.0.0-alpha.21

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.js CHANGED
@@ -1,61 +1,66 @@
1
1
  "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
2
8
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
9
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
10
  };
5
11
  Object.defineProperty(exports, "__esModule", { value: true });
6
- /* eslint-disable @typescript-eslint/ban-types */
7
- /* eslint-disable @typescript-eslint/no-namespace */
8
- /* eslint-disable @typescript-eslint/no-explicit-any */
9
12
  const koishi_1 = require("koishi");
10
13
  const md5_1 = __importDefault(require("md5"));
11
- const crypto_1 = __importDefault(require("crypto"));
14
+ const node_crypto_1 = __importDefault(require("node:crypto"));
12
15
  const axios_1 = __importDefault(require("axios"));
13
16
  const tough_cookie_1 = require("tough-cookie");
14
17
  const axios_cookiejar_support_1 = require("axios-cookiejar-support");
15
18
  const jsdom_1 = require("jsdom");
16
- const luxon_1 = require("luxon");
19
+ const utils_1 = require("./utils");
17
20
  const mixinKeyEncTab = [
18
21
  46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
19
- 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
20
- 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
21
- 36, 20, 34, 44, 52
22
+ 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61,
23
+ 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36,
24
+ 20, 34, 44, 52,
22
25
  ];
23
26
  // 在getUserInfo中检测到番剧出差的UID时,要传回的数据:
24
- const bangumiTripData = { "code": 0, "data": { "live_room": { "roomid": 931774 } } };
25
- const GET_USER_SPACE_DYNAMIC_LIST = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space';
26
- const GET_ALL_DYNAMIC_LIST = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all';
27
- const HAS_NEW_DYNAMIC = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all/update';
28
- const GET_COOKIES_INFO = 'https://passport.bilibili.com/x/passport-login/web/cookie/info';
29
- const GET_USER_INFO = 'https://api.bilibili.com/x/space/wbi/acc/info';
30
- const GET_MYSELF_INFO = 'https://api.bilibili.com/x/member/web/account';
31
- const GET_LOGIN_QRCODE = 'https://passport.bilibili.com/x/passport-login/web/qrcode/generate';
32
- const GET_LOGIN_STATUS = 'https://passport.bilibili.com/x/passport-login/web/qrcode/poll';
33
- const GET_LIVE_ROOM_INFO = 'https://api.live.bilibili.com/room/v1/Room/get_info';
34
- const GET_MASTER_INFO = 'https://api.live.bilibili.com/live_user/v1/Master/info';
35
- const GET_TIME_NOW = 'https://api.bilibili.com/x/report/click/now';
36
- const GET_SERVER_UTC_TIME = 'https://interface.bilibili.com/serverdate.js';
27
+ const bangumiTripData = { code: 0, data: { live_room: { roomid: 931774 } } };
28
+ const GET_USER_SPACE_DYNAMIC_LIST = "https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space";
29
+ const GET_ALL_DYNAMIC_LIST = "https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all";
30
+ const HAS_NEW_DYNAMIC = "https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all/update";
31
+ const GET_COOKIES_INFO = "https://passport.bilibili.com/x/passport-login/web/cookie/info";
32
+ const GET_USER_INFO = "https://api.bilibili.com/x/space/wbi/acc/info";
33
+ const GET_MYSELF_INFO = "https://api.bilibili.com/x/member/web/account";
34
+ const GET_LOGIN_QRCODE = "https://passport.bilibili.com/x/passport-login/web/qrcode/generate";
35
+ const GET_LOGIN_STATUS = "https://passport.bilibili.com/x/passport-login/web/qrcode/poll";
36
+ const GET_LIVE_ROOM_INFO = "https://api.live.bilibili.com/room/v1/Room/get_info";
37
+ const GET_MASTER_INFO = "https://api.live.bilibili.com/live_user/v1/Master/info";
38
+ const GET_TIME_NOW = "https://api.bilibili.com/x/report/click/now";
39
+ const GET_SERVER_UTC_TIME = "https://interface.bilibili.com/serverdate.js";
37
40
  // 最近更新UP
38
- const GET_LATEST_UPDATED_UPS = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/portal';
41
+ const GET_LATEST_UPDATED_UPS = "https://api.bilibili.com/x/polymer/web-dynamic/v1/portal";
39
42
  // 操作
40
- const MODIFY_RELATION = 'https://api.bilibili.com/x/relation/modify';
41
- const CREATE_GROUP = 'https://api.bilibili.com/x/relation/tag/create';
42
- const MODIFY_GROUP_MEMBER = 'https://api.bilibili.com/x/relation/tags/addUsers';
43
- const GET_ALL_GROUP = 'https://api.bilibili.com/x/relation/tags';
44
- const COPY_USER_TO_GROUP = 'https://api.bilibili.com/x/relation/tags/copyUsers';
45
- const GET_RELATION_GROUP_DETAIL = 'https://api.bilibili.com/x/relation/tag';
43
+ const MODIFY_RELATION = "https://api.bilibili.com/x/relation/modify";
44
+ const CREATE_GROUP = "https://api.bilibili.com/x/relation/tag/create";
45
+ const MODIFY_GROUP_MEMBER = "https://api.bilibili.com/x/relation/tags/addUsers";
46
+ const GET_ALL_GROUP = "https://api.bilibili.com/x/relation/tags";
47
+ const COPY_USER_TO_GROUP = "https://api.bilibili.com/x/relation/tags/copyUsers";
48
+ const GET_RELATION_GROUP_DETAIL = "https://api.bilibili.com/x/relation/tag";
46
49
  // 直播
47
- const GET_LIVE_ROOM_INFO_STREAM_KEY = 'https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo';
50
+ const GET_LIVE_ROOM_INFO_STREAM_KEY = "https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo";
48
51
  class BiliAPI extends koishi_1.Service {
49
- static inject = ['database', 'notifier'];
52
+ static inject = ["database", "notifier"];
50
53
  jar;
54
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
51
55
  client;
52
56
  apiConfig;
57
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
53
58
  loginData;
54
59
  loginNotifier;
55
60
  refreshCookieTimer;
56
61
  loginInfoIsLoaded = false;
57
62
  constructor(ctx, config) {
58
- super(ctx, 'ba');
63
+ super(ctx, "ba");
59
64
  this.apiConfig = config;
60
65
  }
61
66
  start() {
@@ -72,7 +77,9 @@ class BiliAPI extends koishi_1.Service {
72
77
  .slice(0, 32);
73
78
  // 为请求参数进行 wbi 签名
74
79
  encWbi(params, img_key, sub_key) {
75
- const mixin_key = this.getMixinKey(img_key + sub_key), curr_time = Math.round(Date.now() / 1000), chr_filter = /[!'()*]/g;
80
+ const mixin_key = this.getMixinKey(img_key + sub_key);
81
+ const curr_time = Math.round(Date.now() / 1000);
82
+ const chr_filter = /[!'()*]/g;
76
83
  Object.assign(params, { wts: curr_time }); // 添加 wts 字段
77
84
  // 按照 key 重排参数
78
85
  const query = Object.keys(params)
@@ -84,207 +91,141 @@ class BiliAPI extends koishi_1.Service {
84
91
  })
85
92
  .join("&");
86
93
  const wbi_sign = (0, md5_1.default)(query + mixin_key); // 计算 w_rid
87
- return query + "&w_rid=" + wbi_sign;
94
+ return `${query}&w_rid=${wbi_sign}`;
88
95
  }
89
96
  async getWbi(params) {
90
97
  const web_keys = await this.getWbiKeys();
91
- const img_key = web_keys.img_key, sub_key = web_keys.sub_key;
98
+ const img_key = web_keys.img_key;
99
+ const sub_key = web_keys.sub_key;
92
100
  const query = this.encWbi(params, img_key, sub_key);
93
101
  return query;
94
102
  }
95
103
  encrypt(text) {
96
- const iv = crypto_1.default.randomBytes(16);
97
- const cipher = crypto_1.default.createCipheriv('aes-256-cbc', Buffer.from(this.apiConfig.key), iv);
104
+ const iv = node_crypto_1.default.randomBytes(16);
105
+ const cipher = node_crypto_1.default.createCipheriv("aes-256-cbc", Buffer.from(this.apiConfig.key), iv);
98
106
  const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
99
- return iv.toString('hex') + ':' + encrypted.toString('hex');
107
+ return `${iv.toString("hex")}:${encrypted.toString("hex")}`;
100
108
  }
101
109
  decrypt(text) {
102
- const textParts = text.split(':');
103
- const iv = Buffer.from(textParts.shift(), 'hex');
104
- const encryptedText = Buffer.from(textParts.join(':'), 'hex');
105
- const decipher = crypto_1.default.createDecipheriv('aes-256-cbc', Buffer.from(this.apiConfig.key), iv);
106
- const decrypted = Buffer.concat([decipher.update(encryptedText), decipher.final()]);
110
+ const textParts = text.split(":");
111
+ const iv = Buffer.from(textParts.shift(), "hex");
112
+ const encryptedText = Buffer.from(textParts.join(":"), "hex");
113
+ const decipher = node_crypto_1.default.createDecipheriv("aes-256-cbc", Buffer.from(this.apiConfig.key), iv);
114
+ const decrypted = Buffer.concat([
115
+ decipher.update(encryptedText),
116
+ decipher.final(),
117
+ ]);
107
118
  return decrypted.toString();
108
119
  }
109
120
  // BA API
110
121
  async getTheUserWhoIsLiveStreaming() {
111
- try {
112
- // 获取直播间信息流密钥
113
- const { data: { live_users } } = await this.client.get(GET_LATEST_UPDATED_UPS);
114
- // 返回data
115
- return live_users;
116
- }
117
- catch (e) {
118
- throw new Error('网络异常,本次请求失败!');
119
- }
122
+ // 获取直播间信息流密钥
123
+ const { data: { live_users }, } = await this.client.get(GET_LATEST_UPDATED_UPS);
124
+ // 返回data
125
+ return live_users;
120
126
  }
121
127
  async getLiveRoomInfoStreamKey(roomId) {
122
- try {
123
- // 获取直播间信息流密钥
124
- const { data } = await this.client.get(`${GET_LIVE_ROOM_INFO_STREAM_KEY}?id=${roomId}`);
125
- // 返回data
126
- return data;
127
- }
128
- catch (e) {
129
- throw new Error('网络异常,本次请求失败!');
130
- }
128
+ // 获取直播间信息流密钥
129
+ const { data } = await this.client.get(`${GET_LIVE_ROOM_INFO_STREAM_KEY}?id=${roomId}`);
130
+ // 返回data
131
+ return data;
131
132
  }
132
133
  async getServerUTCTime() {
133
- try {
134
- const { data } = await this.client.get(GET_SERVER_UTC_TIME);
135
- const regex = /Date\.UTC\((.*?)\)/;
136
- const match = data.match(regex);
137
- if (match) {
138
- const timestamp = new Function(`return Date.UTC(${match[1]})`)();
139
- return timestamp / 1000;
140
- }
141
- else {
142
- throw new Error('解析服务器时间失败!');
143
- }
144
- }
145
- catch (e) {
146
- throw new Error('网络异常,本次请求失败!');
134
+ const { data } = await this.client.get(GET_SERVER_UTC_TIME);
135
+ const regex = /Date\.UTC\((.*?)\)/;
136
+ const match = data.match(regex);
137
+ if (match) {
138
+ const timestamp = new Function(`return Date.UTC(${match[1]})`)();
139
+ return timestamp / 1000;
147
140
  }
141
+ throw new Error("解析服务器时间失败!");
148
142
  }
149
143
  async getTimeNow() {
150
- try {
151
- const { data } = await this.client.get(GET_TIME_NOW);
152
- return data;
153
- }
154
- catch (e) {
155
- throw new Error('网络异常,本次请求失败!');
156
- }
144
+ const { data } = await this.client.get(GET_TIME_NOW);
145
+ return data;
157
146
  }
158
147
  async getAllGroup() {
159
- try {
160
- const { data } = await this.client.get(GET_ALL_GROUP);
161
- return data;
162
- }
163
- catch (e) {
164
- throw new Error('网络异常,本次请求失败!');
165
- }
148
+ const { data } = await this.client.get(GET_ALL_GROUP);
149
+ return data;
166
150
  }
167
151
  async removeUserFromGroup(mid) {
168
152
  // 获取csrf
169
153
  const csrf = this.getCSRF();
170
- try {
171
- // 将用户mid添加到groupId
172
- const { data } = await this.client.post(MODIFY_GROUP_MEMBER, {
173
- fids: mid,
174
- tagids: 0,
175
- csrf
176
- }, {
177
- headers: {
178
- 'Content-Type': 'application/x-www-form-urlencoded',
179
- }
180
- });
181
- return data;
182
- }
183
- catch (e) {
184
- throw new Error('网络异常,本次请求失败!');
185
- }
154
+ // 将用户mid添加到groupId
155
+ const { data } = await this.client.post(MODIFY_GROUP_MEMBER, {
156
+ fids: mid,
157
+ tagids: 0,
158
+ csrf,
159
+ }, {
160
+ headers: {
161
+ "Content-Type": "application/x-www-form-urlencoded",
162
+ },
163
+ });
164
+ return data;
186
165
  }
187
166
  async copyUserToGroup(mid, groupId) {
188
167
  // 获取csrf
189
168
  const csrf = this.getCSRF();
190
- try {
191
- // 将用户mid添加到groupId
192
- const { data } = await this.client.post(COPY_USER_TO_GROUP, {
193
- fids: mid,
194
- tagids: groupId,
195
- csrf
196
- }, {
197
- headers: {
198
- 'Content-Type': 'application/x-www-form-urlencoded',
199
- }
200
- });
201
- return data;
202
- }
203
- catch (e) {
204
- throw new Error('网络异常,本次请求失败!');
205
- }
169
+ // 将用户mid添加到groupId
170
+ const { data } = await this.client.post(COPY_USER_TO_GROUP, {
171
+ fids: mid,
172
+ tagids: groupId,
173
+ csrf,
174
+ }, {
175
+ headers: {
176
+ "Content-Type": "application/x-www-form-urlencoded",
177
+ },
178
+ });
179
+ return data;
206
180
  }
207
181
  async getUserSpaceDynamic(mid) {
208
- try {
209
- const { data } = await this.client.get(`${GET_USER_SPACE_DYNAMIC_LIST}?host_mid=${mid}`);
210
- return data;
211
- }
212
- catch (e) {
213
- throw new Error('网络异常,本次请求失败!');
214
- }
182
+ const { data } = await this.client.get(`${GET_USER_SPACE_DYNAMIC_LIST}?host_mid=${mid}`);
183
+ return data;
215
184
  }
216
185
  async createGroup(tag) {
217
- try {
218
- const { data } = await this.client.post(CREATE_GROUP, {
219
- tag,
220
- csrf: this.getCSRF()
221
- }, {
222
- headers: {
223
- 'Content-Type': 'application/x-www-form-urlencoded',
224
- }
225
- });
226
- return data;
227
- }
228
- catch (e) {
229
- throw new Error('网络异常,本次请求失败!');
230
- }
186
+ const { data } = await this.client.post(CREATE_GROUP, {
187
+ tag,
188
+ csrf: this.getCSRF(),
189
+ }, {
190
+ headers: {
191
+ "Content-Type": "application/x-www-form-urlencoded",
192
+ },
193
+ });
194
+ return data;
231
195
  }
232
196
  async getAllDynamic(updateBaseline) {
233
197
  let url = GET_ALL_DYNAMIC_LIST;
234
- updateBaseline && (url += `?update_baseline=${updateBaseline}`);
235
- try {
236
- const { data } = await this.client.get(url);
237
- return data;
238
- }
239
- catch (e) {
240
- throw new Error('网络异常,本次请求失败!');
198
+ if (updateBaseline) {
199
+ url += `?update_baseline=${updateBaseline}`;
241
200
  }
201
+ const { data } = await this.client.get(url);
202
+ return data;
242
203
  }
243
204
  async hasNewDynamic(updateBaseline) {
244
- try {
245
- const { data } = await this.client.get(`${HAS_NEW_DYNAMIC}?update_baseline=${updateBaseline}`);
246
- return data;
247
- }
248
- catch (e) {
249
- throw new Error('网络异常,本次请求失败!');
250
- }
205
+ const { data } = await this.client.get(`${HAS_NEW_DYNAMIC}?update_baseline=${updateBaseline}`);
206
+ return data;
251
207
  }
252
208
  async follow(fid) {
253
- try {
254
- const { data } = await this.client.post(MODIFY_RELATION, {
255
- fid,
256
- act: 1,
257
- re_src: 11,
258
- csrf: this.getCSRF()
259
- }, {
260
- headers: {
261
- 'Content-Type': 'application/x-www-form-urlencoded',
262
- }
263
- });
264
- return data;
265
- }
266
- catch (e) {
267
- throw new Error('网络异常,本次请求失败!');
268
- }
209
+ const { data } = await this.client.post(MODIFY_RELATION, {
210
+ fid,
211
+ act: 1,
212
+ re_src: 11,
213
+ csrf: this.getCSRF(),
214
+ }, {
215
+ headers: {
216
+ "Content-Type": "application/x-www-form-urlencoded",
217
+ },
218
+ });
219
+ return data;
269
220
  }
270
221
  async getRelationGroupDetail(tagid) {
271
- try {
272
- const { data } = await this.client.get(`${GET_RELATION_GROUP_DETAIL}?tagid=${tagid}`);
273
- return data;
274
- }
275
- catch (e) {
276
- throw new Error('网络异常,本次请求失败!');
277
- }
222
+ const { data } = await this.client.get(`${GET_RELATION_GROUP_DETAIL}?tagid=${tagid}`);
223
+ return data;
278
224
  }
279
225
  // Check if Token need refresh
280
226
  async getCookieInfo(refreshToken) {
281
- try {
282
- const { data } = await this.client.get(`${GET_COOKIES_INFO}?csrf=${refreshToken}`);
283
- return data;
284
- }
285
- catch (e) {
286
- throw new Error('网络异常,本次请求失败!');
287
- }
227
+ const { data } = await this.client.get(`${GET_COOKIES_INFO}?csrf=${refreshToken}`);
228
+ return data;
288
229
  }
289
230
  async getUserInfo(mid) {
290
231
  //如果为番剧出差的UID,则不从远程接口拉取数据,直接传回一段精简过的有效数据
@@ -292,78 +233,50 @@ class BiliAPI extends koishi_1.Service {
292
233
  console.log("检测到番剧出差UID,跳过远程用户接口访问");
293
234
  return bangumiTripData;
294
235
  }
295
- try {
296
- const wbi = await this.getWbi({ mid });
297
- const { data } = await this.client.get(`${GET_USER_INFO}?${wbi}`);
298
- return data;
299
- }
300
- catch (e) {
301
- throw new Error('网络异常,本次请求失败!');
302
- }
236
+ const wbi = await this.getWbi({ mid });
237
+ const { data } = await this.client.get(`${GET_USER_INFO}?${wbi}`);
238
+ return data;
303
239
  }
304
240
  // 获取最新的 img_key 和 sub_key
305
241
  async getWbiKeys() {
306
- const { data } = await this.client.get('https://api.bilibili.com/x/web-interface/nav');
242
+ const { data } = await this.client.get("https://api.bilibili.com/x/web-interface/nav");
307
243
  const { data: { wbi_img: { img_url, sub_url }, }, } = data;
308
244
  return {
309
- img_key: img_url.slice(img_url.lastIndexOf('/') + 1, img_url.lastIndexOf('.')),
310
- sub_key: sub_url.slice(sub_url.lastIndexOf('/') + 1, sub_url.lastIndexOf('.'))
245
+ img_key: img_url.slice(img_url.lastIndexOf("/") + 1, img_url.lastIndexOf(".")),
246
+ sub_key: sub_url.slice(sub_url.lastIndexOf("/") + 1, sub_url.lastIndexOf(".")),
311
247
  };
312
248
  }
313
249
  async getMyselfInfo() {
314
- try {
315
- const { data } = await this.client.get(GET_MYSELF_INFO);
316
- return data;
317
- }
318
- catch (e) {
319
- throw new Error('网络异常,本次请求失败!');
320
- }
250
+ const { data } = await this.client.get(GET_MYSELF_INFO);
251
+ return data;
321
252
  }
322
253
  async getLoginQRCode() {
323
- try {
324
- const { data } = await this.client.get(GET_LOGIN_QRCODE);
325
- return data;
326
- }
327
- catch (e) {
328
- throw new Error('网络异常,本次请求失败!');
329
- }
254
+ const { data } = await this.client.get(GET_LOGIN_QRCODE);
255
+ return data;
330
256
  }
331
257
  async getLoginStatus(qrcodeKey) {
332
- try {
333
- const { data } = await this.client.get(`${GET_LOGIN_STATUS}?qrcode_key=${qrcodeKey}`);
334
- return data;
335
- }
336
- catch (e) {
337
- throw new Error('网络异常,本次请求失败!');
338
- }
258
+ const { data } = await this.client.get(`${GET_LOGIN_STATUS}?qrcode_key=${qrcodeKey}`);
259
+ return data;
339
260
  }
340
261
  async getLiveRoomInfo(roomId) {
341
- try {
342
- const { data } = await this.client.get(`${GET_LIVE_ROOM_INFO}?room_id=${roomId}`);
343
- return data;
344
- }
345
- catch (e) {
346
- throw new Error('网络异常,本次请求失败!');
347
- }
262
+ const { data } = await this.client.get(`${GET_LIVE_ROOM_INFO}?room_id=${roomId}`);
263
+ return data;
348
264
  }
349
265
  async getMasterInfo(mid) {
350
- try {
351
- const { data } = await this.client.get(`${GET_MASTER_INFO}?uid=${mid}`);
352
- return data;
353
- }
354
- catch (e) {
355
- throw new Error('网络异常,本次请求失败!');
356
- }
266
+ const { data } = await this.client.get(`${GET_MASTER_INFO}?uid=${mid}`);
267
+ return data;
268
+ }
269
+ disposeNotifier() {
270
+ if (this.loginNotifier)
271
+ this.loginNotifier.dispose();
357
272
  }
358
- disposeNotifier() { if (this.loginNotifier)
359
- this.loginNotifier.dispose(); }
360
273
  getRandomUserAgent() {
361
274
  const userAgents = [
362
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
363
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36',
364
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
365
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0',
366
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'
275
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
276
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36",
277
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
278
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0",
279
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
367
280
  ];
368
281
  const index = Math.floor(Math.random() * userAgents.length);
369
282
  return userAgents[index];
@@ -373,17 +286,16 @@ class BiliAPI extends koishi_1.Service {
373
286
  this.client = (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({
374
287
  jar: this.jar,
375
288
  headers: {
376
- 'Content-Type': 'application/json',
377
- 'User-Agent': this.apiConfig.userAgent !== 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36' ?
378
- this.apiConfig.userAgent : this.getRandomUserAgent(),
379
- 'Origin': 'https://www.bilibili.com',
380
- 'Referer': 'https://www.bilibili.com/'
381
- }
289
+ "Content-Type": "application/json",
290
+ "User-Agent": this.apiConfig.userAgent !==
291
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
292
+ ? this.apiConfig.userAgent
293
+ : this.getRandomUserAgent(),
294
+ Origin: "https://www.bilibili.com",
295
+ Referer: "https://www.bilibili.com/",
296
+ },
382
297
  }));
383
298
  }
384
- getTimeOfUTC8() {
385
- return Math.floor(luxon_1.DateTime.now().setZone('UTC+8').toSeconds());
386
- }
387
299
  getCookies() {
388
300
  const cookies = JSON.stringify(this.jar.serializeSync().cookies);
389
301
  return cookies;
@@ -394,8 +306,8 @@ class BiliAPI extends koishi_1.Service {
394
306
  const cookies = this.jar.serializeSync().cookies;
395
307
  // 将每个 cookie 对象转换为 "key=value" 形式,并用 "; " 连接起来
396
308
  const cookieHeader = cookies
397
- .map(cookie => `${cookie.key}=${cookie.value}`)
398
- .join('; ');
309
+ .map((cookie) => `${cookie.key}=${cookie.value}`)
310
+ .join("; ");
399
311
  return cookieHeader;
400
312
  }
401
313
  catch (e) {
@@ -408,18 +320,19 @@ class BiliAPI extends koishi_1.Service {
408
320
  }
409
321
  async getLoginInfoFromDB() {
410
322
  // 读取数据库获取cookies
411
- const data = (await this.ctx.database.get('loginBili', 1))[0];
323
+ const data = (await this.ctx.database.get("loginBili", 1))[0];
412
324
  // 判断是否登录
413
- if (data === undefined) { // 没有数据则直接返回
325
+ if (data === undefined) {
326
+ // 没有数据则直接返回
414
327
  // 未登录,在控制台提示
415
328
  this.loginNotifier = this.ctx.notifier.create({
416
- type: 'warning',
417
- content: '您尚未登录,将无法使用插件提供的指令'
329
+ type: "warning",
330
+ content: "您尚未登录,将无法使用插件提供的指令",
418
331
  });
419
332
  // 返回空值
420
333
  return {
421
334
  cookies: null,
422
- refresh_token: null
335
+ refresh_token: null,
423
336
  };
424
337
  }
425
338
  // 尝试解密
@@ -433,27 +346,29 @@ class BiliAPI extends koishi_1.Service {
433
346
  // 返回值
434
347
  return {
435
348
  cookies,
436
- refresh_token: decryptedRefreshToken
349
+ refresh_token: decryptedRefreshToken,
437
350
  };
438
351
  }
439
352
  catch (e) {
440
353
  // 数据库被篡改,在控制台提示
441
354
  this.loginNotifier = this.ctx.notifier.create({
442
- type: 'warning',
443
- content: '数据库被篡改,请重新登录'
355
+ type: "warning",
356
+ content: "数据库被篡改,请重新登录",
444
357
  });
445
358
  // 解密或解析失败,删除数据库登录信息
446
- await this.ctx.database.remove('loginBili', [1]);
359
+ await this.ctx.database.remove("loginBili", [1]);
447
360
  // 返回空值
448
361
  return {
449
362
  cookies: null,
450
- refresh_token: null
363
+ refresh_token: null,
451
364
  };
452
365
  }
453
366
  }
454
367
  getCSRF() {
455
368
  // 获取csrf
456
- return this.jar.serializeSync().cookies.find(cookie => cookie.key === 'bili_jct').value;
369
+ return this.jar
370
+ .serializeSync()
371
+ .cookies.find((cookie) => cookie.key === "bili_jct").value;
457
372
  }
458
373
  async loadCookiesFromDatabase() {
459
374
  // Get login info from db
@@ -465,10 +380,16 @@ class BiliAPI extends koishi_1.Service {
465
380
  return;
466
381
  }
467
382
  // 定义CSRF Token
468
- let csrf, expires, domain, path, secure, httpOnly, sameSite;
469
- cookies.forEach(cookieData => {
383
+ let csrf;
384
+ let expires;
385
+ let domain;
386
+ let path;
387
+ let secure;
388
+ let httpOnly;
389
+ let sameSite;
390
+ for (const cookieData of cookies) {
470
391
  // 获取key为bili_jct的值
471
- if (cookieData.key === 'bili_jct') {
392
+ if (cookieData.key === "bili_jct") {
472
393
  csrf = cookieData.value;
473
394
  expires = new Date(cookieData.expires);
474
395
  domain = cookieData.domain;
@@ -486,22 +407,22 @@ class BiliAPI extends koishi_1.Service {
486
407
  path: cookieData.path,
487
408
  secure: cookieData.secure,
488
409
  httpOnly: cookieData.httpOnly,
489
- sameSite: cookieData.sameSite
410
+ sameSite: cookieData.sameSite,
490
411
  });
491
- this.jar.setCookieSync(cookie, `http${cookie.secure ? 's' : ''}://${cookie.domain}${cookie.path}`, {});
492
- });
412
+ this.jar.setCookieSync(cookie, `http${cookie.secure ? "s" : ""}://${cookie.domain}${cookie.path}`, {});
413
+ }
493
414
  // 对于某些 IP 地址,需要在 Cookie 中提供任意非空的 buvid3 字段
494
415
  const buvid3Cookie = new tough_cookie_1.Cookie({
495
- key: 'buvid3',
496
- value: 'some_non_empty_value', // 设置任意非空值
416
+ key: "buvid3",
417
+ value: "some_non_empty_value", // 设置任意非空值
497
418
  expires, // 设置过期时间
498
419
  domain, // 设置域名
499
420
  path, // 设置路径
500
421
  secure, // 设置是否为安全 cookie
501
422
  httpOnly, // 设置是否为 HttpOnly cookie
502
- sameSite // 设置 SameSite 属性
423
+ sameSite, // 设置 SameSite 属性
503
424
  });
504
- this.jar.setCookieSync(buvid3Cookie, `http${buvid3Cookie.secure ? 's' : ''}://${buvid3Cookie.domain}${buvid3Cookie.path}`, {});
425
+ this.jar.setCookieSync(buvid3Cookie, `http${buvid3Cookie.secure ? "s" : ""}://${buvid3Cookie.domain}${buvid3Cookie.path}`, {});
505
426
  // Login info is loaded
506
427
  this.loginInfoIsLoaded = true;
507
428
  // restart plugin check
@@ -515,15 +436,16 @@ class BiliAPI extends koishi_1.Service {
515
436
  this.refreshCookieTimer();
516
437
  // Open scheduled tasks and check if token need refresh
517
438
  this.refreshCookieTimer = this.ctx.setInterval(async () => {
439
+ // 每12小时检测一次
518
440
  // 从数据库获取登录信息
519
441
  const { cookies, refresh_token } = await this.getLoginInfoFromDB();
520
442
  // 判断是否有值
521
443
  if (!cookies || !refresh_token)
522
444
  return;
523
445
  // 获取csrf
524
- const csrf = cookies.find(cookie => {
446
+ const csrf = cookies.find((cookie) => {
525
447
  // 判断key是否为bili_jct
526
- if (cookie.key === 'bili_jct')
448
+ if (cookie.key === "bili_jct")
527
449
  return true;
528
450
  }).value;
529
451
  // 检查是否需要更新
@@ -535,8 +457,8 @@ class BiliAPI extends koishi_1.Service {
535
457
  const notifyAndError = (info) => {
536
458
  // 设置控制台通知
537
459
  this.loginNotifier = this.ctx.notifier.create({
538
- type: 'warning',
539
- content: info
460
+ type: "warning",
461
+ content: info,
540
462
  });
541
463
  // 重置为未登录状态
542
464
  this.createNewClient();
@@ -563,7 +485,7 @@ class BiliAPI extends koishi_1.Service {
563
485
  // 如果请求失败,有可能是404,直接刷新cookie
564
486
  }
565
487
  // 定义Key
566
- const publicKey = await crypto_1.default.subtle.importKey("jwk", {
488
+ const publicKey = await node_crypto_1.default.subtle.importKey("jwk", {
567
489
  kty: "RSA",
568
490
  n: "y4HdjgJHBlbaBN04VERG4qNBIFHP6a3GozCl75AihQloSWCXC5HDNgyinEnhaQ_4-gaMud_GF50elYXLlCToR9se9Z8z433U3KjM-3Yx7ptKkmQNAMggQwAVKgq3zYAoidNEWuxpkY_mAitTSRLnsJW-NCTa0bqBFF6Wm1MxgfE",
569
491
  e: "AQAB",
@@ -571,7 +493,7 @@ class BiliAPI extends koishi_1.Service {
571
493
  // 定义获取CorrespondPath方法
572
494
  async function getCorrespondPath(timestamp) {
573
495
  const data = new TextEncoder().encode(`refresh_${timestamp}`);
574
- const encrypted = new Uint8Array(await crypto_1.default.subtle.encrypt({ name: "RSA-OAEP" }, publicKey, data));
496
+ const encrypted = new Uint8Array(await node_crypto_1.default.subtle.encrypt({ name: "RSA-OAEP" }, publicKey, data));
575
497
  return encrypted.reduce((str, c) => str + c.toString(16).padStart(2, "0"), "");
576
498
  }
577
499
  // 获取CorrespondPath
@@ -582,73 +504,245 @@ class BiliAPI extends koishi_1.Service {
582
504
  // 创建一个虚拟的DOM元素
583
505
  const { document } = new jsdom_1.JSDOM(refreshCsrfHtml).window;
584
506
  // 提取标签name为1-name的内容
585
- const targetElement = document.getElementById('1-name');
507
+ const targetElement = document.getElementById("1-name");
586
508
  const refresh_csrf = targetElement ? targetElement.textContent : null;
587
509
  // 发送刷新请求
588
- const { data: refreshData } = await this.client.post('https://passport.bilibili.com/x/passport-login/web/cookie/refresh', {
510
+ const { data: refreshData } = await this.client.post("https://passport.bilibili.com/x/passport-login/web/cookie/refresh", {
589
511
  csrf,
590
512
  refresh_csrf,
591
- source: 'main_web',
592
- refresh_token: refreshToken
513
+ source: "main_web",
514
+ refresh_token: refreshToken,
593
515
  }, {
594
516
  headers: {
595
- 'Content-Type': 'application/x-www-form-urlencoded',
596
- }
517
+ "Content-Type": "application/x-www-form-urlencoded",
518
+ },
597
519
  });
598
520
  // 检查是否有其他问题
599
521
  switch (refreshData.code) {
600
522
  // 账号未登录
601
- case -101: return this.createNewClient();
523
+ case -101:
524
+ return this.createNewClient();
602
525
  case -111: {
603
- await this.ctx.database.remove('loginBili', [1]);
604
- notifyAndError('csrf 校验错误,请重新登录');
526
+ await this.ctx.database.remove("loginBili", [1]);
527
+ notifyAndError("csrf 校验错误,请重新登录");
605
528
  break;
606
529
  }
607
530
  case 86095: {
608
- await this.ctx.database.remove('loginBili', [1]);
609
- notifyAndError('refresh_csrf 错误或 refresh_token 与 cookie 不匹配,请重新登录');
531
+ await this.ctx.database.remove("loginBili", [1]);
532
+ notifyAndError("refresh_csrf 错误或 refresh_token 与 cookie 不匹配,请重新登录");
610
533
  }
611
534
  }
612
535
  // 更新 新的cookies和refresh_token
613
536
  const encryptedCookies = this.encrypt(this.getCookies());
614
537
  const encryptedRefreshToken = this.encrypt(refreshData.data.refresh_token);
615
- await this.ctx.database.upsert('loginBili', [{
538
+ await this.ctx.database.upsert("loginBili", [
539
+ {
616
540
  id: 1,
617
541
  bili_cookies: encryptedCookies,
618
- bili_refresh_token: encryptedRefreshToken
619
- }]);
542
+ bili_refresh_token: encryptedRefreshToken,
543
+ },
544
+ ]);
620
545
  // Get new csrf from cookies
621
- const newCsrf = this.jar.serializeSync().cookies.find(cookie => {
622
- if (cookie.key === 'bili_jct')
546
+ const newCsrf = this.jar.serializeSync().cookies.find((cookie) => {
547
+ if (cookie.key === "bili_jct")
623
548
  return true;
624
549
  }).value;
625
550
  // Accept update
626
- const { data: aceeptData } = await this.client.post('https://passport.bilibili.com/x/passport-login/web/confirm/refresh', {
551
+ const { data: aceeptData } = await this.client.post("https://passport.bilibili.com/x/passport-login/web/confirm/refresh", {
627
552
  csrf: newCsrf,
628
- refresh_token: refreshToken
553
+ refresh_token: refreshToken,
629
554
  }, {
630
555
  headers: {
631
- 'Content-Type': 'application/x-www-form-urlencoded',
632
- }
556
+ "Content-Type": "application/x-www-form-urlencoded",
557
+ },
633
558
  });
634
559
  // 检查是否有其他问题
635
560
  switch (aceeptData.code) {
636
561
  case -111: {
637
- await this.ctx.database.remove('loginBili', [1]);
638
- notifyAndError('csrf 校验失败,请重新登录');
562
+ await this.ctx.database.remove("loginBili", [1]);
563
+ notifyAndError("csrf 校验失败,请重新登录");
639
564
  break;
640
565
  }
641
- case -400: throw new Error('请求错误');
566
+ case -400:
567
+ throw new Error("请求错误");
642
568
  }
643
569
  // 没有问题,cookies已更新完成
644
570
  }
645
571
  }
572
+ __decorate([
573
+ (0, utils_1.Retry)({
574
+ attempts: 3,
575
+ onFailure(error, attempts) {
576
+ this.logger.error(`getTheUserWhoIsLiveStreaming() 第${attempts}次失败: ${error.message}`);
577
+ },
578
+ })
579
+ ], BiliAPI.prototype, "getTheUserWhoIsLiveStreaming", null);
580
+ __decorate([
581
+ (0, utils_1.Retry)({
582
+ attempts: 3,
583
+ onFailure(error, attempts) {
584
+ this.logger.error(`getLiveRoomInfoStreamKey() 第${attempts}次失败: ${error.message}`);
585
+ },
586
+ })
587
+ ], BiliAPI.prototype, "getLiveRoomInfoStreamKey", null);
588
+ __decorate([
589
+ (0, utils_1.Retry)({
590
+ attempts: 3,
591
+ onFailure(error, attempts) {
592
+ this.logger.error(`getServerUTCTime() 第${attempts}次失败: ${error.message}`);
593
+ },
594
+ })
595
+ ], BiliAPI.prototype, "getServerUTCTime", null);
596
+ __decorate([
597
+ (0, utils_1.Retry)({
598
+ attempts: 3,
599
+ onFailure(error, attempts) {
600
+ this.logger.error(`getTimeNow() 第${attempts}次失败: ${error.message}`);
601
+ },
602
+ })
603
+ ], BiliAPI.prototype, "getTimeNow", null);
604
+ __decorate([
605
+ (0, utils_1.Retry)({
606
+ attempts: 3,
607
+ onFailure(error, attempts) {
608
+ this.logger.error(`getAllGroup() 第${attempts}次失败: ${error.message}`);
609
+ },
610
+ })
611
+ ], BiliAPI.prototype, "getAllGroup", null);
612
+ __decorate([
613
+ (0, utils_1.Retry)({
614
+ attempts: 3,
615
+ onFailure(error, attempts) {
616
+ this.logger.error(`removeUserFromGroup() 第${attempts}次失败: ${error.message}`);
617
+ },
618
+ })
619
+ ], BiliAPI.prototype, "removeUserFromGroup", null);
620
+ __decorate([
621
+ (0, utils_1.Retry)({
622
+ attempts: 3,
623
+ onFailure(error, attempts) {
624
+ this.logger.error(`copyUserToGroup() 第${attempts}次失败: ${error.message}`);
625
+ },
626
+ })
627
+ ], BiliAPI.prototype, "copyUserToGroup", null);
628
+ __decorate([
629
+ (0, utils_1.Retry)({
630
+ attempts: 3,
631
+ onFailure(error, attempts) {
632
+ this.logger.error(`getUserSpaceDynamic() 第${attempts}次失败: ${error.message}`);
633
+ },
634
+ })
635
+ ], BiliAPI.prototype, "getUserSpaceDynamic", null);
636
+ __decorate([
637
+ (0, utils_1.Retry)({
638
+ attempts: 3,
639
+ onFailure(error, attempts) {
640
+ this.logger.error(`createGroup() 第${attempts}次失败: ${error.message}`);
641
+ },
642
+ })
643
+ ], BiliAPI.prototype, "createGroup", null);
644
+ __decorate([
645
+ (0, utils_1.Retry)({
646
+ attempts: 3,
647
+ onFailure(error, attempts) {
648
+ this.logger.error(`getAllDynamic() 第${attempts}次失败: ${error.message}`);
649
+ },
650
+ })
651
+ ], BiliAPI.prototype, "getAllDynamic", null);
652
+ __decorate([
653
+ (0, utils_1.Retry)({
654
+ attempts: 3,
655
+ onFailure(error, attempts) {
656
+ this.logger.error(`hasNewDynamic() 第${attempts}次失败: ${error.message}`);
657
+ },
658
+ })
659
+ ], BiliAPI.prototype, "hasNewDynamic", null);
660
+ __decorate([
661
+ (0, utils_1.Retry)({
662
+ attempts: 3,
663
+ onFailure(error, attempts) {
664
+ this.logger.error(`follow() 第${attempts}次失败: ${error.message}`);
665
+ },
666
+ })
667
+ ], BiliAPI.prototype, "follow", null);
668
+ __decorate([
669
+ (0, utils_1.Retry)({
670
+ attempts: 3,
671
+ onFailure(error, attempts) {
672
+ this.logger.error(`getRelationGroupDetail() 第${attempts}次失败: ${error.message}`);
673
+ },
674
+ })
675
+ ], BiliAPI.prototype, "getRelationGroupDetail", null);
676
+ __decorate([
677
+ (0, utils_1.Retry)({
678
+ attempts: 3,
679
+ onFailure(error, attempts) {
680
+ this.logger.error(`getCookieInfo() 第${attempts}次失败: ${error.message}`);
681
+ },
682
+ })
683
+ ], BiliAPI.prototype, "getCookieInfo", null);
684
+ __decorate([
685
+ (0, utils_1.Retry)({
686
+ attempts: 3,
687
+ onFailure(error, attempts) {
688
+ this.logger.error(`getUserInfo() 第${attempts}次失败: ${error.message}`);
689
+ },
690
+ })
691
+ ], BiliAPI.prototype, "getUserInfo", null);
692
+ __decorate([
693
+ (0, utils_1.Retry)({
694
+ attempts: 3,
695
+ onFailure(error, attempts) {
696
+ this.logger.error(`getWbiKeys() 第${attempts}次失败: ${error.message}`);
697
+ },
698
+ })
699
+ ], BiliAPI.prototype, "getWbiKeys", null);
700
+ __decorate([
701
+ (0, utils_1.Retry)({
702
+ attempts: 3,
703
+ onFailure(error, attempts) {
704
+ this.logger.error(`getMyselfInfo() 第${attempts}次失败: ${error.message}`);
705
+ },
706
+ })
707
+ ], BiliAPI.prototype, "getMyselfInfo", null);
708
+ __decorate([
709
+ (0, utils_1.Retry)({
710
+ attempts: 3,
711
+ onFailure(error, attempts) {
712
+ this.logger.error(`getLoginQRCode() 第${attempts}次失败: ${error.message}`);
713
+ },
714
+ })
715
+ ], BiliAPI.prototype, "getLoginQRCode", null);
716
+ __decorate([
717
+ (0, utils_1.Retry)({
718
+ attempts: 3,
719
+ onFailure(error, attempts) {
720
+ this.logger.error(`getLoginStatus() 第${attempts}次失败: ${error.message}`);
721
+ },
722
+ })
723
+ ], BiliAPI.prototype, "getLoginStatus", null);
724
+ __decorate([
725
+ (0, utils_1.Retry)({
726
+ attempts: 3,
727
+ onFailure(error, attempts) {
728
+ this.logger.error(`getLiveRoomInfo() 第${attempts}次失败: ${error.message}`);
729
+ },
730
+ })
731
+ ], BiliAPI.prototype, "getLiveRoomInfo", null);
732
+ __decorate([
733
+ (0, utils_1.Retry)({
734
+ attempts: 3,
735
+ onFailure(error, attempts) {
736
+ this.logger.error(`getMasterInfo() 第${attempts}次失败: ${error.message}`);
737
+ },
738
+ })
739
+ ], BiliAPI.prototype, "getMasterInfo", null);
646
740
  (function (BiliAPI) {
647
741
  BiliAPI.Config = koishi_1.Schema.object({
648
742
  userAgent: koishi_1.Schema.string(),
649
743
  key: koishi_1.Schema.string()
650
744
  .pattern(/^[0-9a-f]{32}$/)
651
- .required()
745
+ .required(),
652
746
  });
653
747
  })(BiliAPI || (BiliAPI = {}));
654
748
  exports.default = BiliAPI;