@floating-live/bilibili 0.15.3 → 0.16.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/LICENSE +21 -0
- package/index.d.ts +4 -5
- package/index.js +4 -21
- package/package.json +13 -9
- package/parser.d.ts +10 -6
- package/parser.js +472 -422
- package/plugin.d.ts +42 -29
- package/plugin.js +163 -67
- package/room.d.ts +105 -74
- package/room.js +294 -230
- package/types.d.ts +39 -484
- package/types.js +1 -2
- package/utils/crypto.d.ts +1 -0
- package/utils/crypto.js +10 -0
- package/utils/request.d.ts +177 -0
- package/utils/request.js +96 -0
- package/index.ts +0 -5
- package/parser.ts +0 -433
- package/plugin.ts +0 -103
- package/room.ts +0 -272
- package/tsconfig.json +0 -14
- package/types.ts +0 -503
- package/utils.d.ts +0 -18
- package/utils.js +0 -138
- package/utils.ts +0 -145
package/room.js
CHANGED
|
@@ -1,230 +1,294 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
this.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
this.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
this.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
this.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
this.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (this.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
7
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
|
+
};
|
|
12
|
+
var _RoomBilibili_tokens, _RoomBilibili_apiClient;
|
|
13
|
+
import { LiveWS, parseLiveConfig } from "bilibili-live-danmaku";
|
|
14
|
+
import { parseGetInfoByRoom, parseMessage, parseRoomBaseInfo } from "./parser";
|
|
15
|
+
import { LiveConnectionStatus, LiveRoom, LiveRoomOpenStatus, } from "floating-live";
|
|
16
|
+
import { BilibiliApiClientEx } from "./utils/request";
|
|
17
|
+
const symbolAbortController = Symbol("abortController");
|
|
18
|
+
export class RoomBilibili extends LiveRoom {
|
|
19
|
+
get userAgent() {
|
|
20
|
+
return __classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").userAgent;
|
|
21
|
+
}
|
|
22
|
+
set userAgent(ua) {
|
|
23
|
+
__classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").userAgent = ua;
|
|
24
|
+
}
|
|
25
|
+
constructor(
|
|
26
|
+
/** 房间id */
|
|
27
|
+
id, options = {}) {
|
|
28
|
+
super();
|
|
29
|
+
/** 平台id */
|
|
30
|
+
this.platform = "bilibili";
|
|
31
|
+
/** 直播间room_id */
|
|
32
|
+
this.roomId = 0;
|
|
33
|
+
/** 直播间短房号 */
|
|
34
|
+
this.shortId = 0;
|
|
35
|
+
/** 房间信息 */
|
|
36
|
+
this.detail = {
|
|
37
|
+
/** 直播标题 */
|
|
38
|
+
title: "",
|
|
39
|
+
/** 分区 */
|
|
40
|
+
area: [],
|
|
41
|
+
/** 封面url */
|
|
42
|
+
cover: "",
|
|
43
|
+
};
|
|
44
|
+
this.stats = {
|
|
45
|
+
/** 观看数 */
|
|
46
|
+
view: 0,
|
|
47
|
+
/** 点赞数 */
|
|
48
|
+
like: 0,
|
|
49
|
+
};
|
|
50
|
+
/** 是否连接上房间 */
|
|
51
|
+
this.connected = false;
|
|
52
|
+
/** 主播信息 */
|
|
53
|
+
this.anchor = { name: "", id: 0 };
|
|
54
|
+
/** 直播间弹幕api客户端 */
|
|
55
|
+
this.client = null;
|
|
56
|
+
/** 连接凭证 */
|
|
57
|
+
_RoomBilibili_tokens.set(this, void 0);
|
|
58
|
+
/** 用户cookie */
|
|
59
|
+
_RoomBilibili_apiClient.set(this, void 0);
|
|
60
|
+
/** 是否处于重连状态 */
|
|
61
|
+
this.reconnecting = false;
|
|
62
|
+
/** 最后一次连接时间 */
|
|
63
|
+
this.lastConnectionTime = 0;
|
|
64
|
+
this.id = id;
|
|
65
|
+
this.connectInterval = options.connectInterval ?? 500;
|
|
66
|
+
this.connectTimeout = options.connectTimeout ?? 45000;
|
|
67
|
+
this.autoReconnect = options.autoReconnect ?? false;
|
|
68
|
+
__classPrivateFieldSet(this, _RoomBilibili_tokens, options.tokens, "f");
|
|
69
|
+
__classPrivateFieldSet(this, _RoomBilibili_apiClient, new BilibiliApiClientEx({
|
|
70
|
+
userAgent: options.userAgent,
|
|
71
|
+
cookie: options.credentials,
|
|
72
|
+
fetch: options.fetch,
|
|
73
|
+
}), "f");
|
|
74
|
+
options.data && this.setData(options.data);
|
|
75
|
+
const init = options.init ?? true;
|
|
76
|
+
if (init) {
|
|
77
|
+
this.whenInit = this.init(options).then(() => this);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.whenInit = new Promise((res) => res(this));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** 初始化
|
|
84
|
+
* 自动获取并设置 `credentials` ,自动获取房间信息和连接 `token`
|
|
85
|
+
*/
|
|
86
|
+
async init(options = {}) {
|
|
87
|
+
const { open, data, tokens } = options;
|
|
88
|
+
if (open)
|
|
89
|
+
this.openStatus = 1;
|
|
90
|
+
// 设置必要 cookie
|
|
91
|
+
// 如果cookie中没有buvid3字段,会自动获取一个
|
|
92
|
+
await this.setCredentials(__classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").cookie, false);
|
|
93
|
+
// 自动更新房间信息
|
|
94
|
+
if (!data)
|
|
95
|
+
await this.update();
|
|
96
|
+
// 自动更新房间 tokens
|
|
97
|
+
if (!tokens)
|
|
98
|
+
await this.updateTokens();
|
|
99
|
+
// 自动开启
|
|
100
|
+
if (open) {
|
|
101
|
+
this.openWebsocketClient();
|
|
102
|
+
}
|
|
103
|
+
this.emit("init");
|
|
104
|
+
}
|
|
105
|
+
/** 更新房间信息 */
|
|
106
|
+
async update() {
|
|
107
|
+
const data = await this.fetchData();
|
|
108
|
+
this.roomId = data.id;
|
|
109
|
+
this.setData(data);
|
|
110
|
+
return data;
|
|
111
|
+
}
|
|
112
|
+
/** 获取房间信息 */
|
|
113
|
+
async fetchData() {
|
|
114
|
+
if (this.customFetchData)
|
|
115
|
+
return this.customFetchData(this.id);
|
|
116
|
+
try {
|
|
117
|
+
const res = await __classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").xliveGetInfoByRoom({
|
|
118
|
+
room_id: this.id,
|
|
119
|
+
});
|
|
120
|
+
return parseGetInfoByRoom(res.data);
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
// fallback
|
|
124
|
+
const res = await __classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").xliveGetRoomBaseInfo({
|
|
125
|
+
room_ids: [this.id],
|
|
126
|
+
});
|
|
127
|
+
for (const r in res.data.by_room_ids) {
|
|
128
|
+
return parseRoomBaseInfo(res.data.by_room_ids[r]);
|
|
129
|
+
}
|
|
130
|
+
throw new Error("房间不存在");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** 设置直播间数据 */
|
|
134
|
+
setData({ roomId, shortId, status, timestamp, detail, stats, anchor, liveId, available, }) {
|
|
135
|
+
this.roomId = roomId;
|
|
136
|
+
this.shortId = shortId;
|
|
137
|
+
this.status = status;
|
|
138
|
+
this.timestamp = timestamp;
|
|
139
|
+
this.detail = detail;
|
|
140
|
+
this.stats = stats;
|
|
141
|
+
this.anchor = anchor;
|
|
142
|
+
this.liveId = liveId;
|
|
143
|
+
this.available = available;
|
|
144
|
+
const data = this.toData();
|
|
145
|
+
this.emit("update", { room: data });
|
|
146
|
+
return data;
|
|
147
|
+
}
|
|
148
|
+
/** 开启直播间监听 */
|
|
149
|
+
async open() {
|
|
150
|
+
// 如果直播间监听已打开或处于正在打开状态,则返回
|
|
151
|
+
if (this.openStatus)
|
|
152
|
+
return;
|
|
153
|
+
this.openStatus = LiveRoomOpenStatus.opening;
|
|
154
|
+
await this.update();
|
|
155
|
+
this.openWebsocketClient();
|
|
156
|
+
}
|
|
157
|
+
/** 设置登录凭据 */
|
|
158
|
+
async setCredentials(credentials, updateTokens = true) {
|
|
159
|
+
__classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").setCookie(credentials);
|
|
160
|
+
// 在没有buvid3的情况下,访问bilibili主页,获得buvid3
|
|
161
|
+
if (!__classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").cookies.has("buvid3")) {
|
|
162
|
+
__classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").wwwBilibili();
|
|
163
|
+
}
|
|
164
|
+
if (updateTokens)
|
|
165
|
+
this.updateTokens();
|
|
166
|
+
}
|
|
167
|
+
/** 更新连接tokens */
|
|
168
|
+
async updateTokens() {
|
|
169
|
+
this.setTokens(await this.fetchTokens());
|
|
170
|
+
}
|
|
171
|
+
/** 请求连接tokens */
|
|
172
|
+
async fetchTokens() {
|
|
173
|
+
if (this.customFetchTokens) {
|
|
174
|
+
return this.customFetchTokens(this.roomId, __classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").cookie);
|
|
175
|
+
}
|
|
176
|
+
const buvid = __classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").cookies.get("buvid3");
|
|
177
|
+
const uid = parseInt(__classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").cookies.get("DedeUserID"));
|
|
178
|
+
const { key } = await parseLiveConfig((await __classPrivateFieldGet(this, _RoomBilibili_apiClient, "f").xliveGetDanmuInfo({ id: this.roomId })).data);
|
|
179
|
+
return {
|
|
180
|
+
uid,
|
|
181
|
+
buvid,
|
|
182
|
+
key,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/** 设置直播连接tokens */
|
|
186
|
+
setTokens(tokens) {
|
|
187
|
+
__classPrivateFieldSet(this, _RoomBilibili_tokens, tokens, "f");
|
|
188
|
+
if (this.opened) {
|
|
189
|
+
// 如果已打开,则重连
|
|
190
|
+
this.reconnect();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/** 无缝重连 */
|
|
194
|
+
reconnect() {
|
|
195
|
+
// 如果正在重连,则返回
|
|
196
|
+
if (this.reconnecting)
|
|
197
|
+
return;
|
|
198
|
+
this.reconnecting = true;
|
|
199
|
+
const lastClient = this.client;
|
|
200
|
+
this.initClient();
|
|
201
|
+
// 重连成功后,关闭上一个连接
|
|
202
|
+
this.client?.addEventListener("open", () => {
|
|
203
|
+
lastClient?.[symbolAbortController].abort();
|
|
204
|
+
lastClient?.close();
|
|
205
|
+
this.reconnecting = false;
|
|
206
|
+
}, { once: true });
|
|
207
|
+
}
|
|
208
|
+
emitConnention(status) {
|
|
209
|
+
this.connectionStatus = status;
|
|
210
|
+
switch (status) {
|
|
211
|
+
case LiveConnectionStatus.connecting:
|
|
212
|
+
this.emit("connecting");
|
|
213
|
+
break;
|
|
214
|
+
case LiveConnectionStatus.connected:
|
|
215
|
+
this.emit("connected");
|
|
216
|
+
break;
|
|
217
|
+
case LiveConnectionStatus.entered:
|
|
218
|
+
this.emit("enter");
|
|
219
|
+
break;
|
|
220
|
+
case LiveConnectionStatus.disconnected:
|
|
221
|
+
this.emit("disconnect");
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** 打开直播弹幕客户端 */
|
|
226
|
+
openWebsocketClient() {
|
|
227
|
+
// 如果直播间不可用,则返回
|
|
228
|
+
if (!this.available) {
|
|
229
|
+
this.openStatus = LiveRoomOpenStatus.closed;
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this.initClient();
|
|
233
|
+
this.openStatus = LiveRoomOpenStatus.opened;
|
|
234
|
+
this.emit("open");
|
|
235
|
+
}
|
|
236
|
+
/** 创建直播弹幕客户端 */
|
|
237
|
+
initClient() {
|
|
238
|
+
this.emitConnention(LiveConnectionStatus.connecting);
|
|
239
|
+
// 与Websocket服务器连接
|
|
240
|
+
const client = new LiveWS(this.roomId || this.id, {
|
|
241
|
+
uid: __classPrivateFieldGet(this, _RoomBilibili_tokens, "f")?.uid,
|
|
242
|
+
buvid: __classPrivateFieldGet(this, _RoomBilibili_tokens, "f")?.buvid,
|
|
243
|
+
key: __classPrivateFieldGet(this, _RoomBilibili_tokens, "f")?.key,
|
|
244
|
+
});
|
|
245
|
+
console.log(__classPrivateFieldGet(this, _RoomBilibili_tokens, "f"));
|
|
246
|
+
const controller = new AbortController();
|
|
247
|
+
const signal = controller.signal;
|
|
248
|
+
client[symbolAbortController] = controller;
|
|
249
|
+
this.lastConnectionTime = Date.now();
|
|
250
|
+
console.log(client.ws.url);
|
|
251
|
+
client.addEventListener("open", () => {
|
|
252
|
+
// 连接到服务器
|
|
253
|
+
this.opened && this.emitConnention(LiveConnectionStatus.connected);
|
|
254
|
+
}, { signal });
|
|
255
|
+
client.addEventListener("close", () => {
|
|
256
|
+
// 断开连接
|
|
257
|
+
this.opened && this.emitConnention(LiveConnectionStatus.disconnected);
|
|
258
|
+
// 自动重连
|
|
259
|
+
if (this.opened && this.autoReconnect) {
|
|
260
|
+
const timeout = this.lastConnectionTime + this.connectInterval - Date.now();
|
|
261
|
+
if (timeout > 0) {
|
|
262
|
+
const t = setTimeout(() => {
|
|
263
|
+
this.reconnect();
|
|
264
|
+
clearTimeout(t);
|
|
265
|
+
}, timeout);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
this.reconnect();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}, { signal });
|
|
272
|
+
client.addEventListener("CONNECT_SUCCESS", () => {
|
|
273
|
+
// 连接到直播间
|
|
274
|
+
this.emitConnention(LiveConnectionStatus.entered);
|
|
275
|
+
}, { signal });
|
|
276
|
+
client.addEventListener("MESSAGE", ({ data }) => {
|
|
277
|
+
const m = parseMessage(data, this);
|
|
278
|
+
m && this.emitMessage(m);
|
|
279
|
+
this.emitRaw(data);
|
|
280
|
+
}, { signal });
|
|
281
|
+
this.client = client;
|
|
282
|
+
}
|
|
283
|
+
/** 关闭直播间监听 */
|
|
284
|
+
close() {
|
|
285
|
+
if (!this.opened)
|
|
286
|
+
return;
|
|
287
|
+
this.openStatus = LiveRoomOpenStatus.closed;
|
|
288
|
+
this.client?.close();
|
|
289
|
+
this.emitConnention(LiveConnectionStatus.off);
|
|
290
|
+
this.emit("close");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
_RoomBilibili_tokens = new WeakMap(), _RoomBilibili_apiClient = new WeakMap();
|
|
294
|
+
export default RoomBilibili;
|