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 +1 -0
- package/lib/index.js +78 -31
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
307
|
+
await sendWithTimeout(session, r.textContent, config.videoSendTimeout);
|
|
285
308
|
if (r.videoContent)
|
|
286
|
-
await session
|
|
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
|
|
312
|
-
|
|
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
|
-
|
|
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
|
}
|