@bililive-tools/douyu-recorder 1.2.0 → 1.3.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.
@@ -17,6 +17,7 @@ interface Message$Chat {
17
17
  dc: string;
18
18
  bdlv: string;
19
19
  ic: string;
20
+ cst: string;
20
21
  }
21
22
  interface Message$Gift {
22
23
  type: "dgb";
@@ -15,7 +15,12 @@ export function createDYClient(channelId, opts = {}) {
15
15
  const send = (message) => ws?.send(coder.encode(STT.serialize(message)));
16
16
  const sendLogin = () => send({ type: "loginreq", roomid: channelId });
17
17
  const sendJoinGroup = () => send({ type: "joingroup", rid: channelId, gid: -9999 });
18
- const sendHeartbeat = () => send({ type: "mrkl" });
18
+ const sendHeartbeat = () => {
19
+ if (ws?.readyState !== WebSocket.OPEN) {
20
+ return;
21
+ }
22
+ send({ type: "mrkl" });
23
+ };
19
24
  const sendLogout = () => send({ type: "logout" });
20
25
  const onOpen = () => {
21
26
  sendLogin();
package/lib/index.js CHANGED
@@ -60,7 +60,7 @@ const ffmpegOutputOptions = [
60
60
  "-movflags",
61
61
  "faststart+frag_keyframe+empty_moov",
62
62
  "-min_frag_duration",
63
- "60000000",
63
+ "10000000",
64
64
  ];
65
65
  const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isManualStart, }) {
66
66
  // 如果已经在录制中,只在需要检查标题关键词时才获取最新信息
@@ -106,7 +106,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
106
106
  }
107
107
  // 获取直播间信息
108
108
  const liveInfo = await getInfo(this.channelId);
109
- const { living, owner, title, liveId } = liveInfo;
109
+ const { living, owner, title } = liveInfo;
110
110
  this.liveInfo = liveInfo;
111
111
  if (liveInfo.liveId === banLiveId) {
112
112
  this.tempStopIntervalCheck = true;
@@ -137,7 +137,6 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
137
137
  return null;
138
138
  }
139
139
  }
140
- this.emit("LiveStart", { liveId });
141
140
  let res;
142
141
  // TODO: 先不做什么错误处理,就简单包一下预期上会有错误的地方
143
142
  try {
@@ -170,6 +169,10 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
170
169
  this.usedStream = stream.name;
171
170
  this.usedSource = stream.source;
172
171
  const onEnd = (...args) => {
172
+ if (isCutting) {
173
+ isCutting = false;
174
+ return;
175
+ }
173
176
  if (isEnded)
174
177
  return;
175
178
  isEnded = true;
@@ -181,14 +184,18 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
181
184
  this.recordHandle?.stop(reason);
182
185
  };
183
186
  let isEnded = false;
187
+ let isCutting = false;
184
188
  const recorder = new FFMPEGRecorder({
185
189
  url: stream.url,
186
190
  outputOptions: ffmpegOutputOptions,
187
191
  segment: this.segment ?? 0,
188
- getSavePath: (opts) => getSavePath({ owner, title, startTime: opts.startTime }),
192
+ getSavePath: (opts) => getSavePath({ owner, title: opts.title ?? title, startTime: opts.startTime }),
189
193
  disableDanma: this.disableProvideCommentsWhenRecording,
190
194
  videoFormat: this.videoFormat ?? "auto",
191
- }, onEnd);
195
+ }, onEnd, async () => {
196
+ const info = await getInfo(this.channelId);
197
+ return info;
198
+ });
192
199
  const savePath = getSavePath({
193
200
  owner,
194
201
  title,
@@ -200,8 +207,14 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
200
207
  this.state = "idle";
201
208
  throw err;
202
209
  }
203
- const handleVideoCreated = async ({ filename }) => {
204
- this.emit("videoFileCreated", { filename });
210
+ const handleVideoCreated = async ({ filename, title, cover }) => {
211
+ this.emit("videoFileCreated", { filename, cover });
212
+ if (title && this?.liveInfo) {
213
+ this.liveInfo.title = title;
214
+ }
215
+ if (cover && this?.liveInfo) {
216
+ this.liveInfo.cover = cover;
217
+ }
205
218
  const extraDataController = recorder.getExtraDataController();
206
219
  extraDataController?.setMeta({
207
220
  room_id: this.channelId,
@@ -236,7 +249,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
236
249
  case "chatmsg": {
237
250
  const comment = {
238
251
  type: "comment",
239
- timestamp: Date.now(),
252
+ timestamp: Number(msg.cst),
240
253
  text: msg.txt,
241
254
  color: colorTab[msg.col] ?? "#ffffff",
242
255
  sender: {
@@ -370,6 +383,16 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
370
383
  const ffmpegArgs = recorder.getArguments();
371
384
  recorder.run();
372
385
  // TODO: 需要一个机制防止空录制,比如检查文件的大小变化、ffmpeg 的输出、直播状态等
386
+ const cut = utils.singleton(async () => {
387
+ if (!this.recordHandle)
388
+ return;
389
+ if (isCutting)
390
+ return;
391
+ isCutting = true;
392
+ await recorder.stop();
393
+ recorder.createCommand();
394
+ recorder.run();
395
+ });
373
396
  const stop = utils.singleton(async (reason) => {
374
397
  if (!this.recordHandle)
375
398
  return;
@@ -400,6 +423,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
400
423
  ffmpegArgs,
401
424
  savePath: savePath,
402
425
  stop,
426
+ cut,
403
427
  };
404
428
  this.emit("RecordStart", this.recordHandle);
405
429
  return this.recordHandle;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bililive-tools/douyu-recorder",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "bililive-tools douyu recorder implemention",
5
5
  "main": "./lib/index.js",
6
6
  "type": "module",
@@ -41,7 +41,7 @@
41
41
  "lodash-es": "^4.17.21",
42
42
  "axios": "^1.7.8",
43
43
  "douyu-api": "^0.1.0",
44
- "@bililive-tools/manager": "^1.2.0"
44
+ "@bililive-tools/manager": "^1.3.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/ws": "^8.5.13"