koishi-plugin-video-parser-all 1.1.0 → 1.1.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
@@ -28,11 +28,28 @@ export declare const Config: Schema<{
28
28
  } & {
29
29
  primaryApiUrl?: string | null | undefined;
30
30
  backupApiUrl?: string | null | undefined;
31
- useDedicatedApiFirst?: boolean | null | undefined;
31
+ platformDedicatedFirst?: ({
32
+ bilibili?: boolean | null | undefined;
33
+ douyin?: boolean | null | undefined;
34
+ kuaishou?: boolean | null | undefined;
35
+ xiaohongshu?: boolean | null | undefined;
36
+ weibo?: boolean | null | undefined;
37
+ xigua?: boolean | null | undefined;
38
+ youtube?: boolean | null | undefined;
39
+ tiktok?: boolean | null | undefined;
40
+ acfun?: boolean | null | undefined;
41
+ zhihu?: boolean | null | undefined;
42
+ weishi?: boolean | null | undefined;
43
+ huya?: boolean | null | undefined;
44
+ haokan?: boolean | null | undefined;
45
+ meipai?: boolean | null | undefined;
46
+ twitter?: boolean | null | undefined;
47
+ instagram?: boolean | null | undefined;
48
+ doubao?: boolean | null | undefined;
49
+ } & import("cosmokit").Dict) | null | undefined;
32
50
  customApis?: ({
33
51
  platform?: "bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao" | null | undefined;
34
52
  apiUrl?: string | null | undefined;
35
- useDedicatedFirst?: boolean | null | undefined;
36
53
  } & import("cosmokit").Dict)[] | null | undefined;
37
54
  } & {
38
55
  waitingTipText?: string | null | undefined;
@@ -68,11 +85,28 @@ export declare const Config: Schema<{
68
85
  } & {
69
86
  primaryApiUrl: string;
70
87
  backupApiUrl: string;
71
- useDedicatedApiFirst: boolean;
88
+ platformDedicatedFirst: Schemastery.ObjectT<{
89
+ bilibili: Schema<boolean, boolean>;
90
+ douyin: Schema<boolean, boolean>;
91
+ kuaishou: Schema<boolean, boolean>;
92
+ xiaohongshu: Schema<boolean, boolean>;
93
+ weibo: Schema<boolean, boolean>;
94
+ xigua: Schema<boolean, boolean>;
95
+ youtube: Schema<boolean, boolean>;
96
+ tiktok: Schema<boolean, boolean>;
97
+ acfun: Schema<boolean, boolean>;
98
+ zhihu: Schema<boolean, boolean>;
99
+ weishi: Schema<boolean, boolean>;
100
+ huya: Schema<boolean, boolean>;
101
+ haokan: Schema<boolean, boolean>;
102
+ meipai: Schema<boolean, boolean>;
103
+ twitter: Schema<boolean, boolean>;
104
+ instagram: Schema<boolean, boolean>;
105
+ doubao: Schema<boolean, boolean>;
106
+ }>;
72
107
  customApis: Schemastery.ObjectT<{
73
108
  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">;
74
109
  apiUrl: Schema<string, string>;
75
- useDedicatedFirst: Schema<boolean, boolean>;
76
110
  }>[];
77
111
  } & {
78
112
  waitingTipText: string;
package/lib/index.js CHANGED
@@ -48,7 +48,25 @@ 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(各平台可单独覆盖)'),
51
+ platformDedicatedFirst: koishi_1.Schema.object({
52
+ bilibili: koishi_1.Schema.boolean().default(false).description('哔哩哔哩'),
53
+ douyin: koishi_1.Schema.boolean().default(false).description('抖音'),
54
+ kuaishou: koishi_1.Schema.boolean().default(false).description('快手'),
55
+ xiaohongshu: koishi_1.Schema.boolean().default(false).description('小红书'),
56
+ weibo: koishi_1.Schema.boolean().default(false).description('微博'),
57
+ xigua: koishi_1.Schema.boolean().default(false).description('西瓜视频'),
58
+ youtube: koishi_1.Schema.boolean().default(false).description('YouTube'),
59
+ tiktok: koishi_1.Schema.boolean().default(false).description('TikTok'),
60
+ acfun: koishi_1.Schema.boolean().default(false).description('AcFun'),
61
+ zhihu: koishi_1.Schema.boolean().default(false).description('知乎'),
62
+ weishi: koishi_1.Schema.boolean().default(false).description('微视'),
63
+ huya: koishi_1.Schema.boolean().default(false).description('虎牙'),
64
+ haokan: koishi_1.Schema.boolean().default(false).description('好看视频'),
65
+ meipai: koishi_1.Schema.boolean().default(false).description('美拍'),
66
+ twitter: koishi_1.Schema.boolean().default(false).description('Twitter/X'),
67
+ instagram: koishi_1.Schema.boolean().default(false).description('Instagram'),
68
+ doubao: koishi_1.Schema.boolean().default(false).description('豆包'),
69
+ }).description('各平台独立开关:是否优先使用专属 API'),
52
70
  customApis: koishi_1.Schema.array(koishi_1.Schema.object({
53
71
  platform: koishi_1.Schema.union([
54
72
  koishi_1.Schema.const('bilibili').description('哔哩哔哩'),
@@ -70,8 +88,7 @@ exports.Config = koishi_1.Schema.intersect([
70
88
  koishi_1.Schema.const('doubao').description('豆包'),
71
89
  ]).description('选择平台'),
72
90
  apiUrl: koishi_1.Schema.string().description('API 地址'),
73
- useDedicatedFirst: koishi_1.Schema.boolean().default(false).description('该平台优先使用此专属 API'),
74
- })).default([]).description('自定义平台专属 API,可覆盖默认专属 API,并可单独设定优先策略'),
91
+ })).default([]).description('自定义平台专属 API 地址,留空则使用内置默认专属 API'),
75
92
  }).description('API 选择设置'),
