koishi-plugin-video-parser-all 0.2.0 → 0.2.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.
package/lib/index.d.ts CHANGED
@@ -21,6 +21,7 @@ export interface Config {
21
21
  retryTimes: number;
22
22
  retryInterval: number;
23
23
  apiUrl: string;
24
+ videoSendTimeout: number;
24
25
  }
25
26
  export declare const Config: Schema<Config>;
26
27
  export declare function apply(ctx: Context, config: Config): void;
package/lib/index.js CHANGED
@@ -14,27 +14,39 @@ const promises_1 = require("stream/promises");
14
14
  const worker_threads_1 = require("worker_threads");
15
15
  exports.name = 'video-parser-all';
16
16
  exports.Config = koishi_1.Schema.object({
17
- enable: koishi_1.Schema.boolean().default(true),
18
- showWaitingTip: koishi_1.Schema.boolean().default(true),
19
- // 修复:boolean.default → Schema.boolean().default
20
- revokeWaitingTip: koishi_1.Schema.boolean().default(true),
21
- waitingTipText: koishi_1.Schema.string().default('正在解析视频…'),
22
- sameLinkInterval: koishi_1.Schema.number().default(180),
23
- imageParseFormat: koishi_1.Schema.string().role('textarea').default('${标题} ${tab} ${UP主}\n${简介}\n${~~~}\n${封面}'),
17
+ enable: koishi_1.Schema.boolean().default(true).description('是否启用插件'),
18
+ showWaitingTip: koishi_1.Schema.boolean().default(true).description('是否显示解析等待提示'),
19
+ revokeWaitingTip: koishi_1.Schema.boolean().default(true).description('解析完成后是否撤回等待提示'),
20
+ waitingTipText: koishi_1.Schema.string().default('正在解析视频…').description('等待提示的文本内容'),
21
+ sameLinkInterval: koishi_1.Schema.number().default(180).description('相同链接解析间隔(秒),防止重复解析'),
22
+ imageParseFormat: koishi_1.Schema.string().role('textarea').default('${标题} ${tab} ${UP主}\n${简介}\n${~~~}\n${封面}').description(`解析结果文本格式,支持的变量:
23
+ - \${标题}:视频标题
24
+ - \${UP主}:作者名称
25
+ - \${简介}:视频简介
26
+ - \${点赞}:点赞数
27
+ - \${投币}:投币数
28
+ - \${收藏}:收藏数
29
+ - \${转发}:转发数
30
+ - \${观看}:播放量
31
+ - \${弹幕}:弹幕数
32
+ - \${tab}:制表符
33
+ - \${~~~}:换行符
34
+ - \${封面}:封面图片位置`),
24
35
  returnContent: koishi_1.Schema.object({
25
- showImageText: koishi_1.Schema.boolean().default(true),
26
- showVideoUrl: koishi_1.Schema.boolean().default(false),
27
- showVideoFile: koishi_1.Schema.boolean().default(true),
28
- }),
29
- maxDescLength: koishi_1.Schema.number().default(200),
30
- timeout: koishi_1.Schema.number().default(15000),
31
- ignoreSendError: koishi_1.Schema.boolean().default(true),
32
- enableForward: koishi_1.Schema.boolean().default(false),
33
- downloadVideoBeforeSend: koishi_1.Schema.boolean().default(false),
34
- messageBufferDelay: koishi_1.Schema.number().default(1).min(0),
35
- retryTimes: koishi_1.Schema.number().default(3).min(0),
36
- retryInterval: koishi_1.Schema.number().default(2000).min(500),
37
- apiUrl: koishi_1.Schema.string().default('https://api.bugpk.com/api/short_videos'),
36
+ showImageText: koishi_1.Schema.boolean().default(true).description('是否显示解析后的文本和封面'),
37
+ showVideoUrl: koishi_1.Schema.boolean().default(false).description('是否显示无水印视频链接'),
38
+ showVideoFile: koishi_1.Schema.boolean().default(true).description('是否发送视频文件/视频链接'),
39
+ }).description('返回内容配置'),
40
+ maxDescLength: koishi_1.Schema.number().default(200).description('简介最大长度限制'),
41
+ timeout: koishi_1.Schema.number().default(15000).description('API 请求超时时间(毫秒)'),
42
+ ignoreSendError: koishi_1.Schema.boolean().default(true).description('是否忽略发送消息时的错误'),
43
+ enableForward: koishi_1.Schema.boolean().default(false).description('是否启用合并转发模式(仅 OneBot 平台)'),
44
+ downloadVideoBeforeSend: koishi_1.Schema.boolean().default(false).description('发送前是否先下载视频(仅 OneBot 平台,解决部分视频无法播放问题)'),
45
+ messageBufferDelay: koishi_1.Schema.number().default(1).min(0).description('消息缓冲延迟(秒),用于合并短时间内的多个解析请求'),
46
+ retryTimes: koishi_1.Schema.number().default(3).min(0).description('API 请求失败重试次数'),
47
+ retryInterval: koishi_1.Schema.number().default(2000).min(500).description('重试间隔(毫秒)'),
48
+ apiUrl: koishi_1.Schema.string().default('https://api.bugpk.com/api/short_videos').description('视频解析接口地址'),
49
+ videoSendTimeout: koishi_1.Schema.number().default(30000).description('视频消息发送超时时间(毫秒),解决发送视频超时问题')
38
50
  });
