koishi-plugin-video-parser-all 0.9.4 → 0.9.6
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.js +44 -43
- package/package.json +1 -1
- package/readme.md +10 -8
package/lib/index.js
CHANGED
|
@@ -16,7 +16,7 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
16
16
|
debug: koishi_1.Schema.boolean().default(false).description('开启调试模式,在控制台输出详细日志'),
|
|
17
17
|
}).description('基础设置'),
|
|
18
18
|
koishi_1.Schema.object({
|
|
19
|
-
unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default(`标题:\${标题}\n作者:\${作者}\n简介:\${简介}\n点赞:\${点赞数}\n收藏:\${收藏数}\n转发:\${转发数}\n播放:\${播放数}\n评论:\${评论数}`).description('统一消息格式,可用变量:${标题} ${作者} ${简介} ${点赞数} ${收藏数} ${转发数} ${播放数} ${评论数} ${视频时长} ${发布时间} ${图片数量} ${作者ID} ${封面}'),
|
|
19
|
+
unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default(`标题:\${标题}\n作者:\${作者}\n简介:\${简介}\n点赞:\${点赞数}\n收藏:\${收藏数}\n转发:\${转发数}\n播放:\${播放数}\n评论:\${评论数}\n图片数量:\${图片数量}`).description('统一消息格式,可用变量:${标题} ${作者} ${简介} ${点赞数} ${收藏数} ${转发数} ${播放数} ${评论数} ${视频时长} ${发布时间} ${图片数量} ${作者ID} ${封面}'),
|
|
20
20
|
}).description('消息格式设置'),
|
|
21
21
|
koishi_1.Schema.object({
|
|
22
22
|
showImageText: koishi_1.Schema.boolean().default(true).description('是否发送解析后的文字内容'),
|
|
@@ -30,8 +30,8 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
30
30
|
}).description('网络与 API 设置'),
|
|
31
31
|
koishi_1.Schema.object({
|
|
32
32
|
ignoreSendError: koishi_1.Schema.boolean().default(true).description('忽略消息发送失败,避免插件崩溃'),
|
|
33
|
-
retryTimes: koishi_1.Schema.number().min(0).default(3).description('API
|
|
34
|
-
retryInterval: koishi_1.Schema.number().min(0).default(1000).description('
|
|
33
|
+
retryTimes: koishi_1.Schema.number().min(0).default(3).description('API 请求及消息发送失败时的重试次数'),
|
|
34
|
+
retryInterval: koishi_1.Schema.number().min(0).default(1000).description('重试间隔(毫秒,同时用于消息发送重试)'),
|
|
35
35
|
}).description('错误与重试设置'),
|
|
36
36
|
koishi_1.Schema.object({
|
|
37
37
|
enableForward: koishi_1.Schema.boolean().default(false).description('启用合并转发(仅 OneBot 平台)'),
|
|
@@ -41,7 +41,7 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
41
41
|
unsupportedPlatformText: koishi_1.Schema.string().default('不支持该平台链接').description('不支持的平台提示'),
|
|
42
42
|
invalidLinkText: koishi_1.Schema.string().default('无效的视频链接').description('无效链接提示(parse 指令)'),
|
|
43
43
|
parseErrorPrefix: koishi_1.Schema.string().default('❌ 解析失败:').description('解析失败消息前缀'),
|
|
44
|
-
parseErrorItemFormat: koishi_1.Schema.string().default('【${url}】: ${msg}').description('
|
|
44
|
+
parseErrorItemFormat: koishi_1.Schema.string().default('【${url}】: ${msg}').description('每条解析失败格式,可用 ${url}(链接)和 ${msg}(错误信息)'),
|
|
45
45
|
}).description('界面文字设置'),
|
|
46
46
|
]);
|
|
47
47
|
const logger = new koishi_1.Logger(exports.name);
|
|
@@ -277,7 +277,7 @@ function generateFormattedText(p, format) {
|
|
|
277
277
|
for (const match of varMatches) {
|
|
278
278
|
const varName = match.replace(/\$\{|\}/g, '');
|
|
279
279
|
const val = vars[varName];
|
|
280
|
-
if (val !== undefined && val !== '') {
|
|
280
|
+
if (val !== undefined && val !== '' && val !== '0') {
|
|
281
281
|
allEmpty = false;
|
|
282
282
|
break;
|
|
283
283
|
}
|
|
@@ -368,28 +368,36 @@ function apply(ctx, config) {
|
|
|
368
368
|
const text = generateFormattedText(result.data, config.unifiedMessageFormat);
|
|
369
369
|
return { success: true, data: { text, parsed: result.data } };
|
|
370
370
|
}
|
|
371
|
-
async function sendWithTimeout(session, content) {
|
|
372
|
-
|
|
371
|
+
async function sendWithTimeout(session, content, customRetries) {
|
|
372
|
+
const maxRetries = customRetries ?? config.retryTimes ?? 3;
|
|
373
|
+
const retryDelay = config.retryInterval || 1000;
|
|
374
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
373
375
|
try {
|
|
374
|
-
|
|
376
|
+
if (config.videoSendTimeout <= 0) {
|
|
377
|
+
return await session.send(content);
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
return await Promise.race([
|
|
381
|
+
session.send(content),
|
|
382
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('发送超时')), config.videoSendTimeout))
|
|
383
|
+
]);
|
|
384
|
+
}
|
|
375
385
|
}
|
|
376
386
|
catch (err) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
387
|
+
const errMsg = getErrorMessage(err);
|
|
388
|
+
debugLog('ERROR', `第${attempt + 1}次发送失败: ${errMsg}`);
|
|
389
|
+
if (attempt < maxRetries) {
|
|
390
|
+
debugLog('INFO', `等待 ${retryDelay}ms 后进行第 ${attempt + 2} 次重试`);
|
|
391
|
+
await delay(retryDelay);
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
if (!config.ignoreSendError)
|
|
395
|
+
throw err;
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
380
398
|
}
|
|
381
399
|
}
|
|
382
|
-
|
|
383
|
-
return await Promise.race([
|
|
384
|
-
session.send(content),
|
|
385
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('发送超时')), config.videoSendTimeout))
|
|
386
|
-
]);
|
|
387
|
-
}
|
|
388
|
-
catch (err) {
|
|
389
|
-
if (!config.ignoreSendError)
|
|
390
|
-
throw err;
|
|
391
|
-
return null;
|
|
392
|
-
}
|
|
400
|
+
return null;
|
|
393
401
|
}
|
|
394
402
|
async function flush(session, urls) {
|
|
395
403
|
const items = [];
|
|
@@ -407,7 +415,7 @@ function apply(ctx, config) {
|
|
|
407
415
|
}
|
|
408
416
|
}
|
|
409
417
|
if (errors.length) {
|
|
410
|
-
await sendWithTimeout(session, `${texts.parseErrorPrefix}\n${errors.join('\n')}`)
|
|
418
|
+
await sendWithTimeout(session, `${texts.parseErrorPrefix}\n${errors.join('\n')}`);
|
|
411
419
|
await delay(500);
|
|
412
420
|
}
|
|
413
421
|
if (!items.length)
|
|
@@ -426,7 +434,7 @@ function apply(ctx, config) {
|
|
|
426
434
|
await delay(300);
|
|
427
435
|
}
|
|
428
436
|
}
|
|
429
|
-
if (p.cover && p.type !== 'live_photo') {
|
|
437
|
+
if (p.cover && p.type !== 'live_photo' && !(p.type === 'live' && (p.live_photo?.length || p.images?.length))) {
|
|
430
438
|
if (enableForward)
|
|
431
439
|
forwardMessages.push(buildForwardNode(session, koishi_1.h.image(p.cover), botName));
|
|
432
440
|
else {
|
|
@@ -434,21 +442,18 @@ function apply(ctx, config) {
|
|
|
434
442
|
await delay(300);
|
|
435
443
|
}
|
|
436
444
|
}
|
|
437
|
-
if (p.video && config.showVideoFile && (p.type === 'video' || p.type === 'live')) {
|
|
445
|
+
if (p.video && config.showVideoFile && (p.type === 'video' || (p.type === 'live' && !p.live_photo?.length && !p.images?.length))) {
|
|
438
446
|
const videoMsg = koishi_1.h.video(p.video);
|
|
439
447
|
if (enableForward) {
|
|
440
448
|
forwardMessages.push(buildForwardNode(session, videoMsg, botName));
|
|
441
449
|
}
|
|
442
450
|
else {
|
|
443
|
-
|
|
444
|
-
await sendWithTimeout(session, videoMsg);
|
|
445
|
-
}
|
|
446
|
-
catch { }
|
|
451
|
+
await sendWithTimeout(session, videoMsg).catch(() => { });
|
|
447
452
|
await delay(500);
|
|
448
453
|
}
|
|
449
454
|
}
|
|
450
|
-
if (p.type === 'image' || p.type === 'live_photo') {
|
|
451
|
-
const imageUrls = p.images?.length ? p.images : [];
|
|
455
|
+
if (p.type === 'image' || p.type === 'live_photo' || (p.type === 'live' && (p.live_photo?.length || p.images?.length))) {
|
|
456
|
+
const imageUrls = p.images?.length ? p.images : (p.live_photo?.map(lp => lp.image) ?? []);
|
|
452
457
|
if (enableForward) {
|
|
453
458
|
for (const url of imageUrls) {
|
|
454
459
|
forwardMessages.push(buildForwardNode(session, koishi_1.h.image(url), botName));
|
|
@@ -456,28 +461,24 @@ function apply(ctx, config) {
|
|
|
456
461
|
}
|
|
457
462
|
else {
|
|
458
463
|
for (const url of imageUrls) {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
await delay(200);
|
|
462
|
-
}
|
|
463
|
-
catch { }
|
|
464
|
+
await sendWithTimeout(session, koishi_1.h.image(url)).catch(() => { });
|
|
465
|
+
await delay(200);
|
|
464
466
|
}
|
|
465
467
|
}
|
|
466
468
|
}
|
|
467
469
|
}
|
|
468
470
|
if (enableForward && forwardMessages.length) {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
for (const node of forwardMessages) {
|
|
471
|
+
const forwardMsg = (0, koishi_1.h)('message', { forward: true }, forwardMessages.slice(0, 100));
|
|
472
|
+
await sendWithTimeout(session, forwardMsg, config.retryTimes).catch(() => {
|
|
473
|
+
debugLog('ERROR', '合并转发发送最终失败,降级为逐条发送');
|
|
474
|
+
forwardMessages.forEach(async (node) => {
|
|
474
475
|
try {
|
|
475
476
|
await sendWithTimeout(session, node.data.content);
|
|
476
477
|
await delay(300);
|
|
477
478
|
}
|
|
478
479
|
catch { }
|
|
479
|
-
}
|
|
480
|
-
}
|
|
480
|
+
});
|
|
481
|
+
});
|
|
481
482
|
}
|
|
482
483
|
}
|
|
483
484
|
ctx.on('message', async (session) => {
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -3,22 +3,24 @@
|
|
|
3
3
|
## 项目介绍 (Project Introduction)
|
|
4
4
|
|
|
5
5
|
### 中文
|
|
6
|
-
这是一个为 Koishi 机器人框架开发的**全平台视频/图集解析插件**,使用统一API接口,支持自动识别并解析抖音、快手、B站、小红书、微博、YouTube、TikTok、剪映、AcFun、知乎、虎牙等20
|
|
6
|
+
这是一个为 Koishi 机器人框架开发的**全平台视频/图集解析插件**,使用统一API接口,支持自动识别并解析抖音、快手、B站、小红书、微博、YouTube、TikTok、剪映、AcFun、知乎、虎牙等20+主流平台的短视频/图集/实况链接。核心特性:
|
|
7
7
|
- 🌐 统一API解析,覆盖20+热门平台,无需繁琐配置
|
|
8
8
|
- 🤖 自动识别链接来源,即丢即用
|
|
9
9
|
- 🎨 完全自定义的解析结果格式,支持多项变量替换,变量无值自动隐藏行
|
|
10
10
|
- 🐛 内置Debug调试模式,可详细记录所有操作与API交互日志
|
|
11
11
|
- 📤 支持OneBot平台消息合并转发,优化多图文展示体验
|
|
12
12
|
- 💬 所有提示文案均可自定义,适配多语言场景
|
|
13
|
+
- 🔁 消息发送支持自动重试,与API重试配置联动,增强稳定性
|
|
13
14
|
|
|
14
15
|
### English
|
|
15
|
-
This is a **multi-platform video/image parsing plugin** developed for the Koishi bot framework, using a unified API interface to automatically recognize and parse short video/image links from 20+ mainstream platforms such as Douyin, Kuaishou, Bilibili, Xiaohongshu, Weibo, YouTube, TikTok, Jianying, AcFun, Zhihu, Huya and more. Core features:
|
|
16
|
+
This is a **multi-platform video/image parsing plugin** developed for the Koishi bot framework, using a unified API interface to automatically recognize and parse short video/image/live photo links from 20+ mainstream platforms such as Douyin, Kuaishou, Bilibili, Xiaohongshu, Weibo, YouTube, TikTok, Jianying, AcFun, Zhihu, Huya and more. Core features:
|
|
16
17
|
- 🌐 Unified API parsing, covering 20+ popular platforms without complex configuration
|
|
17
18
|
- 🤖 Auto-detection of link sources, just drop & go
|
|
18
19
|
- 🎨 Fully customizable parsing result format with variable substitutions, empty variables hide the line automatically
|
|
19
20
|
- 🐛 Built-in Debug mode, recording detailed operations and API interaction logs
|
|
20
21
|
- 📤 Support OneBot message forwarding for better image/video display
|
|
21
22
|
- 💬 All prompt texts are customizable for multilingual scenarios
|
|
23
|
+
- 🔁 Message sending supports automatic retries, linked with API retry configuration for improved stability
|
|
22
24
|
|
|
23
25
|
## 项目仓库 (Repository)
|
|
24
26
|
- GitHub: `https://github.com/Minecraft-1314/koishi-plugin-video-parser-all`
|
|
@@ -43,7 +45,7 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
|
|
|
43
45
|
### 统一消息格式
|
|
44
46
|
| 配置项 | 类型 | 默认值 | 说明 |
|
|
45
47
|
|--------|------|--------|------|
|
|
46
|
-
| `unifiedMessageFormat` | string | `标题:${标题}\n作者:${作者}\n简介:${简介}\n点赞:${点赞数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}` |
|
|
48
|
+
| `unifiedMessageFormat` | string | `标题:${标题}\n作者:${作者}\n简介:${简介}\n点赞:${点赞数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}\n图片数量:${图片数量}` | 自定义解析结果的输出格式,支持变量替换。某行所有变量为空(或为"0")时自动隐藏该行 |
|
|
47
49
|
|
|
48
50
|
### 内容显示设置
|
|
49
51
|
| 配置项 | 类型 | 默认值 | 说明 |
|
|
@@ -63,8 +65,8 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
|
|
|
63
65
|
| 配置项 | 类型 | 默认值 | 说明 |
|
|
64
66
|
|--------|------|--------|------|
|
|
65
67
|
| `ignoreSendError` | boolean | true | 是否忽略消息发送失败,避免插件崩溃 |
|
|
66
|
-
| `retryTimes` | number | 3 | API
|
|
67
|
-
| `retryInterval` | number | 1000 |
|
|
68
|
+
| `retryTimes` | number | 3 | API 请求及消息发送失败时的重试次数 |
|
|
69
|
+
| `retryInterval` | number | 1000 | API 请求及消息发送重试的间隔时间(毫秒) |
|
|
68
70
|
|
|
69
71
|
### 发送方式设置
|
|
70
72
|
| 配置项 | 类型 | 默认值 | 说明 |
|
|
@@ -81,7 +83,7 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
|
|
|
81
83
|
| `parseErrorItemFormat` | string | 【${url}】: ${msg} | 每条解析失败的展示格式,可用 ${url}(链接)和 ${msg}(错误信息) |
|
|
82
84
|
|
|
83
85
|
## 支持的变量 (Supported Variables)
|
|
84
|
-
在 `unifiedMessageFormat`
|
|
86
|
+
在 `unifiedMessageFormat` 中可使用以下变量进行自定义格式化,某行所有变量均为空(或为"0")时该行不显示:
|
|
85
87
|
|
|
86
88
|
| 变量名 | 说明 | 适用平台 |
|
|
87
89
|
|--------|------|----------|
|
|
@@ -95,11 +97,11 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
|
|
|
95
97
|
| `${播放数}` | 播放量 | 部分平台 |
|
|
96
98
|
| `${评论数}` | 评论数量 | 所有平台 |
|
|
97
99
|
| `${发布时间}` | 发布时间(格式化) | 所有平台 |
|
|
98
|
-
| `${图片数量}` |
|
|
100
|
+
| `${图片数量}` | 图集/实况图片数量 | 图集/实况 |
|
|
99
101
|
| `${作者ID}` | 作者唯一标识ID | 部分平台 |
|
|
100
102
|
| `${封面}` | 封面图片地址 | 所有平台 |
|
|
101
103
|
|
|
102
|
-
> 注:部分变量可能因平台API
|
|
104
|
+
> 注:部分变量可能因平台API返回数据不同而显示为空,某行所有变量为空(或为"0")时该行会自动隐藏。
|
|
103
105
|
|
|
104
106
|
## 支持的平台 (Supported Platforms)
|
|
105
107
|
| 平台名称 | 关键词识别 | 解析能力 |
|