koishi-plugin-video-parser-all 0.4.1 → 0.4.2
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 +409 -88
- 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;
|
|
@@ -596,6 +603,9 @@ function apply(ctx, config) {
|
|
|
596
603
|
const realUrl = await resolveShortUrl(url);
|
|
597
604
|
const platform = getPlatformType(realUrl);
|
|
598
605
|
if (!platform || !config.platformEnable[platform]) {
|
|
606
|
+
if (!config.debug) {
|
|
607
|
+
ctx.logger.error(`不支持该平台或未启用: ${platform || '未知'}, URL: ${url}`);
|
|
608
|
+
}
|
|
599
609
|
return { data: null, msg: platform ? '该平台解析已关闭' : '不支持该平台链接' };
|
|
600
610
|
}
|
|
601
611
|
if (platform === 'bilibili') {
|
|
@@ -609,193 +619,444 @@ function apply(ctx, config) {
|
|
|
609
619
|
params.ep_id = bangumiIds.ep_id;
|
|
610
620
|
if (config.bilibiliAccessKey)
|
|
611
621
|
params.access_key = config.bilibiliAccessKey;
|
|
622
|
+
if (config.debug)
|
|
623
|
+
ctx.logger.debug(`请求B站番剧API: ${API_CONFIG.xingzhige.bilibili.bangumiUrl}, 参数: ${JSON.stringify(params)}`);
|
|
612
624
|
const res = await http({
|
|
613
625
|
method: 'GET',
|
|
614
626
|
url: API_CONFIG.xingzhige.bilibili.bangumiUrl,
|
|
615
627
|
params
|
|
616
628
|
});
|
|
629
|
+
if (config.debug)
|
|
630
|
+
ctx.logger.debug(`B站番剧API响应状态: ${res.status}`);
|
|
617
631
|
if (res.data && (res.data.season || res.data.bangumi)) {
|
|
618
632
|
const xgData = parse_xingzhige_data(res.data, 'bilibili_bangumi');
|
|
619
633
|
const parseResult = parseData(xgData, config.maxDescLength, 'bilibili_bangumi');
|
|
634
|
+
if (config.debug)
|
|
635
|
+
ctx.logger.debug('B站番剧解析成功');
|
|
620
636
|
return { data: parseResult, msg: 'B站解析成功' };
|
|
621
637
|
}
|
|
638
|
+
else {
|
|
639
|
+
if (config.debug)
|
|
640
|
+
ctx.logger.debug('B站番剧API返回数据无效');
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
catch (error) {
|
|
644
|
+
if (config.debug) {
|
|
645
|
+
ctx.logger.debug(`B站番剧API请求失败: ${getErrorMessage(error)}`);
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
ctx.logger.error(`B站番剧解析失败: ${getErrorMessage(error)}`);
|
|
649
|
+
}
|
|
622
650
|
}
|
|
623
|
-
catch (error) { }
|
|
624
651
|
}
|
|
625
652
|
try {
|
|
653
|
+
const apiUrl = API_CONFIG.xingzhige.bilibili.vidUrl;
|
|
654
|
+
const params = (() => {
|
|
655
|
+
const biliId = realUrl.startsWith('BV') || realUrl.startsWith('av') || realUrl.startsWith('AV') ? realUrl : extract_bilibili_id(realUrl);
|
|
656
|
+
if (!biliId)
|
|
657
|
+
return { url: realUrl };
|
|
658
|
+
const vid = vid_type_parse(biliId);
|
|
659
|
+
return vid.type === 'bv' ? { bvid: vid.id } : { aid: vid.id };
|
|
660
|
+
})();
|
|
661
|
+
if (config.debug)
|
|
662
|
+
ctx.logger.debug(`请求B站VID API: ${apiUrl}, 参数: ${JSON.stringify(params)}`);
|
|
626
663
|
const res = await http({
|
|
627
664
|
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
|
-
})()
|
|
665
|
+
url: apiUrl,
|
|
666
|
+
params
|
|
636
667
|
});
|
|
668
|
+
if (config.debug)
|
|
669
|
+
ctx.logger.debug(`B站VID API响应状态: ${res.status}`);
|
|
637
670
|
if (res.data && (res.data.url || res.data.title)) {
|
|
638
671
|
const xgData = parse_xingzhige_data(res.data, platform);
|
|
639
672
|
const parseResult = parseData(xgData, config.maxDescLength, platform);
|
|
673
|
+
if (config.debug)
|
|
674
|
+
ctx.logger.debug('B站VID解析成功');
|
|
675
|
+
return { data: parseResult, msg: 'B站解析成功' };
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
if (config.debug)
|
|
679
|
+
ctx.logger.debug('B站VID API返回数据无效');
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
catch (error) {
|
|
683
|
+
if (config.debug) {
|
|
684
|
+
ctx.logger.debug(`B站VID API请求失败: ${getErrorMessage(error)}`);
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
ctx.logger.error(`B站VID解析失败: ${getErrorMessage(error)}`);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
try {
|
|
691
|
+
const universalUrl = API_CONFIG.universal;
|
|
692
|
+
if (config.debug)
|
|
693
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
694
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
695
|
+
if (config.debug)
|
|
696
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
697
|
+
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
698
|
+
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
699
|
+
if (config.debug)
|
|
700
|
+
ctx.logger.debug('通用API解析成功');
|
|
640
701
|
return { data: parseResult, msg: 'B站解析成功' };
|
|
641
702
|
}
|
|
703
|
+
else {
|
|
704
|
+
if (config.debug)
|
|
705
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
catch (error) {
|
|
709
|
+
if (config.debug) {
|
|
710
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
711
|
+
}
|
|
712
|
+
else {
|
|
713
|
+
ctx.logger.error(`通用API解析失败: ${getErrorMessage(error)}`);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
try {
|
|
717
|
+
const biliId = realUrl.startsWith('BV') || realUrl.startsWith('av') || realUrl.startsWith('AV') ? realUrl : extract_bilibili_id(realUrl);
|
|
718
|
+
if (biliId) {
|
|
719
|
+
if (config.debug)
|
|
720
|
+
ctx.logger.debug(`请求B站官方API: 获取信息 ${biliId}`);
|
|
721
|
+
const officialInfo = await fetch_bilibili_official_info(biliId, config.userAgent);
|
|
722
|
+
if (officialInfo && officialInfo.code === 0 && officialInfo.data) {
|
|
723
|
+
const { bvid, cid } = officialInfo.data;
|
|
724
|
+
if (config.debug)
|
|
725
|
+
ctx.logger.debug(`请求B站官方播放地址: bvid=${bvid}, cid=${cid}`);
|
|
726
|
+
const playInfo = await get_bilibili_play_url(bvid, cid, config.userAgent);
|
|
727
|
+
if (playInfo) {
|
|
728
|
+
const parseResult = parseData({
|
|
729
|
+
...officialInfo,
|
|
730
|
+
playUrl: playInfo.url,
|
|
731
|
+
duration: playInfo.duration
|
|
732
|
+
}, config.maxDescLength, platform);
|
|
733
|
+
if (config.debug)
|
|
734
|
+
ctx.logger.debug('B站官方API解析成功');
|
|
735
|
+
return { data: parseResult, msg: 'B站解析成功' };
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
if (config.debug)
|
|
739
|
+
ctx.logger.debug('B站官方播放地址获取失败');
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
if (config.debug)
|
|
744
|
+
ctx.logger.debug('B站官方信息获取失败');
|
|
745
|
+
}
|
|
746
|
+
}
|
|
642
747
|
}
|
|
643
748
|
catch (error) {
|
|
749
|
+
if (config.debug) {
|
|
750
|
+
ctx.logger.debug(`B站官方API请求失败: ${getErrorMessage(error)}`);
|
|
751
|
+
}
|
|
752
|
+
else {
|
|
753
|
+
ctx.logger.error(`B站官方API解析失败: ${getErrorMessage(error)}`);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
const platformApis = API_CONFIG.platform.bilibili || [];
|
|
757
|
+
for (const apiUrl of platformApis) {
|
|
644
758
|
try {
|
|
645
|
-
|
|
646
|
-
|
|
759
|
+
if (config.debug)
|
|
760
|
+
ctx.logger.debug(`请求B站平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
761
|
+
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
762
|
+
if (config.debug)
|
|
763
|
+
ctx.logger.debug(`B站平台API响应状态: ${res.status}`);
|
|
764
|
+
if ((res.data.code === 0 || res.data.code === 200) && res.data.data) {
|
|
647
765
|
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
766
|
+
if (config.debug)
|
|
767
|
+
ctx.logger.debug('B站平台API解析成功');
|
|
648
768
|
return { data: parseResult, msg: 'B站解析成功' };
|
|
649
769
|
}
|
|
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
|
-
}
|
|
770
|
+
else {
|
|
771
|
+
if (config.debug)
|
|
772
|
+
ctx.logger.debug('B站平台API返回数据无效');
|
|
668
773
|
}
|
|
669
774
|
}
|
|
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;
|
|
775
|
+
catch (error) {
|
|
776
|
+
if (config.debug) {
|
|
777
|
+
ctx.logger.debug(`B站平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
682
778
|
}
|
|
683
779
|
}
|
|
684
780
|
}
|
|
781
|
+
if (config.debug) {
|
|
782
|
+
ctx.logger.debug(`所有B站API尝试失败, URL: ${realUrl}`);
|
|
783
|
+
}
|
|
784
|
+
else {
|
|
785
|
+
ctx.logger.error(`B站解析失败: ${realUrl}`);
|
|
786
|
+
}
|
|
685
787
|
return { data: null, msg: 'B站解析失败' };
|
|
686
788
|
}
|
|
687
789
|
if (platform === 'kuaishou') {
|
|
688
790
|
try {
|
|
791
|
+
const apiUrl = API_CONFIG.xingzhige.kuaishou.url;
|
|
792
|
+
if (config.debug)
|
|
793
|
+
ctx.logger.debug(`请求快手xingzhige API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
689
794
|
const res = await http({
|
|
690
795
|
method: 'GET',
|
|
691
|
-
url:
|
|
796
|
+
url: apiUrl,
|
|
692
797
|
params: { url: realUrl }
|
|
693
798
|
});
|
|
799
|
+
if (config.debug)
|
|
800
|
+
ctx.logger.debug(`快手xingzhige API响应状态: ${res.status}`);
|
|
694
801
|
if (res.data && res.data.jx && res.data.jx.length > 0) {
|
|
695
802
|
const xgData = parse_xingzhige_data(res.data, platform);
|
|
696
803
|
const parseResult = parseData(xgData, config.maxDescLength, platform);
|
|
804
|
+
if (config.debug)
|
|
805
|
+
ctx.logger.debug('快手xingzhige解析成功');
|
|
697
806
|
return { data: parseResult, msg: '快手解析成功' };
|
|
698
807
|
}
|
|
808
|
+
else {
|
|
809
|
+
if (config.debug)
|
|
810
|
+
ctx.logger.debug('快手xingzhige API返回数据无效');
|
|
811
|
+
}
|
|
699
812
|
}
|
|
700
813
|
catch (error) {
|
|
814
|
+
if (config.debug) {
|
|
815
|
+
ctx.logger.debug(`快手xingzhige API请求失败: ${getErrorMessage(error)}`);
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
ctx.logger.error(`快手xingzhige解析失败: ${getErrorMessage(error)}`);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
try {
|
|
822
|
+
const universalUrl = API_CONFIG.universal;
|
|
823
|
+
if (config.debug)
|
|
824
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
825
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
826
|
+
if (config.debug)
|
|
827
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
828
|
+
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
829
|
+
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
830
|
+
if (config.debug)
|
|
831
|
+
ctx.logger.debug('通用API解析成功');
|
|
832
|
+
return { data: parseResult, msg: '快手解析成功' };
|
|
833
|
+
}
|
|
834
|
+
else {
|
|
835
|
+
if (config.debug)
|
|
836
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
catch (error) {
|
|
840
|
+
if (config.debug) {
|
|
841
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
ctx.logger.error(`通用API解析失败: ${getErrorMessage(error)}`);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
const platformApis = API_CONFIG.platform.kuaishou || [];
|
|
848
|
+
for (const apiUrl of platformApis) {
|
|
701
849
|
try {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
850
|
+
if (config.debug)
|
|
851
|
+
ctx.logger.debug(`请求快手平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
852
|
+
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
853
|
+
if (config.debug)
|
|
854
|
+
ctx.logger.debug(`快手平台API响应状态: ${res.status}`);
|
|
855
|
+
if ((res.data.code === 200 || res.data.code === 0) && (res.data.data || res.data.image)) {
|
|
856
|
+
const parseResult = parseData(res.data.data || res.data, config.maxDescLength, platform);
|
|
857
|
+
if (config.debug)
|
|
858
|
+
ctx.logger.debug('快手平台API解析成功');
|
|
705
859
|
return { data: parseResult, msg: '快手解析成功' };
|
|
706
860
|
}
|
|
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
|
-
}
|
|
861
|
+
else {
|
|
862
|
+
if (config.debug)
|
|
863
|
+
ctx.logger.debug('快手平台API返回数据无效');
|
|
717
864
|
}
|
|
718
|
-
|
|
719
|
-
|
|
865
|
+
}
|
|
866
|
+
catch (error) {
|
|
867
|
+
if (config.debug) {
|
|
868
|
+
ctx.logger.debug(`快手平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
720
869
|
}
|
|
721
870
|
}
|
|
722
871
|
}
|
|
872
|
+
if (config.debug) {
|
|
873
|
+
ctx.logger.debug(`所有快手API尝试失败, URL: ${realUrl}`);
|
|
874
|
+
}
|
|
875
|
+
else {
|
|
876
|
+
ctx.logger.error(`快手解析失败: ${realUrl}`);
|
|
877
|
+
}
|
|
723
878
|
return { data: null, msg: '快手解析失败' };
|
|
724
879
|
}
|
|
725
880
|
if (platform === 'douyin') {
|
|
726
881
|
try {
|
|
882
|
+
const apiUrl = API_CONFIG.xingzhige.douyin.url;
|
|
883
|
+
if (config.debug)
|
|
884
|
+
ctx.logger.debug(`请求抖音xingzhige API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
727
885
|
const res = await http({
|
|
728
886
|
method: 'GET',
|
|
729
|
-
url:
|
|
887
|
+
url: apiUrl,
|
|
730
888
|
params: { url: realUrl }
|
|
731
889
|
});
|
|
890
|
+
if (config.debug)
|
|
891
|
+
ctx.logger.debug(`抖音xingzhige API响应状态: ${res.status}`);
|
|
732
892
|
if (res.data && res.data.jx && res.data.jx.length > 0) {
|
|
733
893
|
const xgData = parse_xingzhige_data(res.data, platform);
|
|
734
894
|
const parseResult = parseData(xgData, config.maxDescLength, platform);
|
|
895
|
+
if (config.debug)
|
|
896
|
+
ctx.logger.debug('抖音xingzhige解析成功');
|
|
735
897
|
return { data: parseResult, msg: '抖音解析成功' };
|
|
736
898
|
}
|
|
899
|
+
else {
|
|
900
|
+
if (config.debug)
|
|
901
|
+
ctx.logger.debug('抖音xingzhige API返回数据无效');
|
|
902
|
+
}
|
|
737
903
|
}
|
|
738
904
|
catch (error) {
|
|
905
|
+
if (config.debug) {
|
|
906
|
+
ctx.logger.debug(`抖音xingzhige API请求失败: ${getErrorMessage(error)}`);
|
|
907
|
+
}
|
|
908
|
+
else {
|
|
909
|
+
ctx.logger.error(`抖音xingzhige解析失败: ${getErrorMessage(error)}`);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
try {
|
|
913
|
+
const universalUrl = API_CONFIG.universal;
|
|
914
|
+
if (config.debug)
|
|
915
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
916
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
917
|
+
if (config.debug)
|
|
918
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
919
|
+
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
920
|
+
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
921
|
+
if (config.debug)
|
|
922
|
+
ctx.logger.debug('通用API解析成功');
|
|
923
|
+
return { data: parseResult, msg: '抖音解析成功' };
|
|
924
|
+
}
|
|
925
|
+
else {
|
|
926
|
+
if (config.debug)
|
|
927
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
catch (error) {
|
|
931
|
+
if (config.debug) {
|
|
932
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
933
|
+
}
|
|
934
|
+
else {
|
|
935
|
+
ctx.logger.error(`通用API解析失败: ${getErrorMessage(error)}`);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
const platformApis = API_CONFIG.platform.douyin || [];
|
|
939
|
+
for (const apiUrl of platformApis) {
|
|
739
940
|
try {
|
|
740
|
-
|
|
941
|
+
if (config.debug)
|
|
942
|
+
ctx.logger.debug(`请求抖音平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
943
|
+
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
944
|
+
if (config.debug)
|
|
945
|
+
ctx.logger.debug(`抖音平台API响应状态: ${res.status}`);
|
|
741
946
|
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
742
947
|
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
948
|
+
if (config.debug)
|
|
949
|
+
ctx.logger.debug('抖音平台API解析成功');
|
|
743
950
|
return { data: parseResult, msg: '抖音解析成功' };
|
|
744
951
|
}
|
|
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
|
-
}
|
|
952
|
+
else {
|
|
953
|
+
if (config.debug)
|
|
954
|
+
ctx.logger.debug('抖音平台API返回数据无效');
|
|
755
955
|
}
|
|
756
|
-
|
|
757
|
-
|
|
956
|
+
}
|
|
957
|
+
catch (error) {
|
|
958
|
+
if (config.debug) {
|
|
959
|
+
ctx.logger.debug(`抖音平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
758
960
|
}
|
|
759
961
|
}
|
|
760
962
|
}
|
|
963
|
+
if (config.debug) {
|
|
964
|
+
ctx.logger.debug(`所有抖音API尝试失败, URL: ${realUrl}`);
|
|
965
|
+
}
|
|
966
|
+
else {
|
|
967
|
+
ctx.logger.error(`抖音解析失败: ${realUrl}`);
|
|
968
|
+
}
|
|
761
969
|
return { data: null, msg: '抖音解析失败' };
|
|
762
970
|
}
|
|
763
971
|
if (platform === 'xigua') {
|
|
764
972
|
try {
|
|
973
|
+
const apiUrl = API_CONFIG.xingzhige.xigua.url;
|
|
974
|
+
if (config.debug)
|
|
975
|
+
ctx.logger.debug(`请求西瓜xingzhige API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
765
976
|
const res = await http({
|
|
766
977
|
method: 'GET',
|
|
767
|
-
url:
|
|
978
|
+
url: apiUrl,
|
|
768
979
|
params: { url: realUrl }
|
|
769
980
|
});
|
|
981
|
+
if (config.debug)
|
|
982
|
+
ctx.logger.debug(`西瓜xingzhige API响应状态: ${res.status}`);
|
|
770
983
|
if (res.data && res.data.jx && res.data.jx.length > 0) {
|
|
771
984
|
const xgData = parse_xingzhige_data(res.data, platform);
|
|
772
985
|
const parseResult = parseData(xgData, config.maxDescLength, platform);
|
|
986
|
+
if (config.debug)
|
|
987
|
+
ctx.logger.debug('西瓜xingzhige解析成功');
|
|
988
|
+
return { data: parseResult, msg: '西瓜视频解析成功' };
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
if (config.debug)
|
|
992
|
+
ctx.logger.debug('西瓜xingzhige API返回数据无效');
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
catch (error) {
|
|
996
|
+
if (config.debug) {
|
|
997
|
+
ctx.logger.debug(`西瓜xingzhige API请求失败: ${getErrorMessage(error)}`);
|
|
998
|
+
}
|
|
999
|
+
else {
|
|
1000
|
+
ctx.logger.error(`西瓜xingzhige解析失败: ${getErrorMessage(error)}`);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
try {
|
|
1004
|
+
const universalUrl = API_CONFIG.universal;
|
|
1005
|
+
if (config.debug)
|
|
1006
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
1007
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
1008
|
+
if (config.debug)
|
|
1009
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
1010
|
+
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
1011
|
+
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
1012
|
+
if (config.debug)
|
|
1013
|
+
ctx.logger.debug('通用API解析成功');
|
|
773
1014
|
return { data: parseResult, msg: '西瓜视频解析成功' };
|
|
774
1015
|
}
|
|
1016
|
+
else {
|
|
1017
|
+
if (config.debug)
|
|
1018
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
1019
|
+
}
|
|
775
1020
|
}
|
|
776
1021
|
catch (error) {
|
|
1022
|
+
if (config.debug) {
|
|
1023
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
1024
|
+
}
|
|
1025
|
+
else {
|
|
1026
|
+
ctx.logger.error(`通用API解析失败: ${getErrorMessage(error)}`);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
const platformApis = API_CONFIG.platform.xigua || [];
|
|
1030
|
+
for (const apiUrl of platformApis) {
|
|
777
1031
|
try {
|
|
778
|
-
|
|
1032
|
+
if (config.debug)
|
|
1033
|
+
ctx.logger.debug(`请求西瓜平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
1034
|
+
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
1035
|
+
if (config.debug)
|
|
1036
|
+
ctx.logger.debug(`西瓜平台API响应状态: ${res.status}`);
|
|
779
1037
|
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
780
1038
|
const parseResult = parseData(res.data.data, config.maxDescLength, platform);
|
|
1039
|
+
if (config.debug)
|
|
1040
|
+
ctx.logger.debug('西瓜平台API解析成功');
|
|
781
1041
|
return { data: parseResult, msg: '西瓜视频解析成功' };
|
|
782
1042
|
}
|
|
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
|
-
}
|
|
1043
|
+
else {
|
|
1044
|
+
if (config.debug)
|
|
1045
|
+
ctx.logger.debug('西瓜平台API返回数据无效');
|
|
793
1046
|
}
|
|
794
|
-
|
|
795
|
-
|
|
1047
|
+
}
|
|
1048
|
+
catch (error) {
|
|
1049
|
+
if (config.debug) {
|
|
1050
|
+
ctx.logger.debug(`西瓜平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
796
1051
|
}
|
|
797
1052
|
}
|
|
798
1053
|
}
|
|
1054
|
+
if (config.debug) {
|
|
1055
|
+
ctx.logger.debug(`所有西瓜API尝试失败, URL: ${realUrl}`);
|
|
1056
|
+
}
|
|
1057
|
+
else {
|
|
1058
|
+
ctx.logger.error(`西瓜解析失败: ${realUrl}`);
|
|
1059
|
+
}
|
|
799
1060
|
return { data: null, msg: '西瓜视频解析失败' };
|
|
800
1061
|
}
|
|
801
1062
|
const currentPlatform = platform;
|
|
@@ -803,16 +1064,32 @@ function apply(ctx, config) {
|
|
|
803
1064
|
if (nonKuaishouPlatforms.includes(currentPlatform)) {
|
|
804
1065
|
for (let retry = 0; retry <= config.retryTimes; retry++) {
|
|
805
1066
|
try {
|
|
806
|
-
const
|
|
1067
|
+
const universalUrl = API_CONFIG.universal;
|
|
1068
|
+
if (config.debug)
|
|
1069
|
+
ctx.logger.debug(`请求通用API: ${universalUrl}, 参数: { url: ${realUrl} }`);
|
|
1070
|
+
const res = await http.get(universalUrl, { params: { url: realUrl } });
|
|
1071
|
+
if (config.debug)
|
|
1072
|
+
ctx.logger.debug(`通用API响应状态: ${res.status}`);
|
|
807
1073
|
if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
|
|
808
1074
|
const parseResult = parseData(res.data.data, config.maxDescLength, currentPlatform);
|
|
1075
|
+
if (config.debug)
|
|
1076
|
+
ctx.logger.debug('通用API解析成功');
|
|
809
1077
|
return { data: parseResult, msg: '解析成功' };
|
|
810
1078
|
}
|
|
811
1079
|
else if (res.data.code === 201) {
|
|
1080
|
+
if (config.debug)
|
|
1081
|
+
ctx.logger.debug('通用API返回code 201');
|
|
812
1082
|
break;
|
|
813
1083
|
}
|
|
1084
|
+
else {
|
|
1085
|
+
if (config.debug)
|
|
1086
|
+
ctx.logger.debug('通用API返回数据无效');
|
|
1087
|
+
}
|
|
814
1088
|
}
|
|
815
1089
|
catch (error) {
|
|
1090
|
+
if (config.debug) {
|
|
1091
|
+
ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
|
|
1092
|
+
}
|
|
816
1093
|
if (retry === config.retryTimes)
|
|
817
1094
|
break;
|
|
818
1095
|
await delay(config.retryInterval);
|
|
@@ -824,7 +1101,11 @@ function apply(ctx, config) {
|
|
|
824
1101
|
const apiUrl = platformApis[apiIndex];
|
|
825
1102
|
for (let retry = 0; retry <= config.retryTimes; retry++) {
|
|
826
1103
|
try {
|
|
1104
|
+
if (config.debug)
|
|
1105
|
+
ctx.logger.debug(`请求平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
|
|
827
1106
|
const res = await http.get(apiUrl, { params: { url: realUrl } });
|
|
1107
|
+
if (config.debug)
|
|
1108
|
+
ctx.logger.debug(`平台API响应状态: ${res.status}`);
|
|
828
1109
|
let shouldContinue = false;
|
|
829
1110
|
if ((res.data.code === 200 || res.data.code === 0)) {
|
|
830
1111
|
let parseResult = null;
|
|
@@ -853,24 +1134,39 @@ function apply(ctx, config) {
|
|
|
853
1134
|
}
|
|
854
1135
|
}
|
|
855
1136
|
if (parseResult) {
|
|
1137
|
+
if (config.debug)
|
|
1138
|
+
ctx.logger.debug('平台API解析成功');
|
|
856
1139
|
return { data: parseResult, msg: '解析成功' };
|
|
857
1140
|
}
|
|
858
1141
|
}
|
|
859
1142
|
if (shouldContinue && retry < config.retryTimes) {
|
|
1143
|
+
if (config.debug)
|
|
1144
|
+
ctx.logger.debug('平台API返回数据无效,准备重试');
|
|
860
1145
|
await delay(config.retryInterval);
|
|
861
1146
|
continue;
|
|
862
1147
|
}
|
|
863
1148
|
else {
|
|
1149
|
+
if (config.debug)
|
|
1150
|
+
ctx.logger.debug('平台API返回数据无效,放弃');
|
|
864
1151
|
break;
|
|
865
1152
|
}
|
|
866
1153
|
}
|
|
867
1154
|
catch (error) {
|
|
1155
|
+
if (config.debug) {
|
|
1156
|
+
ctx.logger.debug(`平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
|
|
1157
|
+
}
|
|
868
1158
|
if (retry === config.retryTimes)
|
|
869
1159
|
break;
|
|
870
1160
|
await delay(config.retryInterval);
|
|
871
1161
|
}
|
|
872
1162
|
}
|
|
873
1163
|
}
|
|
1164
|
+
if (config.debug) {
|
|
1165
|
+
ctx.logger.debug(`所有API尝试失败,平台: ${platform}, URL: ${realUrl}`);
|
|
1166
|
+
}
|
|
1167
|
+
else {
|
|
1168
|
+
ctx.logger.error(`解析失败: ${platform} ${realUrl}`);
|
|
1169
|
+
}
|
|
874
1170
|
return { data: null, msg: '解析失败,请稍后重试' };
|
|
875
1171
|
}
|
|
876
1172
|
async function processSingleUrl(session, url) {
|
|
@@ -925,8 +1221,17 @@ function apply(ctx, config) {
|
|
|
925
1221
|
}
|
|
926
1222
|
else {
|
|
927
1223
|
errs.push(`【${url.slice(0, 22)}...】:${result.msg}`);
|
|
1224
|
+
if (config.debug) {
|
|
1225
|
+
ctx.logger.debug(`解析失败: ${url}, 原因: ${result.msg}`);
|
|
1226
|
+
}
|
|
1227
|
+
else {
|
|
1228
|
+
ctx.logger.error(`解析失败: ${url}, 原因: ${result.msg}`);
|
|
1229
|
+
}
|
|
928
1230
|
}
|
|
929
1231
|
}
|
|
1232
|
+
if (errs.length) {
|
|
1233
|
+
ctx.logger.error(`解析失败数量: ${errs.length}, 示例: ${errs[0]}`);
|
|
1234
|
+
}
|
|
930
1235
|
const enableForward = config.enableForward && session.platform === 'onebot';
|
|
931
1236
|
const forwardMessages = [];
|
|
932
1237
|
const botName = config.botName || '视频解析机器人';
|
|
@@ -973,6 +1278,12 @@ function apply(ctx, config) {
|
|
|
973
1278
|
videoElem = koishi_1.h.file(filePath);
|
|
974
1279
|
}
|
|
975
1280
|
catch (error) {
|
|
1281
|
+
if (config.debug) {
|
|
1282
|
+
ctx.logger.debug(`视频下载失败: ${getErrorMessage(error)}`);
|
|
1283
|
+
}
|
|
1284
|
+
else {
|
|
1285
|
+
ctx.logger.error(`视频下载失败: ${getErrorMessage(error)}`);
|
|
1286
|
+
}
|
|
976
1287
|
videoElem = koishi_1.h.video(item.video);
|
|
977
1288
|
}
|
|
978
1289
|
}
|
|
@@ -1009,6 +1320,12 @@ function apply(ctx, config) {
|
|
|
1009
1320
|
videoElem = koishi_1.h.file(filePath);
|
|
1010
1321
|
}
|
|
1011
1322
|
catch (error) {
|
|
1323
|
+
if (config.debug) {
|
|
1324
|
+
ctx.logger.debug(`视频下载失败: ${getErrorMessage(error)}`);
|
|
1325
|
+
}
|
|
1326
|
+
else {
|
|
1327
|
+
ctx.logger.error(`视频下载失败: ${getErrorMessage(error)}`);
|
|
1328
|
+
}
|
|
1012
1329
|
videoElem = koishi_1.h.video(item.video);
|
|
1013
1330
|
}
|
|
1014
1331
|
}
|
|
@@ -1027,7 +1344,8 @@ function apply(ctx, config) {
|
|
|
1027
1344
|
}
|
|
1028
1345
|
}
|
|
1029
1346
|
catch (error) {
|
|
1030
|
-
|
|
1347
|
+
ctx.logger.error(`处理内容失败: ${getErrorMessage(error)}`);
|
|
1348
|
+
await sendTimeout(session, `❌ 处理${item.type}内容失败: ${getErrorMessage(error)}`);
|
|
1031
1349
|
}
|
|
1032
1350
|
}
|
|
1033
1351
|
if (enableForward && forwardMessages.length) {
|
|
@@ -1037,6 +1355,7 @@ function apply(ctx, config) {
|
|
|
1037
1355
|
await sendTimeout(session, forwardMsg);
|
|
1038
1356
|
}
|
|
1039
1357
|
catch (error) {
|
|
1358
|
+
ctx.logger.error(`合并转发失败: ${getErrorMessage(error)}`);
|
|
1040
1359
|
for (const node of forwardMessages) {
|
|
1041
1360
|
await sendTimeout(session, node.data.content);
|
|
1042
1361
|
await delay(500);
|
|
@@ -1114,7 +1433,9 @@ function apply(ctx, config) {
|
|
|
1114
1433
|
fs_1.default.unlinkSync(path_1.default.join(tempDir, file));
|
|
1115
1434
|
}
|
|
1116
1435
|
}
|
|
1117
|
-
catch (error) {
|
|
1436
|
+
catch (error) {
|
|
1437
|
+
ctx.logger.error(`清理临时文件失败: ${file}, ${getErrorMessage(error)}`);
|
|
1438
|
+
}
|
|
1118
1439
|
});
|
|
1119
1440
|
}, 1800000);
|
|
1120
1441
|
if (config.autoClearCacheInterval > 0) {
|
package/package.json
CHANGED