39
51
  if (!worker_threads_1.isMainThread) {
40
52
  const { url, filePath } = worker_threads_1.workerData;
@@ -236,9 +248,20 @@ function apply(ctx, config) {
236
248
  if (!buf?.tipMsgId)
237
249
  return;
238
250
  try {
239
- await session.bot.deleteMessage(session.channelId, buf.tipMsgId);
251
+ await session.bot.deleteMessage(session.channelId, buf.tipMsgId.toString());
240
252
  }
241
- catch { }
253
+ catch (e) {
254
+ ctx.logger.warn(`撤回提示消息失败: ${e.message}`);
255
+ }
256
+ }
257
+ async function sendWithTimeout(session, content, timeout) {
258
+ return Promise.race([
259
+ session.send(content),
260
+ new Promise((_, reject) => setTimeout(() => reject(new Error('消息发送超时')), timeout))
261
+ ]).catch((e) => {
262
+ ctx.logger.warn(`消息发送超时: ${e.message}`);
263
+ return null;
264
+ });
242
265
  }
243
266
  async function flush(session) {
244
267
  const key = `${session.platform}:${session.userId}:${session.channelId}`;
@@ -255,7 +278,7 @@ function apply(ctx, config) {
255
278
  results.push(r);
256
279
  }
257
280
  if (results.length === 0) {
258
- await session.send('视频解析失败');
281
+ await sendWithTimeout(session, '视频解析失败', config.videoSendTimeout);
259
282
  return;
260
283
  }
261
284
  if (config.enableForward && session.platform === 'onebot') {
@@ -271,21 +294,24 @@ function apply(ctx, config) {
271
294
  ...content
272
295
  ]);
273
296
  });
274
- await session.send((0, koishi_1.h)('message', { forward: true }, forwardMessages));
297
+ await sendWithTimeout(session, (0, koishi_1.h)('message', { forward: true }, forwardMessages), config.videoSendTimeout);
275
298
  return;
276
299
  }
277
300
  catch (e) {
278
- await session.send('合并转发失败,将分开发送');
301
+ await sendWithTimeout(session, '合并转发失败,将分开发送', config.videoSendTimeout);
279
302
  }
280
303
  }
281
304
  for (const r of results) {
282
305
  try {
283
306
  if (r.textContent)
284
- await session.send(r.textContent);
307
+ await sendWithTimeout(session, r.textContent, config.videoSendTimeout);
285
308
  if (r.videoContent)
286
- await session.send(r.videoContent);
309
+ await sendWithTimeout(session, r.videoContent, config.videoSendTimeout);
310
+ }
311
+ catch (e) {
312
+ if (!config.ignoreSendError)
313
+ ctx.logger.error(`发送消息失败: ${e.message}`);
287
314
  }
288
- catch { }
289
315
  }
290
316
  }
291
317
  ctx.on('message', async (session) => {
@@ -308,8 +334,10 @@ function apply(ctx, config) {
308
334
  }
309
335
  let tipId;
310
336
  if (config.showWaitingTip) {
311
- const m = await session.send(config.waitingTipText).catch(() => null);
312
- tipId = m?.messageId || m?.id || m;
337
+ const m = await sendWithTimeout(session, config.waitingTipText, config.videoSendTimeout);
338
+ if (m) {
339
+ tipId = m?.messageId || m?.id || m;
340
+ }
313
341
  }
314
342
  linkBuffer.set(key, {
315
343
  urls,
@@ -321,5 +349,24 @@ function apply(ctx, config) {
321
349
  const now = Date.now();
322
350
  processed.forEach((t, h) => now - t > 86400000 && processed.delete(h));
323
351
  }, 3600000);
324
- ctx.logger.info('视频解析已加载');
352
+ setInterval(() => {
353
+ const tempDir = path_1.default.join(process.cwd(), 'temp_videos');
354
+ if (fs_1.default.existsSync(tempDir)) {
355
+ const files = fs_1.default.readdirSync(tempDir);
356
+ const now = Date.now();
357
+ files.forEach(file => {
358
+ const filePath = path_1.default.join(tempDir, file);
359
+ try {
360
+ const stats = fs_1.default.statSync(filePath);
361
+ if (now - stats.mtimeMs > 3600000) {
362
+ fs_1.default.unlinkSync(filePath);
363
+ }
364
+ }
365
+ catch (e) {
366
+ ctx.logger.error(`清理临时文件失败: ${e.message}`);
367
+ }
368
+ });
369
+ }
370
+ }, 1800000);
371
+ ctx.logger.info('视频解析插件已加载完成');
325
372
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-video-parser-all",
3
3
  "description": "Koishi 视频解析插件,支持抖音/快手/B站链接解析,可自定义API和解析规则",
4
- "version": "0.2.0",
4
+ "version": "0.2.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [