koishi-plugin-video-parser-all 1.0.3 → 1.0.5
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 +0 -2
- package/lib/index.js +112 -128
- package/package.json +1 -1
- package/readme.md +5 -5
package/lib/index.d.ts
CHANGED
|
@@ -15,7 +15,6 @@ export declare const Config: Schema<{
|
|
|
15
15
|
tempDir?: string | null | undefined;
|
|
16
16
|
maxVideoSize?: number | null | undefined;
|
|
17
17
|
forceDownloadVideo?: boolean | null | undefined;
|
|
18
|
-
videoLoadWaitTime?: number | null | undefined;
|
|
19
18
|
} & {
|
|
20
19
|
timeout?: number | null | undefined;
|
|
21
20
|
videoSendTimeout?: number | null | undefined;
|
|
@@ -47,7 +46,6 @@ export declare const Config: Schema<{
|
|
|
47
46
|
tempDir: string;
|
|
48
47
|
maxVideoSize: number;
|
|
49
48
|
forceDownloadVideo: boolean;
|
|
50
|
-
videoLoadWaitTime: number;
|
|
51
49
|
} & {
|
|
52
50
|
timeout: number;
|
|
53
51
|
videoSendTimeout: number;
|
package/lib/index.js
CHANGED
|
@@ -30,8 +30,7 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
30
30
|
videoDownloadTimeout: koishi_1.Schema.number().min(0).step(1).default(120000).description('视频下载超时(毫秒)'),
|
|
31
31
|
tempDir: koishi_1.Schema.string().default('./temp_videos').description('临时视频存储目录'),
|
|
32
32
|
maxVideoSize: koishi_1.Schema.number().min(0).step(1).default(0).description('最大下载视频大小(MB),0 为不限制大小'),
|
|
33
|
-
forceDownloadVideo: koishi_1.Schema.boolean().default(
|
|
34
|
-
videoLoadWaitTime: koishi_1.Schema.number().min(0).step(1).default(180000).description('视频链接加载等待时间(毫秒),获取到视频链接后等待指定时间再发送,0为不等待'),
|
|
33
|
+
forceDownloadVideo: koishi_1.Schema.boolean().default(false).description('强制下载视频后发送'),
|
|
35
34
|
}).description('内容显示设置'),
|
|
36
35
|
koishi_1.Schema.object({
|
|
37
36
|
timeout: koishi_1.Schema.number().min(0).step(1).default(180000).description('API 请求超时(毫秒)'),
|
|
@@ -77,32 +76,32 @@ function linkTypeParser(content) {
|
|
|
77
76
|
content = content.replace(/\\\//g, '/');
|
|
78
77
|
const rules = [
|
|
79
78
|
{ pattern: /bilibili\.com\/video\/([ab]v[0-9a-zA-Z]+)/gi, type: 'bilibili', buildUrl: (id) => `https://www.bilibili.com/video/${id}` },
|
|
80
|
-
{ pattern: /b23\.tv\/([0-9a-zA-Z]
|
|
81
|
-
{ pattern: /bili(?:22|23|33)\.cn\/([0-9a-zA-Z]
|
|
82
|
-
{ pattern: /bili2233\.cn\/([0-9a-zA-Z]
|
|
83
|
-
{ pattern: /douyin\.com\/video\/(\d
|
|
84
|
-
{ pattern: /v\.douyin\.com\/([0-9a-zA-Z]
|
|
85
|
-
{ pattern: /kuaishou\.com\/short-video\/([0-9a-zA-Z]
|
|
86
|
-
{ pattern: /v\.kuaishou\.com\/([0-9a-zA-Z]
|
|
87
|
-
{ pattern: /xiaohongshu\.com\/discovery\/item\/([0-9a-zA-Z]
|
|
88
|
-
{ pattern: /xhslink\.com\/([0-9a-zA-Z]
|
|
89
|
-
{ pattern: /weibo\.com\/\d+\/([0-9a-zA-Z]
|
|
90
|
-
{ pattern: /video\.weibo\.com\/show\?fid=([0-9a-zA-Z]
|
|
91
|
-
{ pattern: /ixigua\.com\/(\d
|
|
92
|
-
{ pattern: /youtube\.com\/watch\?v=([a-zA-Z0-9_-]
|
|
93
|
-
{ pattern: /youtu\.be\/([a-zA-Z0-9_-]
|
|
94
|
-
{ pattern: /tiktok\.com\/@[\w.]+\/video\/(\d
|
|
95
|
-
{ pattern: /vm\.tiktok\.com\/([0-9a-zA-Z]
|
|
96
|
-
{ pattern: /acfun\.cn\/v\/(ac\d
|
|
97
|
-
{ pattern: /zhihu\.com\/video\/(\d
|
|
98
|
-
{ pattern: /weishi\.qq\.com\/weishi\/feed\/([0-9a-zA-Z]
|
|
99
|
-
{ pattern: /huya\.com\/video\/([0-9a-zA-Z]
|
|
100
|
-
{ pattern: /haokan\.baidu\.com\/v\?vid=([0-9a-zA-Z]
|
|
101
|
-
{ pattern: /meipai\.com\/media\/(\d
|
|
102
|
-
{ pattern: /twitter\.com\/\w+\/status\/(\d
|
|
103
|
-
{ pattern: /x\.com\/\w+\/status\/(\d
|
|
104
|
-
{ pattern: /instagram\.com\/p\/([0-9a-zA-Z_-]
|
|
105
|
-
{ pattern: /doubao\.com\/video\/(\d
|
|
79
|
+
{ pattern: /b23\.tv\/([0-9a-zA-Z]{5,})/gi, type: 'bilibili', buildUrl: (id) => `https://b23.tv/${id}` },
|
|
80
|
+
{ pattern: /bili(?:22|23|33)\.cn\/([0-9a-zA-Z]{5,})/gi, type: 'bilibili', buildUrl: (id) => `https://bili23.cn/${id}` },
|
|
81
|
+
{ pattern: /bili2233\.cn\/([0-9a-zA-Z]{5,})/gi, type: 'bilibili', buildUrl: (id) => `https://bili2233.cn/${id}` },
|
|
82
|
+
{ pattern: /douyin\.com\/video\/(\d{10,})/gi, type: 'douyin', buildUrl: (id) => `https://www.douyin.com/video/${id}` },
|
|
83
|
+
{ pattern: /v\.douyin\.com\/([0-9a-zA-Z]{8,})/gi, type: 'douyin', buildUrl: (id) => `https://v.douyin.com/${id}/` },
|
|
84
|
+
{ pattern: /kuaishou\.com\/short-video\/([0-9a-zA-Z]{10,})/gi, type: 'kuaishou', buildUrl: (id) => `https://www.kuaishou.com/short-video/${id}` },
|
|
85
|
+
{ pattern: /v\.kuaishou\.com\/([0-9a-zA-Z]{8,})/gi, type: 'kuaishou', buildUrl: (id) => `https://v.kuaishou.com/${id}` },
|
|
86
|
+
{ pattern: /xiaohongshu\.com\/discovery\/item\/([0-9a-zA-Z]{10,})/gi, type: 'xiaohongshu', buildUrl: (id) => `https://www.xiaohongshu.com/discovery/item/${id}` },
|
|
87
|
+
{ pattern: /xhslink\.com\/([0-9a-zA-Z]{8,})/gi, type: 'xiaohongshu', buildUrl: (id) => `https://xhslink.com/${id}` },
|
|
88
|
+
{ pattern: /weibo\.com\/\d+\/([0-9a-zA-Z]{10,})/gi, type: 'weibo', buildUrl: (id) => `https://weibo.com/${id}` },
|
|
89
|
+
{ pattern: /video\.weibo\.com\/show\?fid=([0-9a-zA-Z]{10,})/gi, type: 'weibo', buildUrl: (id) => `https://video.weibo.com/show?fid=${id}` },
|
|
90
|
+
{ pattern: /ixigua\.com\/(\d{10,})/gi, type: 'xigua', buildUrl: (id) => `https://www.ixigua.com/${id}` },
|
|
91
|
+
{ pattern: /youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/gi, type: 'youtube', buildUrl: (id) => `https://www.youtube.com/watch?v=${id}` },
|
|
92
|
+
{ pattern: /youtu\.be\/([a-zA-Z0-9_-]{11})/gi, type: 'youtube', buildUrl: (id) => `https://youtu.be/${id}` },
|
|
93
|
+
{ pattern: /tiktok\.com\/@[\w.]+\/video\/(\d{10,})/gi, type: 'tiktok', buildUrl: (id) => `https://www.tiktok.com/@user/video/${id}` },
|
|
94
|
+
{ pattern: /vm\.tiktok\.com\/([0-9a-zA-Z]{8,})/gi, type: 'tiktok', buildUrl: (id) => `https://vm.tiktok.com/${id}` },
|
|
95
|
+
{ pattern: /acfun\.cn\/v\/(ac\d{10,})/gi, type: 'acfun', buildUrl: (id) => `https://www.acfun.cn/v/${id}` },
|
|
96
|
+
{ pattern: /zhihu\.com\/video\/(\d{10,})/gi, type: 'zhihu', buildUrl: (id) => `https://www.zhihu.com/video/${id}` },
|
|
97
|
+
{ pattern: /weishi\.qq\.com\/weishi\/feed\/([0-9a-zA-Z]{10,})/gi, type: 'weishi', buildUrl: (id) => `https://weishi.qq.com/weishi/feed/${id}` },
|
|
98
|
+
{ pattern: /huya\.com\/video\/([0-9a-zA-Z]{10,})/gi, type: 'huya', buildUrl: (id) => `https://www.huya.com/video/${id}` },
|
|
99
|
+
{ pattern: /haokan\.baidu\.com\/v\?vid=([0-9a-zA-Z]{10,})/gi, type: 'haokan', buildUrl: (id) => `https://haokan.baidu.com/v?vid=${id}` },
|
|
100
|
+
{ pattern: /meipai\.com\/media\/(\d{10,})/gi, type: 'meipai', buildUrl: (id) => `https://www.meipai.com/media/${id}` },
|
|
101
|
+
{ pattern: /twitter\.com\/\w+\/status\/(\d{10,})/gi, type: 'twitter', buildUrl: (id) => `https://twitter.com/i/status/${id}` },
|
|
102
|
+
{ pattern: /x\.com\/\w+\/status\/(\d{10,})/gi, type: 'twitter', buildUrl: (id) => `https://x.com/i/status/${id}` },
|
|
103
|
+
{ pattern: /instagram\.com\/p\/([0-9a-zA-Z_-]{10,})/gi, type: 'instagram', buildUrl: (id) => `https://www.instagram.com/p/${id}` },
|
|
104
|
+
{ pattern: /doubao\.com\/video\/(\d{10,})/gi, type: 'doubao', buildUrl: (id) => `https://www.doubao.com/video/${id}` },
|
|
106
105
|
];
|
|
107
106
|
const matches = [];
|
|
108
107
|
const seen = new Set();
|
|
@@ -133,6 +132,10 @@ function extractUrl(content) {
|
|
|
133
132
|
hostname.includes('qlogo.cn')) {
|
|
134
133
|
return false;
|
|
135
134
|
}
|
|
135
|
+
if (hostname === 'v.douyin.com' && urlObj.pathname.length < 3)
|
|
136
|
+
return false;
|
|
137
|
+
if (hostname === 'www.douyin.com' && urlObj.pathname === '/')
|
|
138
|
+
return false;
|
|
136
139
|
return true;
|
|
137
140
|
}
|
|
138
141
|
catch {
|
|
@@ -194,7 +197,19 @@ function extractAllUrlsFromMessage(session) {
|
|
|
194
197
|
}
|
|
195
198
|
}
|
|
196
199
|
}
|
|
197
|
-
return [...new Set(urls)]
|
|
200
|
+
return [...new Set(urls)].filter(url => {
|
|
201
|
+
try {
|
|
202
|
+
const urlObj = new URL(url);
|
|
203
|
+
if (urlObj.hostname === 'v.douyin.com' && urlObj.pathname.length < 3)
|
|
204
|
+
return false;
|
|
205
|
+
if (urlObj.hostname === 'www.douyin.com' && urlObj.pathname === '/')
|
|
206
|
+
return false;
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
198
213
|
}
|
|
199
214
|
function cleanUrl(url) {
|
|
200
215
|
try {
|
|
@@ -459,7 +474,7 @@ async function downloadVideoFile(videoUrl, tempDir, timeout, maxSizeMB) {
|
|
|
459
474
|
timeout: timeout,
|
|
460
475
|
headers: {
|
|
461
476
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
462
|
-
'Referer': 'https://www.
|
|
477
|
+
'Referer': 'https://www.bilibili.com/',
|
|
463
478
|
},
|
|
464
479
|
validateStatus: (status) => status >= 200 && status < 300,
|
|
465
480
|
});
|
|
@@ -501,45 +516,6 @@ function getErrorMessage(error) {
|
|
|
501
516
|
return error.message;
|
|
502
517
|
return String(error);
|
|
503
518
|
}
|
|
504
|
-
function isSpecialPlatformVideo(url) {
|
|
505
|
-
const specialHosts = [
|
|
506
|
-
'bilibili.com',
|
|
507
|
-
'akamaized.net',
|
|
508
|
-
'hdslb.com',
|
|
509
|
-
'xiaohongshu.com',
|
|
510
|
-
'xhslink.com',
|
|
511
|
-
'zhihu.com',
|
|
512
|
-
'weibo.com',
|
|
513
|
-
'sinaimg.cn',
|
|
514
|
-
'ixigua.com',
|
|
515
|
-
'toutiao.com',
|
|
516
|
-
];
|
|
517
|
-
return specialHosts.some(host => url.includes(host));
|
|
518
|
-
}
|
|
519
|
-
async function getShortUrl(url) {
|
|
520
|
-
if (!url)
|
|
521
|
-
return '';
|
|
522
|
-
try {
|
|
523
|
-
const urlObj = new URL(url);
|
|
524
|
-
if (urlObj.hostname.includes('bilibili.com')) {
|
|
525
|
-
const bvMatch = url.match(/\/video\/(bv[0-9a-zA-Z]+)/i);
|
|
526
|
-
if (bvMatch)
|
|
527
|
-
return `https://b23.tv/${bvMatch[1]}`;
|
|
528
|
-
}
|
|
529
|
-
if (urlObj.hostname.includes('douyin.com')) {
|
|
530
|
-
const idMatch = url.match(/\/video\/(\d+)/);
|
|
531
|
-
if (idMatch)
|
|
532
|
-
return `https://v.douyin.com/${idMatch[1].substring(0, 8)}/`;
|
|
533
|
-
}
|
|
534
|
-
if (urlObj.hostname.includes('xiaohongshu.com')) {
|
|
535
|
-
const idMatch = url.match(/\/item\/([0-9a-zA-Z]+)/);
|
|
536
|
-
if (idMatch)
|
|
537
|
-
return `https://xhslink.com/${idMatch[1].substring(0, 8)}`;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
catch { }
|
|
541
|
-
return url;
|
|
542
|
-
}
|
|
543
519
|
function apply(ctx, config) {
|
|
544
520
|
debugEnabled = config.debug || false;
|
|
545
521
|
debugLog('INFO', '插件初始化开始');
|
|
@@ -617,13 +593,11 @@ function apply(ctx, config) {
|
|
|
617
593
|
return { success: false, msg: result.msg, url };
|
|
618
594
|
}
|
|
619
595
|
const text = generateFormattedText(result.data, config.unifiedMessageFormat);
|
|
620
|
-
const shortUrl = await getShortUrl(result.data.video);
|
|
621
596
|
return {
|
|
622
597
|
success: true,
|
|
623
598
|
data: {
|
|
624
599
|
text,
|
|
625
|
-
parsed: result.data
|
|
626
|
-
shortUrl
|
|
600
|
+
parsed: result.data
|
|
627
601
|
}
|
|
628
602
|
};
|
|
629
603
|
}
|
|
@@ -665,41 +639,52 @@ function apply(ctx, config) {
|
|
|
665
639
|
}
|
|
666
640
|
return null;
|
|
667
641
|
}
|
|
668
|
-
async function sendVideoFile(session, videoUrl
|
|
642
|
+
async function sendVideoFile(session, videoUrl) {
|
|
669
643
|
if (!videoUrl)
|
|
670
644
|
throw new Error('视频链接为空');
|
|
671
|
-
if (config.videoLoadWaitTime > 0) {
|
|
672
|
-
await delay(config.videoLoadWaitTime);
|
|
673
|
-
}
|
|
674
|
-
if (shortUrl) {
|
|
675
|
-
await sendWithTimeout(session, `视频链接:${shortUrl}`).catch(() => { });
|
|
676
|
-
}
|
|
677
645
|
if (!config.showVideoFile) {
|
|
678
|
-
return
|
|
646
|
+
return await sendWithTimeout(session, `视频链接:${videoUrl}`);
|
|
679
647
|
}
|
|
680
|
-
const
|
|
681
|
-
|
|
648
|
+
const sendLinkAsFallback = async () => {
|
|
649
|
+
await sendWithTimeout(session, `视频链接:${videoUrl}`).catch(() => { });
|
|
650
|
+
};
|
|
651
|
+
const tryDownloadAndSend = async () => {
|
|
652
|
+
let tempFilePath = null;
|
|
682
653
|
try {
|
|
683
|
-
|
|
684
|
-
|
|
654
|
+
tempFilePath = await downloadVideoFile(videoUrl, config.tempDir || './temp_videos', config.videoDownloadTimeout || 120000, config.maxVideoSize || 0);
|
|
655
|
+
const localFile = `file://${tempFilePath}`;
|
|
656
|
+
debugLog('INFO', `发送本地视频文件: ${localFile}`);
|
|
657
|
+
return await sendWithTimeout(session, koishi_1.h.video(localFile));
|
|
658
|
+
}
|
|
659
|
+
finally {
|
|
660
|
+
if (tempFilePath) {
|
|
661
|
+
promises_1.default.unlink(tempFilePath).catch(e => debugLog('WARN', `删除临时文件失败: ${e}`));
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
if (config.forceDownloadVideo) {
|
|
666
|
+
try {
|
|
667
|
+
return await tryDownloadAndSend();
|
|
685
668
|
}
|
|
686
669
|
catch (err) {
|
|
687
|
-
debugLog('ERROR',
|
|
670
|
+
debugLog('ERROR', `下载并发送视频失败: ${getErrorMessage(err)}`);
|
|
671
|
+
await sendLinkAsFallback();
|
|
688
672
|
}
|
|
689
673
|
}
|
|
690
674
|
else {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
675
|
+
try {
|
|
676
|
+
debugLog('INFO', `尝试直接发送视频URL: ${videoUrl.substring(0, 100)}...`);
|
|
677
|
+
return await sendWithTimeout(session, koishi_1.h.video(videoUrl));
|
|
678
|
+
}
|
|
679
|
+
catch (err) {
|
|
680
|
+
debugLog('ERROR', `直接发送URL失败,尝试下载: ${getErrorMessage(err)}`);
|
|
681
|
+
try {
|
|
682
|
+
return await tryDownloadAndSend();
|
|
683
|
+
}
|
|
684
|
+
catch (downloadErr) {
|
|
685
|
+
debugLog('ERROR', `下载并发送视频也失败: ${getErrorMessage(downloadErr)}`);
|
|
686
|
+
await sendLinkAsFallback();
|
|
687
|
+
}
|
|
703
688
|
}
|
|
704
689
|
}
|
|
705
690
|
}
|
|
@@ -708,25 +693,21 @@ function apply(ctx, config) {
|
|
|
708
693
|
debugLog('INFO', `开始解析 ${uniqueUrls.length} 个链接`);
|
|
709
694
|
const items = [];
|
|
710
695
|
const errors = [];
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
.replace(/\$\{url\}/g, url.length > 50 ? url.slice(0, 50) + '...' : url)
|
|
727
|
-
.replace(/\$\{msg\}/g, res.msg);
|
|
728
|
-
errors.push(item);
|
|
729
|
-
}
|
|
696
|
+
for (let i = 0; i < uniqueUrls.length; i++) {
|
|
697
|
+
const url = uniqueUrls[i];
|
|
698
|
+
debugLog('INFO', `正在解析第 ${i + 1}/${uniqueUrls.length} 个链接: ${url}`);
|
|
699
|
+
const result = await processSingleUrl(url);
|
|
700
|
+
if (result.success) {
|
|
701
|
+
items.push(result.data);
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
const item = texts.parseErrorItemFormat
|
|
705
|
+
.replace(/\$\{url\}/g, url.length > 50 ? url.slice(0, 50) + '...' : url)
|
|
706
|
+
.replace(/\$\{msg\}/g, result.msg);
|
|
707
|
+
errors.push(item);
|
|
708
|
+
}
|
|
709
|
+
if (i < uniqueUrls.length - 1) {
|
|
710
|
+
await delay(500);
|
|
730
711
|
}
|
|
731
712
|
}
|
|
732
713
|
if (errors.length) {
|
|
@@ -745,7 +726,6 @@ function apply(ctx, config) {
|
|
|
745
726
|
for (const item of items) {
|
|
746
727
|
const p = item.parsed;
|
|
747
728
|
const text = item.text;
|
|
748
|
-
const shortUrl = item.shortUrl;
|
|
749
729
|
if (text && config.showImageText) {
|
|
750
730
|
forwardMessages.push(buildForwardNode(session, text, botName));
|
|
751
731
|
}
|
|
@@ -758,10 +738,10 @@ function apply(ctx, config) {
|
|
|
758
738
|
forwardMessages.push(buildForwardNode(session, koishi_1.h.image(imgUrl), botName));
|
|
759
739
|
}
|
|
760
740
|
}
|
|
761
|
-
if (p.video
|
|
762
|
-
|
|
763
|
-
if (
|
|
764
|
-
|
|
741
|
+
if (p.video) {
|
|
742
|
+
forwardMessages.push(buildForwardNode(session, `视频链接:${p.video}`, botName));
|
|
743
|
+
if (config.showVideoFile && (p.type === 'video' || (p.type === 'live' && !p.live_photo?.length && !p.images?.length))) {
|
|
744
|
+
videoItems.push(p);
|
|
765
745
|
}
|
|
766
746
|
}
|
|
767
747
|
}
|
|
@@ -779,9 +759,9 @@ function apply(ctx, config) {
|
|
|
779
759
|
}
|
|
780
760
|
}
|
|
781
761
|
}
|
|
782
|
-
for (const
|
|
762
|
+
for (const p of videoItems) {
|
|
783
763
|
try {
|
|
784
|
-
await sendVideoFile(session,
|
|
764
|
+
await sendVideoFile(session, p.video);
|
|
785
765
|
}
|
|
786
766
|
catch (err) {
|
|
787
767
|
debugLog('ERROR', `视频发送失败: ${getErrorMessage(err)}`);
|
|
@@ -793,7 +773,6 @@ function apply(ctx, config) {
|
|
|
793
773
|
for (const item of items) {
|
|
794
774
|
const p = item.parsed;
|
|
795
775
|
const text = item.text;
|
|
796
|
-
const shortUrl = item.shortUrl;
|
|
797
776
|
if (text && config.showImageText) {
|
|
798
777
|
await sendWithTimeout(session, text);
|
|
799
778
|
await delay(300);
|
|
@@ -803,11 +782,16 @@ function apply(ctx, config) {
|
|
|
803
782
|
await delay(300);
|
|
804
783
|
}
|
|
805
784
|
if (p.video && (p.type === 'video' || (p.type === 'live' && !p.live_photo?.length && !p.images?.length))) {
|
|
806
|
-
|
|
807
|
-
|
|
785
|
+
if (config.showVideoFile) {
|
|
786
|
+
try {
|
|
787
|
+
await sendVideoFile(session, p.video);
|
|
788
|
+
}
|
|
789
|
+
catch (err) {
|
|
790
|
+
debugLog('ERROR', `视频发送失败: ${getErrorMessage(err)}`);
|
|
791
|
+
}
|
|
808
792
|
}
|
|
809
|
-
|
|
810
|
-
|
|
793
|
+
else {
|
|
794
|
+
await sendWithTimeout(session, `视频链接:${p.video}`);
|
|
811
795
|
}
|
|
812
796
|
await delay(500);
|
|
813
797
|
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
- 📤 支持OneBot平台消息合并转发,优化多图文展示体验
|
|
12
12
|
- 💬 所有提示文案均可自定义,适配多语言场景
|
|
13
13
|
- 🔁 消息发送支持自动重试,与API重试配置联动,增强稳定性
|
|
14
|
-
- 🚀 内置LRU
|
|
15
|
-
- ⚡
|
|
14
|
+
- 🚀 内置LRU内存缓存,避免短时间内重复解析同一链接;串行解析防止API限流
|
|
15
|
+
- ⚡ 智能视频发送策略:优先直接发送URL,失败自动降级为本地文件发送
|
|
16
16
|
- 🛡️ 可选视频大小限制,防止超大文件占满服务器磁盘;自动清理所有临时文件
|
|
17
17
|
|
|
18
18
|
### English
|
|
@@ -24,8 +24,8 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
|
|
|
24
24
|
- 📤 Support OneBot message forwarding for better image/video display
|
|
25
25
|
- 💬 All prompt texts are customizable for multilingual scenarios
|
|
26
26
|
- 🔁 Message sending supports automatic retries, linked with API retry configuration for improved stability
|
|
27
|
-
- 🚀 Built-in LRU memory cache to avoid repeated parsing of the same URL;
|
|
28
|
-
- ⚡ Smart video sending strategy: priority to send URL directly
|
|
27
|
+
- 🚀 Built-in LRU memory cache to avoid repeated parsing of the same URL; serial parsing to prevent API rate limiting
|
|
28
|
+
- ⚡ Smart video sending strategy: priority to send URL directly, auto downgrade to local file on failure
|
|
29
29
|
- 🛡️ Optional video size limit to prevent oversized files from filling up server disk; automatic cleanup of all temporary files
|
|
30
30
|
|
|
31
31
|
## 项目仓库 (Repository)
|
|
@@ -62,7 +62,7 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
|
|
|
62
62
|
| `videoDownloadTimeout` | number | 120000 | 视频下载超时(毫秒) |
|
|
63
63
|
| `tempDir` | string | `./temp_videos` | 临时视频存储目录 |
|
|
64
64
|
| `maxVideoSize` | number | 0 | 最大下载视频大小(MB),0 为不限制大小 |
|
|
65
|
-
| `forceDownloadVideo` | boolean |
|
|
65
|
+
| `forceDownloadVideo` | boolean | false | 强制下载视频后发送 |
|
|
66
66
|
| `videoLoadWaitTime` | number | 180000 | 视频链接加载等待时间(毫秒),获取到视频链接后等待指定时间再发送,0为不等待 |
|
|
67
67
|
|
|
68
68
|
### 网络与 API 设置
|