koishi-plugin-video-parser-all 0.4.2 → 0.4.4

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.
Files changed (3) hide show
  1. package/lib/index.d.ts +26 -0
  2. package/lib/index.js +565 -506
  3. package/package.json +1 -1
package/lib/index.d.ts CHANGED
@@ -57,6 +57,19 @@ export declare const Config: Schema<{
57
57
  messageBufferDelay?: number | null | undefined;
58
58
  } & {
59
59
  autoClearCacheInterval?: number | null | undefined;
60
+ } & {
61
+ preferredApi?: ({
62
+ bilibili?: "xingzhige" | "universal" | "platform" | "official" | null | undefined;
63
+ douyin?: "xingzhige" | "universal" | "platform" | null | undefined;
64
+ kuaishou?: "xingzhige" | "universal" | "platform" | null | undefined;
65
+ xigua?: "xingzhige" | "universal" | "platform" | null | undefined;
66
+ xiaohongshu?: "universal" | "platform" | null | undefined;
67
+ weibo?: "universal" | "platform" | null | undefined;
68
+ toutiao?: "universal" | "platform" | null | undefined;
69
+ pipigx?: "universal" | "platform" | null | undefined;
70
+ pipixia?: "universal" | "platform" | null | undefined;
71
+ zuiyou?: "universal" | "platform" | null | undefined;
72
+ } & Dict) | null | undefined;
60
73
  }, {
61
74
  enable: boolean;
62
75
  botName: string;
@@ -114,5 +127,18 @@ export declare const Config: Schema<{
114
127
  messageBufferDelay: number;
115
128
  } & {
116
129
  autoClearCacheInterval: number;
130
+ } & {
131
+ preferredApi: Schemastery.ObjectT<{
132
+ bilibili: Schema<"xingzhige" | "universal" | "platform" | "official", "xingzhige" | "universal" | "platform" | "official">;
133
+ douyin: Schema<"xingzhige" | "universal" | "platform", "xingzhige" | "universal" | "platform">;
134
+ kuaishou: Schema<"xingzhige" | "universal" | "platform", "xingzhige" | "universal" | "platform">;
135
+ xigua: Schema<"xingzhige" | "universal" | "platform", "xingzhige" | "universal" | "platform">;
136
+ xiaohongshu: Schema<"universal" | "platform", "universal" | "platform">;
137
+ weibo: Schema<"universal" | "platform", "universal" | "platform">;
138
+ toutiao: Schema<"universal" | "platform", "universal" | "platform">;
139
+ pipigx: Schema<"universal" | "platform", "universal" | "platform">;
140
+ pipixia: Schema<"universal" | "platform", "universal" | "platform">;
141
+ zuiyou: Schema<"universal" | "platform", "universal" | "platform">;
142
+ }>;
117
143
  }>;
118
144
  export declare function apply(ctx: any, config: any): void;
package/lib/index.js CHANGED
@@ -81,8 +81,21 @@ exports.Config = koishi_1.Schema.intersect([
81
81
  koishi_1.Schema.object({
82
82
  autoClearCacheInterval: koishi_1.Schema.number().min(0).default(0).description('自动清理缓存间隔(分钟,0为关闭)'),
83
83
  }).description('缓存清理设置'),
84
+ koishi_1.Schema.object({
85
+ preferredApi: koishi_1.Schema.object({
86
+ bilibili: koishi_1.Schema.union(['xingzhige', 'universal', 'platform', 'official']).default('xingzhige').description('B站首选解析源'),
87
+ douyin: koishi_1.Schema.union(['xingzhige', 'universal', 'platform']).default('xingzhige').description('抖音首选解析源'),
88
+ kuaishou: koishi_1.Schema.union(['xingzhige', 'universal', 'platform']).default('xingzhige').description('快手首选解析源'),
89
+ xigua: koishi_1.Schema.union(['xingzhige', 'universal', 'platform']).default('xingzhige').description('西瓜视频首选解析源'),
90
+ xiaohongshu: koishi_1.Schema.union(['universal', 'platform']).default('universal').description('小红书首选解析源'),
91
+ weibo: koishi_1.Schema.union(['universal', 'platform']).default('universal').description('微博首选解析源'),
92
+ toutiao: koishi_1.Schema.union(['universal', 'platform']).default('universal').description('今日头条首选解析源'),
93
+ pipigx: koishi_1.Schema.union(['universal', 'platform']).default('universal').description('皮皮搞笑首选解析源'),
94
+ pipixia: koishi_1.Schema.union(['universal', 'platform']).default('universal').description('皮皮虾首选解析源'),
95
+ zuiyou: koishi_1.Schema.union(['universal', 'platform']).default('universal').description('最右首选解析源'),
96
+ }).description('首选解析源设置(将优先尝试用户选择的API,失败后自动尝试其他)')
97
+ }).description('API选择设置'),
84
98
  ]);
85
- // 辅助函数:安全获取错误消息
86
99
  function getErrorMessage(error) {
87
100
  if (error instanceof Error)
88
101
  return error.message;
@@ -149,24 +162,24 @@ const PLATFORM_KEYWORDS = {
149
162
  universal_card: ['mini_program', '小程序卡片', 'lightapp', 'json', 'markdown', 'share', 'contact', 'location', 'music', 'forward', 'node', 'mface', 'file']
150
163
  };
151
164
  const API_CONFIG = {
152
- universal: 'https://api.bugpk.com/api/short_videos',
165
+ universal: 'https://api.bugpk.com/api/short_videos ',
153
166
  xingzhige: {
154
- bilibili: { url: 'https://api.xingzhige.com/API/b_parse/', vidUrl: 'https://api.xingzhige.com/API/b_video/', bangumiUrl: 'https://api.xingzhige.com/API/b_bangumi/' },
155
- kuaishou: { url: 'https://api.xingzhige.com/API/kuaishou/' },
156
- douyin: { url: 'https://api.xingzhige.com/API/douyin/' },
157
- xigua: { url: 'https://api.xingzhige.com/API/xigua/' }
167
+ bilibili: { url: 'https://api.xingzhige.com/API/b_parse/ ', vidUrl: 'https://api.xingzhige.com/API/b_parse/ ', bangumiUrl: 'https://api.xingzhige.com/API/b_bangumi/ ' },
168
+ kuaishou: { url: 'https://api.xingzhige.com/API/kuaishou/ ' },
169
+ douyin: { url: 'https://api.xingzhige.com/API/douyin/ ' },
170
+ xigua: { url: 'https://api.xingzhige.com/API/xigua/ ' }
158
171
  },
159
172
  platform: {
160
- bilibili: ['https://api.bugpk.com/api/bilibili'],
161
- kuaishou: ['https://api.bugpk.com/api/ksjx', 'https://api.bugpk.com/api/kuaishou', 'https://api.bugpk.com/api/ksimg', 'https://api.suyanw.cn/api/kuaishou.php'],
162
- xiaohongshu: ['https://api.bugpk.com/api/xhsjx', 'https://api.bugpk.com/api/xhsimg', 'https://api.bugpk.com/api/xhslive'],
163
- weibo: ['https://api.bugpk.com/api/weibo', 'https://api.bugpk.com/api/weibo_v'],
164
- toutiao: ['https://api.bugpk.com/api/toutiao'],
165
- pipigx: ['https://api.bugpk.com/api/pipigx', 'https://api.suyanw.cn/api/pipigx.php'],
166
- pipixia: ['https://api.bugpk.com/api/pipixia'],
167
- douyin: ['https://api.bugpk.com/api/douyin', 'https://api.bugpk.com/api/dyjx', 'https://api.bugpk.com/api/dylive'],
168
- zuiyou: ['https://api.suyanw.cn/api/zuiyou.php'],
169
- xigua: ['https://api.bugpk.com/api/toutiao']
173
+ bilibili: ['https://api.bugpk.com/api/bilibili '],
174
+ kuaishou: ['https://api.bugpk.com/api/ksjx ', 'https://api.bugpk.com/api/kuaishou ', 'https://api.bugpk.com/api/ksimg ', 'https://api.suyanw.cn/api/kuaishou.php '],
175
+ xiaohongshu: ['https://api.bugpk.com/api/xhsjx ', 'https://api.bugpk.com/api/xhsimg ', 'https://api.bugpk.com/api/xhslive '],
176
+ weibo: ['https://api.bugpk.com/api/weibo ', 'https://api.bugpk.com/api/weibo_v '],
177
+ toutiao: ['https://api.bugpk.com/api/toutiao '],
178
+ pipigx: ['https://api.bugpk.com/api/pipigx ', 'https://api.suyanw.cn/api/pipigx.php '],
179
+ pipixia: ['https://api.bugpk.com/api/pipixia '],
180
+ douyin: ['https://api.bugpk.com/api/douyin ', 'https://api.bugpk.com/api/dyjx ', 'https://api.bugpk.com/api/dylive '],
181
+ zuiyou: ['https://api.suyanw.cn/api/zuiyou.php '],
182
+ xigua: ['https://api.bugpk.com/api/toutiao ']
170
183
  }
171
184
  };
172
185
  function vid_type_parse(id) {
@@ -187,10 +200,10 @@ async function fetch_bilibili_official_info(id, userAgent) {
187
200
  let url = '';
188
201
  switch (vid.type) {
189
202
  case "av":
190
- url = `https://api.bilibili.com/x/web-interface/view?aid=${vid.id}`;
203
+ url = `https://api.bilibili.com/x/web-interface/view?aid= ${vid.id}`;
191
204
  break;
192
205
  case "bv":
193
- url = `https://api.bilibili.com/x/web-interface/view?bvid=${vid.id}`;
206
+ url = `https://api.bilibili.com/x/web-interface/view?bvid= ${vid.id}`;
194
207
  break;
195
208
  default:
196
209
  return null;
@@ -208,11 +221,11 @@ async function fetch_bilibili_official_info(id, userAgent) {
208
221
  }
209
222
  async function get_bilibili_play_url(bvid, cid, userAgent) {
210
223
  try {
211
- const playUrl = `https://api.bilibili.com/x/player/playurl?fnval=80&cid=${cid}&bvid=${bvid}`;
224
+ const playUrl = `https://api.bilibili.com/x/player/playurl?fnval=80&cid= ${cid}&bvid=${bvid}`;
212
225
  const playData = await axios_1.default.get(playUrl, {
213
226
  headers: {
214
227
  "User-Agent": userAgent,
215
- "Referer": "https://www.bilibili.com/"
228
+ "Referer": "https://www.bilibili.com/ "
216
229
  },
217
230
  timeout: 10000
218
231
  });
@@ -285,20 +298,21 @@ function parse_xingzhige_data(resData, platform) {
285
298
  result.type = result.images.length > 0 ? 'image' : 'video';
286
299
  }
287
300
  else if (platform === 'bilibili') {
288
- result.title = resData.title || '';
289
- result.author = resData.name || '未知UP主';
290
- result.desc = resData.desc || '';
291
- result.cover = resData.fm || '';
292
- result.video = resData.url || '';
301
+ const d = resData.data || resData;
302
+ result.title = d.video?.title || d.title || '';
303
+ result.author = d.owner?.name || d.name || '未知UP主';
304
+ result.desc = d.video?.desc || d.desc || '';
305
+ result.cover = d.video?.fm || d.fm || '';
306
+ result.video = d.video?.url || d.url || '';
293
307
  result.stat = {
294
- view: resData.view || 0,
295
- reply: resData.reply || 0,
296
- favorite: resData.favorite || 0,
297
- like: resData.like || 0,
298
- coin: resData.coin || 0,
299
- share: resData.share || 0,
300
- danmuku: resData.danmuku || 0,
301
- duration: resData.duration || 0
308
+ view: d.stat?.view || 0,
309
+ reply: d.stat?.reply || 0,
310
+ favorite: d.stat?.favorite || 0,
311
+ like: d.stat?.like || 0,
312
+ coin: d.stat?.coin || 0,
313
+ share: d.stat?.share || 0,
314
+ danmuku: d.stat?.danmuku || 0,
315
+ duration: d.duration || 0
302
316
  };
303
317
  }
304
318
  else if (platform === 'bilibili_bangumi') {
@@ -359,7 +373,7 @@ function extractCardUrl(content) {
359
373
  if (appid === '1108291530') {
360
374
  const vidMatch = jsonData.data.pagePath.match(/vid=(\w+)/);
361
375
  if (vidMatch)
362
- realUrls.push(`https://www.bilibili.com/video/${vidMatch[1]}`);
376
+ realUrls.push(`https://www.bilibili.com/video/ ${vidMatch[1]}`);
363
377
  }
364
378
  }
365
379
  }
@@ -455,7 +469,7 @@ async function resolveShortUrl(url) {
455
469
  }
456
470
  async function shortUrl(url) {
457
471
  try {
458
- const res = await axios_1.default.get('https://api.oick.cn/dwz/api.php', { params: { url }, timeout: 5000 });
472
+ const res = await axios_1.default.get('https://api.oick.cn/dwz/api.php ', { params: { url }, timeout: 5000 });
459
473
  if (res.data.code === 200)
460
474
  return res.data.short_url;
461
475
  }
@@ -581,15 +595,22 @@ function clearAllCache() {
581
595
  }
582
596
  const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
583
597
  function buildForwardNode(session, content, botName) {
584
- return {
585
- type: 'node',
586
- data: {
587
- name: botName.substring(0, 15),
588
- uin: session.selfId.toString(),
589
- content: Array.isArray(content) ? content : [koishi_1.h.text(content)],
590
- time: Math.floor(Date.now() / 1000)
598
+ let messageContent;
599
+ if (Array.isArray(content)) {
600
+ messageContent = content;
601
+ }
602
+ else if (content && typeof content === 'object' && content.type) {
603
+ messageContent = [content];
604
+ }
605
+ else {
606
+ messageContent = [koishi_1.h.text(String(content))];
607
+ }
608
+ return (0, koishi_1.h)('node', {
609
+ user: {
610
+ nickname: botName.substring(0, 15),
611
+ user_id: session.selfId
591
612
  }
592
- };
613
+ }, messageContent);
593
614
  }
594
615
  function apply(ctx, config) {
595
616
  if (!worker_threads_1.isMainThread)
@@ -609,177 +630,187 @@ function apply(ctx, config) {
609
630
  return { data: null, msg: platform ? '该平台解析已关闭' : '不支持该平台链接' };
610
631
  }
611
632
  if (platform === 'bilibili') {
612
- const bangumiIds = extract_bangumi_ids(realUrl);
613
- if (bangumiIds.ss_id || bangumiIds.ep_id) {
614
- try {
615
- const params = {};
616
- if (bangumiIds.ss_id)
617
- params.ss_id = bangumiIds.ss_id;
618
- if (bangumiIds.ep_id)
619
- params.ep_id = bangumiIds.ep_id;
620
- if (config.bilibiliAccessKey)
621
- params.access_key = config.bilibiliAccessKey;
622
- if (config.debug)
623
- ctx.logger.debug(`请求B站番剧API: ${API_CONFIG.xingzhige.bilibili.bangumiUrl}, 参数: ${JSON.stringify(params)}`);
624
- const res = await http({
625
- method: 'GET',
626
- url: API_CONFIG.xingzhige.bilibili.bangumiUrl,
627
- params
628
- });
629
- if (config.debug)
630
- ctx.logger.debug(`B站番剧API响应状态: ${res.status}`);
631
- if (res.data && (res.data.season || res.data.bangumi)) {
632
- const xgData = parse_xingzhige_data(res.data, 'bilibili_bangumi');
633
- const parseResult = parseData(xgData, config.maxDescLength, 'bilibili_bangumi');
634
- if (config.debug)
635
- ctx.logger.debug('B站番剧解析成功');
636
- return { data: parseResult, msg: 'B站解析成功' };
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
- }
650
- }
633
+ const preferred = config.preferredApi?.bilibili || 'xingzhige';
634
+ // 根据首选源构建尝试顺序
635
+ const tryOrder = [];
636
+ if (preferred === 'xingzhige') {
637
+ tryOrder.push('xingzhige_vid', 'xingzhige_bangumi', 'universal', 'official', 'platform');
651
638
  }
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)}`);
663
- const res = await http({
664
- method: 'GET',
665
- url: apiUrl,
666
- params
667
- });
668
- if (config.debug)
669
- ctx.logger.debug(`B站VID API响应状态: ${res.status}`);
670
- if (res.data && (res.data.url || res.data.title)) {
671
- const xgData = parse_xingzhige_data(res.data, platform);
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
- }
639
+ else if (preferred === 'universal') {
640
+ tryOrder.push('universal', 'xingzhige_vid', 'xingzhige_bangumi', 'official', 'platform');
681
641
  }
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
- }
642
+ else if (preferred === 'official') {
643
+ tryOrder.push('official', 'xingzhige_vid', 'xingzhige_bangumi', 'universal', 'platform');
689
644
  }
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解析成功');
701
- return { data: parseResult, msg: 'B站解析成功' };
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
- }
645
+ else if (preferred === 'platform') {
646
+ tryOrder.push('platform', 'xingzhige_vid', 'xingzhige_bangumi', 'universal', 'official');
715
647
  }
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;
648
+ for (const step of tryOrder) {
649
+ if (step === 'xingzhige_vid') {
650
+ try {
651
+ const apiUrl = API_CONFIG.xingzhige.bilibili.vidUrl;
652
+ const params = { url: realUrl };
653
+ if (config.debug)
654
+ ctx.logger.debug(`${apiUrl}?${new URLSearchParams(params).toString()}`);
655
+ const res = await http({
656
+ method: 'GET',
657
+ url: apiUrl,
658
+ params
659
+ });
724
660
  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);
661
+ ctx.logger.debug(`响应状态: ${res.status}`);
662
+ if (res.data && (res.data.data || res.data.title)) {
663
+ const xgData = parse_xingzhige_data(res.data, platform);
664
+ const parseResult = parseData(xgData, config.maxDescLength, platform);
733
665
  if (config.debug)
734
- ctx.logger.debug('B站官方API解析成功');
666
+ ctx.logger.debug('解析成功');
735
667
  return { data: parseResult, msg: 'B站解析成功' };
736
668
  }
737
669
  else {
738
670
  if (config.debug)
739
- ctx.logger.debug('B站官方播放地址获取失败');
671
+ ctx.logger.debug('返回数据无效');
740
672
  }
741
673
  }
742
- else {
743
- if (config.debug)
744
- ctx.logger.debug('B站官方信息获取失败');
674
+ catch (error) {
675
+ if (config.debug) {
676
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
677
+ }
745
678
  }
746
679
  }
747
- }
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)}`);
680
+ else if (step === 'xingzhige_bangumi') {
681
+ const bangumiIds = extract_bangumi_ids(realUrl);
682
+ if (bangumiIds.ss_id || bangumiIds.ep_id) {
683
+ try {
684
+ const params = {};
685
+ if (bangumiIds.ss_id)
686
+ params.ss_id = bangumiIds.ss_id;
687
+ if (bangumiIds.ep_id)
688
+ params.ep_id = bangumiIds.ep_id;
689
+ if (config.bilibiliAccessKey)
690
+ params.access_key = config.bilibiliAccessKey;
691
+ const apiUrl = API_CONFIG.xingzhige.bilibili.bangumiUrl;
692
+ if (config.debug)
693
+ ctx.logger.debug(`${apiUrl}?${new URLSearchParams(params).toString()}`);
694
+ const res = await http({
695
+ method: 'GET',
696
+ url: apiUrl,
697
+ params
698
+ });
699
+ if (config.debug)
700
+ ctx.logger.debug(`响应状态: ${res.status}`);
701
+ if (res.data && (res.data.season || res.data.bangumi)) {
702
+ const xgData = parse_xingzhige_data(res.data, 'bilibili_bangumi');
703
+ const parseResult = parseData(xgData, config.maxDescLength, 'bilibili_bangumi');
704
+ if (config.debug)
705
+ ctx.logger.debug('解析成功');
706
+ return { data: parseResult, msg: 'B站解析成功' };
707
+ }
708
+ else {
709
+ if (config.debug)
710
+ ctx.logger.debug('返回数据无效');
711
+ }
712
+ }
713
+ catch (error) {
714
+ if (config.debug) {
715
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
716
+ }
717
+ }
718
+ }
754
719
  }
755
- }
756
- const platformApis = API_CONFIG.platform.bilibili || [];
757
- for (const apiUrl of platformApis) {
758
- try {
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) {
765
- const parseResult = parseData(res.data.data, config.maxDescLength, platform);
720
+ else if (step === 'universal') {
721
+ try {
722
+ const universalUrl = API_CONFIG.universal;
766
723
  if (config.debug)
767
- ctx.logger.debug('B站平台API解析成功');
768
- return { data: parseResult, msg: 'B站解析成功' };
769
- }
770
- else {
724
+ ctx.logger.debug(`${universalUrl}?url=${encodeURIComponent(realUrl)}`);
725
+ const res = await http.get(universalUrl, { params: { url: realUrl } });
771
726
  if (config.debug)
772
- ctx.logger.debug('B站平台API返回数据无效');
727
+ ctx.logger.debug(`响应状态: ${res.status}`);
728
+ if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
729
+ const parseResult = parseData(res.data.data, config.maxDescLength, platform);
730
+ if (config.debug)
731
+ ctx.logger.debug('解析成功');
732
+ return { data: parseResult, msg: 'B站解析成功' };
733
+ }
734
+ else {
735
+ if (config.debug)
736
+ ctx.logger.debug('返回数据无效');
737
+ }
738
+ }
739
+ catch (error) {
740
+ if (config.debug) {
741
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
742
+ }
773
743
  }
774
744
  }
775
- catch (error) {
776
- if (config.debug) {
777
- ctx.logger.debug(`B站平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
745
+ else if (step === 'official') {
746
+ try {
747
+ const biliId = realUrl.startsWith('BV') || realUrl.startsWith('av') || realUrl.startsWith('AV') ? realUrl : extract_bilibili_id(realUrl);
748
+ if (biliId) {
749
+ if (config.debug)
750
+ ctx.logger.debug(`官方信息获取: ${biliId}`);
751
+ const officialInfo = await fetch_bilibili_official_info(biliId, config.userAgent);
752
+ if (officialInfo && officialInfo.code === 0 && officialInfo.data) {
753
+ const { bvid, cid } = officialInfo.data;
754
+ if (config.debug)
755
+ ctx.logger.debug(`官方播放地址: bvid=${bvid}, cid=${cid}`);
756
+ const playInfo = await get_bilibili_play_url(bvid, cid, config.userAgent);
757
+ if (playInfo) {
758
+ const parseResult = parseData({
759
+ ...officialInfo,
760
+ playUrl: playInfo.url,
761
+ duration: playInfo.duration
762
+ }, config.maxDescLength, platform);
763
+ if (config.debug)
764
+ ctx.logger.debug('解析成功');
765
+ return { data: parseResult, msg: 'B站解析成功' };
766
+ }
767
+ else {
768
+ if (config.debug)
769
+ ctx.logger.debug('播放地址获取失败');
770
+ }
771
+ }
772
+ else {
773
+ if (config.debug)
774
+ ctx.logger.debug('官方信息获取失败');
775
+ }
776
+ }
777
+ }
778
+ catch (error) {
779
+ if (config.debug) {
780
+ ctx.logger.debug(`官方API请求失败: ${getErrorMessage(error)}`);
781
+ }
782
+ }
783
+ }
784
+ else if (step === 'platform') {
785
+ const platformApis = API_CONFIG.platform.bilibili || [];
786
+ for (const apiUrl of platformApis) {
787
+ try {
788
+ if (config.debug)
789
+ ctx.logger.debug(`${apiUrl}?url=${encodeURIComponent(realUrl)}`);
790
+ const res = await http.get(apiUrl, { params: { url: realUrl } });
791
+ if (config.debug)
792
+ ctx.logger.debug(`响应状态: ${res.status}`);
793
+ if ((res.data.code === 0 || res.data.code === 200) && res.data.data) {
794
+ const parseResult = parseData(res.data.data, config.maxDescLength, platform);
795
+ if (config.debug)
796
+ ctx.logger.debug('解析成功');
797
+ return { data: parseResult, msg: 'B站解析成功' };
798
+ }
799
+ else {
800
+ if (config.debug)
801
+ ctx.logger.debug('返回数据无效');
802
+ }
803
+ }
804
+ catch (error) {
805
+ if (config.debug) {
806
+ ctx.logger.debug(`请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
807
+ }
808
+ }
778
809
  }
779
810
  }
780
811
  }
781
812
  if (config.debug) {
782
- ctx.logger.debug(`所有B站API尝试失败, URL: ${realUrl}`);
813
+ ctx.logger.debug(`所有API尝试失败, URL: ${realUrl}`);
783
814
  }
784
815
  else {
785
816
  ctx.logger.error(`B站解析失败: ${realUrl}`);
@@ -787,85 +818,91 @@ function apply(ctx, config) {
787
818
  return { data: null, msg: 'B站解析失败' };
788
819
  }
789
820
  if (platform === 'kuaishou') {
790
- try {
791
- const apiUrl = API_CONFIG.xingzhige.kuaishou.url;
792
- if (config.debug)
793
- ctx.logger.debug(`请求快手xingzhige API: ${apiUrl}, 参数: { url: ${realUrl} }`);
794
- const res = await http({
795
- method: 'GET',
796
- url: apiUrl,
797
- params: { url: realUrl }
798
- });
799
- if (config.debug)
800
- ctx.logger.debug(`快手xingzhige API响应状态: ${res.status}`);
801
- if (res.data && res.data.jx && res.data.jx.length > 0) {
802
- const xgData = parse_xingzhige_data(res.data, platform);
803
- const parseResult = parseData(xgData, config.maxDescLength, platform);
804
- if (config.debug)
805
- ctx.logger.debug('快手xingzhige解析成功');
806
- return { data: parseResult, msg: '快手解析成功' };
807
- }
808
- else {
809
- if (config.debug)
810
- ctx.logger.debug('快手xingzhige API返回数据无效');
811
- }
812
- }
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) {
849
- try {
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);
821
+ const preferred = config.preferredApi?.kuaishou || 'xingzhige';
822
+ const tryOrder = preferred === 'xingzhige' ? ['xingzhige', 'universal', 'platform'] :
823
+ preferred === 'universal' ? ['universal', 'xingzhige', 'platform'] :
824
+ ['platform', 'xingzhige', 'universal'];
825
+ for (const step of tryOrder) {
826
+ if (step === 'xingzhige') {
827
+ try {
828
+ const apiUrl = API_CONFIG.xingzhige.kuaishou.url;
829
+ if (config.debug)
830
+ ctx.logger.debug(`${apiUrl}?url=${encodeURIComponent(realUrl)}`);
831
+ const res = await http({
832
+ method: 'GET',
833
+ url: apiUrl,
834
+ params: { url: realUrl }
835
+ });
857
836
  if (config.debug)
858
- ctx.logger.debug('快手平台API解析成功');
859
- return { data: parseResult, msg: '快手解析成功' };
837
+ ctx.logger.debug(`响应状态: ${res.status}`);
838
+ if (res.data && res.data.jx && res.data.jx.length > 0) {
839
+ const xgData = parse_xingzhige_data(res.data, platform);
840
+ const parseResult = parseData(xgData, config.maxDescLength, platform);
841
+ if (config.debug)
842
+ ctx.logger.debug('解析成功');
843
+ return { data: parseResult, msg: '快手解析成功' };
844
+ }
845
+ else {
846
+ if (config.debug)
847
+ ctx.logger.debug('返回数据无效');
848
+ }
860
849
  }
861
- else {
850
+ catch (error) {
851
+ if (config.debug) {
852
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
853
+ }
854
+ }
855
+ }
856
+ else if (step === 'universal') {
857
+ try {
858
+ const universalUrl = API_CONFIG.universal;
859
+ if (config.debug)
860
+ ctx.logger.debug(`${universalUrl}?url=${encodeURIComponent(realUrl)}`);
861
+ const res = await http.get(universalUrl, { params: { url: realUrl } });
862
862
  if (config.debug)
863
- ctx.logger.debug('快手平台API返回数据无效');
863
+ ctx.logger.debug(`响应状态: ${res.status}`);
864
+ if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
865
+ const parseResult = parseData(res.data.data, config.maxDescLength, platform);
866
+ if (config.debug)
867
+ ctx.logger.debug('解析成功');
868
+ return { data: parseResult, msg: '快手解析成功' };
869
+ }
870
+ else {
871
+ if (config.debug)
872
+ ctx.logger.debug('返回数据无效');
873
+ }
874
+ }
875
+ catch (error) {
876
+ if (config.debug) {
877
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
878
+ }
864
879
  }
865
880
  }
866
- catch (error) {
867
- if (config.debug) {
868
- ctx.logger.debug(`快手平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
881
+ else if (step === 'platform') {
882
+ const platformApis = API_CONFIG.platform.kuaishou || [];
883
+ for (const apiUrl of platformApis) {
884
+ try {
885
+ if (config.debug)
886
+ ctx.logger.debug(`${apiUrl}?url=${encodeURIComponent(realUrl)}`);
887
+ const res = await http.get(apiUrl, { params: { url: realUrl } });
888
+ if (config.debug)
889
+ ctx.logger.debug(`响应状态: ${res.status}`);
890
+ if ((res.data.code === 200 || res.data.code === 0) && (res.data.data || res.data.image)) {
891
+ const parseResult = parseData(res.data.data || res.data, config.maxDescLength, platform);
892
+ if (config.debug)
893
+ ctx.logger.debug('解析成功');
894
+ return { data: parseResult, msg: '快手解析成功' };
895
+ }
896
+ else {
897
+ if (config.debug)
898
+ ctx.logger.debug('返回数据无效');
899
+ }
900
+ }
901
+ catch (error) {
902
+ if (config.debug) {
903
+ ctx.logger.debug(`请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
904
+ }
905
+ }
869
906
  }
870
907
  }
871
908
  }
@@ -878,85 +915,91 @@ function apply(ctx, config) {
878
915
  return { data: null, msg: '快手解析失败' };
879
916
  }
880
917
  if (platform === 'douyin') {
881
- try {
882
- const apiUrl = API_CONFIG.xingzhige.douyin.url;
883
- if (config.debug)
884
- ctx.logger.debug(`请求抖音xingzhige API: ${apiUrl}, 参数: { url: ${realUrl} }`);
885
- const res = await http({
886
- method: 'GET',
887
- url: apiUrl,
888
- params: { url: realUrl }
889
- });
890
- if (config.debug)
891
- ctx.logger.debug(`抖音xingzhige API响应状态: ${res.status}`);
892
- if (res.data && res.data.jx && res.data.jx.length > 0) {
893
- const xgData = parse_xingzhige_data(res.data, platform);
894
- const parseResult = parseData(xgData, config.maxDescLength, platform);
895
- if (config.debug)
896
- ctx.logger.debug('抖音xingzhige解析成功');
897
- return { data: parseResult, msg: '抖音解析成功' };
898
- }
899
- else {
900
- if (config.debug)
901
- ctx.logger.debug('抖音xingzhige API返回数据无效');
902
- }
903
- }
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) {
940
- try {
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}`);
946
- if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
947
- const parseResult = parseData(res.data.data, config.maxDescLength, platform);
918
+ const preferred = config.preferredApi?.douyin || 'xingzhige';
919
+ const tryOrder = preferred === 'xingzhige' ? ['xingzhige', 'universal', 'platform'] :
920
+ preferred === 'universal' ? ['universal', 'xingzhige', 'platform'] :
921
+ ['platform', 'xingzhige', 'universal'];
922
+ for (const step of tryOrder) {
923
+ if (step === 'xingzhige') {
924
+ try {
925
+ const apiUrl = API_CONFIG.xingzhige.douyin.url;
948
926
  if (config.debug)
949
- ctx.logger.debug('抖音平台API解析成功');
950
- return { data: parseResult, msg: '抖音解析成功' };
927
+ ctx.logger.debug(`${apiUrl}?url=${encodeURIComponent(realUrl)}`);
928
+ const res = await http({
929
+ method: 'GET',
930
+ url: apiUrl,
931
+ params: { url: realUrl }
932
+ });
933
+ if (config.debug)
934
+ ctx.logger.debug(`响应状态: ${res.status}`);
935
+ if (res.data && res.data.jx && res.data.jx.length > 0) {
936
+ const xgData = parse_xingzhige_data(res.data, platform);
937
+ const parseResult = parseData(xgData, config.maxDescLength, platform);
938
+ if (config.debug)
939
+ ctx.logger.debug('解析成功');
940
+ return { data: parseResult, msg: '抖音解析成功' };
941
+ }
942
+ else {
943
+ if (config.debug)
944
+ ctx.logger.debug('返回数据无效');
945
+ }
951
946
  }
952
- else {
947
+ catch (error) {
948
+ if (config.debug) {
949
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
950
+ }
951
+ }
952
+ }
953
+ else if (step === 'universal') {
954
+ try {
955
+ const universalUrl = API_CONFIG.universal;
956
+ if (config.debug)
957
+ ctx.logger.debug(`${universalUrl}?url=${encodeURIComponent(realUrl)}`);
958
+ const res = await http.get(universalUrl, { params: { url: realUrl } });
953
959
  if (config.debug)
954
- ctx.logger.debug('抖音平台API返回数据无效');
960
+ ctx.logger.debug(`响应状态: ${res.status}`);
961
+ if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
962
+ const parseResult = parseData(res.data.data, config.maxDescLength, platform);
963
+ if (config.debug)
964
+ ctx.logger.debug('解析成功');
965
+ return { data: parseResult, msg: '抖音解析成功' };
966
+ }
967
+ else {
968
+ if (config.debug)
969
+ ctx.logger.debug('返回数据无效');
970
+ }
971
+ }
972
+ catch (error) {
973
+ if (config.debug) {
974
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
975
+ }
955
976
  }
956
977
  }
957
- catch (error) {
958
- if (config.debug) {
959
- ctx.logger.debug(`抖音平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
978
+ else if (step === 'platform') {
979
+ const platformApis = API_CONFIG.platform.douyin || [];
980
+ for (const apiUrl of platformApis) {
981
+ try {
982
+ if (config.debug)
983
+ ctx.logger.debug(`${apiUrl}?url=${encodeURIComponent(realUrl)}`);
984
+ const res = await http.get(apiUrl, { params: { url: realUrl } });
985
+ if (config.debug)
986
+ ctx.logger.debug(`响应状态: ${res.status}`);
987
+ if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
988
+ const parseResult = parseData(res.data.data, config.maxDescLength, platform);
989
+ if (config.debug)
990
+ ctx.logger.debug('解析成功');
991
+ return { data: parseResult, msg: '抖音解析成功' };
992
+ }
993
+ else {
994
+ if (config.debug)
995
+ ctx.logger.debug('返回数据无效');
996
+ }
997
+ }
998
+ catch (error) {
999
+ if (config.debug) {
1000
+ ctx.logger.debug(`请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
1001
+ }
1002
+ }
960
1003
  }
961
1004
  }
962
1005
  }
@@ -969,85 +1012,91 @@ function apply(ctx, config) {
969
1012
  return { data: null, msg: '抖音解析失败' };
970
1013
  }
971
1014
  if (platform === 'xigua') {
972
- try {
973
- const apiUrl = API_CONFIG.xingzhige.xigua.url;
974
- if (config.debug)
975
- ctx.logger.debug(`请求西瓜xingzhige API: ${apiUrl}, 参数: { url: ${realUrl} }`);
976
- const res = await http({
977
- method: 'GET',
978
- url: apiUrl,
979
- params: { url: realUrl }
980
- });
981
- if (config.debug)
982
- ctx.logger.debug(`西瓜xingzhige API响应状态: ${res.status}`);
983
- if (res.data && res.data.jx && res.data.jx.length > 0) {
984
- const xgData = parse_xingzhige_data(res.data, platform);
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解析成功');
1014
- return { data: parseResult, msg: '西瓜视频解析成功' };
1015
- }
1016
- else {
1017
- if (config.debug)
1018
- ctx.logger.debug('通用API返回数据无效');
1019
- }
1020
- }
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) {
1031
- try {
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}`);
1037
- if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
1038
- const parseResult = parseData(res.data.data, config.maxDescLength, platform);
1015
+ const preferred = config.preferredApi?.xigua || 'xingzhige';
1016
+ const tryOrder = preferred === 'xingzhige' ? ['xingzhige', 'universal', 'platform'] :
1017
+ preferred === 'universal' ? ['universal', 'xingzhige', 'platform'] :
1018
+ ['platform', 'xingzhige', 'universal'];
1019
+ for (const step of tryOrder) {
1020
+ if (step === 'xingzhige') {
1021
+ try {
1022
+ const apiUrl = API_CONFIG.xingzhige.xigua.url;
1023
+ if (config.debug)
1024
+ ctx.logger.debug(`${apiUrl}?url=${encodeURIComponent(realUrl)}`);
1025
+ const res = await http({
1026
+ method: 'GET',
1027
+ url: apiUrl,
1028
+ params: { url: realUrl }
1029
+ });
1039
1030
  if (config.debug)
1040
- ctx.logger.debug('西瓜平台API解析成功');
1041
- return { data: parseResult, msg: '西瓜视频解析成功' };
1031
+ ctx.logger.debug(`响应状态: ${res.status}`);
1032
+ if (res.data && res.data.jx && res.data.jx.length > 0) {
1033
+ const xgData = parse_xingzhige_data(res.data, platform);
1034
+ const parseResult = parseData(xgData, config.maxDescLength, platform);
1035
+ if (config.debug)
1036
+ ctx.logger.debug('解析成功');
1037
+ return { data: parseResult, msg: '西瓜视频解析成功' };
1038
+ }
1039
+ else {
1040
+ if (config.debug)
1041
+ ctx.logger.debug('返回数据无效');
1042
+ }
1042
1043
  }
1043
- else {
1044
+ catch (error) {
1045
+ if (config.debug) {
1046
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
1047
+ }
1048
+ }
1049
+ }
1050
+ else if (step === 'universal') {
1051
+ try {
1052
+ const universalUrl = API_CONFIG.universal;
1044
1053
  if (config.debug)
1045
- ctx.logger.debug('西瓜平台API返回数据无效');
1054
+ ctx.logger.debug(`${universalUrl}?url=${encodeURIComponent(realUrl)}`);
1055
+ const res = await http.get(universalUrl, { params: { url: realUrl } });
1056
+ if (config.debug)
1057
+ ctx.logger.debug(`响应状态: ${res.status}`);
1058
+ if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
1059
+ const parseResult = parseData(res.data.data, config.maxDescLength, platform);
1060
+ if (config.debug)
1061
+ ctx.logger.debug('解析成功');
1062
+ return { data: parseResult, msg: '西瓜视频解析成功' };
1063
+ }
1064
+ else {
1065
+ if (config.debug)
1066
+ ctx.logger.debug('返回数据无效');
1067
+ }
1068
+ }
1069
+ catch (error) {
1070
+ if (config.debug) {
1071
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
1072
+ }
1046
1073
  }
1047
1074
  }
1048
- catch (error) {
1049
- if (config.debug) {
1050
- ctx.logger.debug(`西瓜平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
1075
+ else if (step === 'platform') {
1076
+ const platformApis = API_CONFIG.platform.xigua || [];
1077
+ for (const apiUrl of platformApis) {
1078
+ try {
1079
+ if (config.debug)
1080
+ ctx.logger.debug(`${apiUrl}?url=${encodeURIComponent(realUrl)}`);
1081
+ const res = await http.get(apiUrl, { params: { url: realUrl } });
1082
+ if (config.debug)
1083
+ ctx.logger.debug(`响应状态: ${res.status}`);
1084
+ if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
1085
+ const parseResult = parseData(res.data.data, config.maxDescLength, platform);
1086
+ if (config.debug)
1087
+ ctx.logger.debug('解析成功');
1088
+ return { data: parseResult, msg: '西瓜视频解析成功' };
1089
+ }
1090
+ else {
1091
+ if (config.debug)
1092
+ ctx.logger.debug('返回数据无效');
1093
+ }
1094
+ }
1095
+ catch (error) {
1096
+ if (config.debug) {
1097
+ ctx.logger.debug(`请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
1098
+ }
1099
+ }
1051
1100
  }
1052
1101
  }
1053
1102
  }
@@ -1062,112 +1111,122 @@ function apply(ctx, config) {
1062
1111
  const currentPlatform = platform;
1063
1112
  const nonKuaishouPlatforms = ['xiaohongshu', 'weibo', 'toutiao', 'pipigx', 'pipixia', 'zuiyou'];
1064
1113
  if (nonKuaishouPlatforms.includes(currentPlatform)) {
1065
- for (let retry = 0; retry <= config.retryTimes; retry++) {
1066
- try {
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}`);
1073
- if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
1074
- const parseResult = parseData(res.data.data, config.maxDescLength, currentPlatform);
1075
- if (config.debug)
1076
- ctx.logger.debug('通用API解析成功');
1077
- return { data: parseResult, msg: '解析成功' };
1078
- }
1079
- else if (res.data.code === 201) {
1080
- if (config.debug)
1081
- ctx.logger.debug('通用API返回code 201');
1082
- break;
1083
- }
1084
- else {
1085
- if (config.debug)
1086
- ctx.logger.debug('通用API返回数据无效');
1087
- }
1088
- }
1089
- catch (error) {
1090
- if (config.debug) {
1091
- ctx.logger.debug(`通用API请求失败: ${getErrorMessage(error)}`);
1092
- }
1093
- if (retry === config.retryTimes)
1094
- break;
1095
- await delay(config.retryInterval);
1096
- }
1097
- }
1098
- }
1099
- const platformApis = API_CONFIG.platform[currentPlatform] || [];
1100
- for (let apiIndex = 0; apiIndex < platformApis.length; apiIndex++) {
1101
- const apiUrl = platformApis[apiIndex];
1102
- for (let retry = 0; retry <= config.retryTimes; retry++) {
1103
- try {
1104
- if (config.debug)
1105
- ctx.logger.debug(`请求平台API: ${apiUrl}, 参数: { url: ${realUrl} }`);
1106
- const res = await http.get(apiUrl, { params: { url: realUrl } });
1107
- if (config.debug)
1108
- ctx.logger.debug(`平台API响应状态: ${res.status}`);
1109
- let shouldContinue = false;
1110
- if ((res.data.code === 200 || res.data.code === 0)) {
1111
- let parseResult = null;
1112
- if (currentPlatform === 'kuaishou') {
1113
- if (res.data.image && !res.data.data) {
1114
- parseResult = parseData({
1115
- title: res.data.data?.title || '快手图集',
1116
- author: res.data.data?.author || '未知作者',
1117
- images: res.data.image,
1118
- type: 'image'
1119
- }, config.maxDescLength, currentPlatform);
1114
+ const preferred = config.preferredApi?.[currentPlatform] || 'universal';
1115
+ const tryOrder = preferred === 'universal' ? ['universal', 'platform'] : ['platform', 'universal'];
1116
+ for (const step of tryOrder) {
1117
+ if (step === 'universal') {
1118
+ for (let retry = 0; retry <= config.retryTimes; retry++) {
1119
+ try {
1120
+ const universalUrl = API_CONFIG.universal;
1121
+ if (config.debug)
1122
+ ctx.logger.debug(`${universalUrl}?url=${encodeURIComponent(realUrl)}`);
1123
+ const res = await http.get(universalUrl, { params: { url: realUrl } });
1124
+ if (config.debug)
1125
+ ctx.logger.debug(`响应状态: ${res.status}`);
1126
+ if ((res.data.code === 200 || res.data.code === 0) && res.data.data) {
1127
+ const parseResult = parseData(res.data.data, config.maxDescLength, currentPlatform);
1128
+ if (config.debug)
1129
+ ctx.logger.debug('解析成功');
1130
+ return { data: parseResult, msg: '解析成功' };
1120
1131
  }
1121
- else if (res.data.data) {
1122
- parseResult = parseData(res.data.data, config.maxDescLength, currentPlatform);
1132
+ else if (res.data.code === 201) {
1133
+ if (config.debug)
1134
+ ctx.logger.debug('返回code 201');
1135
+ break;
1123
1136
  }
1124
1137
  else {
1125
- shouldContinue = true;
1138
+ if (config.debug)
1139
+ ctx.logger.debug('返回数据无效');
1126
1140
  }
1127
1141
  }
1128
- else {
1129
- if (res.data.data) {
1130
- parseResult = parseData(res.data.data, config.maxDescLength, currentPlatform);
1142
+ catch (error) {
1143
+ if (config.debug) {
1144
+ ctx.logger.debug(`请求失败: ${getErrorMessage(error)}`);
1131
1145
  }
1132
- else {
1133
- shouldContinue = true;
1134
- }
1135
- }
1136
- if (parseResult) {
1137
- if (config.debug)
1138
- ctx.logger.debug('平台API解析成功');
1139
- return { data: parseResult, msg: '解析成功' };
1146
+ if (retry === config.retryTimes)
1147
+ break;
1148
+ await delay(config.retryInterval);
1140
1149
  }
1141
1150
  }
1142
- if (shouldContinue && retry < config.retryTimes) {
1143
- if (config.debug)
1144
- ctx.logger.debug('平台API返回数据无效,准备重试');
1145
- await delay(config.retryInterval);
1146
- continue;
1147
- }
1148
- else {
1149
- if (config.debug)
1150
- ctx.logger.debug('平台API返回数据无效,放弃');
1151
- break;
1152
- }
1153
1151
  }
1154
- catch (error) {
1155
- if (config.debug) {
1156
- ctx.logger.debug(`平台API请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
1152
+ else if (step === 'platform') {
1153
+ const platformApis = API_CONFIG.platform[currentPlatform] || [];
1154
+ for (let apiIndex = 0; apiIndex < platformApis.length; apiIndex++) {
1155
+ const apiUrl = platformApis[apiIndex];
1156
+ for (let retry = 0; retry <= config.retryTimes; retry++) {
1157
+ try {
1158
+ if (config.debug)
1159
+ ctx.logger.debug(`${apiUrl}?url=${encodeURIComponent(realUrl)}`);
1160
+ const res = await http.get(apiUrl, { params: { url: realUrl } });
1161
+ if (config.debug)
1162
+ ctx.logger.debug(`响应状态: ${res.status}`);
1163
+ let shouldContinue = false;
1164
+ if ((res.data.code === 200 || res.data.code === 0)) {
1165
+ let parseResult = null;
1166
+ if (currentPlatform === 'kuaishou') {
1167
+ if (res.data.image && !res.data.data) {
1168
+ parseResult = parseData({
1169
+ title: res.data.data?.title || '快手图集',
1170
+ author: res.data.data?.author || '未知作者',
1171
+ images: res.data.image,
1172
+ type: 'image'
1173
+ }, config.maxDescLength, currentPlatform);
1174
+ }
1175
+ else if (res.data.data) {
1176
+ parseResult = parseData(res.data.data, config.maxDescLength, currentPlatform);
1177
+ }
1178
+ else {
1179
+ shouldContinue = true;
1180
+ }
1181
+ }
1182
+ else {
1183
+ if (res.data.data) {
1184
+ parseResult = parseData(res.data.data, config.maxDescLength, currentPlatform);
1185
+ }
1186
+ else {
1187
+ shouldContinue = true;
1188
+ }
1189
+ }
1190
+ if (parseResult) {
1191
+ if (config.debug)
1192
+ ctx.logger.debug('解析成功');
1193
+ return { data: parseResult, msg: '解析成功' };
1194
+ }
1195
+ }
1196
+ if (shouldContinue && retry < config.retryTimes) {
1197
+ if (config.debug)
1198
+ ctx.logger.debug('返回数据无效,准备重试');
1199
+ await delay(config.retryInterval);
1200
+ continue;
1201
+ }
1202
+ else {
1203
+ if (config.debug)
1204
+ ctx.logger.debug('返回数据无效,放弃');
1205
+ break;
1206
+ }
1207
+ }
1208
+ catch (error) {
1209
+ if (config.debug) {
1210
+ ctx.logger.debug(`请求失败: ${apiUrl}, 错误: ${getErrorMessage(error)}`);
1211
+ }
1212
+ if (retry === config.retryTimes)
1213
+ break;
1214
+ await delay(config.retryInterval);
1215
+ }
1216
+ }
1157
1217
  }
1158
- if (retry === config.retryTimes)
1159
- break;
1160
- await delay(config.retryInterval);
1161
1218
  }
1162
1219
  }
1220
+ if (config.debug) {
1221
+ ctx.logger.debug(`所有API尝试失败,平台: ${platform}, URL: ${realUrl}`);
1222
+ }
1223
+ else {
1224
+ ctx.logger.error(`解析失败: ${platform} ${realUrl}`);
1225
+ }
1226
+ return { data: null, msg: '解析失败,请稍后重试' };
1163
1227
  }
1164
- if (config.debug) {
1165
- ctx.logger.debug(`所有API尝试失败,平台: ${platform}, URL: ${realUrl}`);
1166
- }
1167
- else {
1168
- ctx.logger.error(`解析失败: ${platform} ${realUrl}`);
1169
- }
1170
- return { data: null, msg: '解析失败,请稍后重试' };
1228
+ // 其他平台(不应该走到这里)
1229
+ return { data: null, msg: '未知平台' };
1171
1230
  }
1172
1231
  async function processSingleUrl(session, url) {
1173
1232
  const hash = crypto_1.default.createHash('md5').update(url).digest('hex');
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.2",
4
+ "version": "0.4.4",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [