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