koishi-plugin-video-parser-all 1.0.8 → 1.0.9

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
@@ -32,6 +32,7 @@ export declare const Config: Schema<{
32
32
  customApis?: ({
33
33
  platform?: "bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao" | null | undefined;
34
34
  apiUrl?: string | null | undefined;
35
+ useDedicatedFirst?: boolean | null | undefined;
35
36
  } & import("cosmokit").Dict)[] | null | undefined;
36
37
  } & {
37
38
  waitingTipText?: string | null | undefined;
@@ -71,6 +72,7 @@ export declare const Config: Schema<{
71
72
  customApis: Schemastery.ObjectT<{
72
73
  platform: Schema<"bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao", "bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao">;
73
74
  apiUrl: Schema<string, string>;
75
+ useDedicatedFirst: Schema<boolean, boolean>;
74
76
  }>[];
75
77
  } & {
76
78
  waitingTipText: string;
package/lib/index.js CHANGED
@@ -48,29 +48,30 @@ exports.Config = koishi_1.Schema.intersect([
48
48
  koishi_1.Schema.object({
49
49
  primaryApiUrl: koishi_1.Schema.string().default('https://api.bugpk.com/api/short_videos').description('主 API 地址'),
50
50
  backupApiUrl: koishi_1.Schema.string().default('https://api.bugpk.com/api/svparse').description('备用主 API 地址(仅支持抖音/小红书/ins/即梦)'),
51
- useDedicatedApiFirst: koishi_1.Schema.boolean().default(false).description('优先使用平台专属 API,失败后回退到通用 API'),
51
+ useDedicatedApiFirst: koishi_1.Schema.boolean().default(false).description('全局默认:是否优先使用平台专属 API(各平台可单独覆盖)'),
52
52
  customApis: koishi_1.Schema.array(koishi_1.Schema.object({
53
53
  platform: koishi_1.Schema.union([
54
- 'bilibili',
55
- 'douyin',
56
- 'kuaishou',
57
- 'xiaohongshu',
58
- 'weibo',
59
- 'xigua',
60
- 'youtube',
61
- 'tiktok',
62
- 'acfun',
63
- 'zhihu',
64
- 'weishi',
65
- 'huya',
66
- 'haokan',
67
- 'meipai',
68
- 'twitter',
69
- 'instagram',
70
- 'doubao',
54
+ koishi_1.Schema.const('bilibili').description('哔哩哔哩'),
55
+ koishi_1.Schema.const('douyin').description('抖音'),
56
+ koishi_1.Schema.const('kuaishou').description('快手'),
57
+ koishi_1.Schema.const('xiaohongshu').description('小红书'),
58
+ koishi_1.Schema.const('weibo').description('微博'),
59
+ koishi_1.Schema.const('xigua').description('西瓜视频'),
60
+ koishi_1.Schema.const('youtube').description('YouTube'),
61
+ koishi_1.Schema.const('tiktok').description('TikTok'),
62
+ koishi_1.Schema.const('acfun').description('AcFun'),
63
+ koishi_1.Schema.const('zhihu').description('知乎'),
64
+ koishi_1.Schema.const('weishi').description('微视'),
65
+ koishi_1.Schema.const('huya').description('虎牙'),
66
+ koishi_1.Schema.const('haokan').description('好看视频'),
67
+ koishi_1.Schema.const('meipai').description('美拍'),
68
+ koishi_1.Schema.const('twitter').description('Twitter/X'),
69
+ koishi_1.Schema.const('instagram').description('Instagram'),
70
+ koishi_1.Schema.const('doubao').description('豆包'),
71
71
  ]).description('选择平台'),
72
72
  apiUrl: koishi_1.Schema.string().description('API 地址'),
73
- })).default([]).description('自定义平台专属 API,可覆盖默认专属 API'),
73
+ useDedicatedFirst: koishi_1.Schema.boolean().default(false).description('该平台优先使用此专属 API'),
74
+ })).default([]).description('自定义平台专属 API,可覆盖默认专属 API,并可单独设定优先策略'),
74
75
  }).description('API 选择设置'),
75
76
  koishi_1.Schema.object({
76
77
  waitingTipText: koishi_1.Schema.string().default('正在解析视频,请稍候...').description('解析等待提示'),
@@ -99,6 +100,11 @@ function debugLog(level, ...args) {
99
100
  }).join(' ')}`;
100
101
  logger.info(message);
101
102
  }
103
+ const urlCache = new lru_cache_1.LRUCache({
104
+ max: 500,
105
+ ttl: 10 * 60 * 1000,
106
+ updateAgeOnGet: false,
107
+ });
102
108
  function linkTypeParser(content) {
103
109
  content = content.replace(/\\\//g, '/');
104
110
  const rules = [
@@ -147,7 +153,54 @@ function linkTypeParser(content) {
147
153
  }
148
154
  function extractAllUrlsFromMessage(session) {
149
155
  const content = session.content?.trim() || '';
150
- return linkTypeParser(content);
156
+ const rawUrls = [];
157
+ const textMatch = content.match(/https?:\/\/[^\s<>"'(){}[\]]+/gi);
158
+ if (textMatch)
159
+ rawUrls.push(...textMatch);
160
+ if (session.elements) {
161
+ for (const elem of session.elements) {
162
+ if (elem.type === 'xml' && elem.data) {
163
+ const matches = elem.data.match(/https?:\/\/[^\s<>"'(){}[\]]+/gi);
164
+ if (matches)
165
+ rawUrls.push(...matches);
166
+ }
167
+ else if (elem.type === 'json' && elem.data) {
168
+ try {
169
+ const json = JSON.parse(elem.data);
170
+ const extract = (obj) => {
171
+ if (!obj || typeof obj !== 'object')
172
+ return;
173
+ for (const val of Object.values(obj)) {
174
+ if (typeof val === 'string') {
175
+ const matches = val.match(/https?:\/\/[^\s<>"'(){}[\]]+/gi);
176
+ if (matches)
177
+ rawUrls.push(...matches);
178
+ }
179
+ else if (typeof val === 'object')
180
+ extract(val);
181
+ }
182
+ };
183
+ extract(json);
184
+ }
185
+ catch { }
186
+ }
187
+ }
188
+ }
189
+ const seen = new Set();
190
+ const result = [];
191
+ for (const rawUrl of rawUrls) {
192
+ const cleanedUrl = rawUrl.replace(/&amp;/g, '&').replace(/[.,;:!?)]+$/, '');
193
+ if (seen.has(cleanedUrl))
194
+ continue;
195
+ const matches = linkTypeParser(cleanedUrl);
196
+ for (const match of matches) {
197
+ if (!seen.has(match.url)) {
198
+ seen.add(match.url);
199
+ result.push(match);
200
+ }
201
+ }
202
+ }
203
+ return result;
151
204
  }
152
205
  function cleanUrl(url) {
153
206
  try {
@@ -385,11 +438,6 @@ function buildForwardNode(session, content, botName) {
385
438
  }
386
439
  }, messageContent);
387
440
  }
388
- const urlCache = new lru_cache_1.LRUCache({
389
- max: 500,
390
- ttl: 10 * 60 * 1000,
391
- updateAgeOnGet: false,
392
- });
393
441
  async function downloadVideoFile(videoUrl, tempDir, timeout, maxSizeMB) {
394
442
  if (!videoUrl)
395
443
  throw new Error('视频链接为空');
@@ -483,13 +531,13 @@ function apply(ctx, config) {
483
531
  zuiyou: 'https://api.bugpk.com/api/zuiyou',
484
532
  };
485
533
  const backupSupportedPlatforms = new Set(['douyin', 'xiaohongshu', 'instagram', 'jimeng']);
486
- function getDedicatedApiUrl(type) {
487
- if (config.customApis && Array.isArray(config.customApis)) {
488
- const found = config.customApis.find((item) => item.platform === type);
489
- if (found && found.apiUrl)
490
- return found.apiUrl;
534
+ function getPlatformConfig(type) {
535
+ const custom = config.customApis?.find((item) => item.platform === type);
536
+ if (custom && custom.apiUrl) {
537
+ return { apiUrl: custom.apiUrl, dedicatedFirst: custom.useDedicatedFirst ?? false };
491
538
  }
492
- return defaultDedicatedApis[type] || null;
539
+ const defaultUrl = defaultDedicatedApis[type] || null;
540
+ return { apiUrl: defaultUrl, dedicatedFirst: config.useDedicatedApiFirst ?? false };
493
541
  }
494
542
  async function fetchApi(url, type) {
495
543
  const cacheKey = url;
@@ -498,14 +546,13 @@ function apply(ctx, config) {
498
546
  debugLog('DEBUG', `使用缓存: ${url}`);
499
547
  return cached.data;
500
548
  }
501
- const dedicatedApiUrl = getDedicatedApiUrl(type);
549
+ const { apiUrl: dedicatedUrl, dedicatedFirst } = getPlatformConfig(type);
502
550
  const primaryApi = config.primaryApiUrl || 'https://api.bugpk.com/api/short_videos';
503
551
  const backupApi = config.backupApiUrl || 'https://api.bugpk.com/api/svparse';
504
552
  const backupAllowed = backupSupportedPlatforms.has(type);
505
553
  const apiList = [];
506
- if (config.useDedicatedApiFirst) {
507
- if (dedicatedApiUrl)
508
- apiList.push({ url: dedicatedApiUrl, label: `专属API(${type})` });
554
+ if (dedicatedFirst && dedicatedUrl) {
555
+ apiList.push({ url: dedicatedUrl, label: `专属API(${type})` });
509
556
  apiList.push({ url: primaryApi, label: '默认主API' });
510
557
  if (backupAllowed)
511
558
  apiList.push({ url: backupApi, label: '备用主API' });
@@ -514,8 +561,8 @@ function apply(ctx, config) {
514
561
  apiList.push({ url: primaryApi, label: '默认主API' });
515
562
  if (backupAllowed)
516
563
  apiList.push({ url: backupApi, label: '备用主API' });
517
- if (dedicatedApiUrl)
518
- apiList.push({ url: dedicatedApiUrl, label: `专属API(${type})` });
564
+ if (dedicatedUrl)
565
+ apiList.push({ url: dedicatedUrl, label: `专属API(${type})` });
519
566
  }
520
567
  let lastError = null;
521
568
  for (const api of apiList) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-video-parser-all",
3
3
  "description": "Koishi 全平台视频解析插件,支持抖音/快手/B站/微博/小红书/剪映/YouTube/TikTok等20+平台",
4
- "version": "1.0.8",
4
+ "version": "1.0.9",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [