@bililive-tools/douyin-recorder 1.17.0 → 1.17.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.
@@ -18,6 +18,7 @@ export declare function getRoomInfo(webRoomId: string, opts?: {
18
18
  uid?: string | number;
19
19
  }): Promise<{
20
20
  living: boolean;
21
+ isLiveRadio?: boolean;
21
22
  roomId: string;
22
23
  owner: string;
23
24
  title: string;
package/lib/douyin_api.js CHANGED
@@ -159,6 +159,7 @@ async function getRoomInfoByUserWeb(secUserId, opts = {}) {
159
159
  if (!res.data.includes("直播中")) {
160
160
  return {
161
161
  living: false,
162
+ isLiveRadio: false,
162
163
  nickname: "",
163
164
  sec_uid: "",
164
165
  avatar: "",
@@ -177,19 +178,38 @@ async function getRoomInfoByUserWeb(secUserId, opts = {}) {
177
178
  .replace(/\\"/g, '"')
178
179
  .replace(/\\"/g, '"')
179
180
  .replace(/"\$\w+"/g, "null");
180
- // const roomRegex = /(\{\\"common\\":.*?)"\]\)/;
181
- // const roomMatch = res.data.match(roomRegex);
182
- // if (!roomMatch) {
183
- // throw new Error("No room match found in HTML");
184
- // }
185
- // let roomJsonStr = roomMatch[1];
186
- // roomJsonStr = roomJsonStr
187
- // .replace(/\\"/g, '"')
188
- // .replace(/\\"/g, '"')
189
- // .replace(/"\$\w+"/g, "null");
190
181
  try {
191
- // console.log(userJsonStr);
192
182
  const userData = JSON.parse(userJsonStr);
183
+ const roomData = userData?.user?.user?.roomData;
184
+ const streamUrl = roomData?.stream_url;
185
+ let liveCoreSdkData = null;
186
+ if (streamUrl) {
187
+ liveCoreSdkData = { live_core_sdk_data: streamUrl.live_core_sdk_data };
188
+ if (liveCoreSdkData?.live_core_sdk_data?.pull_data) {
189
+ const flvPullUrl = streamUrl.flv_pull_url;
190
+ let streamData = {};
191
+ for (const quality of [{ key: "or4", desc: "原画" }, ...qualityList]) {
192
+ const flvUrls = Object.values(flvPullUrl);
193
+ if (flvUrls.some((url) => url.includes(`${quality.key}`))) {
194
+ const url = flvUrls.find((url) => url.includes(`${quality.key}`));
195
+ const convertedQuality = quality.key === "or4" ? "origin" : quality.key;
196
+ streamData[convertedQuality] = {
197
+ // @ts-ignore
198
+ main: {
199
+ flv: url,
200
+ hls: "",
201
+ },
202
+ };
203
+ }
204
+ }
205
+ liveCoreSdkData.live_core_sdk_data.pull_data.stream_data = streamData;
206
+ }
207
+ else {
208
+ liveCoreSdkData = null;
209
+ }
210
+ }
211
+ // console.log("pppp", JSON.stringify(liveCoreSdkData, null, 2));
212
+ // console.log(JSON.stringify(streamUrl, null, 2));
193
213
  // console.log(JSON.stringify(userData, null, 2));
194
214
  // const roomData = JSON.parse(roomJsonStr);
195
215
  // console.log(roomData);
@@ -197,15 +217,16 @@ async function getRoomInfoByUserWeb(secUserId, opts = {}) {
197
217
  // const streamData = data.state.streamStore.streamData;
198
218
  return {
199
219
  living: userData?.user?.user?.roomData?.status === 2,
220
+ isLiveRadio: roomData?.live_type_audio ?? false,
200
221
  nickname: userData?.user?.user?.nickname ?? "",
201
222
  sec_uid: userData?.user?.user?.secUid ?? "",
202
223
  avatar: userData?.user?.user?.avatar ?? "",
203
- api: "webHTML",
224
+ api: "userHTML",
204
225
  room: {
205
226
  title: "",
206
227
  cover: "",
207
228
  id_str: userData?.user?.user?.roomIdStr,
208
- stream_url: null,
229
+ stream_url: liveCoreSdkData,
209
230
  },
210
231
  };
211
232
  }
@@ -250,8 +271,10 @@ async function getRoomInfoByHtml(webRoomId, opts = {}) {
250
271
  const data = JSON.parse(jsonStr);
251
272
  const roomInfo = data.state.roomStore.roomInfo;
252
273
  const streamData = data.state.streamStore.streamData;
274
+ const isLiveRadio = roomInfo.enter_mode == 1;
253
275
  return {
254
- living: roomInfo?.room?.status === 2,
276
+ living: roomInfo?.room?.status === 2 || isLiveRadio,
277
+ isLiveRadio: isLiveRadio,
255
278
  nickname: roomInfo?.anchor?.nickname ?? "",
256
279
  sec_uid: roomInfo?.anchor?.sec_uid ?? "",
257
280
  avatar: roomInfo?.anchor?.avatar_thumb?.url_list?.[0] ?? "",
@@ -260,15 +283,17 @@ async function getRoomInfoByHtml(webRoomId, opts = {}) {
260
283
  title: roomInfo?.room?.title ?? "",
261
284
  cover: roomInfo?.room?.cover?.url_list?.[0] ?? "",
262
285
  id_str: roomInfo?.room?.id_str ?? "",
263
- stream_url: {
264
- pull_datas: roomInfo?.room?.stream_url?.pull_datas,
265
- live_core_sdk_data: {
266
- pull_data: {
267
- options: { qualities: streamData.H264_streamData?.options?.qualities ?? [] },
268
- stream_data: streamData.H264_streamData?.stream ?? {},
286
+ stream_url: roomInfo?.room?.stream_url?.pull_datas
287
+ ? {
288
+ pull_datas: roomInfo?.room?.stream_url?.pull_datas,
289
+ live_core_sdk_data: {
290
+ pull_data: {
291
+ options: { qualities: streamData.H264_streamData?.options?.qualities ?? [] },
292
+ stream_data: streamData.H264_streamData?.stream ?? {},
293
+ },
269
294
  },
270
- },
271
- },
295
+ }
296
+ : null,
272
297
  },
273
298
  };
274
299
  }
@@ -316,6 +341,7 @@ async function getRoomInfoByWeb(webRoomId, opts = {}) {
316
341
  // 直播已结束
317
342
  return {
318
343
  living: false,
344
+ isLiveRadio: false,
319
345
  nickname: "",
320
346
  sec_uid: "",
321
347
  avatar: "",
@@ -332,7 +358,8 @@ async function getRoomInfoByWeb(webRoomId, opts = {}) {
332
358
  const data = res.data.data;
333
359
  const room = data?.data?.[0];
334
360
  return {
335
- living: data?.room_status === 0,
361
+ living: data?.room_status === 0 || data?.room_status === 1,
362
+ isLiveRadio: data?.room_status === 1,
336
363
  nickname: data?.user?.nickname ?? "",
337
364
  avatar: data?.user?.avatar_thumb?.url_list?.[0] ?? "",
338
365
  sec_uid: data?.user?.sec_uid ?? "",
@@ -371,6 +398,7 @@ async function getRoomInfoByMobile(secUserId, opts = {}) {
371
398
  const room = res?.data?.data?.room;
372
399
  return {
373
400
  living: room?.status === 2,
401
+ isLiveRadio: room?.live_type_audio ?? false,
374
402
  nickname: room?.owner?.nickname,
375
403
  sec_uid: room?.owner?.sec_uid,
376
404
  avatar: room?.owner?.avatar_thumb?.url_list?.[0],
@@ -408,11 +436,12 @@ export async function getRoomInfo(webRoomId, opts = {}) {
408
436
  else {
409
437
  data = await getRoomInfoByWeb(webRoomId, opts);
410
438
  }
411
- // console.log(JSON.stringify(data, null, 2));
412
439
  const room = data.room;
413
- if (api === "userHTML") {
440
+ assert(room, `No room data, id ${webRoomId}`);
441
+ if (!room?.stream_url) {
414
442
  return {
415
443
  living: data.living,
444
+ isLiveRadio: data.isLiveRadio,
416
445
  roomId: webRoomId,
417
446
  owner: data.nickname,
418
447
  title: room?.title ?? data.nickname,
@@ -425,22 +454,6 @@ export async function getRoomInfo(webRoomId, opts = {}) {
425
454
  api: data.api,
426
455
  };
427
456
  }
428
- assert(room, `No room data, id ${webRoomId}`);
429
- if (room?.stream_url == null) {
430
- return {
431
- living: false,
432
- roomId: webRoomId,
433
- owner: data.nickname,
434
- title: room?.title ?? data.nickname,
435
- streams: [],
436
- sources: [],
437
- avatar: data.avatar,
438
- cover: room.cover,
439
- liveId: room.id_str,
440
- uid: data.sec_uid,
441
- api: data.api,
442
- };
443
- }
444
457
  let qualities = [];
445
458
  let stream_data = "";
446
459
  if (opts.doubleScreen && !isEmpty(room.stream_url.pull_datas)) {
@@ -509,6 +522,7 @@ export async function getRoomInfo(webRoomId, opts = {}) {
509
522
  // console.log(JSON.stringify(sources, null, 2), qualities);
510
523
  return {
511
524
  living: data.living,
525
+ isLiveRadio: data.isLiveRadio,
512
526
  roomId: webRoomId,
513
527
  owner: data.nickname,
514
528
  title: room.title,
package/lib/index.js CHANGED
@@ -77,6 +77,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
77
77
  return this.recordHandle;
78
78
  }
79
79
  // 获取直播间信息
80
+ let isLiveRadio = false;
80
81
  try {
81
82
  const liveInfo = await getInfo(this.channelId, {
82
83
  auth: this.auth,
@@ -84,6 +85,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
84
85
  uid: this.uid,
85
86
  });
86
87
  this.liveInfo = liveInfo;
88
+ isLiveRadio = liveInfo.isLiveRadio;
87
89
  this.emit("stateChange", { state: "idle" });
88
90
  }
89
91
  catch (error) {
@@ -121,6 +123,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
121
123
  doubleScreen: this.doubleScreen,
122
124
  api: this.api,
123
125
  uid: this.uid,
126
+ isLiveRadio: isLiveRadio,
124
127
  });
125
128
  this.liveInfo.owner = res.owner;
126
129
  this.liveInfo.title = res.title;
package/lib/stream.d.ts CHANGED
@@ -6,6 +6,7 @@ export declare function getInfo(channelId: string, opts?: {
6
6
  uid?: string | number;
7
7
  }): Promise<{
8
8
  living: boolean;
9
+ isLiveRadio: boolean;
9
10
  owner: string;
10
11
  title: string;
11
12
  roomId: string;
@@ -26,6 +27,7 @@ export declare function getStream(opts: Pick<Recorder, "channelId" | "quality" |
26
27
  doubleScreen?: boolean;
27
28
  api?: APIType;
28
29
  uid?: string | number;
30
+ isLiveRadio?: boolean;
29
31
  }): Promise<{
30
32
  currentStream: {
31
33
  name: string;
@@ -34,6 +36,7 @@ export declare function getStream(opts: Pick<Recorder, "channelId" | "quality" |
34
36
  onlyAudio: boolean;
35
37
  };
36
38
  living: boolean;
39
+ isLiveRadio?: boolean;
37
40
  roomId: string;
38
41
  owner: string;
39
42
  title: string;
package/lib/stream.js CHANGED
@@ -15,6 +15,7 @@ export async function getInfo(channelId, opts) {
15
15
  const startTime = new Date();
16
16
  return {
17
17
  living: info.living,
18
+ isLiveRadio: info.isLiveRadio,
18
19
  owner: info.owner,
19
20
  title: info.title,
20
21
  roomId: info.roomId,
@@ -30,12 +31,20 @@ export async function getInfo(channelId, opts) {
30
31
  }
31
32
  export async function getStream(opts) {
32
33
  let api = opts.api ?? "web";
33
- if (api === "userHTML") {
34
+ if (api === "userHTML" || api === "webHTML") {
34
35
  // userHTML 接口只能用于状态检测
35
36
  api = "web";
36
37
  }
37
38
  else if (api === "random") {
38
- api = selectRandomAPI(["userHTML"]);
39
+ api = selectRandomAPI(["userHTML", "webHTML"]);
40
+ }
41
+ if (opts.isLiveRadio) {
42
+ // 直播电台可能需要特殊处理,优先使用 userHTML 接口
43
+ api = "userHTML";
44
+ // 如果用户指定了mobile接口,那么优先使用mobile接口获取流信息
45
+ if (opts.api === "mobile") {
46
+ api = "mobile";
47
+ }
39
48
  }
40
49
  const info = await getRoomInfo(opts.channelId, {
41
50
  doubleScreen: opts.doubleScreen ?? true,
package/lib/types.d.ts CHANGED
@@ -24,6 +24,7 @@ export interface RoomInfo {
24
24
  sec_uid: string;
25
25
  avatar: string;
26
26
  api: RealAPIType;
27
+ isLiveRadio: boolean;
27
28
  room: {
28
29
  title: string;
29
30
  cover: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bililive-tools/douyin-recorder",
3
- "version": "1.17.0",
3
+ "version": "1.17.1",
4
4
  "description": "@bililive-tools douyin recorder implemention",
5
5
  "main": "./lib/index.js",
6
6
  "type": "module",