koishi-plugin-video-parser-all 1.1.1 → 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,8 +28,25 @@ export declare const Config: Schema<{
28
28
  } & {
29
29
  primaryApiUrl?: string | null | undefined;
30
30
  backupApiUrl?: string | null | undefined;
31
- useDedicatedApiFirst?: boolean | null | undefined;
32
- platformDedicatedFirst?: import("cosmokit").Dict<boolean, string> | 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;
33
50
  customApis?: ({
34
51
  platform?: "bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao" | null | undefined;
35
52
  apiUrl?: string | null | undefined;
@@ -68,8 +85,25 @@ export declare const Config: Schema<{
68
85
  } & {
69
86
  primaryApiUrl: string;
70
87
  backupApiUrl: string;
71
- useDedicatedApiFirst: boolean;
72
- platformDedicatedFirst: import("cosmokit").Dict<boolean, string>;
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
+ }>;
73
107
  customApis: Schemastery.ObjectT<{
74
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">;
75
109
  apiUrl: Schema<string, string>;
package/lib/index.js CHANGED
@@ -10,6 +10,7 @@ const axios_1 = __importDefault(require("axios"));
10
10
  const promises_1 = __importDefault(require("fs/promises"));
11
11
  const path_1 = __importDefault(require("path"));
12
12
  const fs_1 = require("fs");
13
+ const promises_2 = require("stream/promises");
13
14
  const lru_cache_1 = require("lru-cache");
14
15
  exports.name = 'video-parser-all';
15
16
  exports.Config = koishi_1.Schema.intersect([
@@ -47,28 +48,25 @@ exports.Config = koishi_1.Schema.intersect([
47
48
  koishi_1.Schema.object({
48
49
  primaryApiUrl: koishi_1.Schema.string().default('https://api.bugpk.com/api/short_videos').description('主 API 地址'),
49
50
  backupApiUrl: koishi_1.Schema.string().default('https://api.bugpk.com/api/svparse').description('备用主 API 地址(仅支持抖音/小红书/ins/即梦)'),
50
- useDedicatedApiFirst: koishi_1.Schema.boolean().default(false).description('全局默认:是否优先使用平台专属 API(各平台可单独覆盖)'),
51
- platformDedicatedFirst: koishi_1.Schema.dict(koishi_1.Schema.boolean())
52
- .default({
53
- bilibili: false,
54
- douyin: false,
55
- kuaishou: false,
56
- xiaohongshu: false,
57
- weibo: false,
58
- xigua: false,
59
- youtube: false,
60
- tiktok: false,
61
- acfun: false,
62
- zhihu: false,
63
- weishi: false,
64
- huya: false,
65
- haokan: false,
66
- meipai: false,
67
- twitter: false,
68
- instagram: false,
69
- doubao: false,
70
- })
71
- .description('各平台独立开关:是否优先使用专属 API(key 为平台名)'),
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'),
72
70
  customApis: koishi_1.Schema.array(koishi_1.Schema.object({
73
71
  platform: koishi_1.Schema.union([
74
72
  koishi_1.Schema.const('bilibili').description('哔哩哔哩'),
@@ -127,32 +125,32 @@ const urlCache = new lru_cache_1.LRUCache({
127
125
  function linkTypeParser(content) {
128
126
  content = content.replace(/\\\//g, '/');
129
127
  const rules = [
130
- { pattern: /bilibili\.com\/video\/([ab]v[0-9a-zA-Z]+)/gi, type: 'bilibili', buildUrl: (id) => `https://www.bilibili.com/video/${id}` },
131
- { pattern: /b23\.tv\/([0-9a-zA-Z_-]{5,})/gi, type: 'bilibili', buildUrl: (id) => `https://b23.tv/${id}` },
132
- { pattern: /bili(?:22|23|33|2233)\.cn\/([0-9a-zA-Z_-]{5,})/gi, type: 'bilibili', buildUrl: (id) => `https://bili${RegExp.$1 || ''}.cn/${id}` },
133
- { pattern: /douyin\.com\/video\/(\d{10,})/gi, type: 'douyin', buildUrl: (id) => `https://www.douyin.com/video/${id}` },
134
- { pattern: /v\.douyin\.com\/([0-9a-zA-Z_-]{8,})/gi, type: 'douyin', buildUrl: (id) => `https://v.douyin.com/${id}/` },
135
- { pattern: /kuaishou\.com\/short-video\/([0-9a-zA-Z_-]{10,})/gi, type: 'kuaishou', buildUrl: (id) => `https://www.kuaishou.com/short-video/${id}` },
136
- { pattern: /v\.kuaishou\.com\/([0-9a-zA-Z_-]{8,})/gi, type: 'kuaishou', buildUrl: (id) => `https://v.kuaishou.com/${id}` },
137
- { pattern: /xiaohongshu\.com\/discovery\/item\/([0-9a-zA-Z_-]{10,})/gi, type: 'xiaohongshu', buildUrl: (id) => `https://www.xiaohongshu.com/discovery/item/${id}` },
138
- { pattern: /xhslink\.com\/([0-9a-zA-Z_-]{8,})/gi, type: 'xiaohongshu', buildUrl: (id) => `https://xhslink.com/${id}` },
139
- { pattern: /weibo\.com\/\d+\/([0-9a-zA-Z_-]{10,})/gi, type: 'weibo', buildUrl: (id) => `https://weibo.com/${id}` },
140
- { pattern: /video\.weibo\.com\/show\?fid=([0-9a-zA-Z_-]{10,})/gi, type: 'weibo', buildUrl: (id) => `https://video.weibo.com/show?fid=${id}` },
141
- { pattern: /ixigua\.com\/(\d{10,})/gi, type: 'xigua', buildUrl: (id) => `https://www.ixigua.com/${id}` },
142
- { pattern: /youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/gi, type: 'youtube', buildUrl: (id) => `https://www.youtube.com/watch?v=${id}` },
143
- { pattern: /youtu\.be\/([a-zA-Z0-9_-]{11})/gi, type: 'youtube', buildUrl: (id) => `https://youtu.be/${id}` },
144
- { pattern: /tiktok\.com\/@[\w.]+\/video\/(\d{10,})/gi, type: 'tiktok', buildUrl: (id) => `https://www.tiktok.com/@user/video/${id}` },
145
- { pattern: /vm\.tiktok\.com\/([0-9a-zA-Z_-]{8,})/gi, type: 'tiktok', buildUrl: (id) => `https://vm.tiktok.com/${id}` },
146
- { pattern: /acfun\.cn\/v\/(ac\d{10,})/gi, type: 'acfun', buildUrl: (id) => `https://www.acfun.cn/v/${id}` },
147
- { pattern: /zhihu\.com\/video\/(\d{10,})/gi, type: 'zhihu', buildUrl: (id) => `https://www.zhihu.com/video/${id}` },
148
- { pattern: /weishi\.qq\.com\/weishi\/feed\/([0-9a-zA-Z_-]{10,})/gi, type: 'weishi', buildUrl: (id) => `https://weishi.qq.com/weishi/feed/${id}` },
149
- { pattern: /huya\.com\/video\/([0-9a-zA-Z_-]{10,})/gi, type: 'huya', buildUrl: (id) => `https://www.huya.com/video/${id}` },
150
- { pattern: /haokan\.baidu\.com\/v\?vid=([0-9a-zA-Z_-]{10,})/gi, type: 'haokan', buildUrl: (id) => `https://haokan.baidu.com/v?vid=${id}` },
151
- { pattern: /meipai\.com\/media\/(\d{10,})/gi, type: 'meipai', buildUrl: (id) => `https://www.meipai.com/media/${id}` },
152
- { pattern: /twitter\.com\/\w+\/status\/(\d{10,})/gi, type: 'twitter', buildUrl: (id) => `https://twitter.com/i/status/${id}` },
153
- { pattern: /x\.com\/\w+\/status\/(\d{10,})/gi, type: 'twitter', buildUrl: (id) => `https://x.com/i/status/${id}` },
154
- { pattern: /instagram\.com\/p\/([0-9a-zA-Z_-]{10,})/gi, type: 'instagram', buildUrl: (id) => `https://www.instagram.com/p/${id}` },
155
- { 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' },
156
154
  ];
157
155
  const matches = [];
158
156
  const seen = new Set();
@@ -160,12 +158,11 @@ function linkTypeParser(content) {
160
158
  let match;
161
159
  rule.pattern.lastIndex = 0;
162
160
  while ((match = rule.pattern.exec(content)) !== null) {
163
- const id = match[1];
164
- if (seen.has(id))
161
+ const url = match[0];
162
+ if (seen.has(url))
165
163
  continue;
166
- seen.add(id);
167
- const url = rule.buildUrl(id);
168
- matches.push({ type: rule.type, url, id });
164
+ seen.add(url);
165
+ matches.push({ type: rule.type, url, id: match[1] || url });
169
166
  }
170
167
  }
171
168
  return matches;
@@ -484,31 +481,9 @@ async function downloadVideoFile(videoUrl, tempDir, timeout, maxSizeMB) {
484
481
  await promises_1.default.unlink(filePath).catch(() => { });
485
482
  throw new Error(`视频文件过大(${Math.round(contentLength / 1024 / 1024)}MB),超过限制(${maxSizeMB}MB)`);
486
483
  }
487
- let downloadedSize = 0;
488
- response.data.on('data', (chunk) => {
489
- downloadedSize += chunk.length;
490
- if (maxSizeMB > 0 && downloadedSize > maxSizeBytes) {
491
- response.data.destroy();
492
- writer.destroy();
493
- promises_1.default.unlink(filePath).catch(() => { });
494
- throw new Error(`视频文件过大,超过限制(${maxSizeMB}MB)`);
495
- }
496
- });
497
484
  try {
498
- await new Promise((resolve, reject) => {
499
- const stream = require('stream');
500
- const pipeline = stream.promises?.pipeline || require('util').promisify(stream.pipeline);
501
- if (typeof pipeline === 'function') {
502
- pipeline(response.data, writer).then(resolve).catch(reject);
503
- }
504
- else {
505
- response.data.pipe(writer);
506
- writer.on('finish', resolve);
507
- writer.on('error', reject);
508
- response.data.on('error', reject);
509
- }
510
- });
511
- debugLog('INFO', `视频下载完成,大小: ${Math.round(downloadedSize / 1024 / 1024)}MB`);
485
+ await (0, promises_2.pipeline)(response.data, writer);
486
+ debugLog('INFO', `视频下载完成`);
512
487
  return filePath;
513
488
  }
514
489
  catch (e) {
@@ -560,7 +535,7 @@ function apply(ctx, config) {
560
535
  if (custom && custom.apiUrl) {
561
536
  apiUrl = custom.apiUrl;
562
537
  }
563
- const dedicatedFirst = config.platformDedicatedFirst?.[type] ?? config.useDedicatedApiFirst ?? false;
538
+ const dedicatedFirst = config.platformDedicatedFirst?.[type] ?? false;
564
539
  return { apiUrl, dedicatedFirst };
565
540
  }
566
541
  async function fetchApi(url, type) {
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.1",
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,7 @@ 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
- | `platformDedicatedFirst` | object | 见下方说明 | 各平台独立开关:是否优先使用专属 API(key 为平台名)。支持的 key:bilibili、douyin、kuaishou、xiaohongshu、weibo、xigua、youtube、tiktok、acfun、zhihu、weishi、huya、haokan、meipai、twitter、instagram、doubao |
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`(豆包) |
61
60
  | `customApis` | array | [] | 自定义平台专属 API 列表。每项包含:`platform`(平台类型)、`apiUrl`(API 地址)。可覆盖内置默认专属 API |
62
61
 
63
62
  ### 错误与重试设置