koishi-plugin-video-parser-all 0.5.9 → 0.6.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.js +86 -308
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -22,7 +22,7 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
22
22
|
sameLinkInterval: koishi_1.Schema.number().min(0).default(180).description('相同链接重复解析间隔(秒)'),
|
|
23
23
|
}).description('基础设置'),
|
|
24
24
|
koishi_1.Schema.object({
|
|
25
|
-
unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n时长:${视频时长}\n点赞:${点赞数}\n投币:${投币数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}\n音乐:${音乐名}').description('统一消息格式(无法获取的变量会自动隐藏)\n变量介绍:\n${标题} - 内容标题\n${作者} - 作者名称\n${简介} - 内容简介\n${视频时长} - 视频时长\n${点赞数} - 点赞数量\n${投币数} -
|
|
25
|
+
unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n时长:${视频时长}\n点赞:${点赞数}\n投币:${投币数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}\n音乐:${音乐名}').description('统一消息格式(无法获取的变量会自动隐藏)\n变量介绍:\n${标题} - 内容标题\n${作者} - 作者名称\n${简介} - 内容简介\n${视频时长} - 视频时长\n${点赞数} - 点赞数量\n${投币数} - 投币数(仅B站)\n收藏数 - 收藏数量\n${转发数} - 转发/分享数量\n${播放数} - 播放数量\n${评论数} - 评论数量\n${音乐名} - 背景音乐名称'),
|
|
26
26
|
}).description('统一消息格式'),
|
|
27
27
|
koishi_1.Schema.object({
|
|
28
28
|
showImageText: koishi_1.Schema.boolean().default(true).description('显示图文内容'),
|
|
@@ -394,73 +394,53 @@ function parseData(rawResponse, maxDescLength) {
|
|
|
394
394
|
const stat = {};
|
|
395
395
|
Object.entries(VARIABLE_MAPPING).forEach(([varName, keys]) => {
|
|
396
396
|
const value = findValueInObject(data, keys) || findValueInObject(rootData, keys);
|
|
397
|
-
|
|
398
|
-
stat[varName] = value;
|
|
397
|
+
stat[varName] = value ?? '';
|
|
399
398
|
});
|
|
400
399
|
let type = 'video';
|
|
401
400
|
if (data.jx?.type)
|
|
402
401
|
type = data.jx.type;
|
|
403
402
|
else if (data.type)
|
|
404
403
|
type = data.type;
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
const title = findValueInObject(data, VARIABLE_MAPPING['标题']) || findValueInObject(rootData, VARIABLE_MAPPING['标题']) || '无标题';
|
|
410
|
-
const author = findValueInObject(data, VARIABLE_MAPPING['作者']) || findValueInObject(rootData, VARIABLE_MAPPING['作者']) || '未知作者';
|
|
411
|
-
let desc = findValueInObject(data, VARIABLE_MAPPING['简介']) || findValueInObject(rootData, VARIABLE_MAPPING['简介']) || title;
|
|
412
|
-
desc = desc.toString().slice(0, maxDescLength);
|
|
413
|
-
const cover = findValueInObject(data, ['cover', 'imgurl', 'pic', 'thumbnail', 'cover_url']) || findValueInObject(rootData, ['cover', 'imgurl', 'pic', 'thumbnail', 'cover_url']) || '';
|
|
404
|
+
const title = stat['标题'] || '无标题';
|
|
405
|
+
const author = stat['作者'] || '未知作者';
|
|
406
|
+
const desc = (stat['简介'] || title).slice(0, maxDescLength);
|
|
407
|
+
const cover = data.cover ?? data.imgurl ?? data.pic ?? data.thumbnail ?? data.cover_url ?? '';
|
|
414
408
|
let images = [];
|
|
415
|
-
const
|
|
416
|
-
if (Array.isArray(
|
|
417
|
-
images =
|
|
418
|
-
else if (
|
|
419
|
-
images = [
|
|
420
|
-
let video = '';
|
|
421
|
-
const
|
|
422
|
-
findValueInObject(data, ['url', 'video_url', 'download_url', 'playUrl', 'mp4_url']),
|
|
423
|
-
findValueInObject(rootData, ['url', 'video_url', 'download_url', 'playUrl', 'mp4_url']),
|
|
424
|
-
data.video?.url,
|
|
425
|
-
data.item?.url,
|
|
426
|
-
rootData.video?.url,
|
|
427
|
-
rootData.item?.url
|
|
428
|
-
];
|
|
429
|
-
for (const url of videoUrls) {
|
|
430
|
-
if (url && typeof url === 'string' && url.startsWith('http')) {
|
|
431
|
-
video = url;
|
|
432
|
-
break;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
const durationValue = findValueInObject(data, VARIABLE_MAPPING['视频时长']) || findValueInObject(rootData, VARIABLE_MAPPING['视频时长']);
|
|
409
|
+
const imgRaw = data.images ?? data.pics ?? data.pic_urls ?? data.image_list ?? [];
|
|
410
|
+
if (Array.isArray(imgRaw))
|
|
411
|
+
images = imgRaw.filter(i => i && typeof i === 'string');
|
|
412
|
+
else if (imgRaw)
|
|
413
|
+
images = [String(imgRaw)];
|
|
414
|
+
let video = data.video?.url ?? data.item?.url ?? data.url ?? data.download_url ?? data.playUrl ?? data.video_url ?? '';
|
|
415
|
+
const durationValue = stat['视频时长'] || 0;
|
|
436
416
|
const duration = typeof durationValue === 'number' ? durationValue : parseInt(durationValue) || 0;
|
|
437
|
-
const durationFormatted = formatDuration(durationValue
|
|
438
|
-
const live_photo = data.live_photo
|
|
439
|
-
const music =
|
|
440
|
-
const h_w = data.item?.h_w
|
|
441
|
-
const quality_urls = data.quality_urls
|
|
442
|
-
const default_quality = data.default_quality
|
|
443
|
-
const download_url = data.download_url
|
|
444
|
-
const play_count = stat['播放数']
|
|
445
|
-
const reposts_count = stat['转发数'] || 0;
|
|
446
|
-
const attitudes_count = stat['点赞数'] || 0;
|
|
447
|
-
const comments_count = stat['评论数'] || 0;
|
|
417
|
+
const durationFormatted = formatDuration(durationValue);
|
|
418
|
+
const live_photo = data.live_photo ?? [];
|
|
419
|
+
const music = stat['音乐名'] || '';
|
|
420
|
+
const h_w = data.item?.h_w ?? [];
|
|
421
|
+
const quality_urls = data.quality_urls ?? {};
|
|
422
|
+
const default_quality = data.default_quality ?? '';
|
|
423
|
+
const download_url = data.download_url ?? video;
|
|
424
|
+
const play_count = stat['播放数'] ?? '';
|
|
425
|
+
const reposts_count = Number(stat['转发数']) || 0;
|
|
426
|
+
const attitudes_count = Number(stat['点赞数']) || 0;
|
|
427
|
+
const comments_count = Number(stat['评论数']) || 0;
|
|
448
428
|
return {
|
|
449
429
|
type: type,
|
|
450
430
|
rawData: rawResponse,
|
|
451
|
-
title,
|
|
452
|
-
author,
|
|
453
|
-
desc,
|
|
454
|
-
cover,
|
|
431
|
+
title: String(title),
|
|
432
|
+
author: String(author),
|
|
433
|
+
desc: String(desc),
|
|
434
|
+
cover: String(cover),
|
|
455
435
|
images,
|
|
456
|
-
video,
|
|
436
|
+
video: String(video),
|
|
457
437
|
duration,
|
|
458
438
|
durationFormatted,
|
|
459
439
|
stat,
|
|
460
440
|
live_photo,
|
|
461
|
-
music,
|
|
441
|
+
music: String(music),
|
|
462
442
|
h_w,
|
|
463
|
-
jx: data.jx
|
|
443
|
+
jx: data.jx ?? null,
|
|
464
444
|
quality_urls,
|
|
465
445
|
default_quality,
|
|
466
446
|
download_url,
|
|
@@ -471,40 +451,16 @@ function parseData(rawResponse, maxDescLength) {
|
|
|
471
451
|
};
|
|
472
452
|
}
|
|
473
453
|
function generateFormattedText(parseData, config) {
|
|
474
|
-
let format = config.unifiedMessageFormat;
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
let isValid = true;
|
|
483
|
-
let processedLine = line;
|
|
484
|
-
const varMatches = line.match(/\$\{([^}]+)\}/g) || [];
|
|
485
|
-
if (varMatches.length === 0) {
|
|
486
|
-
validLines.push(line);
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
varMatches.forEach((varMatch) => {
|
|
490
|
-
const varName = varMatch.replace(/\$\{|\}/g, '');
|
|
491
|
-
const value = parseData.stat[varName];
|
|
492
|
-
if (value === undefined || value === null || value === '' || value === 0 || value === '00:00') {
|
|
493
|
-
isValid = false;
|
|
494
|
-
}
|
|
495
|
-
else {
|
|
496
|
-
processedLine = processedLine.replace(varMatch, String(value));
|
|
497
|
-
}
|
|
498
|
-
});
|
|
499
|
-
if (isValid && processedLine.trim() !== '') {
|
|
500
|
-
validLines.push(processedLine);
|
|
501
|
-
}
|
|
454
|
+
let format = config.unifiedMessageFormat || '标题:${标题}\n作者:${作者}\n简介:${简介}';
|
|
455
|
+
let result = format;
|
|
456
|
+
const varMatches = result.match(/\$\{([^}]+)\}/g) || [];
|
|
457
|
+
varMatches.forEach((varMatch) => {
|
|
458
|
+
const varName = varMatch.replace(/\$\{|\}/g, '');
|
|
459
|
+
const value = parseData.stat[varName];
|
|
460
|
+
const showValue = value ?? '';
|
|
461
|
+
result = result.replace(varMatch, String(showValue));
|
|
502
462
|
});
|
|
503
|
-
|
|
504
|
-
if (!result) {
|
|
505
|
-
result = `标题:${parseData.title}\n作者:${parseData.author}\n简介:${parseData.desc}`;
|
|
506
|
-
}
|
|
507
|
-
return result;
|
|
463
|
+
return result.trim() || `标题:${parseData.title}\n作者:${parseData.author}\n简介:${parseData.desc}`;
|
|
508
464
|
}
|
|
509
465
|
function clearAllCache() {
|
|
510
466
|
processed.clear();
|
|
@@ -611,17 +567,6 @@ function apply(ctx, config) {
|
|
|
611
567
|
}
|
|
612
568
|
try {
|
|
613
569
|
const parseResult = parseData(resData, config.maxDescLength);
|
|
614
|
-
const hasValidContent = parseResult.video ||
|
|
615
|
-
(parseResult.images && parseResult.images.length > 0) ||
|
|
616
|
-
(parseResult.live_photo && parseResult.live_photo.length > 0) ||
|
|
617
|
-
parseResult.type === 'live' ||
|
|
618
|
-
parseResult.type === '图集';
|
|
619
|
-
if (!hasValidContent) {
|
|
620
|
-
const code = ErrorCode.NO_VIDEO_FOUND;
|
|
621
|
-
const msg = getErrorInfo(code, '链接有效但未获取到有效视频/图片内容,可能是私密/需要登录/已删除内容');
|
|
622
|
-
logger.warn(`[${code}] 解析成功但无有效内容: ${url}`);
|
|
623
|
-
return { data: null, code, msg };
|
|
624
|
-
}
|
|
625
570
|
logger.info(`[${ErrorCode.SUCCESS}] 解析成功: ${url}`);
|
|
626
571
|
return {
|
|
627
572
|
data: parseResult,
|
|
@@ -724,20 +669,17 @@ function apply(ctx, config) {
|
|
|
724
669
|
items.push(result.data);
|
|
725
670
|
}
|
|
726
671
|
else {
|
|
727
|
-
errors.push({ url,
|
|
728
|
-
logger.error(`[${result.code}] 解析失败: ${url}, 原因: ${result.msg}`);
|
|
672
|
+
errors.push({ url, msg: result.msg });
|
|
729
673
|
}
|
|
730
674
|
}
|
|
731
675
|
if (errors.length > 0) {
|
|
732
676
|
const errorLines = errors.map(err => `【${err.url.slice(0, 50)}${err.url.length > 50 ? '...' : ''}】: ${err.msg}`);
|
|
733
|
-
const errorMsg = `❌
|
|
734
|
-
logger.error(`解析失败数量: ${errors.length}, 错误码列表: ${errors.map(e => e.code).join(', ')}`);
|
|
677
|
+
const errorMsg = `❌ 解析失败:\n${errorLines.join('\n')}`;
|
|
735
678
|
await sendTimeout(session, errorMsg);
|
|
736
679
|
await delay(500);
|
|
737
680
|
}
|
|
738
681
|
if (items.length === 0) {
|
|
739
|
-
|
|
740
|
-
await sendTimeout(session, `⚠ ${failMsg}`);
|
|
682
|
+
await sendTimeout(session, '⚠ 未解析到有效内容');
|
|
741
683
|
return;
|
|
742
684
|
}
|
|
743
685
|
const enableForward = config.enableForward && session.platform === 'onebot';
|
|
@@ -748,72 +690,31 @@ function apply(ctx, config) {
|
|
|
748
690
|
if (enableForward) {
|
|
749
691
|
if (item.text)
|
|
750
692
|
forwardMessages.push(buildForwardNode(session, item.text, botName));
|
|
751
|
-
if (item.cover
|
|
693
|
+
if (item.cover)
|
|
752
694
|
forwardMessages.push(buildForwardNode(session, koishi_1.h.image(item.cover), botName));
|
|
753
|
-
if (item.type === '图集' && item.images?.length) {
|
|
754
|
-
for (
|
|
755
|
-
forwardMessages.push(buildForwardNode(session, koishi_1.h.image(
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
if (item.type === 'image' && item.images?.length) {
|
|
759
|
-
for (let i = 0; i < item.images.length && forwardMessages.length < 100; i++) {
|
|
760
|
-
forwardMessages.push(buildForwardNode(session, koishi_1.h.image(item.images[i]), botName));
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
if (item.type === 'live' || item.type === 'live_photo') {
|
|
764
|
-
if (item.live_photo?.length) {
|
|
765
|
-
for (let i = 0; i < item.live_photo.length && forwardMessages.length < 100; i++) {
|
|
766
|
-
const liveItem = item.live_photo[i];
|
|
767
|
-
forwardMessages.push(buildForwardNode(session, koishi_1.h.image(liveItem.image), botName));
|
|
768
|
-
if (liveItem.video) {
|
|
769
|
-
try {
|
|
770
|
-
const videoElem = koishi_1.h.video(liveItem.video);
|
|
771
|
-
forwardMessages.push(buildForwardNode(session, videoElem, botName));
|
|
772
|
-
}
|
|
773
|
-
catch (e) {
|
|
774
|
-
forwardMessages.push(buildForwardNode(session, koishi_1.h.text(`视频链接: ${liveItem.video}`), botName));
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
else if (item.images?.length) {
|
|
780
|
-
for (let i = 0; i < item.images.length && forwardMessages.length < 100; i++) {
|
|
781
|
-
forwardMessages.push(buildForwardNode(session, koishi_1.h.image(item.images[i]), botName));
|
|
782
|
-
}
|
|
695
|
+
if ((item.type === '图集' || item.type === 'image') && item.images?.length) {
|
|
696
|
+
for (const img of item.images) {
|
|
697
|
+
forwardMessages.push(buildForwardNode(session, koishi_1.h.image(img), botName));
|
|
783
698
|
}
|
|
784
699
|
}
|
|
785
|
-
if (item.video && config.showVideoFile
|
|
786
|
-
let videoElem;
|
|
700
|
+
if (item.video && config.showVideoFile) {
|
|
787
701
|
try {
|
|
788
702
|
if (config.downloadVideoBeforeSend) {
|
|
789
703
|
const filename = crypto_1.default.createHash('md5').update(item.video).digest('hex');
|
|
790
|
-
const
|
|
791
|
-
if (
|
|
792
|
-
|
|
793
|
-
forwardMessages.push(buildForwardNode(session, koishi_1.h.text(`${errorMsg}\n链接:${item.video}`), botName));
|
|
704
|
+
const dl = await downloadVideo(item.video, filename, config.userAgent, config.maxVideoSize, config.downloadThreads);
|
|
705
|
+
if (dl.code === ErrorCode.SUCCESS) {
|
|
706
|
+
forwardMessages.push(buildForwardNode(session, koishi_1.h.file(dl.filePath), botName));
|
|
794
707
|
}
|
|
795
708
|
else {
|
|
796
|
-
|
|
797
|
-
forwardMessages.push(buildForwardNode(session, videoElem, botName));
|
|
709
|
+
forwardMessages.push(buildForwardNode(session, koishi_1.h.text(`视频:${item.video}`), botName));
|
|
798
710
|
}
|
|
799
711
|
}
|
|
800
712
|
else {
|
|
801
|
-
|
|
802
|
-
if (config.maxVideoSize > 0 && fileSize > config.maxVideoSize) {
|
|
803
|
-
const code = ErrorCode.VIDEO_SIZE_EXCEEDED;
|
|
804
|
-
const errorMsg = getErrorInfo(code, `${fileSize}MB超过限制${config.maxVideoSize}MB`);
|
|
805
|
-
videoElem = koishi_1.h.text(`${errorMsg},仅发送链接:${item.video}`);
|
|
806
|
-
}
|
|
807
|
-
else {
|
|
808
|
-
videoElem = koishi_1.h.video(item.video);
|
|
809
|
-
}
|
|
713
|
+
forwardMessages.push(buildForwardNode(session, koishi_1.h.video(item.video), botName));
|
|
810
714
|
}
|
|
811
715
|
}
|
|
812
|
-
catch (
|
|
813
|
-
|
|
814
|
-
const code = ErrorCode.VIDEO_DOWNLOAD_FAILED;
|
|
815
|
-
logger.error(`[${code}] 视频处理失败: ${errorMsg}`);
|
|
816
|
-
forwardMessages.push(buildForwardNode(session, koishi_1.h.text(getErrorInfo(code, errorMsg) + `\n链接:${item.video}`), botName));
|
|
716
|
+
catch (e) {
|
|
717
|
+
forwardMessages.push(buildForwardNode(session, koishi_1.h.text(`视频:${item.video}`), botName));
|
|
817
718
|
}
|
|
818
719
|
}
|
|
819
720
|
}
|
|
@@ -822,98 +723,37 @@ function apply(ctx, config) {
|
|
|
822
723
|
await sendTimeout(session, item.text);
|
|
823
724
|
await delay(300);
|
|
824
725
|
}
|
|
825
|
-
if (item.
|
|
826
|
-
|
|
827
|
-
await
|
|
726
|
+
if (item.cover) {
|
|
727
|
+
await sendTimeout(session, koishi_1.h.image(item.cover));
|
|
728
|
+
await delay(300);
|
|
828
729
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
await delay(200);
|
|
834
|
-
if (liveItem.video) {
|
|
835
|
-
try {
|
|
836
|
-
await sendTimeout(session, koishi_1.h.video(liveItem.video));
|
|
837
|
-
}
|
|
838
|
-
catch (e) {
|
|
839
|
-
await sendTimeout(session, koishi_1.h.text(`Live Photo 视频链接: ${liveItem.video}`));
|
|
840
|
-
}
|
|
841
|
-
await delay(300);
|
|
842
|
-
}
|
|
843
|
-
}
|
|
730
|
+
if ((item.type === '图集' || item.type === 'image') && item.images?.length) {
|
|
731
|
+
for (const img of item.images) {
|
|
732
|
+
await sendTimeout(session, koishi_1.h.image(img));
|
|
733
|
+
await delay(200);
|
|
844
734
|
}
|
|
845
|
-
else if (item.images?.length) {
|
|
846
|
-
const imgMsg = (0, koishi_1.h)('message', ...item.images.map((url) => koishi_1.h.image(url)));
|
|
847
|
-
await sendTimeout(session, imgMsg);
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
else if (item.type === 'image' && item.images?.length) {
|
|
851
|
-
const imgMsg = (0, koishi_1.h)('message', ...item.images.map((url) => koishi_1.h.image(url)));
|
|
852
|
-
await sendTimeout(session, imgMsg);
|
|
853
735
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
await sendTimeout(session, koishi_1.h.
|
|
857
|
-
await delay(300);
|
|
736
|
+
if (item.video && config.showVideoFile) {
|
|
737
|
+
try {
|
|
738
|
+
await sendTimeout(session, koishi_1.h.video(item.video));
|
|
858
739
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
let videoElem;
|
|
862
|
-
if (config.downloadVideoBeforeSend) {
|
|
863
|
-
const filename = crypto_1.default.createHash('md5').update(item.video).digest('hex');
|
|
864
|
-
const downloadResult = await downloadVideo(item.video, filename, config.userAgent, config.maxVideoSize, config.downloadThreads);
|
|
865
|
-
if (downloadResult.code !== ErrorCode.SUCCESS) {
|
|
866
|
-
await sendTimeout(session, koishi_1.h.text(`${getErrorInfo(downloadResult.code)}\n链接:${item.video}`));
|
|
867
|
-
continue;
|
|
868
|
-
}
|
|
869
|
-
else {
|
|
870
|
-
videoElem = koishi_1.h.file(downloadResult.filePath);
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
else {
|
|
874
|
-
const fileSize = await getFileSize(item.video, config.userAgent);
|
|
875
|
-
if (config.maxVideoSize > 0 && fileSize > config.maxVideoSize) {
|
|
876
|
-
const code = ErrorCode.VIDEO_SIZE_EXCEEDED;
|
|
877
|
-
const errorMsg = getErrorInfo(code, `${fileSize}MB超过限制${config.maxVideoSize}MB`);
|
|
878
|
-
videoElem = koishi_1.h.text(`${errorMsg},仅发送链接:${item.video}`);
|
|
879
|
-
}
|
|
880
|
-
else {
|
|
881
|
-
videoElem = koishi_1.h.video(item.video);
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
await sendTimeout(session, videoElem);
|
|
885
|
-
}
|
|
886
|
-
catch (error) {
|
|
887
|
-
const errorMsg = getErrorMessage(error);
|
|
888
|
-
const code = ErrorCode.VIDEO_DOWNLOAD_FAILED;
|
|
889
|
-
logger.error(`[${code}] 视频处理失败: ${errorMsg}`);
|
|
890
|
-
await sendTimeout(session, koishi_1.h.text(getErrorInfo(code, errorMsg) + `\n链接:${item.video}`));
|
|
891
|
-
}
|
|
740
|
+
catch (e) {
|
|
741
|
+
await sendTimeout(session, `视频:${item.video}`);
|
|
892
742
|
}
|
|
743
|
+
await delay(500);
|
|
893
744
|
}
|
|
894
|
-
await delay(1000);
|
|
895
745
|
}
|
|
896
746
|
}
|
|
897
|
-
catch (
|
|
898
|
-
const errorMsg = getErrorMessage(error);
|
|
899
|
-
const code = ErrorCode.UNKNOWN_ERROR;
|
|
900
|
-
logger.error(`[${code}] 处理内容失败: ${errorMsg}`);
|
|
901
|
-
await sendTimeout(session, koishi_1.h.text(getErrorInfo(code, `处理${item.type}内容失败: ${errorMsg}`)));
|
|
902
|
-
}
|
|
747
|
+
catch (e) { }
|
|
903
748
|
}
|
|
904
749
|
if (enableForward && forwardMessages.length) {
|
|
905
750
|
try {
|
|
906
|
-
|
|
907
|
-
const forwardMsg = (0, koishi_1.h)('message', { forward: true }, safeForwardMessages);
|
|
908
|
-
await sendTimeout(session, forwardMsg);
|
|
751
|
+
await sendTimeout(session, (0, koishi_1.h)('message', { forward: true }, forwardMessages.slice(0, 100)));
|
|
909
752
|
}
|
|
910
|
-
catch (
|
|
911
|
-
const errorMsg = getErrorMessage(error);
|
|
912
|
-
const code = ErrorCode.FORWARD_MESSAGE_FAILED;
|
|
913
|
-
logger.error(`[${code}] 合并转发失败: ${errorMsg}`);
|
|
753
|
+
catch (e) {
|
|
914
754
|
for (const node of forwardMessages) {
|
|
915
755
|
await sendTimeout(session, node.data.content);
|
|
916
|
-
await delay(
|
|
756
|
+
await delay(300);
|
|
917
757
|
}
|
|
918
758
|
}
|
|
919
759
|
}
|
|
@@ -922,88 +762,26 @@ function apply(ctx, config) {
|
|
|
922
762
|
if (!config.enable)
|
|
923
763
|
return;
|
|
924
764
|
const content = session.content?.trim() || '';
|
|
925
|
-
|
|
926
|
-
if (urls.length
|
|
927
|
-
const allLinks = content.match(/https?:\/\/[^\s\"\'\>\]]+/gi) || [];
|
|
928
|
-
urls = allLinks.filter((u) => getPlatformType(u));
|
|
929
|
-
}
|
|
930
|
-
if (urls.length === 0)
|
|
931
|
-
return;
|
|
932
|
-
const key = `${session.platform}:${session.userId}:${session.channelId}`;
|
|
933
|
-
if (linkBuffer.has(key)) {
|
|
934
|
-
const buffer = linkBuffer.get(key);
|
|
935
|
-
const newUrls = urls.filter(url => !buffer.urls.includes(url));
|
|
936
|
-
if (newUrls.length) {
|
|
937
|
-
buffer.urls.push(...newUrls);
|
|
938
|
-
clearTimeout(buffer.timer);
|
|
939
|
-
buffer.timer = setTimeout(() => flush(session), config.messageBufferDelay * 1000);
|
|
940
|
-
}
|
|
765
|
+
const urls = extractUrl(content);
|
|
766
|
+
if (!urls.length)
|
|
941
767
|
return;
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
if (config.showWaitingTip) {
|
|
945
|
-
const msg = await sendTimeout(session, config.waitingTipText);
|
|
946
|
-
tipMsgId = msg?.messageId || msg?.id || msg;
|
|
947
|
-
}
|
|
948
|
-
linkBuffer.set(key, {
|
|
949
|
-
urls,
|
|
950
|
-
timer: setTimeout(() => flush(session), config.messageBufferDelay * 1000),
|
|
951
|
-
tipMsgId
|
|
952
|
-
});
|
|
953
|
-
});
|
|
954
|
-
ctx.command('parse <url>', '手动解析视频链接')
|
|
955
|
-
.action(async ({ session }, url) => {
|
|
956
|
-
if (!url) {
|
|
957
|
-
const code = ErrorCode.INVALID_URL;
|
|
958
|
-
return getErrorInfo(code, '请输入视频链接');
|
|
959
|
-
}
|
|
960
|
-
let urls = extractUrl(url);
|
|
961
|
-
if (urls.length === 0 && hasPlatformKeyword(url)) {
|
|
962
|
-
const allLinks = url.match(/https?:\/\/[^\s\"\'\>\]]+/gi) || [];
|
|
963
|
-
urls = allLinks.filter((u) => getPlatformType(u));
|
|
964
|
-
}
|
|
965
|
-
if (urls.length === 0) {
|
|
966
|
-
const code = ErrorCode.UNSUPPORTED_PLATFORM;
|
|
967
|
-
return getErrorInfo(code, '不支持该链接');
|
|
968
|
-
}
|
|
768
|
+
if (config.showWaitingTip)
|
|
769
|
+
await sendTimeout(session, config.waitingTipText);
|
|
969
770
|
await flush(session, urls);
|
|
970
771
|
});
|
|
971
|
-
ctx.command('
|
|
972
|
-
|
|
772
|
+
ctx.command('parse <url>', '手动解析视频').action(async ({ session }, url) => {
|
|
773
|
+
const us = extractUrl(url);
|
|
774
|
+
if (!us.length)
|
|
775
|
+
return getErrorInfo(ErrorCode.INVALID_URL);
|
|
776
|
+
await flush(session, us);
|
|
777
|
+
});
|
|
778
|
+
ctx.command('clear-cache', '清空缓存').action(() => {
|
|
973
779
|
clearAllCache();
|
|
974
|
-
return
|
|
780
|
+
return '✅ 缓存已清空';
|
|
975
781
|
});
|
|
976
782
|
setInterval(() => {
|
|
977
783
|
const now = Date.now();
|
|
978
|
-
processed.forEach((
|
|
979
|
-
if (now - timestamp > 86400000)
|
|
980
|
-
processed.delete(hash);
|
|
981
|
-
});
|
|
784
|
+
processed.forEach((t, h) => now - t > 86400000 && processed.delete(h));
|
|
982
785
|
}, 3600000);
|
|
983
|
-
|
|
984
|
-
const tempDir = path_1.default.join(process.cwd(), 'temp_videos');
|
|
985
|
-
if (!fs_1.default.existsSync(tempDir))
|
|
986
|
-
return;
|
|
987
|
-
const now = Date.now();
|
|
988
|
-
fs_1.default.readdirSync(tempDir).forEach(file => {
|
|
989
|
-
try {
|
|
990
|
-
const stat = fs_1.default.statSync(path_1.default.join(tempDir, file));
|
|
991
|
-
if (now - stat.mtimeMs > 3600000) {
|
|
992
|
-
fs_1.default.unlinkSync(path_1.default.join(tempDir, file));
|
|
993
|
-
logger.info(`清理过期临时文件: ${file}`);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
catch (error) {
|
|
997
|
-
const errorMsg = getErrorMessage(error);
|
|
998
|
-
logger.error(`[${ErrorCode.UNKNOWN_ERROR}] 清理临时文件失败: ${file}, ${errorMsg}`);
|
|
999
|
-
}
|
|
1000
|
-
});
|
|
1001
|
-
}, 1800000);
|
|
1002
|
-
if (config.autoClearCacheInterval > 0) {
|
|
1003
|
-
setInterval(() => {
|
|
1004
|
-
clearAllCache();
|
|
1005
|
-
logger.info(getErrorInfo(ErrorCode.SUCCESS, '自动清理缓存完成'));
|
|
1006
|
-
}, config.autoClearCacheInterval * 60000);
|
|
1007
|
-
}
|
|
1008
|
-
logger.info(getErrorInfo(ErrorCode.SUCCESS, '视频解析插件已加载'));
|
|
786
|
+
logger.info('✅ 视频解析插件已启动');
|
|
1009
787
|
}
|
package/package.json
CHANGED