koishi-plugin-bilibili-notify 1.0.14 → 1.1.0-beta.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/biliAPI.d.ts +2 -0
- package/lib/biliAPI.js +58 -34
- package/lib/comRegister.js +5 -3
- package/lib/font/HYZhengYuan-75W.ttf +0 -0
- package/lib/generateImg.js +5 -5
- package/package.json +1 -1
- package/readme.md +7 -5
- package/lib/HYZhengYuan-55W.ttf +0 -0
- /package/lib/{0.html → page/0.html} +0 -0
package/lib/biliAPI.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ declare class BiliAPI extends Service {
|
|
|
15
15
|
refreshCookieTimer: Function;
|
|
16
16
|
constructor(ctx: Context);
|
|
17
17
|
protected start(): void | Promise<void>;
|
|
18
|
+
test_refresh_token(): Promise<void>;
|
|
18
19
|
getServerUTCTime(): Promise<number>;
|
|
19
20
|
getTimeNow(): Promise<any>;
|
|
20
21
|
getUserSpaceDynamic(mid: string): Promise<any>;
|
|
@@ -25,6 +26,7 @@ declare class BiliAPI extends Service {
|
|
|
25
26
|
getLoginStatus(qrcodeKey: string): Promise<any>;
|
|
26
27
|
getLiveRoomInfo(roomId: string): Promise<any>;
|
|
27
28
|
getMasterInfo(mid: string): Promise<any>;
|
|
29
|
+
enableRefreshCookiesDetect(refreshToken: string, csrf?: string): void;
|
|
28
30
|
disposeNotifier(): void;
|
|
29
31
|
createNewClient(): void;
|
|
30
32
|
getCookies(): string;
|
package/lib/biliAPI.js
CHANGED
|
@@ -36,52 +36,50 @@ class BiliAPI extends koishi_1.Service {
|
|
|
36
36
|
this.loadCookiesFromDatabase();
|
|
37
37
|
// this.logger.info('BiliAPI已被注册到Context中')
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
const publicKey = await crypto.subtle.importKey(
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
e: "AQAB",
|
|
46
|
-
},
|
|
47
|
-
{ name: "RSA-OAEP", hash: "SHA-256" },
|
|
48
|
-
true,
|
|
49
|
-
["encrypt"],
|
|
50
|
-
)
|
|
51
|
-
|
|
39
|
+
async test_refresh_token() {
|
|
40
|
+
const publicKey = await crypto.subtle.importKey("jwk", {
|
|
41
|
+
kty: "RSA",
|
|
42
|
+
n: "y4HdjgJHBlbaBN04VERG4qNBIFHP6a3GozCl75AihQloSWCXC5HDNgyinEnhaQ_4-gaMud_GF50elYXLlCToR9se9Z8z433U3KjM-3Yx7ptKkmQNAMggQwAVKgq3zYAoidNEWuxpkY_mAitTSRLnsJW-NCTa0bqBFF6Wm1MxgfE",
|
|
43
|
+
e: "AQAB",
|
|
44
|
+
}, { name: "RSA-OAEP", hash: "SHA-256" }, true, ["encrypt"]);
|
|
52
45
|
async function getCorrespondPath(timestamp) {
|
|
53
46
|
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"), "")
|
|
47
|
+
const encrypted = new Uint8Array(await crypto.subtle.encrypt({ name: "RSA-OAEP" }, publicKey, data));
|
|
48
|
+
return encrypted.reduce((str, c) => str + c.toString(16).padStart(2, "0"), "");
|
|
56
49
|
}
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const { data } = await this.client.get(`https://www.bilibili.com/correspond/1/${correspondPath}`)
|
|
50
|
+
const ts = Date.now();
|
|
51
|
+
const correspondPath = await getCorrespondPath(ts);
|
|
52
|
+
const { data } = await this.client.get(`https://www.bilibili.com/correspond/1/${correspondPath}`);
|
|
61
53
|
// 创建一个虚拟的DOM元素
|
|
62
|
-
const { document } = new JSDOM(data).window;
|
|
54
|
+
const { document } = new jsdom_1.JSDOM(data).window;
|
|
63
55
|
// 提取标签name为1-name的内容
|
|
64
56
|
const targetElement = document.getElementById('1-name');
|
|
65
57
|
const refresh_csrf = targetElement ? targetElement.textContent : null;
|
|
66
58
|
// 获取csrf
|
|
67
|
-
let csrf
|
|
68
|
-
const cookies = JSON.parse(this.getCookies())
|
|
59
|
+
let csrf;
|
|
60
|
+
const cookies = JSON.parse(this.getCookies());
|
|
69
61
|
cookies.forEach(cookie => {
|
|
70
|
-
if (cookie.key === 'bili_jct')
|
|
71
|
-
|
|
62
|
+
if (cookie.key === 'bili_jct')
|
|
63
|
+
csrf = cookie.value;
|
|
64
|
+
});
|
|
72
65
|
// 读取数据库获取cookies
|
|
73
|
-
const database = (await this.ctx.database.get('loginBili', 1))[0]
|
|
66
|
+
const database = (await this.ctx.database.get('loginBili', 1))[0];
|
|
74
67
|
// 获取refreshToken
|
|
75
|
-
const refresh_token = this.ctx.wbi.decrypt(database.bili_refresh_token)
|
|
68
|
+
const refresh_token = this.ctx.wbi.decrypt(database.bili_refresh_token);
|
|
76
69
|
// 发送请求
|
|
70
|
+
// const { data: refreshData } = await this.client.post(`https://passport.bilibili.com/x/passport-login/web/cookie/refresh?csrf=${csrf}&refresh_csrf=${refresh_csrf}&source=main_web&refresh_token=${refresh_token}`)
|
|
77
71
|
const { data: refreshData } = await this.client.post('https://passport.bilibili.com/x/passport-login/web/cookie/refresh', {
|
|
78
72
|
csrf,
|
|
79
73
|
refresh_csrf,
|
|
80
74
|
source: 'main_web',
|
|
81
75
|
refresh_token
|
|
82
|
-
}
|
|
76
|
+
}, {
|
|
77
|
+
headers: {
|
|
78
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
79
|
+
}
|
|
80
|
+
});
|
|
83
81
|
console.log(refreshData);
|
|
84
|
-
}
|
|
82
|
+
}
|
|
85
83
|
async getServerUTCTime() {
|
|
86
84
|
try {
|
|
87
85
|
const { data } = await this.client.get(GET_SERVER_UTC_TIME);
|
|
@@ -182,13 +180,33 @@ class BiliAPI extends koishi_1.Service {
|
|
|
182
180
|
throw new Error('网络异常,本次请求失败!');
|
|
183
181
|
}
|
|
184
182
|
}
|
|
183
|
+
enableRefreshCookiesDetect(refreshToken, csrf) {
|
|
184
|
+
// 获取cookies
|
|
185
|
+
const cookies = JSON.parse(this.getCookies());
|
|
186
|
+
// 获取csrf
|
|
187
|
+
if (!csrf) {
|
|
188
|
+
cookies.find(cookie => {
|
|
189
|
+
// 获取key为bili_jct的值
|
|
190
|
+
if (cookie.key === 'bili_jct') {
|
|
191
|
+
csrf = cookie.value;
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
// 判断之前是否启动检测
|
|
197
|
+
this.refreshCookieTimer && this.refreshCookieTimer();
|
|
198
|
+
// Open scheduled tasks and check if token need refresh
|
|
199
|
+
this.refreshCookieTimer = this.ctx.setInterval(() => {
|
|
200
|
+
this.checkIfTokenNeedRefresh(refreshToken, csrf);
|
|
201
|
+
}, 43200000);
|
|
202
|
+
}
|
|
185
203
|
disposeNotifier() { this.loginNotifier && this.loginNotifier.dispose(); }
|
|
186
204
|
createNewClient() {
|
|
187
205
|
this.jar = new tough_cookie_1.CookieJar();
|
|
188
206
|
this.client = (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({
|
|
189
207
|
jar: this.jar,
|
|
190
208
|
headers: {
|
|
191
|
-
'Content-Type': 'application/json
|
|
209
|
+
'Content-Type': 'application/json',
|
|
192
210
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
193
211
|
'Origin': 'https://www.bilibili.com',
|
|
194
212
|
'Referer': 'https://www.bilibili.com/'
|
|
@@ -250,10 +268,8 @@ class BiliAPI extends koishi_1.Service {
|
|
|
250
268
|
});
|
|
251
269
|
// restart plugin check
|
|
252
270
|
this.checkIfTokenNeedRefresh(decryptedRefreshToken, csrf);
|
|
253
|
-
//
|
|
254
|
-
this.
|
|
255
|
-
this.checkIfTokenNeedRefresh(decryptedRefreshToken, csrf);
|
|
256
|
-
}, 43200000);
|
|
271
|
+
// enable refresh cookies detect
|
|
272
|
+
this.enableRefreshCookiesDetect(decryptedRefreshToken, csrf);
|
|
257
273
|
}
|
|
258
274
|
async checkIfTokenNeedRefresh(refreshToken, csrf, times = 0) {
|
|
259
275
|
// 定义数据
|
|
@@ -318,6 +334,10 @@ class BiliAPI extends koishi_1.Service {
|
|
|
318
334
|
refresh_csrf,
|
|
319
335
|
source: 'main_web',
|
|
320
336
|
refresh_token: refreshToken
|
|
337
|
+
}, {
|
|
338
|
+
headers: {
|
|
339
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
340
|
+
}
|
|
321
341
|
});
|
|
322
342
|
// 检查是否有其他问题
|
|
323
343
|
switch (refreshData.code) {
|
|
@@ -333,7 +353,7 @@ class BiliAPI extends koishi_1.Service {
|
|
|
333
353
|
}
|
|
334
354
|
}
|
|
335
355
|
// 更新 新的cookies和refresh_token
|
|
336
|
-
const encryptedCookies = this.ctx.wbi.encrypt(this.
|
|
356
|
+
const encryptedCookies = this.ctx.wbi.encrypt(this.getCookies());
|
|
337
357
|
const encryptedRefreshToken = this.ctx.wbi.encrypt(refreshData.data.refresh_token);
|
|
338
358
|
await this.ctx.database.upsert('loginBili', [{
|
|
339
359
|
id: 1,
|
|
@@ -350,6 +370,10 @@ class BiliAPI extends koishi_1.Service {
|
|
|
350
370
|
const { data: aceeptData } = await this.client.post('https://passport.bilibili.com/x/passport-login/web/confirm/refresh', {
|
|
351
371
|
csrf: newCsrf,
|
|
352
372
|
refresh_token: refreshToken
|
|
373
|
+
}, {
|
|
374
|
+
headers: {
|
|
375
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
376
|
+
}
|
|
353
377
|
});
|
|
354
378
|
// 检查是否有其他问题
|
|
355
379
|
switch (aceeptData.code) {
|
package/lib/comRegister.js
CHANGED
|
@@ -187,7 +187,7 @@ class ComRegister {
|
|
|
187
187
|
}
|
|
188
188
|
if (loginContent.code !== 0) {
|
|
189
189
|
this.loginTimer();
|
|
190
|
-
return await session.send('
|
|
190
|
+
return await session.send('登录失败请重试');
|
|
191
191
|
}
|
|
192
192
|
if (loginContent.data.code === 86038) {
|
|
193
193
|
this.loginTimer();
|
|
@@ -211,6 +211,8 @@ class ComRegister {
|
|
|
211
211
|
await session.send('登录成功');
|
|
212
212
|
// bili show
|
|
213
213
|
await session.execute('bili show');
|
|
214
|
+
// 开启cookies刷新检测
|
|
215
|
+
ctx.biliAPI.enableRefreshCookiesDetect(loginContent.data.refresh_token);
|
|
214
216
|
return;
|
|
215
217
|
}
|
|
216
218
|
}
|
|
@@ -650,7 +652,7 @@ class ComRegister {
|
|
|
650
652
|
let uData;
|
|
651
653
|
// 相当于锁的作用,防止上一个循环没处理完
|
|
652
654
|
let flag = true;
|
|
653
|
-
async
|
|
655
|
+
const sendLiveNotifyCard = async (data, uData, liveType) => {
|
|
654
656
|
let attempts = 3;
|
|
655
657
|
for (let i = 0; i < attempts; i++) {
|
|
656
658
|
try {
|
|
@@ -672,7 +674,7 @@ class ComRegister {
|
|
|
672
674
|
}
|
|
673
675
|
}
|
|
674
676
|
}
|
|
675
|
-
}
|
|
677
|
+
};
|
|
676
678
|
return async () => {
|
|
677
679
|
try {
|
|
678
680
|
// 如果flag为false则说明前面的代码还未执行完,则直接返回
|
|
Binary file
|
package/lib/generateImg.js
CHANGED
|
@@ -49,7 +49,7 @@ class GenerateImg extends koishi_1.Service {
|
|
|
49
49
|
async generateLiveImg(data, userData, liveStatus /*0未开播 1刚开播 2已开播 */) {
|
|
50
50
|
const [titleStatus, liveTime, cover] = await this.getLiveStatus(data.live_time, liveStatus);
|
|
51
51
|
// 加载字体
|
|
52
|
-
const fontURL = (0, url_1.pathToFileURL)((0, path_1.resolve)(__dirname, '
|
|
52
|
+
const fontURL = (0, url_1.pathToFileURL)((0, path_1.resolve)(__dirname, 'font/HYZhengYuan-75W.ttf'));
|
|
53
53
|
// 卡片内容
|
|
54
54
|
const html = `
|
|
55
55
|
<!DOCTYPE html>
|
|
@@ -61,7 +61,7 @@ class GenerateImg extends koishi_1.Service {
|
|
|
61
61
|
font-family: "Custom Font";
|
|
62
62
|
src: url(${fontURL});
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
* {
|
|
66
66
|
margin: 0;
|
|
67
67
|
padding: 0;
|
|
@@ -187,7 +187,7 @@ class GenerateImg extends koishi_1.Service {
|
|
|
187
187
|
`;
|
|
188
188
|
// 判断渲染方式
|
|
189
189
|
if (this.config.renderType) { // 为1则为真,进入page模式
|
|
190
|
-
const htmlPath = 'file://' + __dirname.replaceAll('\\', '/') + '/0.html';
|
|
190
|
+
const htmlPath = 'file://' + __dirname.replaceAll('\\', '/') + '/page/0.html';
|
|
191
191
|
const page = await this.ctx.puppeteer.page();
|
|
192
192
|
await page.goto(htmlPath);
|
|
193
193
|
await page.setContent(html, { waitUntil: 'networkidle0' });
|
|
@@ -514,7 +514,7 @@ class GenerateImg extends koishi_1.Service {
|
|
|
514
514
|
// 获取动态主要内容
|
|
515
515
|
const [main, link] = await getDynamicMajor(data, false);
|
|
516
516
|
// 加载字体
|
|
517
|
-
const fontURL = (0, url_1.pathToFileURL)((0, path_1.resolve)(__dirname, '
|
|
517
|
+
const fontURL = (0, url_1.pathToFileURL)((0, path_1.resolve)(__dirname, 'font/HYZhengYuan-75W.ttf'));
|
|
518
518
|
// 判断是否开启大字体模式
|
|
519
519
|
let style;
|
|
520
520
|
if (this.config.enableLargeFont) {
|
|
@@ -1259,7 +1259,7 @@ class GenerateImg extends koishi_1.Service {
|
|
|
1259
1259
|
`;
|
|
1260
1260
|
// 判断渲染方式
|
|
1261
1261
|
if (this.config.renderType) { // 为1则为真,进入page模式
|
|
1262
|
-
const htmlPath = 'file://' + __dirname.replaceAll('\\', '/') + '/0.html';
|
|
1262
|
+
const htmlPath = 'file://' + __dirname.replaceAll('\\', '/') + '/page/0.html';
|
|
1263
1263
|
const page = await this.ctx.puppeteer.page();
|
|
1264
1264
|
await page.goto(htmlPath);
|
|
1265
1265
|
await page.setContent(html, { waitUntil: 'networkidle0' });
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -81,15 +81,17 @@
|
|
|
81
81
|
- ver 1.0.3 修复了一些bug,提供用户自己选择推送卡片字体样式的选项
|
|
82
82
|
- ver 1.0.4 修复了重复推送的bug,提供用户选择推送卡片渲染方式的选项
|
|
83
83
|
- ver 1.0.5 修复了用户非法篡改数据库内容可能导致程序异常运行的bug,修复了UP主开播动态推送空白卡片的bug
|
|
84
|
-
- ver 1.0.6
|
|
85
|
-
- ver 1.0.7 修复了在已登录情况下,再次登录会导致重复订阅和提示用户未订阅任何UP主的提示(实际上已订阅)的bug
|
|
84
|
+
- ver 1.0.6 修复了转发动态转发信息出现`undefined`的bug,修复了再次登录订阅显示错误的bug,优化了动态推送的逻辑
|
|
85
|
+
- ver 1.0.7 修复了在已登录情况下,再次登录会导致重复订阅和提示用户未订阅任何UP主的提示(实际上已订阅)的bug,新增了订阅对象在控制台的显示,优化了`bili show`指令的逻辑
|
|
86
86
|
- ver 1.0.8 修复了取消订阅的bug
|
|
87
87
|
- ver 1.0.9 更新请求客户端header信息。优化了动态推送卡片的页面布局,增加了字体大小。提供用户开放订阅数量限制的选项,提供用户移除推送卡片边框的选项。在控制台页面增加订阅信息提示
|
|
88
|
-
- ver 1.0.10
|
|
89
|
-
- ver 1.0.11
|
|
88
|
+
- ver 1.0.10 增加对`onebot`的支持,添加动态关键字屏蔽功能
|
|
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
|
|
92
|
+
- ver 1.0.14 修复了获取二维码,二维码失效后会多次发送提示的bug,新增对`red`的支持,新增开播艾特全体成员功能,优化了部分逻辑
|
|
93
|
+
- ver 1.1.0-alpha.0 修复了直播订阅一段时间过后提示房间不存在的bug,修复了自动登录刷新错误的bug
|
|
94
|
+
- ver 1.1.0-beta.0 修复了一个bug(如果本身已经存在乱码问题的情况下,使用page模式仍然会乱码),修复了日志bug
|
|
93
95
|
|
|
94
96
|
## 感谢
|
|
95
97
|
|
package/lib/HYZhengYuan-55W.ttf
DELETED
|
Binary file
|
|
File without changes
|