@bililive-tools/huya-recorder 1.7.0 → 1.8.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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/lib/index.js +53 -16
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -37,6 +37,7 @@ interface Options {
37
37
  quality: number; // 见画质参数
38
38
  qualityRetry?: number; // 画质匹配重试次数, -1为强制匹配画质,0为自动配置,正整数为最大匹配次数
39
39
  streamPriorities: []; // 废弃
40
+ titleKeywords?: string; // 禁止录制的标题关键字,英文逗号分开多个
40
41
  sourcePriorities: []; // 按提供的源优先级去给CDN列表排序,并过滤掉不在优先级配置中的源,在未匹配到的情况下会优先使用TX的CDN,具体参数见 CDN 参数
41
42
  formatPriorities?: string[]; // 支持,`flv`和`hls` 参数,默认为['flv','hls']
42
43
  disableAutoCheck?: boolean; // 为 true 时 manager 将跳过自动检查
@@ -47,6 +48,7 @@ interface Options {
47
48
  api?: "auto" | "mp" | "web"; // 默认为auto,在星秀区使用mp接口,其他使用web接口,你也可以强制指定
48
49
  videoFormat?: "auto"; // 视频格式: "auto", "ts", "mkv" ,auto模式下, 分段使用 "ts",不分段使用 "mp4"
49
50
  recorderType?: "auto" | "ffmpeg" | "mesio"; // 底层录制器,使用mesio时videoFormat参数无效
51
+ debugLevel?: `verbose` | "basic"; // verbose参数时,录制器会输出更加详细的log
50
52
  }
51
53
  ```
52
54
 
package/lib/index.js CHANGED
@@ -64,22 +64,47 @@ const ffmpegOutputOptions = [
64
64
  "-min_frag_duration",
65
65
  "10000000",
66
66
  ];
67
- const ffmpegInputOptions = [
68
- "-reconnect",
69
- "1",
70
- "-reconnect_streamed",
71
- "1",
72
- "-reconnect_delay_max",
73
- "10",
74
- "-rw_timeout",
75
- "15000000",
76
- ];
67
+ const ffmpegInputOptions = ["-rw_timeout", "10000000", "-timeout", "10000000"];
77
68
  const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isManualStart, }) {
78
- if (this.recordHandle != null)
69
+ // 如果已经在录制中,只在需要检查标题关键词时才获取最新信息
70
+ if (this.recordHandle != null) {
71
+ // 只有当设置了标题关键词时,并且不是手动启动的录制,才获取最新的直播间信息
72
+ if (utils.shouldCheckTitleKeywords(isManualStart, this.titleKeywords)) {
73
+ const now = Date.now();
74
+ // 每5分钟检查一次标题变化
75
+ const titleCheckInterval = 5 * 60 * 1000; // 5分钟
76
+ // 获取上次检查时间
77
+ const lastCheckTime = typeof this.extra.lastTitleCheckTime === "number" ? this.extra.lastTitleCheckTime : 0;
78
+ // 如果距离上次检查时间不足指定间隔,则跳过检查
79
+ if (now - lastCheckTime < titleCheckInterval) {
80
+ return this.recordHandle;
81
+ }
82
+ // 更新检查时间
83
+ this.extra.lastTitleCheckTime = now;
84
+ // 获取直播间信息
85
+ const liveInfo = await getInfo(this.channelId);
86
+ const { title } = liveInfo;
87
+ // 检查标题是否包含关键词
88
+ if (utils.hasBlockedTitleKeywords(title, this.titleKeywords)) {
89
+ this.state = "title-blocked";
90
+ this.emit("DebugLog", {
91
+ type: "common",
92
+ text: `检测到标题包含关键词,停止录制:直播间标题 "${title}" 包含关键词 "${this.titleKeywords}"`,
93
+ });
94
+ // 停止录制
95
+ await this.recordHandle.stop("直播间标题包含关键词");
96
+ // 返回 null,停止录制
97
+ return null;
98
+ }
99
+ }
100
+ // 已经在录制中,直接返回
79
101
  return this.recordHandle;
102
+ }
103
+ // 获取直播间信息
80
104
  try {
81
105
  const liveInfo = await getInfo(this.channelId);
82
106
  this.liveInfo = liveInfo;
107
+ this.state = "idle";
83
108
  }
84
109
  catch (error) {
85
110
  this.state = "check-error";
@@ -96,6 +121,18 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
96
121
  return null;
97
122
  if (!living)
98
123
  return null;
124
+ // 检查标题是否包含关键词,如果包含则不自动录制
125
+ // 手动开始录制时不检查标题关键词
126
+ if (utils.shouldCheckTitleKeywords(isManualStart, this.titleKeywords)) {
127
+ if (utils.hasBlockedTitleKeywords(title, this.titleKeywords)) {
128
+ this.state = "title-blocked";
129
+ this.emit("DebugLog", {
130
+ type: "common",
131
+ text: `跳过录制:直播间标题 "${title}" 包含关键词 "${this.titleKeywords}"`,
132
+ });
133
+ return null;
134
+ }
135
+ }
99
136
  let res;
100
137
  // TODO: 先不做什么错误处理,就简单包一下预期上会有错误的地方
101
138
  try {
@@ -148,8 +185,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
148
185
  const reason = args[0] instanceof Error ? args[0].message : String(args[0]);
149
186
  this.recordHandle?.stop(reason);
150
187
  };
151
- let recorderType = this.recorderType === "mesio" ? "mesio" : "ffmpeg";
152
- const recorder = createBaseRecorder(recorderType, {
188
+ const recorder = createBaseRecorder(this.recorderType, {
153
189
  url: stream.url,
154
190
  outputOptions: ffmpegOutputOptions,
155
191
  inputOptions: ffmpegInputOptions,
@@ -157,6 +193,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
157
193
  getSavePath: (opts) => getSavePath({ owner, title: opts.title ?? title, startTime: opts.startTime }),
158
194
  disableDanma: this.disableProvideCommentsWhenRecording,
159
195
  videoFormat: this.videoFormat ?? "auto",
196
+ debugLevel: this.debugLevel ?? "none",
160
197
  }, onEnd, async () => {
161
198
  const info = await getInfo(this.channelId);
162
199
  return info;
@@ -172,8 +209,8 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
172
209
  this.state = "idle";
173
210
  throw err;
174
211
  }
175
- const handleVideoCreated = async ({ filename, title, cover }) => {
176
- this.emit("videoFileCreated", { filename, cover });
212
+ const handleVideoCreated = async ({ filename, title, cover, rawFilename }) => {
213
+ this.emit("videoFileCreated", { filename, cover, rawFilename });
177
214
  if (title && this?.liveInfo) {
178
215
  this.liveInfo.title = title;
179
216
  }
@@ -254,7 +291,7 @@ const checkLiveStatusAndRecord = async function ({ getSavePath, banLiveId, isMan
254
291
  client.on("retry", (e) => {
255
292
  this.emit("DebugLog", {
256
293
  type: "common",
257
- text: `huya danmu retry: ${e.count}/${e.max}`,
294
+ text: `${this?.liveInfo?.owner}:${this.channelId} huya danmu retry: ${e.count}/${e.max}`,
258
295
  });
259
296
  });
260
297
  client.start();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bililive-tools/huya-recorder",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "bililive-tools huya recorder implemention",
5
5
  "main": "./lib/index.js",
6
6
  "type": "module",
@@ -37,8 +37,8 @@
37
37
  "mitt": "^3.0.1",
38
38
  "lodash-es": "^4.17.21",
39
39
  "axios": "^1.7.8",
40
- "huya-danma-listener": "0.1.2",
41
- "@bililive-tools/manager": "^1.6.1"
40
+ "@bililive-tools/manager": "^1.8.0",
41
+ "huya-danma-listener": "0.1.3"
42
42
  },
43
43
  "devDependencies": {},
44
44
  "scripts": {