koishi-plugin-video-parser-all 0.4.0 → 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 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
@@ -15,72 +15,79 @@ const worker_threads_1 = require("worker_threads");
15
15
  exports.name = 'video-parser-all';
16
16
  exports.Config = koishi_1.Schema.intersect([
17
17
  koishi_1.Schema.object({
18
- enable: koishi_1.Schema.boolean().default(true),
19
- botName: koishi_1.Schema.string().default('视频解析机器人'),
20
- showWaitingTip: koishi_1.Schema.boolean().default(true),
21
- waitingTipText: koishi_1.Schema.string().default('正在解析视频,请稍候...'),
22
- sameLinkInterval: koishi_1.Schema.number().min(0).default(180),
23
- maxVideoSize: koishi_1.Schema.number().min(0).default(50),
24
- downloadThreads: koishi_1.Schema.number().min(0).default(4),
25
- }),
18
+ enable: koishi_1.Schema.boolean().default(true).description('是否启用视频解析插件'),
19
+ botName: koishi_1.Schema.string().default('视频解析机器人').description('机器人显示名称'),
20
+ showWaitingTip: koishi_1.Schema.boolean().default(true).description('解析时显示等待提示'),
21
+ waitingTipText: koishi_1.Schema.string().default('正在解析视频,请稍候...').description('等待提示文本内容'),
22
+ sameLinkInterval: koishi_1.Schema.number().min(0).default(180).description('相同链接重复解析间隔(秒)'),
23
+ maxVideoSize: koishi_1.Schema.number().min(0).default(50).description('允许发送的最大视频大小(MB)'),
24
+ downloadThreads: koishi_1.Schema.number().min(0).default(4).description('视频下载线程数'),
25
+ debug: koishi_1.Schema.boolean().default(false).description('调试模式,输出详细日志'),
26
+ }).description('基础设置'),
26
27
  koishi_1.Schema.object({
27
28
  platformEnable: koishi_1.Schema.object({
28
- bilibili: koishi_1.Schema.boolean().default(true),
29
- douyin: koishi_1.Schema.boolean().default(true),
30
- kuaishou: koishi_1.Schema.boolean().default(true),
31
- xigua: koishi_1.Schema.boolean().default(true),
32
- xiaohongshu: koishi_1.Schema.boolean().default(true),
33
- weibo: koishi_1.Schema.boolean().default(true),
34
- toutiao: koishi_1.Schema.boolean().default(true),
35
- pipigx: koishi_1.Schema.boolean().default(true),
36
- pipixia: koishi_1.Schema.boolean().default(true),
37
- zuiyou: koishi_1.Schema.boolean().default(true),
38
- })
39
- }),
29
+ bilibili: koishi_1.Schema.boolean().default(true).description('B站'),
30
+ douyin: koishi_1.Schema.boolean().default(true).description('抖音'),
31
+ kuaishou: koishi_1.Schema.boolean().default(true).description('快手'),
32
+ xigua: koishi_1.Schema.boolean().default(true).description('西瓜视频'),
33
+ xiaohongshu: koishi_1.Schema.boolean().default(true).description('小红书'),
34
+ weibo: koishi_1.Schema.boolean().default(true).description('微博'),
35
+ toutiao: koishi_1.Schema.boolean().default(true).description('今日头条'),
36
+ pipigx: koishi_1.Schema.boolean().default(true).description('皮皮搞笑'),
37
+ pipixia: koishi_1.Schema.boolean().default(true).description('皮皮虾'),
38
+ zuiyou: koishi_1.Schema.boolean().default(true).description('最右'),
39
+ }).description('启用平台(勾选即开启对应平台解析)')
40
+ }).description('平台开关'),
40
41
  koishi_1.Schema.object({
41
42
  platformFormat: koishi_1.Schema.object({
42
- bilibili: koishi_1.Schema.string().role('textarea').default('标题:${标题}\nUP主:${作者}\n简介:${简介}\n时长:${视频时长}\n点赞:${点赞数}\n投币:${投币数}\n收藏:${收藏数}\n转发:${转发数}'),
43
- douyin: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n点赞:${点赞数}\n收藏:${收藏数}\n转发:${转发数}'),
44
- kuaishou: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n点赞:${点赞数}\n播放:${播放数}\n转发:${转发数}'),
45
- xigua: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n播放:${播放数}\n点赞:${点赞数}\n视频大小:${视频大小}MB'),
46
- xiaohongshu: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}'),
47
- weibo: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}'),
48
- toutiao: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}'),
49
- pipigx: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}'),
50
- pipixia: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}'),
51
- zuiyou: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}'),
52
- })
53
- }),
43
+ bilibili: koishi_1.Schema.string().role('textarea').default('标题:${标题}\nUP主:${作者}\n简介:${简介}\n时长:${视频时长}\n点赞:${点赞数}\n投币:${投币数}\n收藏:${收藏数}\n转发:${转发数}').description('B站消息格式'),
44
+ douyin: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n点赞:${点赞数}\n收藏:${收藏数}\n转发:${转发数}').description('抖音消息格式'),
45
+ kuaishou: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n点赞:${点赞数}\n播放:${播放数}\n转发:${转发数}').description('快手消息格式'),
46
+ xigua: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n播放:${播放数}\n点赞:${点赞数}\n视频大小:${视频大小}MB').description('西瓜视频消息格式'),
47
+ xiaohongshu: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}').description('小红书消息格式'),
48
+ weibo: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}').description('微博消息格式'),
49
+ toutiao: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}').description('今日头条消息格式'),
50
+ pipigx: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}').description('皮皮搞笑消息格式'),
51
+ pipixia: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}').description('皮皮虾消息格式'),
52
+ zuiyou: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}').description('最右消息格式'),
53
+ }).description('各平台消息输出格式(支持${变量}占位符)')
54
+ }).description('消息格式'),
54
55
  koishi_1.Schema.object({
55
- showImageText: koishi_1.Schema.boolean().default(true),
56
- showVideoUrl: koishi_1.Schema.boolean().default(false),
57
- showVideoFile: koishi_1.Schema.boolean().default(true),
58
- }),
56
+ showImageText: koishi_1.Schema.boolean().default(true).description('显示图文内容'),
57
+ showVideoUrl: koishi_1.Schema.boolean().default(false).description('显示视频无水印链接'),
58
+ showVideoFile: koishi_1.Schema.boolean().default(true).description('发送视频文件(关闭则只发链接)'),
59
+ }).description('内容显示设置'),
59
60
  koishi_1.Schema.object({
60
- maxDescLength: koishi_1.Schema.number().default(200),
61
- }),
61
+ maxDescLength: koishi_1.Schema.number().default(200).description('简介内容最大长度(字符)'),
62
+ }).description('内容长度限制'),
62
63
  koishi_1.Schema.object({
63
- timeout: koishi_1.Schema.number().min(0).default(180000),
64
- videoSendTimeout: koishi_1.Schema.number().min(0).default(0),
65
- userAgent: koishi_1.Schema.string().default('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'),
66
- bilibiliAccessKey: koishi_1.Schema.string().default(''),
67
- }),
64
+ timeout: koishi_1.Schema.number().min(0).default(180000).description('API请求超时时间(毫秒)'),
65
+ videoSendTimeout: koishi_1.Schema.number().min(0).default(0).description('视频发送超时时间(毫秒,0为不限制)'),
66
+ userAgent: koishi_1.Schema.string().default('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36').description('请求UA标识'),
67
+ bilibiliAccessKey: koishi_1.Schema.string().default('').description('B站AccessKey(可选,用于高级解析)'),
68
+ }).description('网络与API设置'),
68
69
  koishi_1.Schema.object({
69
- ignoreSendError: koishi_1.Schema.boolean().default(true),
70
- retryTimes: koishi_1.Schema.number().min(0).default(0),
71
- retryInterval: koishi_1.Schema.number().min(0).default(0),
72
- }),
70
+ ignoreSendError: koishi_1.Schema.boolean().default(true).description('忽略发送失败错误'),
71
+ retryTimes: koishi_1.Schema.number().min(0).default(0).description('API请求重试次数'),
72
+ retryInterval: koishi_1.Schema.number().min(0).default(0).description('重试间隔时间(毫秒)'),
73
+ }).description('错误与重试设置'),
73
74
  koishi_1.Schema.object({
74
- enableForward: koishi_1.Schema.boolean().default(false),
75
- downloadVideoBeforeSend: koishi_1.Schema.boolean().default(false),
76
- }),
75
+ enableForward: koishi_1.Schema.boolean().default(false).description('启用合并转发(仅OneBot平台)'),
76
+ downloadVideoBeforeSend: koishi_1.Schema.boolean().default(false).description('发送前先下载视频(避免链接失效)'),
77
+ }).description('发送方式设置'),
77
78
  koishi_1.Schema.object({
78
- messageBufferDelay: koishi_1.Schema.number().min(0).default(0),
79
- }),
79
+ messageBufferDelay: koishi_1.Schema.number().min(0).default(0).description('消息缓冲延迟(毫秒,批量处理链接)'),
80
+ }).description('消息处理设置'),
80
81
  koishi_1.Schema.object({
81
- autoClearCacheInterval: koishi_1.Schema.number().min(0).default(0),
82
- }),
82
+ autoClearCacheInterval: koishi_1.Schema.number().min(0).default(0).description('自动清理缓存间隔(分钟,0为关闭)'),
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: API_CONFIG.xingzhige.bilibili.vidUrl,
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
- const res = await http.get(API_CONFIG.universal, { params: { url: realUrl } });
646
- if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
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
- catch (e) { }
652
- try {
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 (e) { }
671
- const platformApis = API_CONFIG.platform.bilibili || [];
672
- for (const apiUrl of platformApis) {
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: API_CONFIG.xingzhige.kuaishou.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
- const res = await http.get(API_CONFIG.universal, { params: { url: realUrl } });
703
- if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
704
- const parseResult = parseData(res.data.data, config.maxDescLength, platform);
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
- catch (e) { }
709
- const platformApis = API_CONFIG.platform.kuaishou || [];
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
- catch (error) {
719
- continue;
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: API_CONFIG.xingzhige.douyin.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
- const res = await http.get(API_CONFIG.universal, { params: { url: realUrl } });
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
- catch (e) { }
747
- const platformApis = API_CONFIG.platform.douyin || [];
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
- catch (error) {
757
- continue;
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: API_CONFIG.xingzhige.xigua.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
- const res = await http.get(API_CONFIG.universal, { params: { url: realUrl } });
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
- catch (e) { }
785
- const platformApis = API_CONFIG.platform.xigua || [];
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
- catch (error) {
795
- continue;
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 res = await http.get(API_CONFIG.universal, { params: { url: realUrl } });
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
- await sendTimeout(session, `❌ 处理${item.type}内容失败: ${error.message}`);
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-video-parser-all",
3
3
  "description": "Koishi 全平台视频解析插件,支持抖音/快手/B站/小红书/微博/今日头条/皮皮搞笑/皮皮虾/西瓜视频/最右视频链接解析",
4
- "version": "0.4.0",
4
+ "version": "0.4.2",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [