koishi-plugin-video-parser-all 0.4.1 → 0.4.3
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 +2 -0
- package/lib/index.js +420 -89
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare const Config: Schema<{
|
|
|
8
8
|
sameLinkInterval?: number | null | undefined;
|
|
9
9
|
maxVideoSize?: number | null | undefined;
|
|
10
10
|
downloadThreads?: number | null | undefined;
|
|
11
|
+
debug?: boolean | null | undefined;
|
|
11
12
|
} & Dict & {
|
|
12
13
|
platformEnable?: ({
|
|
13
14
|
bilibili?: boolean | null | undefined;
|
|
@@ -64,6 +65,7 @@ export declare const Config: Schema<{
|
|
|
64
65
|
sameLinkInterval: number;
|
|
65
66
|
maxVideoSize: number;
|
|
66
67
|
downloadThreads: number;
|
|
68
|
+
debug: boolean;
|
|
67
69
|
} & Dict & {
|
|
68
70
|
platformEnable: Schemastery.ObjectT<{
|
|
69
71
|
bilibili: Schema<boolean, boolean>;
|
package/lib/index.js
CHANGED
|
@@ -22,6 +22,7 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
22
22
|
sameLinkInterval: koishi_1.Schema.number().min(0).default(180).description('相同链接重复解析间隔(秒)'),
|
|
23
23
|
maxVideoSize: koishi_1.Schema.number().min(0).default(50).description('允许发送的最大视频大小(MB)'),
|
|
24
24
|
downloadThreads: koishi_1.Schema.number().min(0).default(4).description('视频下载线程数'),
|
|
25
|
+
debug: koishi_1.Schema.boolean().default(false).description('调试模式,输出详细日志'),
|
|
25
26
|
}).description('基础设置'),
|
|
26
27
|
koishi_1.Schema.object({
|
|
27
28
|
platformEnable: koishi_1.Schema.object({
|
|
@@ -81,6 +82,12 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
81
82
|
autoClearCacheInterval: koishi_1.Schema.number().min(0).default(0).description('自动清理缓存间隔(分钟,0为关闭)'),
|
|
82
83
|
}).description('缓存清理设置'),
|
|
83
84
|
]);
|
|
85
|
+
// 辅助函数:安全获取错误消息
|
|
86
|
+
function getErrorMessage(error) {
|
|
87
|
+
if (error instanceof Error)
|
|
88
|
+
return error.message;
|
|
89
|
+
return String(error);
|
|
90
|
+
}
|
|
84
91
|
if (!worker_threads_1.isMainThread) {
|
|
85
92
|
const workerDataTyped = worker_threads_1.workerData;
|
|
86
93
|
const { url, filePath, maxSize } = workerDataTyped;
|
|
@@ -574,12 +581,22 @@ function clearAllCache() {
|
|
|
574
581
|
}
|
|
575
582
|
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
576
583
|
function buildForwardNode(session, content, botName) {
|
|
584
|
+
let messageContent;
|
|
585
|
+
if (Array.isArray(content)) {
|
|
586
|
+
messageContent = content;
|
|
587
|
+
}
|
|
588
|
+
else if (content && typeof content === 'object' && content.type) {
|
|
589
|
+
messageContent = [content];
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
messageContent = [koishi_1.h.text(String(content))];
|
|
593
|
+
}
|
|
577
594
|
return {
|
|
578
595
|
type: 'node',
|
|
579
596
|
data: {
|
|
580
597
|
name: botName.substring(0, 15),
|
|
581
598
|
uin: session.selfId.toString(),
|
|
582
|
-
content:
|
|
599
|
+
content: messageContent,
|
|
583
600
|
time: Math.floor(Date.now() / 1000)
|
|
584
601
|
}
|
|
585
602
|
};
|
|
@@ -596,6 +613,9 @@ function apply(ctx, config) {
|
|
|
596
613
|
const realUrl = await resolveShortUrl(url);
|
|
597
614
|
const platform = getPlatformType(realUrl);
|
|
598
615
|
if (!platform || !config.platformEnable[platform]) {
|
|
616
|
+
if (!config.debug) {
|
|
617
|
+
ctx.logger.error(`不支持该平台或未启用: ${platform || '未知'}, URL: ${url}`);
|
|
618
|
+
}
|
|
599
619
|
return { data: null, msg: platform ? '该平台解析已关闭' : '不支持该平台链接' };
|
|
600
620
|
}
|
|
601
621
|
if (platform === 'bilibili') {
|
|
@@ -609,193 +629,444 @@ function apply(ctx, config) {
|
|
|
609
629
|
params.ep_id = bangumiIds.ep_id;
|
|
610
630
|
if (config.bilibiliAccessKey)
|
|
611
631
|
params.access_key = config.bilibiliAccessKey;
|
|
632
|
+
if (config.debug)
|
|
633
|
+
ctx.logger.debug(`请求B站番剧API: ${API_CONFIG.xingzhige.bilibili.bangumiUrl}, 参数: ${JSON.stringify(params)}`);
|
|
612
634
|
const res = await http({
|
|
613
635
|
method: 'GET',
|
|
614
636
|
url: API_CONFIG.xingzhige.bilibili.bangumiUrl,
|
|
615
637
|
params
|
|
616
638
|
});
|
|
639
|
+
if (config.debug)
|
|
640
|
+
ctx.logger.debug(`B站番剧API响应状态: ${res.status}`);
|
|
617
641
|
if (res.data && (res.data.season || res.data.bangumi)) {
|
|
618
642
|
const xgData = parse_xingzhige_data(res.data, 'bilibili_bangumi');
|
|
619
643
|
const parseResult = parseData(xgData, config.maxDescLength, 'bilibili_bangumi');
|
|
644
|
+
if (config.debug)
|
|
645
|
+
ctx.logger.debug('B站番剧解析成功');
|
|
620
646
|
return { data: parseResult, msg: 'B站解析成功' };
|
|
621
647
|
}
|
|
648
|
+
else {
|
|
649
|
+
if (config.debug)
|
|
650
|
+
ctx.logger.debug('B站番剧API返回数据无效');
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
catch (error) {
|
|
654
|
+
if (config.debug) {
|
|
655
|
+
ctx.logger.debug(`B站番剧API请求失败: ${getErrorMessage(error)}`);
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
ctx.logger.error(`B站番剧解析失败: ${getErrorMessage(error)}`);
|
|
659
|
+
}
|
|
622
660
|
}
|
|
623
|
-
catch (error) { }
|
|
624
661
|
}
|
|
625
662
|
try {
|
|
663
|
+
const apiUrl = API_CONFIG.xingzhige.bilibili.vidUrl;
|
|
664
|
+
const params = (() => {
|
|
665
|
+
const biliId = realUrl.startsWith('BV') || realUrl.startsWith('av') || realUrl.startsWith('AV') ? realUrl : extract_bilibili_id(realUrl);
|
|
666
|
+
if (!biliId)
|
|
667
|
+
return { url: realUrl };
|
|
668
|
+
const vid = vid_type_parse(biliId);
|
|
669
|
+
return vid.type === 'bv' ? { bvid: vid.id } : { aid: vid.id };
|
|
670
|
+
})();
|
|
671
|
+
if (config.debug)
|
|
672
|
+
ctx.logger.debug(`请求B站VID API: ${apiUrl}, 参数: ${JSON.stringify(params)}`);
|
|
626
673
|
const res = await http({
|
|
627
674
|
method: 'GET',
|
|
628
|
-
url:
|
|
629
|
-
params
|
|
630
|
-
const biliId = realUrl.startsWith('BV') || realUrl.startsWith('av') || realUrl.startsWith('AV') ? realUrl : extract_bilibili_id(realUrl);
|
|
631
|
-
if (!biliId)
|
|
632
|
-
return { url: realUrl };
|
|
633
|
-
const vid = vid_type_parse(biliId);
|
|
634
|
-
return vid.type === 'bv' ? { bvid: vid.id } : { aid: vid.id };
|
|
635
|
-
})()
|
|
675
|
+
url: apiUrl,
|
|
676
|
+
params
|
|
636
677
|
});
|
|
678
|
+
if (config.debug)
|
|
679
|
+
ctx.logger.debug(`B站VID API响应状态: ${res.status}`);
|
|
637
680
|
if (res.data && (res.data.url || res.data.title)) {
|
|
638
681
|
const xgData = parse_xingzhige_data(res.data, platform);
|
|
639
682
|
const parseResult = parseData(xgData, config.maxDescLength, platform);
|
|
683
|
+
if (config.debug)
|
|
684
|
+
ctx.logger.debug('B站VID解析成功');
|
|
685
|
+
return { data: parseResult, msg: 'B站解析成功' };
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
if (config.debug)
|
|
689
|
+
ctx.logger.debug('B站VID API返回数据无效');
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
catch (error) {
|
|
693
|
+
if (config.debug) {
|
|
694
|
+
ctx.logger.debug(`B站VID API请求失败: ${getErrorMessage(error)}`);
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
ctx.logger.error(`B站VID解析失败: ${getErrorMessage(error)}`);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
try {
|
|
701
|
+
const universalUrl = API_CONFIG.universal;
|
|
702
|
+
if (config.debug)
|
|
703
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
704
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
705
|
+
if (config.debug)
|
|
706
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
707
|
+
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
708
|
+
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
709
|
+
if (config.debug)
|
|
710
|
+
ctx.logger.debug('通用API解析成功');
|
|
640
711
|
return { data: parseResult, msg: 'B站解析成功' };
|
|
641
712
|
}
|
|
713
|
+
else {
|
|
714
|
+
if (config.debug)
|
|
715
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
catch (error) {
|
|
719
|
+
if (config.debug) {
|
|
720
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
721
|
+
}
|
|
722
|
+
else {
|
|
723
|
+
ctx.logger.error(`通用API解析失败: ${getErrorMessage(error)}`);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
try {
|
|
727
|
+
const biliId = realUrl.startsWith('BV') || realUrl.startsWith('av') || realUrl.startsWith('AV') ? realUrl : extract_bilibili_id(realUrl);
|
|
728
|
+
if (biliId) {
|
|
729
|
+
if (config.debug)
|
|
730
|
+
ctx.logger.debug(`请求B站官方API: 获取信息 ${biliId}`);
|
|
731
|
+
const officialInfo = await fetch_bilibili_official_info(biliId, config.userAgent);
|
|
732
|
+
if (officialInfo && officialInfo.code === 0 && officialInfo.data) {
|
|
733
|
+
const { bvid, cid } = officialInfo.data;
|
|
734
|
+
if (config.debug)
|
|
735
|
+
ctx.logger.debug(`请求B站官方播放地址: bvid=${bvid}, cid=${cid}`);
|
|
736
|
+
const playInfo = await get_bilibili_play_url(bvid, cid, config.userAgent);
|
|
737
|
+
if (playInfo) {
|
|
738
|
+
const parseResult = parseData({
|
|
739
|
+
...officialInfo,
|
|
740
|
+
playUrl: playInfo.url,
|
|
741
|
+
duration: playInfo.duration
|
|
742
|
+
}, config.maxDescLength, platform);
|
|
743
|
+
if (config.debug)
|
|
744
|
+
ctx.logger.debug('B站官方API解析成功');
|
|
745
|
+
return { data: parseResult, msg: 'B站解析成功' };
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
if (config.debug)
|
|
749
|
+
ctx.logger.debug('B站官方播放地址获取失败');
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
else {
|
|
753
|
+
if (config.debug)
|
|
754
|
+
ctx.logger.debug('B站官方信息获取失败');
|
|
755
|
+
}
|
|
756
|
+
}
|
|
642
757
|
}
|
|
643
758
|
catch (error) {
|
|
759
|
+
if (config.debug) {
|
|
760
|
+
ctx.logger.debug(`B站官方API请求失败: ${getErrorMessage(error)}`);
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
ctx.logger.error(`B站官方API解析失败: ${getErrorMessage(error)}`);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
const platformApis = API_CONFIG.platform.bilibili || [];
|
|
767
|
+
for (const apiUrl of platformApis) {
|
|
644
768
|
try {
|
|
645
|
-
|
|
646
|
-
|
|
769
|
+
if (config.debug)
|
|
770
|
+
ctx.logger.debug(`请求B站平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
771
|
+
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
772
|
+
if (config.debug)
|
|
773
|
+
ctx.logger.debug(`B站平台API响应状态: ${res.status}`);
|
|
774
|
+
if ((res.data.code === 0 || res.data.code === 200) && res.data.data) {
|
|
647
775
|
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
776
|
+
if (config.debug)
|
|
777
|
+
ctx.logger.debug('B站平台API解析成功');
|
|
648
778
|
return { data: parseResult, msg: 'B站解析成功' };
|
|
649
779
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
const biliId = realUrl.startsWith('BV') || realUrl.startsWith('av') || realUrl.startsWith('AV') ? realUrl : extract_bilibili_id(realUrl);
|
|
654
|
-
if (biliId) {
|
|
655
|
-
const officialInfo = await fetch_bilibili_official_info(biliId, config.userAgent);
|
|
656
|
-
if (officialInfo && officialInfo.code === 0 && officialInfo.data) {
|
|
657
|
-
const { bvid, cid } = officialInfo.data;
|
|
658
|
-
const playInfo = await get_bilibili_play_url(bvid, cid, config.userAgent);
|
|
659
|
-
if (playInfo) {
|
|
660
|
-
const parseResult = parseData({
|
|
661
|
-
...officialInfo,
|
|
662
|
-
playUrl: playInfo.url,
|
|
663
|
-
duration: playInfo.duration
|
|
664
|
-
}, config.maxDescLength, platform);
|
|
665
|
-
return { data: parseResult, msg: 'B站解析成功' };
|
|
666
|
-
}
|
|
667
|
-
}
|
|
780
|
+
else {
|
|
781
|
+
if (config.debug)
|
|
782
|
+
ctx.logger.debug('B站平台API返回数据无效');
|
|
668
783
|
}
|
|
669
784
|
}
|
|
670
|
-
catch (
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
try {
|
|
674
|
-
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
675
|
-
if ((res.data.code === 0 || res.data.code === 200) && res.data.data) {
|
|
676
|
-
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
677
|
-
return { data: parseResult, msg: 'B站解析成功' };
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
catch (error) {
|
|
681
|
-
continue;
|
|
785
|
+
catch (error) {
|
|
786
|
+
if (config.debug) {
|
|
787
|
+
ctx.logger.debug(`B站平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
682
788
|
}
|
|
683
789
|
}
|
|
684
790
|
}
|
|
791
|
+
if (config.debug) {
|
|
792
|
+
ctx.logger.debug(`所有B站API尝试失败, URL: ${realUrl}`);
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
ctx.logger.error(`B站解析失败: ${realUrl}`);
|
|
796
|
+
}
|
|
685
797
|
return { data: null, msg: 'B站解析失败' };
|
|
686
798
|
}
|
|
687
799
|
if (platform === 'kuaishou') {
|
|
688
800
|
try {
|
|
801
|
+
const apiUrl = API_CONFIG.xingzhige.kuaishou.url;
|
|
802
|
+
if (config.debug)
|
|
803
|
+
ctx.logger.debug(`请求快手xingzhige API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
689
804
|
const res = await http({
|
|
690
805
|
method: 'GET',
|
|
691
|
-
url:
|
|
806
|
+
url: apiUrl,
|
|
692
807
|
params: { url: realUrl }
|
|
693
808
|
});
|
|
809
|
+
if (config.debug)
|
|
810
|
+
ctx.logger.debug(`快手xingzhige API响应状态: ${res.status}`);
|
|
694
811
|
if (res.data && res.data.jx && res.data.jx.length > 0) {
|
|
695
812
|
const xgData = parse_xingzhige_data(res.data, platform);
|
|
696
813
|
const parseResult = parseData(xgData, config.maxDescLength, platform);
|
|
814
|
+
if (config.debug)
|
|
815
|
+
ctx.logger.debug('快手xingzhige解析成功');
|
|
816
|
+
return { data: parseResult, msg: '快手解析成功' };
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
if (config.debug)
|
|
820
|
+
ctx.logger.debug('快手xingzhige API返回数据无效');
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
catch (error) {
|
|
824
|
+
if (config.debug) {
|
|
825
|
+
ctx.logger.debug(`快手xingzhige API请求失败: ${getErrorMessage(error)}`);
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
ctx.logger.error(`快手xingzhige解析失败: ${getErrorMessage(error)}`);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
try {
|
|
832
|
+
const universalUrl = API_CONFIG.universal;
|
|
833
|
+
if (config.debug)
|
|
834
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
835
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
836
|
+
if (config.debug)
|
|
837
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
838
|
+
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
839
|
+
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
840
|
+
if (config.debug)
|
|
841
|
+
ctx.logger.debug('通用API解析成功');
|
|
697
842
|
return { data: parseResult, msg: '快手解析成功' };
|
|
698
843
|
}
|
|
844
|
+
else {
|
|
845
|
+
if (config.debug)
|
|
846
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
847
|
+
}
|
|
699
848
|
}
|
|
700
849
|
catch (error) {
|
|
850
|
+
if (config.debug) {
|
|
851
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
852
|
+
}
|
|
853
|
+
else {
|
|
854
|
+
ctx.logger.error(`通用API解析失败: ${getErrorMessage(error)}`);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
const platformApis = API_CONFIG.platform.kuaishou || [];
|
|
858
|
+
for (const apiUrl of platformApis) {
|
|
701
859
|
try {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
860
|
+
if (config.debug)
|
|
861
|
+
ctx.logger.debug(`请求快手平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
862
|
+
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
863
|
+
if (config.debug)
|
|
864
|
+
ctx.logger.debug(`快手平台API响应状态: ${res.status}`);
|
|
865
|
+
if ((res.data.code === 200 || res.data.code === 0) && (res.data.data || res.data.image)) {
|
|
866
|
+
const parseResult = parseData(res.data.data || res.data, config.maxDescLength, platform);
|
|
867
|
+
if (config.debug)
|
|
868
|
+
ctx.logger.debug('快手平台API解析成功');
|
|
705
869
|
return { data: parseResult, msg: '快手解析成功' };
|
|
706
870
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
for (const apiUrl of platformApis) {
|
|
711
|
-
try {
|
|
712
|
-
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
713
|
-
if ((res.data.code === 200 || res.data.code === 0) && (res.data.data || res.data.image)) {
|
|
714
|
-
const parseResult = parseData(res.data.data || res.data, config.maxDescLength, platform);
|
|
715
|
-
return { data: parseResult, msg: '快手解析成功' };
|
|
716
|
-
}
|
|
871
|
+
else {
|
|
872
|
+
if (config.debug)
|
|
873
|
+
ctx.logger.debug('快手平台API返回数据无效');
|
|
717
874
|
}
|
|
718
|
-
|
|
719
|
-
|
|
875
|
+
}
|
|
876
|
+
catch (error) {
|
|
877
|
+
if (config.debug) {
|
|
878
|
+
ctx.logger.debug(`快手平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
720
879
|
}
|
|
721
880
|
}
|
|
722
881
|
}
|
|
882
|
+
if (config.debug) {
|
|
883
|
+
ctx.logger.debug(`所有快手API尝试失败, URL: ${realUrl}`);
|
|
884
|
+
}
|
|
885
|
+
else {
|
|
886
|
+
ctx.logger.error(`快手解析失败: ${realUrl}`);
|
|
887
|
+
}
|
|
723
888
|
return { data: null, msg: '快手解析失败' };
|
|
724
889
|
}
|
|
725
890
|
if (platform === 'douyin') {
|
|
726
891
|
try {
|
|
892
|
+
const apiUrl = API_CONFIG.xingzhige.douyin.url;
|
|
893
|
+
if (config.debug)
|
|
894
|
+
ctx.logger.debug(`请求抖音xingzhige API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
727
895
|
const res = await http({
|
|
728
896
|
method: 'GET',
|
|
729
|
-
url:
|
|
897
|
+
url: apiUrl,
|
|
730
898
|
params: { url: realUrl }
|
|
731
899
|
});
|
|
900
|
+
if (config.debug)
|
|
901
|
+
ctx.logger.debug(`抖音xingzhige API响应状态: ${res.status}`);
|
|
732
902
|
if (res.data && res.data.jx && res.data.jx.length > 0) {
|
|
733
903
|
const xgData = parse_xingzhige_data(res.data, platform);
|
|
734
904
|
const parseResult = parseData(xgData, config.maxDescLength, platform);
|
|
905
|
+
if (config.debug)
|
|
906
|
+
ctx.logger.debug('抖音xingzhige解析成功');
|
|
907
|
+
return { data: parseResult, msg: '抖音解析成功' };
|
|
908
|
+
}
|
|
909
|
+
else {
|
|
910
|
+
if (config.debug)
|
|
911
|
+
ctx.logger.debug('抖音xingzhige API返回数据无效');
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
catch (error) {
|
|
915
|
+
if (config.debug) {
|
|
916
|
+
ctx.logger.debug(`抖音xingzhige API请求失败: ${getErrorMessage(error)}`);
|
|
917
|
+
}
|
|
918
|
+
else {
|
|
919
|
+
ctx.logger.error(`抖音xingzhige解析失败: ${getErrorMessage(error)}`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
try {
|
|
923
|
+
const universalUrl = API_CONFIG.universal;
|
|
924
|
+
if (config.debug)
|
|
925
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
926
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
927
|
+
if (config.debug)
|
|
928
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
929
|
+
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
930
|
+
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
931
|
+
if (config.debug)
|
|
932
|
+
ctx.logger.debug('通用API解析成功');
|
|
735
933
|
return { data: parseResult, msg: '抖音解析成功' };
|
|
736
934
|
}
|
|
935
|
+
else {
|
|
936
|
+
if (config.debug)
|
|
937
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
938
|
+
}
|
|
737
939
|
}
|
|
738
940
|
catch (error) {
|
|
941
|
+
if (config.debug) {
|
|
942
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
ctx.logger.error(`通用API解析失败: ${getErrorMessage(error)}`);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
const platformApis = API_CONFIG.platform.douyin || [];
|
|
949
|
+
for (const apiUrl of platformApis) {
|
|
739
950
|
try {
|
|
740
|
-
|
|
951
|
+
if (config.debug)
|
|
952
|
+
ctx.logger.debug(`请求抖音平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
953
|
+
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
954
|
+
if (config.debug)
|
|
955
|
+
ctx.logger.debug(`抖音平台API响应状态: ${res.status}`);
|
|
741
956
|
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
742
957
|
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
958
|
+
if (config.debug)
|
|
959
|
+
ctx.logger.debug('抖音平台API解析成功');
|
|
743
960
|
return { data: parseResult, msg: '抖音解析成功' };
|
|
744
961
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
for (const apiUrl of platformApis) {
|
|
749
|
-
try {
|
|
750
|
-
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
751
|
-
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
752
|
-
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
753
|
-
return { data: parseResult, msg: '抖音解析成功' };
|
|
754
|
-
}
|
|
962
|
+
else {
|
|
963
|
+
if (config.debug)
|
|
964
|
+
ctx.logger.debug('抖音平台API返回数据无效');
|
|
755
965
|
}
|
|
756
|
-
|
|
757
|
-
|
|
966
|
+
}
|
|
967
|
+
catch (error) {
|
|
968
|
+
if (config.debug) {
|
|
969
|
+
ctx.logger.debug(`抖音平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
758
970
|
}
|
|
759
971
|
}
|
|
760
972
|
}
|
|
973
|
+
if (config.debug) {
|
|
974
|
+
ctx.logger.debug(`所有抖音API尝试失败, URL: ${realUrl}`);
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
ctx.logger.error(`抖音解析失败: ${realUrl}`);
|
|
978
|
+
}
|
|
761
979
|
return { data: null, msg: '抖音解析失败' };
|
|
762
980
|
}
|
|
763
981
|
if (platform === 'xigua') {
|
|
764
982
|
try {
|
|
983
|
+
const apiUrl = API_CONFIG.xingzhige.xigua.url;
|
|
984
|
+
if (config.debug)
|
|
985
|
+
ctx.logger.debug(`请求西瓜xingzhige API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
765
986
|
const res = await http({
|
|
766
987
|
method: 'GET',
|
|
767
|
-
url:
|
|
988
|
+
url: apiUrl,
|
|
768
989
|
params: { url: realUrl }
|
|
769
990
|
});
|
|
991
|
+
if (config.debug)
|
|
992
|
+
ctx.logger.debug(`西瓜xingzhige API响应状态: ${res.status}`);
|
|
770
993
|
if (res.data && res.data.jx && res.data.jx.length > 0) {
|
|
771
994
|
const xgData = parse_xingzhige_data(res.data, platform);
|
|
772
995
|
const parseResult = parseData(xgData, config.maxDescLength, platform);
|
|
996
|
+
if (config.debug)
|
|
997
|
+
ctx.logger.debug('西瓜xingzhige解析成功');
|
|
998
|
+
return { data: parseResult, msg: '西瓜视频解析成功' };
|
|
999
|
+
}
|
|
1000
|
+
else {
|
|
1001
|
+
if (config.debug)
|
|
1002
|
+
ctx.logger.debug('西瓜xingzhige API返回数据无效');
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
catch (error) {
|
|
1006
|
+
if (config.debug) {
|
|
1007
|
+
ctx.logger.debug(`西瓜xingzhige API请求失败: ${getErrorMessage(error)}`);
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
ctx.logger.error(`西瓜xingzhige解析失败: ${getErrorMessage(error)}`);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
try {
|
|
1014
|
+
const universalUrl = API_CONFIG.universal;
|
|
1015
|
+
if (config.debug)
|
|
1016
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
1017
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
1018
|
+
if (config.debug)
|
|
1019
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
1020
|
+
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
1021
|
+
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
1022
|
+
if (config.debug)
|
|
1023
|
+
ctx.logger.debug('通用API解析成功');
|
|
773
1024
|
return { data: parseResult, msg: '西瓜视频解析成功' };
|
|
774
1025
|
}
|
|
1026
|
+
else {
|
|
1027
|
+
if (config.debug)
|
|
1028
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
1029
|
+
}
|
|
775
1030
|
}
|
|
776
1031
|
catch (error) {
|
|
1032
|
+
if (config.debug) {
|
|
1033
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
1034
|
+
}
|
|
1035
|
+
else {
|
|
1036
|
+
ctx.logger.error(`通用API解析失败: ${getErrorMessage(error)}`);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
const platformApis = API_CONFIG.platform.xigua || [];
|
|
1040
|
+
for (const apiUrl of platformApis) {
|
|
777
1041
|
try {
|
|
778
|
-
|
|
1042
|
+
if (config.debug)
|
|
1043
|
+
ctx.logger.debug(`请求西瓜平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
1044
|
+
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
1045
|
+
if (config.debug)
|
|
1046
|
+
ctx.logger.debug(`西瓜平台API响应状态: ${res.status}`);
|
|
779
1047
|
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
780
1048
|
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
1049
|
+
if (config.debug)
|
|
1050
|
+
ctx.logger.debug('西瓜平台API解析成功');
|
|
781
1051
|
return { data: parseResult, msg: '西瓜视频解析成功' };
|
|
782
1052
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
for (const apiUrl of platformApis) {
|
|
787
|
-
try {
|
|
788
|
-
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
789
|
-
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
790
|
-
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
791
|
-
return { data: parseResult, msg: '西瓜视频解析成功' };
|
|
792
|
-
}
|
|
1053
|
+
else {
|
|
1054
|
+
if (config.debug)
|
|
1055
|
+
ctx.logger.debug('西瓜平台API返回数据无效');
|
|
793
1056
|
}
|
|
794
|
-
|
|
795
|
-
|
|
1057
|
+
}
|
|
1058
|
+
catch (error) {
|
|
1059
|
+
if (config.debug) {
|
|
1060
|
+
ctx.logger.debug(`西瓜平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
796
1061
|
}
|
|
797
1062
|
}
|
|
798
1063
|
}
|
|
1064
|
+
if (config.debug) {
|
|
1065
|
+
ctx.logger.debug(`所有西瓜API尝试失败, URL: ${realUrl}`);
|
|
1066
|
+
}
|
|
1067
|
+
else {
|
|
1068
|
+
ctx.logger.error(`西瓜解析失败: ${realUrl}`);
|
|
1069
|
+
}
|
|
799
1070
|
return { data: null, msg: '西瓜视频解析失败' };
|
|
800
1071
|
}
|
|
801
1072
|
const currentPlatform = platform;
|
|
@@ -803,16 +1074,32 @@ function apply(ctx, config) {
|
|
|
803
1074
|
if (nonKuaishouPlatforms.includes(currentPlatform)) {
|
|
804
1075
|
for (let retry = 0; retry <= config.retryTimes; retry++) {
|
|
805
1076
|
try {
|
|
806
|
-
const
|
|
1077
|
+
const universalUrl = API_CONFIG.universal;
|
|
1078
|
+
if (config.debug)
|
|
1079
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
1080
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
1081
|
+
if (config.debug)
|
|
1082
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
807
1083
|
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
808
1084
|
const parseResult = parseData(res.data.data, config.maxDescLength, currentPlatform);
|
|
1085
|
+
if (config.debug)
|
|
1086
|
+
ctx.logger.debug('通用API解析成功');
|
|
809
1087
|
return { data: parseResult, msg: '解析成功' };
|
|
810
1088
|
}
|
|
811
1089
|
else if (res.data.code === 201) {
|
|
1090
|
+
if (config.debug)
|
|
1091
|
+
ctx.logger.debug('通用API返回code 201');
|
|
812
1092
|
break;
|
|
813
1093
|
}
|
|
1094
|
+
else {
|
|
1095
|
+
if (config.debug)
|
|
1096
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
1097
|
+
}
|
|
814
1098
|
}
|
|
815
1099
|
catch (error) {
|
|
1100
|
+
if (config.debug) {
|
|
1101
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
1102
|
+
}
|
|
816
1103
|
if (retry === config.retryTimes)
|
|
817
1104
|
break;
|
|
818
1105
|
await delay(config.retryInterval);
|
|
@@ -824,7 +1111,11 @@ function apply(ctx, config) {
|
|
|
824
1111
|
const apiUrl = platformApis[apiIndex];
|
|
825
1112
|
for (let retry = 0; retry <= config.retryTimes; retry++) {
|
|
826
1113
|
try {
|
|
1114
|
+
if (config.debug)
|
|
1115
|
+
ctx.logger.debug(`请求平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
827
1116
|
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
1117
|
+
if (config.debug)
|
|
1118
|
+
ctx.logger.debug(`平台API响应状态: ${res.status}`);
|
|
828
1119
|
let shouldContinue = false;
|
|
829
1120
|
if ((res.data.code === 200 || res.data.code === 0)) {
|
|
830
1121
|
let parseResult = null;
|
|
@@ -853,24 +1144,39 @@ function apply(ctx, config) {
|
|
|
853
1144
|
}
|
|
854
1145
|
}
|
|
855
1146
|
if (parseResult) {
|
|
1147
|
+
if (config.debug)
|
|
1148
|
+
ctx.logger.debug('平台API解析成功');
|
|
856
1149
|
return { data: parseResult, msg: '解析成功' };
|
|
857
1150
|
}
|
|
858
1151
|
}
|
|
859
1152
|
if (shouldContinue && retry < config.retryTimes) {
|
|
1153
|
+
if (config.debug)
|
|
1154
|
+
ctx.logger.debug('平台API返回数据无效,准备重试');
|
|
860
1155
|
await delay(config.retryInterval);
|
|
861
1156
|
continue;
|
|
862
1157
|
}
|
|
863
1158
|
else {
|
|
1159
|
+
if (config.debug)
|
|
1160
|
+
ctx.logger.debug('平台API返回数据无效,放弃');
|
|
864
1161
|
break;
|
|
865
1162
|
}
|
|
866
1163
|
}
|
|
867
1164
|
catch (error) {
|
|
1165
|
+
if (config.debug) {
|
|
1166
|
+
ctx.logger.debug(`平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
1167
|
+
}
|
|
868
1168
|
if (retry === config.retryTimes)
|
|
869
1169
|
break;
|
|
870
1170
|
await delay(config.retryInterval);
|
|
871
1171
|
}
|
|
872
1172
|
}
|
|
873
1173
|
}
|
|
1174
|
+
if (config.debug) {
|
|
1175
|
+
ctx.logger.debug(`所有API尝试失败,平台: ${platform}, URL: ${realUrl}`);
|
|
1176
|
+
}
|
|
1177
|
+
else {
|
|
1178
|
+
ctx.logger.error(`解析失败: ${platform} ${realUrl}`);
|
|
1179
|
+
}
|
|
874
1180
|
return { data: null, msg: '解析失败,请稍后重试' };
|
|
875
1181
|
}
|
|
876
1182
|
async function processSingleUrl(session, url) {
|
|
@@ -925,8 +1231,17 @@ function apply(ctx, config) {
|
|
|
925
1231
|
}
|
|
926
1232
|
else {
|
|
927
1233
|
errs.push(`【${url.slice(0, 22)}...】:${result.msg}`);
|
|
1234
|
+
if (config.debug) {
|
|
1235
|
+
ctx.logger.debug(`解析失败: ${url}, 原因: ${result.msg}`);
|
|
1236
|
+
}
|
|
1237
|
+
else {
|
|
1238
|
+
ctx.logger.error(`解析失败: ${url}, 原因: ${result.msg}`);
|
|
1239
|
+
}
|
|
928
1240
|
}
|
|
929
1241
|
}
|
|
1242
|
+
if (errs.length) {
|
|
1243
|
+
ctx.logger.error(`解析失败数量: ${errs.length}, 示例: ${errs[0]}`);
|
|
1244
|
+
}
|
|
930
1245
|
const enableForward = config.enableForward && session.platform === 'onebot';
|
|
931
1246
|
const forwardMessages = [];
|
|
932
1247
|
const botName = config.botName || '视频解析机器人';
|
|
@@ -973,6 +1288,12 @@ function apply(ctx, config) {
|
|
|
973
1288
|
videoElem = koishi_1.h.file(filePath);
|
|
974
1289
|
}
|
|
975
1290
|
catch (error) {
|
|
1291
|
+
if (config.debug) {
|
|
1292
|
+
ctx.logger.debug(`视频下载失败: ${getErrorMessage(error)}`);
|
|
1293
|
+
}
|
|
1294
|
+
else {
|
|
1295
|
+
ctx.logger.error(`视频下载失败: ${getErrorMessage(error)}`);
|
|
1296
|
+
}
|
|
976
1297
|
videoElem = koishi_1.h.video(item.video);
|
|
977
1298
|
}
|
|
978
1299
|
}
|
|
@@ -1009,6 +1330,12 @@ function apply(ctx, config) {
|
|
|
1009
1330
|
videoElem = koishi_1.h.file(filePath);
|
|
1010
1331
|
}
|
|
1011
1332
|
catch (error) {
|
|
1333
|
+
if (config.debug) {
|
|
1334
|
+
ctx.logger.debug(`视频下载失败: ${getErrorMessage(error)}`);
|
|
1335
|
+
}
|
|
1336
|
+
else {
|
|
1337
|
+
ctx.logger.error(`视频下载失败: ${getErrorMessage(error)}`);
|
|
1338
|
+
}
|
|
1012
1339
|
videoElem = koishi_1.h.video(item.video);
|
|
1013
1340
|
}
|
|
1014
1341
|
}
|
|
@@ -1027,7 +1354,8 @@ function apply(ctx, config) {
|
|
|
1027
1354
|
}
|
|
1028
1355
|
}
|
|
1029
1356
|
catch (error) {
|
|
1030
|
-
|
|
1357
|
+
ctx.logger.error(`处理内容失败: ${getErrorMessage(error)}`);
|
|
1358
|
+
await sendTimeout(session, `❌ 处理${item.type}内容失败: ${getErrorMessage(error)}`);
|
|
1031
1359
|
}
|
|
1032
1360
|
}
|
|
1033
1361
|
if (enableForward && forwardMessages.length) {
|
|
@@ -1037,6 +1365,7 @@ function apply(ctx, config) {
|
|
|
1037
1365
|
await sendTimeout(session, forwardMsg);
|
|
1038
1366
|
}
|
|
1039
1367
|
catch (error) {
|
|
1368
|
+
ctx.logger.error(`合并转发失败: ${getErrorMessage(error)}`);
|
|
1040
1369
|
for (const node of forwardMessages) {
|
|
1041
1370
|
await sendTimeout(session, node.data.content);
|
|
1042
1371
|
await delay(500);
|
|
@@ -1114,7 +1443,9 @@ function apply(ctx, config) {
|
|
|
1114
1443
|
fs_1.default.unlinkSync(path_1.default.join(tempDir, file));
|
|
1115
1444
|
}
|
|
1116
1445
|
}
|
|
1117
|
-
catch (error) {
|
|
1446
|
+
catch (error) {
|
|
1447
|
+
ctx.logger.error(`清理临时文件失败: ${file}, ${getErrorMessage(error)}`);
|
|
1448
|
+
}
|
|
1118
1449
|
});
|
|
1119
1450
|
}, 1800000);
|
|
1120
1451
|
if (config.autoClearCacheInterval > 0) {
|
package/package.json
CHANGED