@floating-live/bilibili 0.15.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/index.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ import type { FloatingLive } from "floating-live";
2
+ interface BilibiliLoginInfo {
3
+ credentials: string;
4
+ tokens: {
5
+ /** 用户uid */
6
+ userId: number;
7
+ /** buvid */
8
+ buvid: string;
9
+ };
10
+ userId: number;
11
+ }
12
+ declare module "floating-live" {
13
+ interface FloatingCommandMap {
14
+ "bilibili.credentials.check": (credentials: string) => Promise<BilibiliLoginInfo>;
15
+ "bilibili.login.qrcode.get": () => Promise<{
16
+ key: string;
17
+ url: string;
18
+ }>;
19
+ "bilibili.login.qrcode.poll": (key: string) => Promise<{
20
+ status: number;
21
+ credentials?: string;
22
+ }>;
23
+ }
24
+ }
25
+ declare class Bilibili {
26
+ static pluginName: string;
27
+ constructor(main: FloatingLive);
28
+ }
29
+ export default Bilibili;
package/index.js ADDED
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const room_1 = require("./room");
4
+ const utils_1 = require("./utils");
5
+ const platformInfo = {
6
+ name: "bilibili",
7
+ membership: {
8
+ id: "guard",
9
+ name: "大航海",
10
+ level: ["", "总督", "提督", "舰长"],
11
+ },
12
+ gift: {
13
+ action: "投喂",
14
+ },
15
+ currency: {
16
+ silver: {
17
+ name: "银瓜子",
18
+ ratio: 1,
19
+ },
20
+ gold: {
21
+ name: "电池",
22
+ ratio: 100,
23
+ money: 1000,
24
+ },
25
+ },
26
+ stats: {
27
+ view: "看过",
28
+ online: "在线",
29
+ like: "点赞",
30
+ },
31
+ };
32
+ class Bilibili {
33
+ constructor(main) {
34
+ main.command.register("bilibili.room.create", (id, options) => {
35
+ return new room_1.RoomBilibili(Number(id), options);
36
+ });
37
+ main.command.register("bilibili.credentials.check", async (credentials) => {
38
+ const buvid = (await (0, utils_1.getBuvid)(credentials)) || "";
39
+ const userId = await (0, utils_1.getLoginUid)(credentials);
40
+ return {
41
+ credentials,
42
+ tokens: {
43
+ userId,
44
+ buvid,
45
+ },
46
+ userId,
47
+ };
48
+ });
49
+ main.manifest.register("platform", "bilibili", platformInfo);
50
+ main.command.register("bilibili.login.qrcode.get", () => {
51
+ return (0, utils_1.generateLoginQRcode)();
52
+ });
53
+ main.command.register("bilibili.login.qrcode.poll", async (key) => {
54
+ const [status, credentials] = await (0, utils_1.checkLoginQRcode)(key);
55
+ return { status, credentials };
56
+ });
57
+ }
58
+ }
59
+ Bilibili.pluginName = "bilibili";
60
+ exports.default = Bilibili;
package/index.ts ADDED
@@ -0,0 +1,98 @@
1
+ import type { FloatingLive, PlatformInfo } from "floating-live";
2
+ import { RoomBilibili, RoomOptions } from "./room";
3
+ import {
4
+ checkLoginQRcode,
5
+ generateLoginQRcode,
6
+ getBuvid,
7
+ getLoginUid,
8
+ parseCookieString,
9
+ } from "./utils";
10
+
11
+ interface BilibiliLoginInfo {
12
+ credentials: string;
13
+ tokens: {
14
+ /** 用户uid */
15
+ userId: number;
16
+ /** buvid */
17
+ buvid: string;
18
+ };
19
+ userId: number;
20
+ }
21
+
22
+ declare module "floating-live" {
23
+ interface FloatingCommandMap {
24
+ "bilibili.credentials.check": (
25
+ credentials: string
26
+ ) => Promise<BilibiliLoginInfo>;
27
+ "bilibili.login.qrcode.get": () => Promise<{ key: string; url: string }>;
28
+ "bilibili.login.qrcode.poll": (
29
+ key: string
30
+ ) => Promise<{ status: number; credentials?: string }>;
31
+ }
32
+ }
33
+
34
+ const platformInfo: PlatformInfo = {
35
+ name: "bilibili",
36
+ membership: {
37
+ id: "guard",
38
+ name: "大航海",
39
+ level: ["", "总督", "提督", "舰长"],
40
+ },
41
+ gift: {
42
+ action: "投喂",
43
+ },
44
+ currency: {
45
+ silver: {
46
+ name: "银瓜子",
47
+ ratio: 1,
48
+ },
49
+ gold: {
50
+ name: "电池",
51
+ ratio: 100,
52
+ money: 1000,
53
+ },
54
+ },
55
+ stats: {
56
+ view: "看过",
57
+ online: "在线",
58
+ like: "点赞",
59
+ },
60
+ };
61
+
62
+ class Bilibili {
63
+ static pluginName = "bilibili";
64
+ constructor(main: FloatingLive) {
65
+ main.command.register(
66
+ "bilibili.room.create",
67
+ (id: string | number, options?: RoomOptions) => {
68
+ return new RoomBilibili(Number(id), options);
69
+ }
70
+ );
71
+
72
+ main.command.register("bilibili.credentials.check", async (credentials) => {
73
+ const buvid = (await getBuvid(credentials)) || "";
74
+ const userId = await getLoginUid(credentials);
75
+ return {
76
+ credentials,
77
+ tokens: {
78
+ userId,
79
+ buvid,
80
+ },
81
+ userId,
82
+ };
83
+ });
84
+
85
+ main.manifest.register("platform", "bilibili", platformInfo);
86
+
87
+ main.command.register("bilibili.login.qrcode.get", () => {
88
+ return generateLoginQRcode();
89
+ });
90
+
91
+ main.command.register("bilibili.login.qrcode.poll", async (key) => {
92
+ const [status, credentials] = await checkLoginQRcode(key);
93
+ return { status, credentials };
94
+ });
95
+ }
96
+ }
97
+
98
+ export default Bilibili;
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@floating-live/bilibili",
3
+ "version": "0.15.0",
4
+ "type": "commonjs",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "author": "Minteea",
8
+ "license": "MIT",
9
+ "scripts": {
10
+ "check": "tsc --noEmit",
11
+ "clear": "rimraf *.js *.d.ts --glob",
12
+ "build": "npm run clear && tsc --build",
13
+ "prepack": "npm run build",
14
+ "postpack": "npm run clear"
15
+ },
16
+ "dependencies": {
17
+ "bilibili-live-ws": "^6.3.1"
18
+ },
19
+ "devDependencies": {
20
+ "@types/websocket": "^1.0.5",
21
+ "@types/ws": "^8.5.3",
22
+ "rimraf": "^3.0.2",
23
+ "ts-node": "^10.9.1",
24
+ "typescript": "^4.8.4"
25
+ },
26
+ "peerDependencies": {
27
+ "floating-live": "^0.15.0"
28
+ }
29
+ }
package/parser.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { Message } from "floating-live/types";
2
+ import { BilibiliRoomInfo, RawInfo, RawMessage } from "./types";
3
+ /** 转换bilibili直播弹幕为floating通用格式 */
4
+ export declare function parseMessage(data: RawMessage.All, room?: BilibiliRoomInfo): Message.All | undefined;
5
+ /** 转换bilibili直播间信息为floating通用格式 */
6
+ export declare function parseInfo(data: RawInfo): BilibiliRoomInfo;
package/parser.js ADDED
@@ -0,0 +1,422 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseInfo = exports.parseMessage = void 0;
4
+ const enums_1 = require("floating-live/enums");
5
+ const utils_1 = require("floating-live/utils");
6
+ // utils
7
+ // 获取当前时间戳,以替代无法从数据中获取时间戳的情况,精度为1s
8
+ function getDateTimestamp() {
9
+ return Math.floor(Date.now() / 1000) * 1000;
10
+ }
11
+ const parsingFunction = {
12
+ DANMU_MSG: (msg, room) => {
13
+ const { info, msg_id } = msg;
14
+ let content = info[1];
15
+ let mode = info[0][1];
16
+ let color = info[0][3];
17
+ let uname = info[2][1];
18
+ let uid = info[2][0];
19
+ let timestamp = info[0][4];
20
+ let guard_level = info[7]; // 舰长级别
21
+ let extra = JSON.parse(info[0][15].extra);
22
+ let medal = info[3][0] != null
23
+ ? {
24
+ level: info[3][0],
25
+ name: info[3][1],
26
+ // user: info[3][2],
27
+ id: info[3][12],
28
+ membership: info[3][10] || 0,
29
+ }
30
+ : null;
31
+ let identity = 0;
32
+ let emoticon = undefined;
33
+ if (extra.emots) {
34
+ emoticon = {};
35
+ for (let key in extra.emots) {
36
+ let emotItem = extra.emots[key];
37
+ emoticon[key] = {
38
+ id: emotItem.emoticon_unique,
39
+ url: emotItem.url,
40
+ name: emotItem.emoji,
41
+ };
42
+ }
43
+ }
44
+ if (info[2][2]) {
45
+ identity = enums_1.UserType.admin;
46
+ }
47
+ else if (uid === room?.anchor.id) {
48
+ identity = enums_1.UserType.anchor;
49
+ }
50
+ let danmaku = {
51
+ platform: "bilibili",
52
+ room: room?.id || 0,
53
+ type: "comment",
54
+ timestamp: timestamp,
55
+ id: msg_id,
56
+ info: {
57
+ color: color,
58
+ mode: mode,
59
+ content: content,
60
+ image: info[0][12]
61
+ ? {
62
+ name: content,
63
+ id: info[0][13].emoticon_unique,
64
+ url: info[0][13].url,
65
+ size: info[0][13].width == info[0][13].height
66
+ ? enums_1.ImageSize.large
67
+ : enums_1.ImageSize.small,
68
+ }
69
+ : undefined,
70
+ emoticon: emoticon,
71
+ user: {
72
+ name: uname,
73
+ id: uid,
74
+ medal: medal,
75
+ membership: guard_level,
76
+ type: identity,
77
+ },
78
+ },
79
+ };
80
+ danmaku.id ?? (danmaku.id = (0, utils_1.generateId)(danmaku));
81
+ return danmaku;
82
+ },
83
+ INTERACT_WORD: (msg, room) => {
84
+ const { data, msg_id, send_time } = msg;
85
+ let type;
86
+ switch (data.msg_type) {
87
+ case 1:
88
+ type = "entry"; // 进入直播间
89
+ break;
90
+ case 2:
91
+ type = "follow"; // 关注直播间
92
+ break;
93
+ case 3:
94
+ type = "share"; // 分享直播间
95
+ break;
96
+ default:
97
+ return;
98
+ }
99
+ let interact = {
100
+ platform: "bilibili",
101
+ room: room?.id || 0,
102
+ type: type,
103
+ id: msg_id,
104
+ timestamp: send_time || Math.floor(data.trigger_time / 1000000),
105
+ info: {
106
+ user: {
107
+ name: data.uname,
108
+ id: data.uid,
109
+ medal: data.fans_medal?.medal_level
110
+ ? {
111
+ level: data.fans_medal.medal_level,
112
+ name: data.fans_medal.medal_name,
113
+ id: data.fans_medal.target_id,
114
+ membership: data.fans_medal.guard_level,
115
+ }
116
+ : null,
117
+ },
118
+ },
119
+ };
120
+ interact.id ?? (interact.id = (0, utils_1.generateId)(interact));
121
+ return interact;
122
+ },
123
+ SEND_GIFT: (msg, room) => {
124
+ const { data, msg_id, send_time } = msg;
125
+ let gift = {
126
+ platform: "bilibili",
127
+ room: room?.id || 0,
128
+ type: "gift",
129
+ id: msg_id || data.combo_id,
130
+ timestamp: send_time || data.timestamp * 1000,
131
+ info: {
132
+ user: {
133
+ name: data.uname,
134
+ id: data.uid,
135
+ medal: data.fans_medal && data.fans_medal.medal_level
136
+ ? {
137
+ level: data.fans_medal.medal_level,
138
+ name: data.fans_medal.medal_name,
139
+ id: data.fans_medal.target_id,
140
+ membership: data.fans_medal.guard_level,
141
+ }
142
+ : null,
143
+ membership: data.guard_level,
144
+ avatar: data.face,
145
+ },
146
+ gift: {
147
+ name: data.giftName,
148
+ id: data.giftId,
149
+ num: data.num,
150
+ value: data.total_coin,
151
+ currency: data.coin_type,
152
+ action: data.action,
153
+ comboId: data.batch_combo_id,
154
+ },
155
+ },
156
+ };
157
+ gift.id ?? (gift.id = (0, utils_1.generateId)(gift));
158
+ return gift;
159
+ },
160
+ GUARD_BUY: (msg, room) => {
161
+ const { data, msg_id, send_time } = msg;
162
+ let gift = {
163
+ platform: "bilibili",
164
+ room: room?.id || 0,
165
+ type: "membership",
166
+ id: msg_id,
167
+ timestamp: send_time || data.start_time * 1000,
168
+ info: {
169
+ user: {
170
+ name: data.username,
171
+ id: data.uid,
172
+ membership: data.guard_level,
173
+ },
174
+ gift: {
175
+ name: data.gift_name,
176
+ id: data.gift_id,
177
+ num: data.num,
178
+ value: data.price,
179
+ currency: "gold",
180
+ },
181
+ name: data.gift_name,
182
+ level: data.guard_level,
183
+ duration: data.num * 30,
184
+ },
185
+ };
186
+ gift.id ?? (gift.id = (0, utils_1.generateId)(gift));
187
+ return gift;
188
+ },
189
+ SUPER_CHAT_MESSAGE: (msg, room) => {
190
+ const { data, msg_id, send_time } = msg;
191
+ let sc = {
192
+ platform: "bilibili",
193
+ room: room?.id || 0,
194
+ type: "superchat",
195
+ id: msg_id,
196
+ timestamp: send_time || data.ts * 1000,
197
+ info: {
198
+ id: data.id,
199
+ user: {
200
+ name: data.user_info.uname,
201
+ id: data.uid,
202
+ avatar: data.user_info.face,
203
+ medal: data.medal_info && data.medal_info.medal_level
204
+ ? {
205
+ level: data.medal_info.medal_level,
206
+ name: data.medal_info.medal_name,
207
+ id: data.medal_info.target_id,
208
+ membership: data.medal_info.guard_level,
209
+ }
210
+ : null,
211
+ membership: data.user_info.guard_level,
212
+ },
213
+ content: data.message,
214
+ color: data.background_bottom_color,
215
+ duration: data.time * 1000,
216
+ gift: {
217
+ id: data.gift.gift_id,
218
+ name: data.gift.gift_name,
219
+ num: data.gift.num,
220
+ value: data.price * 1000,
221
+ currency: "gold",
222
+ },
223
+ },
224
+ };
225
+ sc.id ?? (sc.id = (0, utils_1.generateId)(sc));
226
+ return sc;
227
+ },
228
+ WATCHED_CHANGE: (msg, room) => {
229
+ const { data, msg_id, send_time } = msg;
230
+ const stats = {
231
+ platform: "bilibili",
232
+ room: room?.id || 0,
233
+ type: "live_stats",
234
+ id: msg_id,
235
+ timestamp: send_time || getDateTimestamp(),
236
+ info: {
237
+ view: data.num,
238
+ },
239
+ };
240
+ stats.id ?? (stats.id = (0, utils_1.generateId)(stats));
241
+ return stats;
242
+ },
243
+ LIKE_INFO_V3_UPDATE: (msg, room) => {
244
+ const { data, msg_id, send_time } = msg;
245
+ const stats = {
246
+ platform: "bilibili",
247
+ room: room?.id || 0,
248
+ type: "live_stats",
249
+ id: msg_id,
250
+ timestamp: send_time || getDateTimestamp(),
251
+ info: {
252
+ like: data.click_count,
253
+ },
254
+ };
255
+ stats.id ?? (stats.id = (0, utils_1.generateId)(stats));
256
+ return stats;
257
+ },
258
+ ONLINE_RANK_COUNT: (msg, room) => {
259
+ const { data, msg_id, send_time } = msg;
260
+ if (data.online_count == null)
261
+ return;
262
+ const stats = {
263
+ platform: "bilibili",
264
+ room: room?.id || 0,
265
+ type: "live_stats",
266
+ id: msg_id,
267
+ timestamp: send_time || getDateTimestamp(),
268
+ info: {
269
+ online: data.online_count,
270
+ },
271
+ };
272
+ stats.id ?? (stats.id = (0, utils_1.generateId)(stats));
273
+ return stats;
274
+ },
275
+ ROOM_BLOCK_MSG: (msg, room) => {
276
+ const { data, msg_id, send_time } = msg;
277
+ const block = {
278
+ platform: "bilibili",
279
+ room: room?.id || 0,
280
+ type: "block",
281
+ id: msg_id,
282
+ timestamp: send_time || getDateTimestamp(),
283
+ info: {
284
+ user: {
285
+ id: data.uid,
286
+ name: data.uname,
287
+ },
288
+ operator: {
289
+ type: data.operator == 2 ? enums_1.UserType.anchor : enums_1.UserType.admin,
290
+ },
291
+ },
292
+ };
293
+ block.id ?? (block.id = (0, utils_1.generateId)(block));
294
+ return block;
295
+ },
296
+ LIVE: (msg, room) => {
297
+ const { msg_id, send_time } = msg;
298
+ // 直播间开播
299
+ if (msg.live_time) {
300
+ let live = {
301
+ platform: "bilibili",
302
+ room: room?.id || 0,
303
+ type: "live_start",
304
+ id: msg_id,
305
+ timestamp: send_time || msg.live_time * 1000,
306
+ info: {
307
+ id: msg.live_key.toString(),
308
+ },
309
+ };
310
+ live.id ?? (live.id = (0, utils_1.generateId)(live));
311
+ return live;
312
+ }
313
+ },
314
+ CUT_OFF: (msg, room) => {
315
+ const { msg_id, send_time } = msg;
316
+ // 直播间被切断
317
+ let cut = {
318
+ platform: "bilibili",
319
+ room: room?.id || 0,
320
+ type: "live_cut",
321
+ id: msg_id,
322
+ timestamp: send_time || getDateTimestamp(),
323
+ info: {
324
+ message: msg.msg,
325
+ },
326
+ };
327
+ cut.id ?? (cut.id = (0, utils_1.generateId)(cut));
328
+ return cut;
329
+ },
330
+ PREPARING: (msg, room) => {
331
+ const { msg_id, send_time } = msg;
332
+ let off = {
333
+ platform: "bilibili",
334
+ room: room?.id || 0,
335
+ type: "live_end",
336
+ id: msg_id,
337
+ timestamp: send_time || getDateTimestamp(),
338
+ info: {
339
+ status: msg.round ? enums_1.RoomStatus.round : enums_1.RoomStatus.off,
340
+ },
341
+ };
342
+ off.id ?? (off.id = (0, utils_1.generateId)(off));
343
+ return off;
344
+ },
345
+ ROOM_CHANGE: (msg, room) => {
346
+ const { data, msg_id, send_time } = msg;
347
+ let change = {
348
+ platform: "bilibili",
349
+ room: room?.id || 0,
350
+ type: "live_detail",
351
+ id: msg_id,
352
+ timestamp: send_time || getDateTimestamp(),
353
+ info: {
354
+ title: data.title,
355
+ area: [data.parent_area_name, data.area_name],
356
+ },
357
+ };
358
+ change.id ?? (change.id = (0, utils_1.generateId)(change));
359
+ return change;
360
+ },
361
+ ANCHOR_LOT_START: (msg, room) => {
362
+ const { data, msg_id, send_time } = msg;
363
+ let m = {
364
+ platform: "bilibili",
365
+ room: room?.id || 0,
366
+ type: "lottery",
367
+ timestamp: send_time || data.current_time * 1000,
368
+ id: msg_id,
369
+ info: {
370
+ id: data.id,
371
+ award: {
372
+ name: data.award_name,
373
+ num: data.award_num,
374
+ image: data.award_image,
375
+ id: -1,
376
+ value: 0,
377
+ currency: "",
378
+ },
379
+ },
380
+ };
381
+ return m;
382
+ },
383
+ };
384
+ /** 转换bilibili直播弹幕为floating通用格式 */
385
+ function parseMessage(data, room) {
386
+ return parsingFunction[data.cmd]?.(data, room);
387
+ }
388
+ exports.parseMessage = parseMessage;
389
+ /** 转换bilibili直播间信息为floating通用格式 */
390
+ function parseInfo(data) {
391
+ const { room_info, anchor_info, like_info_v3, watched_show } = data;
392
+ return {
393
+ platform: "bilibili",
394
+ id: room_info.room_id,
395
+ roomId: room_info.room_id,
396
+ shortId: room_info.short_id,
397
+ key: `bilibili:${room_info.room_id}`,
398
+ detail: {
399
+ title: room_info.title,
400
+ area: [room_info.parent_area_name, room_info.area_name],
401
+ cover: room_info.cover,
402
+ },
403
+ anchor: {
404
+ id: room_info.uid,
405
+ name: anchor_info.base_info.uname,
406
+ avatar: anchor_info.base_info.face,
407
+ },
408
+ stats: {
409
+ view: watched_show.num,
410
+ like: like_info_v3.total_likes,
411
+ },
412
+ liveId: room_info.live_id_str,
413
+ available: room_info.lock_status ? false : true,
414
+ status: room_info.lock_status ? enums_1.RoomStatus.banned : room_info.live_status,
415
+ timestamp: room_info.live_status == enums_1.RoomStatus.live
416
+ ? room_info.live_start_time * 1000
417
+ : 0,
418
+ opened: false,
419
+ connection: 0,
420
+ };
421
+ }
422
+ exports.parseInfo = parseInfo;