koishi-plugin-bilibili-notify 0.1.2 → 1.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/authority.d.ts +5 -0
- package/lib/authority.js +12 -0
- package/lib/biliAPI.d.ts +2 -2
- package/lib/biliAPI.js +91 -25
- package/lib/comRegister.d.ts +6 -2
- package/lib/comRegister.js +280 -107
- package/lib/index.js +2 -0
- package/package.json +5 -1
package/lib/authority.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class Authority {
|
|
4
|
+
constructor(ctx) {
|
|
5
|
+
// 授予权限
|
|
6
|
+
/* ctx.permissions.provide('telegram:admin', async (name, session) => {
|
|
7
|
+
console.log(session);
|
|
8
|
+
return session.telegram?.sender?.role === 'admin'
|
|
9
|
+
}) */
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.default = Authority;
|
package/lib/biliAPI.d.ts
CHANGED
|
@@ -22,8 +22,8 @@ declare class BiliAPI extends Service {
|
|
|
22
22
|
getLiveRoomInfo(roomId: string): Promise<any>;
|
|
23
23
|
getMasterInfo(mid: string): Promise<any>;
|
|
24
24
|
createNewClient(): void;
|
|
25
|
-
getCookies():
|
|
25
|
+
getCookies(): string;
|
|
26
26
|
loadCookiesFromDatabase(): Promise<void>;
|
|
27
|
-
checkIfTokenNeedRefresh(refreshToken: string, csrf: string): Promise<void>;
|
|
27
|
+
checkIfTokenNeedRefresh(refreshToken: string, csrf: string, times?: number): Promise<void>;
|
|
28
28
|
}
|
|
29
29
|
export default BiliAPI;
|
package/lib/biliAPI.js
CHANGED
|
@@ -35,48 +35,93 @@ class BiliAPI extends koishi_1.Service {
|
|
|
35
35
|
this.logger.info('BiliAPI已被注册到Context中');
|
|
36
36
|
}
|
|
37
37
|
async getTimeNow() {
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
try {
|
|
39
|
+
const { data } = await this.client.get(GET_TIME_NOW);
|
|
40
|
+
return data;
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
throw new Error('网络异常,本次请求失败!');
|
|
44
|
+
}
|
|
40
45
|
}
|
|
41
46
|
async getUserSpaceDynamic(mid) {
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
try {
|
|
48
|
+
const { data } = await this.client.get(`${GET_USER_SPACE_DYNAMIC_LIST}?host_mid=${mid}`);
|
|
49
|
+
return data;
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
throw new Error('网络异常,本次请求失败!');
|
|
53
|
+
}
|
|
44
54
|
}
|
|
45
55
|
// Check if Token need refresh
|
|
46
56
|
async getCookieInfo(refreshToken) {
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
try {
|
|
58
|
+
const { data } = await this.client.get(`${GET_COOKIES_INFO}?csrf=${refreshToken}`);
|
|
59
|
+
return data;
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
throw new Error('网络异常,本次请求失败!');
|
|
63
|
+
}
|
|
49
64
|
}
|
|
50
65
|
async getUserInfo(mid) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
try {
|
|
67
|
+
const wbi = await this.ctx.wbi.getWbi({ mid });
|
|
68
|
+
const { data } = await this.client.get(`${GET_USER_INFO}?${wbi}`);
|
|
69
|
+
return data;
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
throw new Error('网络异常,本次请求失败!');
|
|
73
|
+
}
|
|
54
74
|
}
|
|
55
75
|
async getMyselfInfo() {
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
try {
|
|
77
|
+
const { data } = await this.client.get(GET_MYSELF_INFO);
|
|
78
|
+
return data;
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
throw new Error('网络异常,本次请求失败!');
|
|
82
|
+
}
|
|
58
83
|
}
|
|
59
84
|
async getLoginQRCode() {
|
|
60
|
-
|
|
61
|
-
|
|
85
|
+
try {
|
|
86
|
+
const { data } = await this.client.get(GET_LOGIN_QRCODE);
|
|
87
|
+
return data;
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
throw new Error('网络异常,本次请求失败!');
|
|
91
|
+
}
|
|
62
92
|
}
|
|
63
93
|
async getLoginStatus(qrcodeKey) {
|
|
64
|
-
|
|
65
|
-
|
|
94
|
+
try {
|
|
95
|
+
const { data } = await this.client.get(`${GET_LOGIN_STATUS}?qrcode_key=${qrcodeKey}`);
|
|
96
|
+
return data;
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
throw new Error('网络异常,本次请求失败!');
|
|
100
|
+
}
|
|
66
101
|
}
|
|
67
102
|
async getLiveRoomInfo(roomId) {
|
|
68
|
-
|
|
69
|
-
|
|
103
|
+
try {
|
|
104
|
+
const { data } = await this.client.get(`${GET_LIVE_ROOM_INFO}?room_id=${roomId}`);
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
throw new Error('网络异常,本次请求失败!');
|
|
109
|
+
}
|
|
70
110
|
}
|
|
71
111
|
async getMasterInfo(mid) {
|
|
72
|
-
|
|
73
|
-
|
|
112
|
+
try {
|
|
113
|
+
const { data } = await this.client.get(`${GET_MASTER_INFO}?uid=${mid}`);
|
|
114
|
+
return data;
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
throw new Error('网络异常,本次请求失败!');
|
|
118
|
+
}
|
|
74
119
|
}
|
|
75
120
|
createNewClient() {
|
|
76
121
|
this.jar = new tough_cookie_1.CookieJar();
|
|
77
122
|
this.client = (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({ jar: this.jar, headers: { 'Content-Type': 'application/json' } }));
|
|
78
123
|
}
|
|
79
|
-
|
|
124
|
+
getCookies() {
|
|
80
125
|
let cookies;
|
|
81
126
|
this.jar.store.getAllCookies((err, c) => {
|
|
82
127
|
if (err)
|
|
@@ -120,8 +165,22 @@ class BiliAPI extends koishi_1.Service {
|
|
|
120
165
|
// Check if token need refresh
|
|
121
166
|
this.checkIfTokenNeedRefresh(decryptedRefreshToken, csrf);
|
|
122
167
|
}
|
|
123
|
-
async checkIfTokenNeedRefresh(refreshToken, csrf) {
|
|
124
|
-
|
|
168
|
+
async checkIfTokenNeedRefresh(refreshToken, csrf, times = 0) {
|
|
169
|
+
let data;
|
|
170
|
+
try {
|
|
171
|
+
const { data: cookieData } = await this.getCookieInfo(refreshToken);
|
|
172
|
+
data = cookieData;
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
// 发送三次仍网络错误则给管理员发送错误信息
|
|
176
|
+
if (times > 3)
|
|
177
|
+
return;
|
|
178
|
+
// 等待3秒再次尝试
|
|
179
|
+
this.ctx.setTimeout(() => {
|
|
180
|
+
this.checkIfTokenNeedRefresh(refreshToken, csrf, times + 1);
|
|
181
|
+
}, 3000);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
125
184
|
// 不需要刷新,直接返回
|
|
126
185
|
if (!data.refresh)
|
|
127
186
|
return;
|
|
@@ -135,7 +194,8 @@ class BiliAPI extends koishi_1.Service {
|
|
|
135
194
|
const encrypted = new Uint8Array(await crypto.subtle.encrypt({ name: "RSA-OAEP" }, publicKey, data));
|
|
136
195
|
return encrypted.reduce((str, c) => str + c.toString(16).padStart(2, "0"), "");
|
|
137
196
|
}
|
|
138
|
-
const correspondPath = await getCorrespondPath(
|
|
197
|
+
const correspondPath = await getCorrespondPath(data.timestamp);
|
|
198
|
+
// 获取refresh_csrf
|
|
139
199
|
const { data: refreshCsrfHtml } = await this.client.get(`https://www.bilibili.com/correspond/1/${correspondPath}`);
|
|
140
200
|
// 创建一个虚拟的DOM元素
|
|
141
201
|
const { document } = new jsdom_1.JSDOM(refreshCsrfHtml).window;
|
|
@@ -153,8 +213,14 @@ class BiliAPI extends koishi_1.Service {
|
|
|
153
213
|
switch (refreshData.code) {
|
|
154
214
|
// 账号未登录
|
|
155
215
|
case -101: return this.createNewClient();
|
|
156
|
-
case -111:
|
|
157
|
-
|
|
216
|
+
case -111: {
|
|
217
|
+
await this.ctx.database.remove('loginBili', [1]);
|
|
218
|
+
throw new Error('csrf 校验失败');
|
|
219
|
+
}
|
|
220
|
+
case 86095: {
|
|
221
|
+
await this.ctx.database.remove('loginBili', [1]);
|
|
222
|
+
throw new Error('refresh_csrf 错误或 refresh_token 与 cookie 不匹配');
|
|
223
|
+
}
|
|
158
224
|
}
|
|
159
225
|
// 更新refresh_token
|
|
160
226
|
await this.ctx.database.upsert('loginBili', [{
|
package/lib/comRegister.d.ts
CHANGED
|
@@ -17,14 +17,18 @@ declare class ComRegister {
|
|
|
17
17
|
qqBot: Bot<Context>;
|
|
18
18
|
qqguildBot: Bot<Context>;
|
|
19
19
|
constructor(ctx: Context, config: ComRegister.Config);
|
|
20
|
-
dynamicDetect(ctx: Context, bot: Bot<Context>,
|
|
21
|
-
liveDetect(ctx: Context, bot: Bot<Context>,
|
|
20
|
+
dynamicDetect(ctx: Context, bot: Bot<Context>, guildId: string, uid: string): () => Promise<void>;
|
|
21
|
+
liveDetect(ctx: Context, bot: Bot<Context>, guildId: string, roomId: string): () => Promise<false | void>;
|
|
22
22
|
checkIfNeedSub(comNeed: boolean, subType: string, session: Session, data?: any): Promise<boolean>;
|
|
23
23
|
getSubFromDatabase(ctx: Context): Promise<void>;
|
|
24
|
+
unsubSingle(ctx: Context, id: string, type: number): string;
|
|
25
|
+
checkIfIsLogin(ctx: Context): Promise<boolean>;
|
|
24
26
|
}
|
|
25
27
|
declare namespace ComRegister {
|
|
26
28
|
interface Config {
|
|
27
29
|
pushTime: number;
|
|
30
|
+
liveLoopTime: number;
|
|
31
|
+
dynamicLoopTime: number;
|
|
28
32
|
}
|
|
29
33
|
const Config: Schema<Config>;
|
|
30
34
|
}
|
package/lib/comRegister.js
CHANGED
|
@@ -30,7 +30,7 @@ class ComRegister {
|
|
|
30
30
|
// 拿到QQ频道机器人
|
|
31
31
|
this.qqguildBot = ctx.bots[ctx.bots.findIndex(bot => bot.platform === 'qqguild')];
|
|
32
32
|
this.getSubFromDatabase(ctx);
|
|
33
|
-
ctx.command('test')
|
|
33
|
+
ctx.command('test', { hidden: true, permissions: ['authority:5'] })
|
|
34
34
|
.subcommand('.cookies')
|
|
35
35
|
.usage('测试指令,用于测试从数据库读取cookies')
|
|
36
36
|
.action(async () => {
|
|
@@ -72,19 +72,12 @@ class ComRegister {
|
|
|
72
72
|
.subcommand('.gimg <uid:string> <index:number>')
|
|
73
73
|
.usage('测试图片生成')
|
|
74
74
|
.example('test.gimg')
|
|
75
|
-
.action(async (
|
|
75
|
+
.action(async ({ session }, uid, index) => {
|
|
76
76
|
// 获取用户空间动态数据
|
|
77
77
|
const { data } = await ctx.biliAPI.getUserSpaceDynamic(uid);
|
|
78
78
|
const [pic] = await ctx.gimg.generateDynamicImg(data.items[index]);
|
|
79
79
|
return pic;
|
|
80
80
|
});
|
|
81
|
-
ctx.command('test')
|
|
82
|
-
.subcommand('.subm')
|
|
83
|
-
.usage('查看订阅对象状态')
|
|
84
|
-
.example('test subm')
|
|
85
|
-
.action(() => {
|
|
86
|
-
console.log(this.subManager);
|
|
87
|
-
});
|
|
88
81
|
ctx.command('test')
|
|
89
82
|
.subcommand('.group')
|
|
90
83
|
.usage('查看session groupId')
|
|
@@ -99,14 +92,20 @@ class ComRegister {
|
|
|
99
92
|
.action(({ session }) => {
|
|
100
93
|
console.log(session);
|
|
101
94
|
});
|
|
102
|
-
ctx.command('bili', 'bili-notify插件相关指令')
|
|
95
|
+
ctx.command('bili', 'bili-notify插件相关指令', { permissions: ['authority:3'] })
|
|
103
96
|
.subcommand('.login', '登录B站之后才可以进行之后的操作')
|
|
104
97
|
.usage('使用二维码登录,登录B站之后才可以进行之后的操作')
|
|
105
98
|
.example('bili login')
|
|
106
99
|
.action(async ({ session }) => {
|
|
107
100
|
this.logger.info('调用bili login指令');
|
|
108
101
|
// 获取二维码
|
|
109
|
-
|
|
102
|
+
let content;
|
|
103
|
+
try {
|
|
104
|
+
content = await ctx.biliAPI.getLoginQRCode();
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
return 'bili login getLoginQRCode() 本次网络请求失败';
|
|
108
|
+
}
|
|
110
109
|
// 判断是否出问题
|
|
111
110
|
if (content.code !== 0)
|
|
112
111
|
return await session.send('出问题咯,请联系管理员解决!');
|
|
@@ -131,7 +130,14 @@ class ComRegister {
|
|
|
131
130
|
let dispose;
|
|
132
131
|
// 发起登录请求检查登录状态
|
|
133
132
|
dispose = ctx.setInterval(async () => {
|
|
134
|
-
|
|
133
|
+
let loginContent;
|
|
134
|
+
try {
|
|
135
|
+
loginContent = await ctx.biliAPI.getLoginStatus(content.data.qrcode_key);
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
this.logger.error(e);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
135
141
|
if (loginContent.code !== 0) {
|
|
136
142
|
dispose();
|
|
137
143
|
return await session.send('登录失败!请联系管理员解决!');
|
|
@@ -148,16 +154,25 @@ class ComRegister {
|
|
|
148
154
|
bili_cookies: encryptedCookies,
|
|
149
155
|
bili_refresh_token: encryptedRefreshToken
|
|
150
156
|
}]);
|
|
157
|
+
// 销毁定时器
|
|
151
158
|
dispose();
|
|
152
|
-
|
|
159
|
+
// 发送成功登录推送
|
|
160
|
+
await session.send('登录成功!');
|
|
161
|
+
// 订阅之前的订阅
|
|
162
|
+
await this.getSubFromDatabase(ctx);
|
|
163
|
+
// 调用bili show指令
|
|
164
|
+
await session.execute('bili show');
|
|
165
|
+
return;
|
|
153
166
|
}
|
|
154
167
|
}, 1000);
|
|
155
168
|
});
|
|
156
169
|
ctx.command('bili')
|
|
157
|
-
.subcommand('.unsub <uid:string>')
|
|
158
|
-
.usage('
|
|
159
|
-
.
|
|
160
|
-
.
|
|
170
|
+
.subcommand('.unsub <uid:string>', '取消订阅UP主动态、直播或全部')
|
|
171
|
+
.usage('取消订阅,加-l为取消直播订阅,加-d为取消动态订阅,什么都不加则为全部取消')
|
|
172
|
+
.option('live', '-l')
|
|
173
|
+
.option('dynamic', '-d')
|
|
174
|
+
.example('bili unsub 用户UID -ld')
|
|
175
|
+
.action(async ({ session, options }, uid) => {
|
|
161
176
|
this.logger.info('调用bili.unsub指令');
|
|
162
177
|
// 若用户UID为空则直接返回
|
|
163
178
|
if (!uid)
|
|
@@ -166,9 +181,21 @@ class ComRegister {
|
|
|
166
181
|
let exist;
|
|
167
182
|
await Promise.all(this.subManager.map(async (sub, i) => {
|
|
168
183
|
if (sub.uid === uid) {
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
184
|
+
// 取消单个订阅
|
|
185
|
+
if (options.live || options.dynamic) {
|
|
186
|
+
if (options.live)
|
|
187
|
+
await session.send(this.unsubSingle(ctx, sub.roomId, 0)); /* 0为取消订阅Live */
|
|
188
|
+
if (options.dynamic)
|
|
189
|
+
await session.send(this.unsubSingle(ctx, sub.uid, 1)); /* 1为取消订阅Dynamic */
|
|
190
|
+
// 将存在flag设置为true
|
|
191
|
+
exist = true;
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// 取消全部订阅 执行dispose方法,销毁定时器
|
|
195
|
+
if (sub.dynamic)
|
|
196
|
+
this.subManager[i].dynamicDispose();
|
|
197
|
+
if (sub.live)
|
|
198
|
+
this.subManager[i].liveDispose();
|
|
172
199
|
// 从数据库中删除订阅
|
|
173
200
|
await ctx.database.remove('bilibili', { uid: this.subManager[i].uid });
|
|
174
201
|
// 将该订阅对象从订阅管理对象中移除
|
|
@@ -185,25 +212,30 @@ class ComRegister {
|
|
|
185
212
|
!exist && session.send('未订阅该用户,无需取消订阅');
|
|
186
213
|
});
|
|
187
214
|
ctx.command('bili')
|
|
188
|
-
.subcommand('.show')
|
|
215
|
+
.subcommand('.show', '展示订阅对象')
|
|
189
216
|
.usage('展示订阅对象')
|
|
190
217
|
.example('bili show')
|
|
191
218
|
.action(async ({ session }) => {
|
|
192
219
|
let table = ``;
|
|
193
220
|
this.subManager.forEach(sub => {
|
|
194
|
-
table +=
|
|
221
|
+
table += `UID:${sub.uid} ${sub.dynamic ? '已订阅动态' : ''} ${sub.live ? '已订阅直播' : ''}` + '\n';
|
|
195
222
|
});
|
|
196
223
|
!table && session.send('没有订阅任何UP');
|
|
197
224
|
table && session.send(table);
|
|
198
225
|
});
|
|
199
226
|
ctx.command('bili')
|
|
200
|
-
.subcommand('.sub <mid:string> [guildId:string]')
|
|
227
|
+
.subcommand('.sub <mid:string> [guildId:string]', '订阅用户动态和直播通知')
|
|
201
228
|
.option('live', '-l')
|
|
202
229
|
.option('dynamic', '-d')
|
|
203
|
-
.usage('订阅用户动态和直播通知,若需要订阅直播请加上-l,需要订阅动态则加上-d
|
|
230
|
+
.usage('订阅用户动态和直播通知,若需要订阅直播请加上-l,需要订阅动态则加上-d。若没有加任何参数,之后会向你单独询问,尖括号中为必选参数,中括号为可选参数,目标群号若不填,则默认为当前群聊')
|
|
204
231
|
.example('bili sub 用户uid 目标QQ群号(暂不支持) -l -d')
|
|
205
232
|
.action(async ({ session, options }, mid, guildId) => {
|
|
206
233
|
this.logger.info('调用bili.sub指令');
|
|
234
|
+
// 检查是否登录
|
|
235
|
+
if (!(await this.checkIfIsLogin(ctx))) {
|
|
236
|
+
// 未登录直接返回
|
|
237
|
+
return '请使用指令bili login登录后再进行订阅操作';
|
|
238
|
+
}
|
|
207
239
|
// 如果订阅人数超过三个则直接返回
|
|
208
240
|
if (this.num >= 3)
|
|
209
241
|
return '目前最多只能订阅三个人';
|
|
@@ -217,7 +249,13 @@ class ComRegister {
|
|
|
217
249
|
// 定义是否需要直播通知,动态订阅,视频推送
|
|
218
250
|
let liveMsg, dynamicMsg;
|
|
219
251
|
// 获取用户信息
|
|
220
|
-
|
|
252
|
+
let content;
|
|
253
|
+
try {
|
|
254
|
+
content = await ctx.biliAPI.getUserInfo(mid);
|
|
255
|
+
}
|
|
256
|
+
catch (e) {
|
|
257
|
+
return 'bili sub getUserInfo() 本次网络请求失败';
|
|
258
|
+
}
|
|
221
259
|
// 判断是否有其他问题
|
|
222
260
|
if (content.code !== 0) {
|
|
223
261
|
let msg;
|
|
@@ -299,7 +337,14 @@ class ComRegister {
|
|
|
299
337
|
dynamicDispose: null
|
|
300
338
|
});
|
|
301
339
|
// 获取用户信息
|
|
302
|
-
|
|
340
|
+
let userData;
|
|
341
|
+
try {
|
|
342
|
+
const { data } = await ctx.biliAPI.getMasterInfo(sub.uid);
|
|
343
|
+
userData = data;
|
|
344
|
+
}
|
|
345
|
+
catch (e) {
|
|
346
|
+
return 'bili sub指令 getMasterInfo() 网络请求失败';
|
|
347
|
+
}
|
|
303
348
|
// 需要订阅直播
|
|
304
349
|
if (liveMsg) {
|
|
305
350
|
await session.execute(`bili live ${data.live_room.roomid} ${guildId} -b ${platform}`);
|
|
@@ -314,7 +359,7 @@ class ComRegister {
|
|
|
314
359
|
}
|
|
315
360
|
});
|
|
316
361
|
ctx.command('bili')
|
|
317
|
-
.subcommand('.dynamic <uid:string>')
|
|
362
|
+
.subcommand('.dynamic <uid:string> <guildId:string>', '订阅用户动态推送', { hidden: true })
|
|
318
363
|
.option('bot', '-b <type:string>')
|
|
319
364
|
.usage('订阅用户动态推送')
|
|
320
365
|
.example('bili dynamic 1')
|
|
@@ -323,6 +368,8 @@ class ComRegister {
|
|
|
323
368
|
// 如果uid为空则返回
|
|
324
369
|
if (!uid)
|
|
325
370
|
return '用户uid不能为空';
|
|
371
|
+
if (!guildId)
|
|
372
|
+
return '目标群组或频道不能为空';
|
|
326
373
|
if (!options.bot)
|
|
327
374
|
return '非法调用';
|
|
328
375
|
// 保存到订阅管理对象
|
|
@@ -349,11 +396,11 @@ class ComRegister {
|
|
|
349
396
|
this.subManager[index].dynamicDispose = dispose;
|
|
350
397
|
});
|
|
351
398
|
ctx.command('bili')
|
|
352
|
-
.subcommand('.live <roomId:string> <guildId:string>')
|
|
399
|
+
.subcommand('.live <roomId:string> <guildId:string>', '订阅主播开播通知', { hidden: true })
|
|
353
400
|
.option('bot', '-b <type:string>')
|
|
354
401
|
.usage('订阅主播开播通知')
|
|
355
402
|
.example('bili live 732')
|
|
356
|
-
.action(async ({
|
|
403
|
+
.action(async ({ options }, roomId, guildId) => {
|
|
357
404
|
this.logger.info('调用bili.live指令');
|
|
358
405
|
// 如果room_id为空则返回
|
|
359
406
|
if (!roomId)
|
|
@@ -384,16 +431,29 @@ class ComRegister {
|
|
|
384
431
|
this.subManager[index].liveDispose = dispose;
|
|
385
432
|
});
|
|
386
433
|
ctx.command('bili')
|
|
387
|
-
.subcommand('.status <roomId:string>')
|
|
434
|
+
.subcommand('.status <roomId:string>', '查询主播当前直播状态', { hidden: true })
|
|
388
435
|
.usage('查询主播当前直播状态')
|
|
389
436
|
.example('bili status 732')
|
|
390
437
|
.action(async ({ session }, roomId) => {
|
|
391
438
|
this.logger.info('调用bili.status指令');
|
|
392
439
|
if (!roomId)
|
|
393
440
|
return session.send('请输入房间号!');
|
|
394
|
-
|
|
441
|
+
let content;
|
|
442
|
+
try {
|
|
443
|
+
content = await ctx.biliAPI.getLiveRoomInfo(roomId);
|
|
444
|
+
}
|
|
445
|
+
catch (e) {
|
|
446
|
+
return 'bili status指令 getLiveRoomInfo() 本次网络请求失败';
|
|
447
|
+
}
|
|
395
448
|
const { data } = content;
|
|
396
|
-
|
|
449
|
+
let userData;
|
|
450
|
+
try {
|
|
451
|
+
const { data: userInfo } = await ctx.biliAPI.getMasterInfo(data.uid);
|
|
452
|
+
userData = userInfo;
|
|
453
|
+
}
|
|
454
|
+
catch (e) {
|
|
455
|
+
return 'bili status指令 getMasterInfo() 网络请求失败';
|
|
456
|
+
}
|
|
397
457
|
// B站出问题了
|
|
398
458
|
if (content.code !== 0) {
|
|
399
459
|
if (content.msg === '未找到该房间') {
|
|
@@ -411,7 +471,7 @@ class ComRegister {
|
|
|
411
471
|
session.send(string);
|
|
412
472
|
});
|
|
413
473
|
}
|
|
414
|
-
dynamicDetect(ctx, bot,
|
|
474
|
+
dynamicDetect(ctx, bot, guildId, uid) {
|
|
415
475
|
let firstSubscription = true;
|
|
416
476
|
let timePoint;
|
|
417
477
|
return async () => {
|
|
@@ -424,17 +484,26 @@ class ComRegister {
|
|
|
424
484
|
return;
|
|
425
485
|
}
|
|
426
486
|
// 获取用户空间动态数据
|
|
427
|
-
|
|
487
|
+
let content;
|
|
488
|
+
try {
|
|
489
|
+
content = await ctx.biliAPI.getUserSpaceDynamic(uid);
|
|
490
|
+
}
|
|
491
|
+
catch (e) {
|
|
492
|
+
return this.logger.error('dynamicDetect getUserSpaceDynamic() 网络请求失败');
|
|
493
|
+
}
|
|
428
494
|
// 判断是否出现其他问题
|
|
429
495
|
if (content.code !== 0) {
|
|
430
496
|
switch (content.code) {
|
|
431
497
|
case -101: { // 账号未登录
|
|
432
|
-
|
|
498
|
+
bot.sendMessage(guildId, '账号未登录,请登录后重新订阅动态');
|
|
433
499
|
}
|
|
434
500
|
default: { // 未知错误
|
|
435
|
-
|
|
501
|
+
bot.sendMessage(guildId, '未知错误,请重新订阅动态');
|
|
436
502
|
}
|
|
437
503
|
}
|
|
504
|
+
// 取消订阅
|
|
505
|
+
this.unsubSingle(ctx, uid, 1); /* 1为取消动态订阅 */
|
|
506
|
+
return;
|
|
438
507
|
}
|
|
439
508
|
// 获取数据内容
|
|
440
509
|
const items = content.data.items;
|
|
@@ -458,94 +527,126 @@ class ComRegister {
|
|
|
458
527
|
}
|
|
459
528
|
// 推送该条动态
|
|
460
529
|
const [pic] = await ctx.gimg.generateDynamicImg(items[num]);
|
|
461
|
-
await bot.sendMessage(
|
|
530
|
+
await bot.sendMessage(guildId, pic);
|
|
462
531
|
}
|
|
463
532
|
}
|
|
464
533
|
};
|
|
465
534
|
}
|
|
466
|
-
liveDetect(ctx, bot,
|
|
535
|
+
liveDetect(ctx, bot, guildId, roomId) {
|
|
467
536
|
let firstSubscription = true;
|
|
468
537
|
let timer = 0;
|
|
469
538
|
let open = false;
|
|
470
539
|
let liveTime;
|
|
471
540
|
let uData;
|
|
541
|
+
// 相当于锁的作用,防止上一个循环没处理完
|
|
542
|
+
let flag = true;
|
|
472
543
|
return async () => {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
544
|
+
try {
|
|
545
|
+
// 如果flag为false则说明前面的代码还未执行完,则直接返回
|
|
546
|
+
if (!flag)
|
|
547
|
+
return flag = false;
|
|
548
|
+
// 发送请求检测直播状态
|
|
549
|
+
let content;
|
|
550
|
+
try {
|
|
551
|
+
content = await ctx.biliAPI.getLiveRoomInfo(roomId);
|
|
480
552
|
}
|
|
481
|
-
|
|
482
|
-
|
|
553
|
+
catch (e) {
|
|
554
|
+
return this.logger.error('liveDetect getLiveRoomInfo 网络请求失败');
|
|
483
555
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
// 获取主播信息
|
|
490
|
-
const { data: userData } = await ctx.biliAPI.getMasterInfo(data.uid);
|
|
491
|
-
// 主播信息不会变,请求一次即可
|
|
492
|
-
uData = userData;
|
|
493
|
-
// 判断直播状态
|
|
494
|
-
if (data.live_status === 1) { // 当前正在直播
|
|
495
|
-
// 推送直播信息
|
|
496
|
-
await bot.sendMessage(groupId, await ctx
|
|
497
|
-
.gimg
|
|
498
|
-
.generateLiveImg(data, uData, LiveType.LiveBroadcast));
|
|
499
|
-
// 改变开播状态
|
|
500
|
-
open = true;
|
|
501
|
-
} // 未开播,直接返回
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
// 检查直播状态
|
|
505
|
-
switch (data.live_status) {
|
|
506
|
-
case 0:
|
|
507
|
-
case 2: { // 状态 0 和 2 说明未开播
|
|
508
|
-
if (open) { // 之前开播,现在下播了
|
|
509
|
-
// 更改直播状态
|
|
510
|
-
open = false;
|
|
511
|
-
// 下播了将定时器清零
|
|
512
|
-
timer = 0;
|
|
513
|
-
// 发送下播通知
|
|
514
|
-
bot.sendMessage(groupId, `${uData.info.uname}下播啦,本次直播了${ctx.gimg.getTimeDifference(liveTime)}`);
|
|
556
|
+
const { data } = content;
|
|
557
|
+
// B站出问题了
|
|
558
|
+
if (content.code !== 0) {
|
|
559
|
+
if (content.msg === '未找到该房间') {
|
|
560
|
+
await bot.sendMessage(guildId, '未找到该房间,请检查房间号后重新订阅');
|
|
515
561
|
}
|
|
516
|
-
|
|
517
|
-
|
|
562
|
+
else {
|
|
563
|
+
await bot.sendMessage(guildId, '未知错误,请呼叫管理员检查问题后重新订阅');
|
|
564
|
+
}
|
|
565
|
+
// dispose
|
|
566
|
+
this.unsubSingle(ctx, roomId, 0); /* 0为取消Live订阅 */
|
|
567
|
+
return;
|
|
518
568
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
569
|
+
if (firstSubscription) {
|
|
570
|
+
firstSubscription = false;
|
|
571
|
+
// 获取主播信息
|
|
572
|
+
let userData;
|
|
573
|
+
try {
|
|
574
|
+
const { data: userInfo } = await ctx.biliAPI.getMasterInfo(data.uid);
|
|
575
|
+
userData = userInfo;
|
|
576
|
+
}
|
|
577
|
+
catch (e) {
|
|
578
|
+
return this.logger.error('liveDetect first sub getMasterInfo() 网络请求错误');
|
|
579
|
+
}
|
|
580
|
+
// 主播信息不会变,请求一次即可
|
|
581
|
+
uData = userData;
|
|
582
|
+
// 判断直播状态
|
|
583
|
+
if (data.live_status === 1) { // 当前正在直播
|
|
584
|
+
// 推送直播信息
|
|
585
|
+
await bot.sendMessage(guildId, await ctx
|
|
586
|
+
.gimg
|
|
587
|
+
.generateLiveImg(data, uData, LiveType.LiveBroadcast));
|
|
588
|
+
// 改变开播状态
|
|
522
589
|
open = true;
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
590
|
+
} // 未开播,直接返回
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
// 检查直播状态
|
|
594
|
+
switch (data.live_status) {
|
|
595
|
+
case 0:
|
|
596
|
+
case 2: { // 状态 0 和 2 说明未开播
|
|
597
|
+
if (open) { // 之前开播,现在下播了
|
|
598
|
+
// 更改直播状态
|
|
599
|
+
open = false;
|
|
600
|
+
// 下播了将定时器清零
|
|
601
|
+
timer = 0;
|
|
602
|
+
// 发送下播通知
|
|
603
|
+
bot.sendMessage(guildId, `${uData.info.uname}下播啦,本次直播了${ctx.gimg.getTimeDifference(liveTime)}`);
|
|
604
|
+
}
|
|
605
|
+
// 未进循环,还未开播,继续循环
|
|
606
|
+
break;
|
|
531
607
|
}
|
|
532
|
-
|
|
533
|
-
if (
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
608
|
+
case 1: {
|
|
609
|
+
if (!open) { // 之前未开播,现在开播了
|
|
610
|
+
// 更改直播状态
|
|
611
|
+
open = true;
|
|
612
|
+
// 设置开播时间
|
|
613
|
+
liveTime = data.live_time;
|
|
614
|
+
// 获取主播信息
|
|
615
|
+
let userData;
|
|
616
|
+
try {
|
|
617
|
+
const { data: userInfo } = await ctx.biliAPI.getMasterInfo(data.uid);
|
|
618
|
+
userData = userInfo;
|
|
619
|
+
}
|
|
620
|
+
catch (e) {
|
|
621
|
+
return this.logger.error('liveDetect open getMasterInfo() 网络请求错误');
|
|
622
|
+
}
|
|
623
|
+
// 主播信息不会变,开播时刷新一次即可
|
|
624
|
+
uData = userData;
|
|
625
|
+
// 发送直播通知
|
|
626
|
+
await bot.sendMessage(guildId, await ctx.gimg.generateLiveImg(data, uData, LiveType.StartBroadcasting));
|
|
627
|
+
}
|
|
628
|
+
else { // 还在直播
|
|
629
|
+
if (this.config.pushTime > 0) {
|
|
630
|
+
timer++;
|
|
631
|
+
// 开始记录时间
|
|
632
|
+
if (timer >= (12 * 30 * this.config.pushTime)) { // 到时间推送直播消息
|
|
633
|
+
// 到时间重新计时
|
|
634
|
+
timer = 0;
|
|
635
|
+
// 发送状态信息
|
|
636
|
+
bot.sendMessage(guildId, await ctx
|
|
637
|
+
.gimg
|
|
638
|
+
.generateLiveImg(data, uData, LiveType.LiveBroadcast));
|
|
639
|
+
}
|
|
543
640
|
}
|
|
641
|
+
// 否则继续循环
|
|
544
642
|
}
|
|
545
|
-
// 否则继续循环
|
|
546
643
|
}
|
|
547
644
|
}
|
|
548
645
|
}
|
|
646
|
+
finally {
|
|
647
|
+
// 执行完方法体不论如何都把flag设置为true
|
|
648
|
+
flag = true;
|
|
649
|
+
}
|
|
549
650
|
};
|
|
550
651
|
}
|
|
551
652
|
async checkIfNeedSub(comNeed, subType, session, data) {
|
|
@@ -583,6 +684,9 @@ class ComRegister {
|
|
|
583
684
|
}
|
|
584
685
|
}
|
|
585
686
|
async getSubFromDatabase(ctx) {
|
|
687
|
+
if (!(await this.checkIfIsLogin(ctx))) { // 如果未登录,则直接返回
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
586
690
|
// 从数据库中获取数据
|
|
587
691
|
const subData = await ctx.database.get('bilibili', { id: { $gt: 0 } });
|
|
588
692
|
// 设定订阅数量
|
|
@@ -614,26 +718,95 @@ class ComRegister {
|
|
|
614
718
|
// 判断需要订阅的服务
|
|
615
719
|
if (sub.dynamic) { // 需要订阅动态
|
|
616
720
|
// 开始循环检测
|
|
617
|
-
const dispose = ctx.setInterval(this.dynamicDetect(ctx, bot, sub.targetId, sub.uid),
|
|
721
|
+
const dispose = ctx.setInterval(this.dynamicDetect(ctx, bot, sub.targetId, sub.uid), this.config.dynamicLoopTime * 1000);
|
|
618
722
|
// 保存销毁函数
|
|
619
723
|
subManagerItem.dynamicDispose = dispose;
|
|
620
724
|
}
|
|
621
725
|
if (sub.live) { // 需要订阅动态
|
|
622
726
|
// 开始循环检测
|
|
623
|
-
const dispose = ctx.setInterval(this.liveDetect(ctx, bot, sub.targetId, sub.room_id),
|
|
727
|
+
const dispose = ctx.setInterval(this.liveDetect(ctx, bot, sub.targetId, sub.room_id), this.config.liveLoopTime * 1000);
|
|
624
728
|
// 保存销毁函数
|
|
625
729
|
subManagerItem.liveDispose = dispose;
|
|
626
730
|
}
|
|
627
731
|
// 保存新订阅对象
|
|
628
732
|
this.subManager.push(subManagerItem);
|
|
629
733
|
// 发送订阅成功通知
|
|
630
|
-
bot.sendMessage(sub.targetId, '重新加载测试发送');
|
|
631
734
|
});
|
|
632
735
|
}
|
|
736
|
+
unsubSingle(ctx, id /* UID或RoomId */, type /* 0取消Live订阅,1取消Dynamic订阅 */) {
|
|
737
|
+
let index;
|
|
738
|
+
switch (type) {
|
|
739
|
+
case 0: { // 取消Live订阅
|
|
740
|
+
index = this.subManager.findIndex(sub => sub.roomId === id);
|
|
741
|
+
if (index === -1)
|
|
742
|
+
return '未订阅该用户,无需取消订阅';
|
|
743
|
+
// 取消订阅
|
|
744
|
+
this.subManager[index].live && this.subManager[index].liveDispose();
|
|
745
|
+
// 如果没有对这个UP的任何订阅,则移除
|
|
746
|
+
if (!this.subManager[index].dynamic) {
|
|
747
|
+
// 获取要删除行的id
|
|
748
|
+
const id = this.subManager[index].id;
|
|
749
|
+
// 从管理对象中移除
|
|
750
|
+
this.subManager = this.subManager.splice(index, index);
|
|
751
|
+
// 从数据库中删除
|
|
752
|
+
ctx.database.remove('bilibili', [id]);
|
|
753
|
+
// num--
|
|
754
|
+
this.num--;
|
|
755
|
+
return '已取消订阅该用户';
|
|
756
|
+
}
|
|
757
|
+
this.subManager[index].liveDispose = null;
|
|
758
|
+
this.subManager[index].live = false;
|
|
759
|
+
// 更新数据库
|
|
760
|
+
ctx.database.upsert('bilibili', [{
|
|
761
|
+
id: +`${this.subManager[index].id}`,
|
|
762
|
+
live: 0
|
|
763
|
+
}]);
|
|
764
|
+
return '已取消订阅Live';
|
|
765
|
+
}
|
|
766
|
+
case 1: { // 取消Dynamic订阅
|
|
767
|
+
index = this.subManager.findIndex(sub => sub.uid === id);
|
|
768
|
+
if (index === -1)
|
|
769
|
+
return '未订阅该用户,无需取消订阅';
|
|
770
|
+
// 取消订阅
|
|
771
|
+
this.subManager[index].dynamic && this.subManager[index].dynamicDispose();
|
|
772
|
+
// 如果没有对这个UP的任何订阅,则移除
|
|
773
|
+
if (!this.subManager[index].live) {
|
|
774
|
+
// 获取要删除行的id
|
|
775
|
+
const id = this.subManager[index].id;
|
|
776
|
+
// 从管理对象中移除
|
|
777
|
+
this.subManager = this.subManager.splice(index, index);
|
|
778
|
+
// 从数据库中删除
|
|
779
|
+
ctx.database.remove('bilibili', [id]);
|
|
780
|
+
// num--
|
|
781
|
+
this.num--;
|
|
782
|
+
return '已取消订阅该用户';
|
|
783
|
+
}
|
|
784
|
+
this.subManager[index].dynamicDispose = null;
|
|
785
|
+
this.subManager[index].dynamic = false;
|
|
786
|
+
// 更新数据库
|
|
787
|
+
ctx.database.upsert('bilibili', [{
|
|
788
|
+
id: +`${this.subManager[index].id}`,
|
|
789
|
+
dynamic: 0
|
|
790
|
+
}]);
|
|
791
|
+
return '已取消订阅Dynamic';
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
async checkIfIsLogin(ctx) {
|
|
796
|
+
if ((await ctx.database.get('loginBili', 1)).length !== 0) { // 数据库中有数据
|
|
797
|
+
// 检查cookie中是否有值
|
|
798
|
+
if (ctx.biliAPI.getCookies() !== '[]') { // 有值说明已登录
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
return false;
|
|
803
|
+
}
|
|
633
804
|
}
|
|
634
805
|
(function (ComRegister) {
|
|
635
806
|
ComRegister.Config = koishi_1.Schema.object({
|
|
636
|
-
pushTime: koishi_1.Schema.number().required()
|
|
807
|
+
pushTime: koishi_1.Schema.number().required(),
|
|
808
|
+
liveLoopTime: koishi_1.Schema.number().default(5),
|
|
809
|
+
dynamicLoopTime: koishi_1.Schema.number().default(60)
|
|
637
810
|
});
|
|
638
811
|
})(ComRegister || (ComRegister = {}));
|
|
639
812
|
exports.default = ComRegister;
|
package/lib/index.js
CHANGED
|
@@ -31,6 +31,7 @@ const koishi_1 = require("koishi");
|
|
|
31
31
|
// import crypto
|
|
32
32
|
const crypto_1 = __importDefault(require("crypto"));
|
|
33
33
|
// import plugins
|
|
34
|
+
// import Authority from './authority'
|
|
34
35
|
const comRegister_1 = __importDefault(require("./comRegister"));
|
|
35
36
|
const Database = __importStar(require("./database"));
|
|
36
37
|
// import Service
|
|
@@ -68,6 +69,7 @@ function apply(ctx, config) {
|
|
|
68
69
|
ctx.plugin(generateImg_1.default, { cardColorStart: config.cardColorStart, cardColorEnd: config.cardColorEnd });
|
|
69
70
|
ctx.plugin(biliAPI_1.default);
|
|
70
71
|
// load plugin
|
|
72
|
+
// ctx.plugin(Authority)
|
|
71
73
|
ctx.plugin(comRegister_1.default, { pushTime: config.pushTime });
|
|
72
74
|
// 当用户输入“恶魔兔,启动!”时,执行 help 指令
|
|
73
75
|
ctx.middleware((session, next) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-bilibili-notify",
|
|
3
3
|
"description": "Koishi bilibili notify plugin",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0-alpha.0",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Akokko <admin@akokko.com>"
|
|
7
7
|
],
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"dist"
|
|
13
13
|
],
|
|
14
14
|
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/Akokk0/koishi-plugin-bilibili-notify"
|
|
18
|
+
},
|
|
15
19
|
"scripts": {},
|
|
16
20
|
"keywords": [
|
|
17
21
|
"chatbot",
|