76
93
  koishi_1.Schema.object({
77
94
  waitingTipText: koishi_1.Schema.string().default('正在解析视频,请稍候...').description('解析等待提示'),
@@ -108,45 +125,44 @@ const urlCache = new lru_cache_1.LRUCache({
108
125
  function linkTypeParser(content) {
109
126
  content = content.replace(/\\\//g, '/');
110
127
  const rules = [
111
- { pattern: /bilibili\.com\/video\/([ab]v[0-9a-zA-Z]+)/gi, type: 'bilibili', buildUrl: (id) => `https://www.bilibili.com/video/${id}` },
112
- { pattern: /b23\.tv\/([0-9a-zA-Z]{5,})/gi, type: 'bilibili', buildUrl: (id) => `https://b23.tv/${id}` },
113
- { pattern: /bili(?:22|23|33)\.cn\/([0-9a-zA-Z]{5,})/gi, type: 'bilibili', buildUrl: (id) => `https://bili23.cn/${id}` },
114
- { pattern: /bili2233\.cn\/([0-9a-zA-Z]{5,})/gi, type: 'bilibili', buildUrl: (id) => `https://bili2233.cn/${id}` },
115
- { pattern: /douyin\.com\/video\/(\d{10,})/gi, type: 'douyin', buildUrl: (id) => `https://www.douyin.com/video/${id}` },
116
- { pattern: /v\.douyin\.com\/([0-9a-zA-Z]{8,})/gi, type: 'douyin', buildUrl: (id) => `https://v.douyin.com/${id}/` },
117
- { pattern: /kuaishou\.com\/short-video\/([0-9a-zA-Z]{10,})/gi, type: 'kuaishou', buildUrl: (id) => `https://www.kuaishou.com/short-video/${id}` },
118
- { pattern: /v\.kuaishou\.com\/([0-9a-zA-Z]{8,})/gi, type: 'kuaishou', buildUrl: (id) => `https://v.kuaishou.com/${id}` },
119
- { pattern: /xiaohongshu\.com\/discovery\/item\/([0-9a-zA-Z]{10,})/gi, type: 'xiaohongshu', buildUrl: (id) => `https://www.xiaohongshu.com/discovery/item/${id}` },
120
- { pattern: /xhslink\.com\/([0-9a-zA-Z]{8,})/gi, type: 'xiaohongshu', buildUrl: (id) => `https://xhslink.com/${id}` },
121
- { pattern: /weibo\.com\/\d+\/([0-9a-zA-Z]{10,})/gi, type: 'weibo', buildUrl: (id) => `https://weibo.com/${id}` },
122
- { pattern: /video\.weibo\.com\/show\?fid=([0-9a-zA-Z]{10,})/gi, type: 'weibo', buildUrl: (id) => `https://video.weibo.com/show?fid=${id}` },
123
- { pattern: /ixigua\.com\/(\d{10,})/gi, type: 'xigua', buildUrl: (id) => `https://www.ixigua.com/${id}` },
124
- { pattern: /youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/gi, type: 'youtube', buildUrl: (id) => `https://www.youtube.com/watch?v=${id}` },
125
- { pattern: /youtu\.be\/([a-zA-Z0-9_-]{11})/gi, type: 'youtube', buildUrl: (id) => `https://youtu.be/${id}` },
126
- { pattern: /tiktok\.com\/@[\w.]+\/video\/(\d{10,})/gi, type: 'tiktok', buildUrl: (id) => `https://www.tiktok.com/@user/video/${id}` },
127
- { pattern: /vm\.tiktok\.com\/([0-9a-zA-Z]{8,})/gi, type: 'tiktok', buildUrl: (id) => `https://vm.tiktok.com/${id}` },
128
- { pattern: /acfun\.cn\/v\/(ac\d{10,})/gi, type: 'acfun', buildUrl: (id) => `https://www.acfun.cn/v/${id}` },
129
- { pattern: /zhihu\.com\/video\/(\d{10,})/gi, type: 'zhihu', buildUrl: (id) => `https://www.zhihu.com/video/${id}` },
130
- { pattern: /weishi\.qq\.com\/weishi\/feed\/([0-9a-zA-Z]{10,})/gi, type: 'weishi', buildUrl: (id) => `https://weishi.qq.com/weishi/feed/${id}` },
131
- { pattern: /huya\.com\/video\/([0-9a-zA-Z]{10,})/gi, type: 'huya', buildUrl: (id) => `https://www.huya.com/video/${id}` },
132
- { pattern: /haokan\.baidu\.com\/v\?vid=([0-9a-zA-Z]{10,})/gi, type: 'haokan', buildUrl: (id) => `https://haokan.baidu.com/v?vid=${id}` },
133
- { pattern: /meipai\.com\/media\/(\d{10,})/gi, type: 'meipai', buildUrl: (id) => `https://www.meipai.com/media/${id}` },
134
- { pattern: /twitter\.com\/\w+\/status\/(\d{10,})/gi, type: 'twitter', buildUrl: (id) => `https://twitter.com/i/status/${id}` },
135
- { pattern: /x\.com\/\w+\/status\/(\d{10,})/gi, type: 'twitter', buildUrl: (id) => `https://x.com/i/status/${id}` },
136
- { pattern: /instagram\.com\/p\/([0-9a-zA-Z_-]{10,})/gi, type: 'instagram', buildUrl: (id) => `https://www.instagram.com/p/${id}` },
137
- { pattern: /doubao\.com\/video\/(\d{10,})/gi, type: 'doubao', buildUrl: (id) => `https://www.doubao.com/video/${id}` },
128
+ { pattern: /https?:\/\/(?:www\.)?bilibili\.com\/video\/([ab]v[0-9a-zA-Z_-]+)/gi, type: 'bilibili' },
129
+ { pattern: /https?:\/\/b23\.tv\/[0-9a-zA-Z_-]{5,}/gi, type: 'bilibili' },
130
+ { pattern: /https?:\/\/bili\d+\.cn\/[0-9a-zA-Z_-]{5,}/gi, type: 'bilibili' },
131
+ { pattern: /https?:\/\/(?:www\.)?douyin\.com\/video\/\d{10,}/gi, type: 'douyin' },
132
+ { pattern: /https?:\/\/v\.douyin\.com\/[0-9a-zA-Z_-]{8,}/gi, type: 'douyin' },
133
+ { pattern: /https?:\/\/(?:www\.)?kuaishou\.com\/short-video\/[0-9a-zA-Z_-]{10,}/gi, type: 'kuaishou' },
134
+ { pattern: /https?:\/\/v\.kuaishou\.com\/[0-9a-zA-Z_-]{8,}/gi, type: 'kuaishou' },
135
+ { pattern: /https?:\/\/(?:www\.)?xiaohongshu\.com\/discovery\/item\/[0-9a-zA-Z_-]{10,}/gi, type: 'xiaohongshu' },
136
+ { pattern: /https?:\/\/xhslink\.com\/[0-9a-zA-Z_-]{8,}/gi, type: 'xiaohongshu' },
137
+ { pattern: /https?:\/\/weibo\.com\/\d+\/[0-9a-zA-Z_-]{10,}/gi, type: 'weibo' },
138
+ { pattern: /https?:\/\/video\.weibo\.com\/show\?fid=[0-9a-zA-Z_-]{10,}/gi, type: 'weibo' },
139
+ { pattern: /https?:\/\/(?:www\.)?ixigua\.com\/\d{10,}/gi, type: 'xigua' },
140
+ { pattern: /https?:\/\/(?:www\.)?youtube\.com\/watch\?v=[a-zA-Z0-9_-]{11}/gi, type: 'youtube' },
141
+ { pattern: /https?:\/\/youtu\.be\/[a-zA-Z0-9_-]{11}/gi, type: 'youtube' },
142
+ { pattern: /https?:\/\/(?:www\.)?tiktok\.com\/@[\w.]+\/video\/\d{10,}/gi, type: 'tiktok' },
143
+ { pattern: /https?:\/\/vm\.tiktok\.com\/[0-9a-zA-Z_-]{8,}/gi, type: 'tiktok' },
144
+ { pattern: /https?:\/\/(?:www\.)?acfun\.cn\/v\/ac\d{10,}/gi, type: 'acfun' },
145
+ { pattern: /https?:\/\/(?:www\.)?zhihu\.com\/video\/\d{10,}/gi, type: 'zhihu' },
146
+ { pattern: /https?:\/\/weishi\.qq\.com\/weishi\/feed\/[0-9a-zA-Z_-]{10,}/gi, type: 'weishi' },
147
+ { pattern: /https?:\/\/(?:www\.)?huya\.com\/video\/[0-9a-zA-Z_-]{10,}/gi, type: 'huya' },
148
+ { pattern: /https?:\/\/haokan\.baidu\.com\/v\?vid=[0-9a-zA-Z_-]{10,}/gi, type: 'haokan' },
149
+ { pattern: /https?:\/\/(?:www\.)?meipai\.com\/media\/\d{10,}/gi, type: 'meipai' },
150
+ { pattern: /https?:\/\/twitter\.com\/\w+\/status\/\d{10,}/gi, type: 'twitter' },
151
+ { pattern: /https?:\/\/x\.com\/\w+\/status\/\d{10,}/gi, type: 'twitter' },
152
+ { pattern: /https?:\/\/(?:www\.)?instagram\.com\/p\/[0-9a-zA-Z_-]{10,}/gi, type: 'instagram' },
153
+ { pattern: /https?:\/\/(?:www\.)?doubao\.com\/video\/\d{10,}/gi, type: 'doubao' },
138
154
  ];
139
155
  const matches = [];
140
156
  const seen = new Set();
141
157
  for (const rule of rules) {
142
158
  let match;
159
+ rule.pattern.lastIndex = 0;
143
160
  while ((match = rule.pattern.exec(content)) !== null) {
144
- const id = match[1];
145
- if (seen.has(id))
161
+ const url = match[0];
162
+ if (seen.has(url))
146
163
  continue;
147
- seen.add(id);
148
- const url = rule.buildUrl(id);
149
- matches.push({ type: rule.type, url, id });
164
+ seen.add(url);
165
+ matches.push({ type: rule.type, url, id: match[1] || url });
150
166
  }
151
167
  }
152
168
  return matches;
@@ -465,19 +481,9 @@ async function downloadVideoFile(videoUrl, tempDir, timeout, maxSizeMB) {
465
481
  await promises_1.default.unlink(filePath).catch(() => { });
466
482
  throw new Error(`视频文件过大(${Math.round(contentLength / 1024 / 1024)}MB),超过限制(${maxSizeMB}MB)`);
467
483
  }
468
- let downloadedSize = 0;
469
- response.data.on('data', (chunk) => {
470
- downloadedSize += chunk.length;
471
- if (maxSizeMB > 0 && downloadedSize > maxSizeBytes) {
472
- response.data.destroy();
473
- writer.destroy();
474
- promises_1.default.unlink(filePath).catch(() => { });
475
- throw new Error(`视频文件过大,超过限制(${maxSizeMB}MB)`);
476
- }
477
- });
478
484
  try {
479
485
  await (0, promises_2.pipeline)(response.data, writer);
480
- debugLog('INFO', `视频下载完成,大小: ${Math.round(downloadedSize / 1024 / 1024)}MB`);
486
+ debugLog('INFO', `视频下载完成`);
481
487
  return filePath;
482
488
  }
483
489
  catch (e) {
@@ -525,11 +531,12 @@ function apply(ctx, config) {
525
531
  const backupSupportedPlatforms = new Set(['douyin', 'xiaohongshu', 'instagram', 'jimeng']);
526
532
  function getPlatformConfig(type) {
527
533
  const custom = config.customApis?.find((item) => item.platform === type);
534
+ let apiUrl = defaultDedicatedApis[type] || null;
528
535
  if (custom && custom.apiUrl) {
529
- return { apiUrl: custom.apiUrl, dedicatedFirst: custom.useDedicatedFirst ?? false };
536
+ apiUrl = custom.apiUrl;
530
537
  }
531
- const defaultUrl = defaultDedicatedApis[type] || null;
532
- return { apiUrl: defaultUrl, dedicatedFirst: config.useDedicatedApiFirst ?? false };
538
+ const dedicatedFirst = config.platformDedicatedFirst?.[type] ?? false;
539
+ return { apiUrl, dedicatedFirst };
533
540
  }
534
541
  async function fetchApi(url, type) {
535
542
  const cacheKey = url;
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.1.0",
4
+ "version": "1.1.2",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md CHANGED
@@ -56,8 +56,8 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
56
56
  |--------|------|--------|------|
57
57
  | `primaryApiUrl` | string | `https://api.bugpk.com/api/short_videos` | 主 API 地址,解析时优先使用 |
58
58
  | `backupApiUrl` | string | `https://api.bugpk.com/api/svparse` | 备用主 API 地址,仅支持抖音、小红书、Instagram、即梦平台解析 |
59
- | `useDedicatedApiFirst` | boolean | false | 全局默认值:是否优先使用平台专属 API,各平台可单独覆盖该行为 |
60
- | `customApis` | array | [] | 自定义平台专属 API 列表。每项包含:`platform`(平台类型)、`apiUrl`(API 地址)、`useDedicatedFirst`(该平台是否优先使用此专属 API)。可覆盖内置默认专属 API,并独立控制专属 API 的优先策略 |
59
+ | `platformDedicatedFirst` | object | 各平台均为 `false` | 各平台独立开关:是否优先使用平台专属 API。对象键为平台标识(英文),值为布尔值。支持的键:`bilibili`(哔哩哔哩)、`douyin`(抖音)、`kuaishou`(快手)、`xiaohongshu`(小红书)、`weibo`(微博)、`xigua`(西瓜视频)、`youtube`(YouTube)、`tiktok`(TikTok)、`acfun`(AcFun)、`zhihu`(知乎)、`weishi`(微视)、`huya`(虎牙)、`haokan`(好看视频)、`meipai`(美拍)、`twitter`(Twitter/X)、`instagram`(Instagram)、`doubao`(豆包) |
60
+ | `customApis` | array | [] | 自定义平台专属 API 列表。每项包含:`platform`(平台类型)、`apiUrl`(API 地址)。可覆盖内置默认专属 API |
61
61
 
62
62
  ### 错误与重试设置
63
63
  | 配置项 | 类型 | 默认值 | 说明 |