@bililive-tools/douyin-recorder 1.16.0 → 1.17.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/README.md CHANGED
@@ -84,14 +84,14 @@ const { id } = await provider.resolveChannelInfoFromURL(url);
84
84
 
85
85
  `mobile` 及 `userHTML` 必须传入 `uid` 参数
86
86
 
87
- | 描述 | 备注 |
88
- | ---------------- | ---------------------------------------- |
89
- | web直播间接口 | 效果不错 |
90
- | mobile直播间接口 | 不易风控,无验证码,海外IP可能无法使用 |
91
- | 直播间web解析 | 易风控,有验证码,单个接口1M流量 |
92
- | 用户web解析 | 不易风控,海外IP无法使用,单个接口1M流量 |
93
- | 负载均衡 | 使用负载均衡算法来分摊防止风控 |
94
- | 随机 | 从几个接口里挑一个 |
87
+ | 描述 | 备注 |
88
+ | ---------------- | ------------------------------------------------------ |
89
+ | web直播间接口 | 效果不错 |
90
+ | mobile直播间接口 | 不易风控,无验证码,海外IP可能无法使用,不会应用Cookie |
91
+ | 直播间web解析 | 易风控,有验证码,单个接口1M流量 |
92
+ | 用户web解析 | 不易风控,海外IP无法使用,单个接口1M流量 |
93
+ | 负载均衡 | 使用负载均衡算法来分摊防止风控 |
94
+ | 随机 | 从几个接口里挑一个 |
95
95
 
96
96
  # 协议
97
97
 
