@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 +8 -8
- package/lib/douyin_api.js +5 -1
- package/lib/index.js +21 -12
- package/package.json +3 -3
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
|
-
|
|
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
|
|
87
|
+
this.emit("stateChange", { state: "idle" });
|
|
87
88
|
}
|
|
88
89
|
catch (error) {
|
|
89
|
-
this.
|
|
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.
|
|
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
|
|
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", (
|
|
202
|
-
this.emit("videoFileCompleted",
|
|
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}
|
|
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}
|
|
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}
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
"
|
|
42
|
-
"
|
|
41
|
+
"@bililive-tools/manager": "^1.17.0",
|
|
42
|
+
"douyin-danma-listener": "0.4.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "*"
|