package/lib/douyin_api.js CHANGED
@@ -153,6 +153,9 @@ async function getRoomInfoByUserWeb(secUserId, opts = {}) {
153
153
  if (res.data.includes("验证码")) {
154
154
  throw new Error("需要验证码,请在浏览器中打开链接获取" + url);
155
155
  }
156
+ if (!res.data.includes("抖音号")) {
157
+ throw new Error("userHTML页面没有正常加载" + String(res.data));
158
+ }
156
159
  if (!res.data.includes("直播中")) {
157
160
  return {
158
161
  living: false,
@@ -344,6 +347,7 @@ async function getRoomInfoByWeb(webRoomId, opts = {}) {
344
347
  }
345
348
  async function getRoomInfoByMobile(secUserId, opts = {}) {
346
349
  if (!secUserId) {
350
+ console.error(opts);
347
351
  throw new Error("Mobile API need secUserId, please set uid field");
348
352
  }
349
353
  if (typeof secUserId === "number") {
@@ -360,7 +364,7 @@ async function getRoomInfoByMobile(secUserId, opts = {}) {
360
364
  const res = await requester.get(`https://webcast.amemv.com/webcast/room/reflow/info/`, {
361
365
  params,
362
366
  headers: {
363
- cookie: opts.auth,
367
+ // cookie: opts.auth,
364
368
  },
365
369
  });
366
370
  // @ts-ignore
package/lib/index.js CHANGED
@@ -20,6 +20,7 @@ function createRecorder(opts) {
20
20
  useServerTimestamp: opts.useServerTimestamp ?? true,
21
21
  state: "idle",
22
22
  cache: null,
23
+ appendTimeline: null,
23
24
  getChannelURL() {
24
25
  return `https://live.douyin.com/${this.channelId}`;
25
26
  },
@@ -83,10 +84,13 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
83
84
  uid: this.uid,
84
85
  });
85
86
  this.liveInfo = liveInfo;
86
- this.state = "idle";
87
+ this.emit("stateChange", { state: "idle" });
87
88
  }
88
89
  catch (error) {
89
- this.state = "check-error";
90
+ this.emit("stateChange", {
91
+ state: "check-error",
92
+ msg: `检查失败,` + (error instanceof Error ? error.message : String(error)),
93
+ });
90
94
  throw error;
91
95
  }
92
96
  if (this.liveInfo.liveId && this.liveInfo.liveId === banLiveId) {
@@ -106,7 +110,6 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
106
110
  const strictQuality = utils.shouldUseStrictQuality(qualityRetryLeft, this.qualityRetry, isManualStart);
107
111
  let res;
108
112
  try {
109
- // TODO: 检查mobile接口处理双屏录播流
110
113
  res = await getStream({
111
114
  channelId: this.channelId,
112
115
  quality: this.quality,
@@ -131,11 +134,14 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
131
134
  catch (err) {
132
135
  if (qualityRetryLeft > 0)
133
136
  await this.cache.set("qualityRetryLeft", qualityRetryLeft - 1);
134
- this.state = "check-error";
137
+ this.emit("stateChange", {
138
+ state: "check-error",
139
+ msg: `检查失败,` + (err instanceof Error ? err.message : String(err)),
140
+ });
135
141
  throw err;
136
142
  }
137
143
  const { owner, title, liveStartTime, recordStartTime } = this.liveInfo;
138
- this.state = "recording";
144
+ this.emit("stateChange", { state: "recording" });
139
145
  const { currentStream: stream, sources: availableSources, streams: availableStreams } = res;
140
146
  this.availableStreams = availableStreams.map((s) => s.desc);
141
147
  this.availableSources = availableSources.map((s) => s.name);
@@ -173,6 +179,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
173
179
  headers: {
174
180
  Cookie: this.auth,
175
181
  },
182
+ proxy: this.proxy,
176
183
  }, onEnd, async () => {
177
184
  const info = await getInfo(this.channelId, {
178
185
  auth: this.auth,
@@ -198,8 +205,8 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
198
205
  });
199
206
  };
200
207
  downloader.on("videoFileCreated", handleVideoCreated);
201
- downloader.on("videoFileCompleted", ({ filename }) => {
202
- this.emit("videoFileCompleted", { filename });
208
+ downloader.on("videoFileCompleted", (data) => {
209
+ this.emit("videoFileCompleted", data);
203
210
  });
204
211
  downloader.on("DebugLog", (data) => {
205
212
  this.emit("DebugLog", data);
@@ -324,24 +331,26 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
324
331
  giftMessageCache.set(groupId, { gift, timer });
325
332
  });
326
333
  client.on("reconnect", (attempts) => {
334
+ this.appendTimeline({ text: `弹幕连接断开,正在重试: ${attempts}` });
327
335
  this.emit("DebugLog", {
328
336
  type: "common",
329
- text: `douyin ${this.channelId} danma has reconnect ${attempts}`,
337
+ text: `douyin ${this.channelId} danma has reconnect ${attempts}`,
330
338
  });
331
339
  });
332
340
  client.on("error", (err) => {
333
341
  this.emit("DebugLog", {
334
342
  type: "common",
335
- text: `douyin ${this.channelId} danma error: ${String(err)}`,
343
+ text: `douyin ${this.channelId} danma error: ${String(err)}`,
336
344
  });
337
345
  });
338
346
  client.on("init", (url) => {
339
347
  this.emit("DebugLog", {
340
348
  type: "common",
341
- text: `douyin ${this.channelId} danma init ${url}`,
349
+ text: `douyin ${this.channelId} danma init ${url}`,
342
350
  });
343
351
  });
344
352
  client.on("open", () => {
353
+ this.appendTimeline({ text: `弹幕连接已建立` });
345
354
  this.emit("DebugLog", {
346
355
  type: "common",
347
356
  text: `douyin ${this.channelId} danma open`,
@@ -378,7 +387,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
378
387
  const stop = singleton(async (reason) => {
379
388
  if (!this.recordHandle)
380
389
  return;
381
- this.state = "stopping-record";
390
+ this.emit("stateChange", { state: "stopping-record" });
382
391
  try {
383
392
  // 清理所有礼物缓存定时器
384
393
  for (const [_groupId, cached] of giftMessageCache.entries()) {
@@ -405,7 +414,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
405
414
  this.emit("RecordStop", { recordHandle: this.recordHandle, reason });
406
415
  this.recordHandle = undefined;
407
416
  this.liveInfo = undefined;
408
- this.state = "idle";
417
+ this.emit("stateChange", { state: "idle" });
409
418
  this.cache.set("qualityRetryLeft", this.qualityRetry);
410
419
  });
411
420
  this.recordHandle = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bililive-tools/douyin-recorder",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "@bililive-tools douyin recorder implemention",
5
5
  "main": "./lib/index.js",
6
6
  "type": "module",
@@ -38,8 +38,8 @@
38
38
  "lodash-es": "^4.17.21",
39
39
  "mitt": "^3.0.1",
40
40
  "sm-crypto": "^0.3.13",
41
- "douyin-danma-listener": "0.4.1",
42
- "@bililive-tools/manager": "^1.16.0"
41
+ "@bililive-tools/manager": "^1.17.0",
42
+ "douyin-danma-listener": "0.4.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "*"