koishi-plugin-video-parser-all 1.2.9 → 1.3.1

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
@@ -22,7 +22,8 @@ export declare const Config: Schema<{
22
22
  videoSendTimeout?: number | null | undefined;
23
23
  userAgent?: string | null | undefined;
24
24
  proxy?: ({
25
- protocol?: string | null | undefined;
25
+ enabled?: boolean | null | undefined;
26
+ protocol?: "http" | "https" | null | undefined;
26
27
  host?: string | null | undefined;
27
28
  port?: number | null | undefined;
28
29
  auth?: ({
@@ -64,11 +65,12 @@ export declare const Config: Schema<{
64
65
  twitter?: boolean | null | undefined;
65
66
  instagram?: boolean | null | undefined;
66
67
  doubao?: boolean | null | undefined;
68
+ doubao_chat?: boolean | null | undefined;
67
69
  oasis?: boolean | null | undefined;
68
70
  wechat_channel?: boolean | null | undefined;
69
71
  } & import("cosmokit").Dict) | null | undefined;
70
72
  customApis?: ({
71
- platform?: "bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao" | "oasis" | "wechat_channel" | null | undefined;
73
+ platform?: "bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao" | "doubao_chat" | "oasis" | "wechat_channel" | null | undefined;
72
74
  apiUrl?: string | null | undefined;
73
75
  apiKey?: string | null | undefined;
74
76
  authHeaderType?: "Bearer" | "X-API-Key" | "Custom" | null | undefined;
@@ -104,7 +106,8 @@ export declare const Config: Schema<{
104
106
  videoSendTimeout: number;
105
107
  userAgent: string;
106
108
  proxy: Schemastery.ObjectT<{
107
- protocol: Schema<string, string>;
109
+ enabled: Schema<boolean, boolean>;
110
+ protocol: Schema<"http" | "https", "http" | "https">;
108
111
  host: Schema<string, string>;
109
112
  port: Schema<number, number>;
110
113
  auth: Schema<Schemastery.ObjectS<{
@@ -149,11 +152,12 @@ export declare const Config: Schema<{
149
152
  twitter: Schema<boolean, boolean>;
150
153
  instagram: Schema<boolean, boolean>;
151
154
  doubao: Schema<boolean, boolean>;
155
+ doubao_chat: Schema<boolean, boolean>;
152
156
  oasis: Schema<boolean, boolean>;
153
157
  wechat_channel: Schema<boolean, boolean>;
154
158
  }>;
155
159
  customApis: Schemastery.ObjectT<{
156
- platform: Schema<"bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao" | "oasis" | "wechat_channel", "bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao" | "oasis" | "wechat_channel">;
160
+ platform: Schema<"bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao" | "doubao_chat" | "oasis" | "wechat_channel", "bilibili" | "douyin" | "kuaishou" | "xiaohongshu" | "weibo" | "xigua" | "youtube" | "tiktok" | "acfun" | "zhihu" | "weishi" | "huya" | "haokan" | "meipai" | "twitter" | "instagram" | "doubao" | "doubao_chat" | "oasis" | "wechat_channel">;
157
161
  apiUrl: Schema<string, string>;
158
162
  apiKey: Schema<string, string>;
159
163
  authHeaderType: Schema<"Bearer" | "X-API-Key" | "Custom", "Bearer" | "X-API-Key" | "Custom">;
package/lib/index.js CHANGED
@@ -76,7 +76,7 @@ exports.Config = koishi_1.Schema.intersect([
76
76
  debug: koishi_1.Schema.boolean().default(false).description('开启调试模式,在控制台输出详细日志'),
77
77
  }).description('基础设置'),
78
78
  koishi_1.Schema.object({
79
- unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n点赞:${点赞数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}\n图片数量:${图片数量}').description('统一消息格式,可用变量:${标题} ${作者} ${简介} ${点赞数} ${收藏数} ${转发数} ${播放数} ${评论数} ${视频时长} ${发布时间} ${图片数量} ${作者ID} ${封面}'),
79
+ unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n点赞:${点赞数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}\n图片数量:${图片数量}').description('统一消息格式,可用变量:${标题} ${作者} ${简介} ${点赞数} ${收藏数} ${转发数} ${播放数} ${评论数} ${视频时长} ${发布时间} ${图片数量} ${作者ID} ${音乐标题} ${音乐作者} ${音乐封面} ${音乐链接}'),
80
80
  }).description('消息格式设置'),
81
81
  koishi_1.Schema.object({
82
82
  showImageText: koishi_1.Schema.boolean().default(true).description('是否发送解析后的文字内容'),
@@ -94,14 +94,18 @@ exports.Config = koishi_1.Schema.intersect([
94
94
  videoSendTimeout: koishi_1.Schema.number().min(0).step(1).default(60000).description('视频消息发送超时(毫秒,0 为不限制)'),
95
95
  userAgent: koishi_1.Schema.string().default('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36').description('API 请求 UA'),
96
96
  proxy: koishi_1.Schema.object({
97
- protocol: koishi_1.Schema.string().default('http').description('代理协议'),
97
+ enabled: koishi_1.Schema.boolean().default(false).description('是否启用 HTTP/HTTPS 代理'),
98
+ protocol: koishi_1.Schema.union([
99
+ koishi_1.Schema.const('http').description('HTTP'),
100
+ koishi_1.Schema.const('https').description('HTTPS'),
101
+ ]).default('http').description('代理协议'),
98
102
  host: koishi_1.Schema.string().default('127.0.0.1').description('代理地址'),
99
103
  port: koishi_1.Schema.number().default(7890).description('代理端口'),
100
104
  auth: koishi_1.Schema.object({
101
105
  username: koishi_1.Schema.string().default('').description('代理用户名'),
102
106
  password: koishi_1.Schema.string().default('').description('代理密码'),
103
107
  }).description('代理认证'),
104
- }).description('HTTP 代理设置'),
108
+ }).description('HTTP/HTTPS 代理设置(需开启 enabled)'),
105
109
  customHeaders: koishi_1.Schema.array(koishi_1.Schema.object({
106
110
  name: koishi_1.Schema.string().required().description('请求头名称'),
107
111
  value: koishi_1.Schema.string().required().description('请求头值'),
@@ -140,6 +144,7 @@ exports.Config = koishi_1.Schema.intersect([
140
144
  twitter: koishi_1.Schema.boolean().default(false).description('Twitter/X - 优先使用专属 API'),
141
145
  instagram: koishi_1.Schema.boolean().default(false).description('Instagram - 优先使用专属 API'),
142
146
  doubao: koishi_1.Schema.boolean().default(false).description('豆包 - 优先使用专属 API'),
147
+ doubao_chat: koishi_1.Schema.boolean().default(false).description('豆包图片 - 优先使用专属 API'),
143
148
  oasis: koishi_1.Schema.boolean().default(false).description('绿洲 - 优先使用专属 API'),
144
149
  wechat_channel: koishi_1.Schema.boolean().default(false).description('视频号 - 优先使用专属 API'),
145
150
  }).description('各平台独立开关:是否优先使用专属 API'),
@@ -162,6 +167,7 @@ exports.Config = koishi_1.Schema.intersect([
162
167
  koishi_1.Schema.const('twitter').description('Twitter/X'),
163
168
  koishi_1.Schema.const('instagram').description('Instagram'),
164
169
  koishi_1.Schema.const('doubao').description('豆包'),
170
+ koishi_1.Schema.const('doubao_chat').description('豆包图片'),
165
171
  koishi_1.Schema.const('oasis').description('绿洲'),
166
172
  koishi_1.Schema.const('wechat_channel').description('视频号'),
167
173
  ]).description('选择平台'),
@@ -175,7 +181,29 @@ exports.Config = koishi_1.Schema.intersect([
175
181
  customHeaderName: koishi_1.Schema.string().description('自定义 Header 名称(仅当选择 Custom 时有效)').default('X-API-Key'),
176
182
  fieldMapping: koishi_1.Schema.string().role('textarea').default('{}').description('字段映射 JSON,例如 {"title":"data.info.name"},支持点号路径'),
177
183
  })).default([]).description('自定义平台专属 API 地址,留空则使用内置默认专属 API'),
178
- globalFieldMapping: koishi_1.Schema.string().role('textarea').default('{}').description('全局字段映射 JSON,优先级低于专属 API 映射'),
184
+ globalFieldMapping: koishi_1.Schema.string().role('textarea').default('{\n' +
185
+ ' "title": "data.title",\n' +
186
+ ' "desc": "data.description",\n' +
187
+ ' "author": "data.author.name",\n' +
188
+ ' "uid": "data.author.id",\n' +
189
+ ' "avatar": "data.author.avatar",\n' +
190
+ ' "cover": "data.cover_url",\n' +
191
+ ' "video": "data.video_url",\n' +
192
+ ' "video_backup": "data.video_qualities",\n' +
193
+ ' "videos": "data.videos",\n' +
194
+ ' "type": "data.type",\n' +
195
+ ' "like": "data.statistics.likes",\n' +
196
+ ' "comment": "data.statistics.comments",\n' +
197
+ ' "collect": "data.statistics.favorites",\n' +
198
+ ' "share": "data.statistics.shares",\n' +
199
+ ' "play": "data.statistics.plays",\n' +
200
+ ' "duration": "data.duration",\n' +
201
+ ' "publishTime": "data.create_time",\n' +
202
+ ' "music_title": "data.music.title",\n' +
203
+ ' "music_author": "data.music.author",\n' +
204
+ ' "music_cover": "data.music.cover",\n' +
205
+ ' "music_url": "data.music.url"\n' +
206
+ '}').description('全局字段映射 JSON,优先级低于专属 API 映射'),
179
207
  }).description('API 选择设置'),
180
208
  koishi_1.Schema.object({
181
209
  waitingTipText: koishi_1.Schema.string().default('正在解析视频,请稍候...').description('解析等待提示文字'),
@@ -219,6 +247,7 @@ const LINK_RULES = [
219
247
  { pattern: /https?:\/\/x\.com\/\w+\/status\/\d{10,}/gi, type: 'twitter' },
220
248
  { pattern: /https?:\/\/(?:www\.)?instagram\.com\/p\/[0-9a-zA-Z_-]{10,}/gi, type: 'instagram' },
221
249
  { pattern: /https?:\/\/(?:www\.)?doubao\.com\/video\/\d{10,}/gi, type: 'doubao' },
250
+ { pattern: /https?:\/\/(?:www\.)?doubao\.com\/thread\/[0-9a-zA-Z_-]+/gi, type: 'doubao_chat' },
222
251
  { pattern: /https?:\/\/(?:www\.)?oasis\.weibo\.com\/v\/[0-9a-zA-Z_-]+/gi, type: 'oasis' },
223
252
  { pattern: /https?:\/\/channels\.weixin\.qq\.com\/[0-9a-zA-Z_-]+/gi, type: 'wechat_channel' },
224
253
  { pattern: /https?:\/\/weixin\.qq\.com\/sph\/[0-9a-zA-Z_-]+/gi, type: 'wechat_channel' },
@@ -342,6 +371,23 @@ function getNestedValue(obj, path) {
342
371
  }
343
372
  return current;
344
373
  }
374
+ function parseCount(val) {
375
+ if (val === undefined || val === null)
376
+ return 0;
377
+ if (typeof val === 'number')
378
+ return val;
379
+ const str = String(val).trim();
380
+ if (str.includes('万')) {
381
+ const num = parseFloat(str);
382
+ return isNaN(num) ? 0 : Math.round(num * 10000);
383
+ }
384
+ if (str.includes('亿')) {
385
+ const num = parseFloat(str);
386
+ return isNaN(num) ? 0 : Math.round(num * 100000000);
387
+ }
388
+ const num = parseInt(str, 10);
389
+ return isNaN(num) ? 0 : num;
390
+ }
345
391
  function parseApiResponse(raw, maxDescLen, fieldMapping) {
346
392
  debugLog('DEBUG', 'API raw response', raw);
347
393
  const data = raw?.data || {};
@@ -355,7 +401,7 @@ function parseApiResponse(raw, maxDescLen, fieldMapping) {
355
401
  return fallback();
356
402
  };
357
403
  let type = mapField('type', () => {
358
- let t = data.type || '';
404
+ let t = data.type || data.videoType || '';
359
405
  if (!t) {
360
406
  if (data.images?.length > 0 && !data.url)
361
407
  t = 'image';
@@ -368,16 +414,16 @@ function parseApiResponse(raw, maxDescLen, fieldMapping) {
368
414
  }
369
415
  return t;
370
416
  });
371
- const authorObj = mapField('author', () => data.author);
417
+ let authorObj = mapField('author', () => data.author || data.user);
372
418
  let author = '', uid = '', avatar = '';
373
419
  if (authorObj && typeof authorObj === 'object') {
374
420
  author = authorObj.name || authorObj.author || '';
375
- uid = String(authorObj.id || data.uid || '');
421
+ uid = String(authorObj.id || authorObj.userID || data.uid || data.userID || data.author_id || '');
376
422
  avatar = authorObj.avatar || data.avatar || '';
377
423
  }
378
424
  else {
379
425
  author = mapField('author', () => data.author || data.auther || '');
380
- uid = String(mapField('uid', () => data.uid || ''));
426
+ uid = String(mapField('uid', () => data.uid || data.userID || data.author_id || ''));
381
427
  avatar = mapField('avatar', () => data.avatar || '');
382
428
  }
383
429
  const title = mapField('title', () => data.title || '');
@@ -402,37 +448,53 @@ function parseApiResponse(raw, maxDescLen, fieldMapping) {
402
448
  }
403
449
  }
404
450
  }
451
+ if (!video && data.quality_urls && typeof data.quality_urls === 'object') {
452
+ const entries = Object.entries(data.quality_urls);
453
+ videos = entries.map(([label, url]) => ({ quality: label, url: String(url) }));
454
+ if (videos.length)
455
+ video = videos[0].url;
456
+ }
405
457
  if (!video)
406
458
  video = mapField('video', () => data.url || '');
407
459
  if (video && !video.startsWith('http'))
408
460
  video = 'https:' + video;
409
- const images = Array.isArray(data.images) ? data.images.filter((img) => img && typeof img === 'string').map((img) => img.startsWith('http') ? img : 'https:' + img) : [];
461
+ let images = [];
462
+ const directImages = mapField('images', () => data.images);
463
+ if (Array.isArray(directImages)) {
464
+ images = directImages.filter((img) => img && typeof img === 'string').map((img) => img.startsWith('http') ? img : 'https:' + img);
465
+ }
466
+ else if (Array.isArray(data.imgurl)) {
467
+ images = data.imgurl.filter((img) => img && typeof img === 'string').map((img) => img.startsWith('http') ? img : 'https:' + img);
468
+ }
410
469
  const live_photo = Array.isArray(data.live_photo) ? data.live_photo.filter((lp) => lp && lp.image).map((lp) => ({
411
470
  image: lp.image.startsWith('http') ? lp.image : 'https:' + lp.image,
412
471
  video: lp.video ? (lp.video.startsWith('http') ? lp.video : 'https:' + lp.video) : ''
413
472
  })) : [];
473
+ const musicCoverRaw = mapField('music_cover', () => data.music?.cover || data.music?.albumCover?.url || '');
474
+ const musicUrlRaw = mapField('music_url', () => data.music?.url || data.music?.playURL || '');
414
475
  const music = {
415
476
  title: mapField('music_title', () => data.music?.title || data.music?.name || ''),
416
477
  author: mapField('music_author', () => data.music?.author || data.music?.artist || ''),
417
- cover: mapField('music_cover', () => data.music?.cover || ''),
418
- url: mapField('music_url', () => data.music?.url || ''),
478
+ cover: musicCoverRaw ? (String(musicCoverRaw).startsWith('http') ? String(musicCoverRaw) : 'https:' + musicCoverRaw) : '',
479
+ url: musicUrlRaw ? (String(musicUrlRaw).startsWith('http') ? String(musicUrlRaw) : 'https:' + musicUrlRaw) : '',
419
480
  };
420
- const stats = { ...(data.statistics || {}), ...(extra.statistics || {}) };
421
- const like = Number(mapField('like', () => data.like ?? stats.digg_count ?? stats.like_count ?? stats.likes ?? 0));
422
- const comment = Number(mapField('comment', () => data.comment ?? stats.comment_count ?? stats.comments ?? stats.comment ?? 0));
423
- const collect = Number(mapField('collect', () => data.collect ?? stats.collect_count ?? stats.favorite_count ?? stats.favorites ?? 0));
424
- const share = Number(mapField('share', () => data.share ?? stats.share_count ?? stats.forward_count ?? stats.shares ?? 0));
425
- const play = Number(mapField('play', () => data.play ?? stats.play_count ?? stats.view_count ?? stats.plays ?? 0));
481
+ const like = parseCount(mapField('like', () => data.like ?? data.statistics?.digg_count ?? data.statistics?.like_count ?? data.statistics?.likes ?? extra.statistics?.digg_count ?? extra.statistics?.like_count ?? extra.statistics?.likes ?? data.attitudes_count ?? 0));
482
+ const comment = parseCount(mapField('comment', () => data.comment ?? data.statistics?.comment_count ?? data.statistics?.comments ?? extra.statistics?.comment_count ?? extra.statistics?.comments ?? data.comments_count ?? 0));
483
+ const collect = parseCount(mapField('collect', () => data.collect ?? data.statistics?.collect_count ?? data.statistics?.favorite_count ?? data.statistics?.favorites ?? extra.statistics?.collect_count ?? extra.statistics?.favorite_count ?? extra.statistics?.favorites ?? data.favorites_count ?? 0));
484
+ const share = parseCount(mapField('share', () => data.share ?? data.statistics?.share_count ?? data.statistics?.forward_count ?? data.statistics?.shares ?? extra.statistics?.share_count ?? extra.statistics?.forward_count ?? extra.statistics?.shares ?? data.reposts_count ?? 0));
485
+ const play = parseCount(mapField('play', () => data.play ?? data.statistics?.play_count ?? data.statistics?.view_count ?? data.statistics?.plays ?? extra.statistics?.play_count ?? extra.statistics?.view_count ?? extra.statistics?.plays ?? data.play_count ?? data.view_count ?? 0));
426
486
  let duration = 0;
427
- const durRaw = mapField('duration', () => data.duration);
428
- if (durRaw) {
429
- duration = typeof durRaw === 'string' ? parseInt(durRaw, 10) : Number(durRaw);
430
- if (duration > 1000000)
431
- duration = Math.floor(duration / 1000);
432
- }
433
- else if (extra.duration_ms) {
487
+ if (extra.duration_ms) {
434
488
  duration = Math.floor(Number(extra.duration_ms) / 1000);
435
489
  }
490
+ else {
491
+ const durRaw = mapField('duration', () => data.duration);
492
+ if (durRaw) {
493
+ duration = typeof durRaw === 'string' ? parseInt(durRaw, 10) : Number(durRaw);
494
+ if (duration > 3600)
495
+ duration = Math.floor(duration / 1000);
496
+ }
497
+ }
436
498
  let publishTime = 0;
437
499
  const timeRaw = mapField('publishTime', () => data.time);
438
500
  if (timeRaw) {
@@ -463,17 +525,32 @@ function generateFormattedText(p, format) {
463
525
  '作者ID': p.uid,
464
526
  '封面': p.cover,
465
527
  '视频链接': p.video,
528
+ '音乐标题': p.music.title || '',
529
+ '音乐作者': p.music.author || '',
530
+ '音乐封面': p.music.cover || '',
531
+ '音乐链接': p.music.url || '',
466
532
  };
467
533
  const lines = format.split('\n');
468
534
  const resultLines = [];
469
535
  for (const line of lines) {
536
+ const varMatches = line.match(formatVarRegex);
537
+ if (varMatches && varMatches.length > 0) {
538
+ let allEmptyOrZero = true;
539
+ for (const match of varMatches) {
540
+ const varName = match.slice(2, -1);
541
+ const val = vars[varName];
542
+ if (val && val !== '0') {
543
+ allEmptyOrZero = false;
544
+ break;
545
+ }
546
+ }
547
+ if (allEmptyOrZero)
548
+ continue;
549
+ }
470
550
  let newLine = line;
471
551
  for (const [key, val] of Object.entries(vars)) {
472
552
  newLine = newLine.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), val);
473
553
  }
474
- const stripped = newLine.replace(/[\s::,,。.、;;!!??【】\[\]「」『』()()《》""''""·—\-_/\\|@#$%^&*+=~`]/g, '').trim();
475
- if (stripped.length === 0)
476
- continue;
477
554
  resultLines.push(newLine);
478
555
  }
479
556
  return resultLines.join('\n').trim();
@@ -531,7 +608,7 @@ function apply(ctx, config) {
531
608
  'Content-Type': 'application/x-www-form-urlencoded'
532
609
  }
533
610
  };
534
- if (proxyConfig.host) {
611
+ if (proxyConfig.enabled && proxyConfig.host) {
535
612
  axiosConfig.proxy = {
536
613
  protocol: proxyConfig.protocol || 'http',
537
614
  host: proxyConfig.host,
@@ -547,6 +624,7 @@ function apply(ctx, config) {
547
624
  bilibili: 'https://api.bugpk.com/api/bilibili',
548
625
  douyin: 'https://api.bugpk.com/api/douyin',
549
626
  doubao: 'https://api.bugpk.com/api/dbvideos',
627
+ doubao_chat: 'https://api.bugpk.com/api/dbduihua',
550
628
  kuaishou: 'https://api.bugpk.com/api/kuaishou',
551
629
  xiaohongshu: 'https://api.bugpk.com/api/xhs',
552
630
  jimeng: 'https://api.bugpk.com/api/jimengai',
@@ -712,7 +790,7 @@ function apply(ctx, config) {
712
790
  for (const candidate of candidates) {
713
791
  try {
714
792
  const info = await fetchApi(candidate, type, fieldMapping);
715
- if (info.video || info.images.length > 0)
793
+ if (info.video || info.images.length > 0 || info.live_photo.length > 0)
716
794
  return { success: true, data: info };
717
795
  debugLog('WARN', `解析成功但无内容: ${candidate}`);
718
796
  }
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.2.9",
4
+ "version": "1.3.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md CHANGED
@@ -31,15 +31,7 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
31
31
  ### 统一消息格式 (Unified Message Format)
32
32
  | 配置项 | 类型 | 默认值 | 说明 |
33
33
  |--------|------|--------|------|
34
- | `unifiedMessageFormat` | string | `标题:${标题}
35
- 作者:${作者}
36
- 简介:${简介}
37
- 点赞:${点赞数}
38
- 收藏:${收藏数}
39
- 转发:${转发数}
40
- 播放:${播放数}
41
- 评论:${评论数}
42
- 图片数量:${图片数量}` | 自定义解析结果的输出格式,支持变量替换。某行所有变量均为空(或为"0")时自动隐藏该行 |
34
+ | `unifiedMessageFormat` | string | `标题:${标题}\n作者:${作者}\n简介:${简介}\n点赞:${点赞数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}\n图片数量:${图片数量}` | 自定义解析结果的输出格式,支持变量替换。某行所有变量均为空(或为"0")时自动隐藏该行 |
43
35
 
44
36
  ### 内容显示设置 (Content Display Settings)
45
37
  | 配置项 | 类型 | 默认值 | 说明 |
@@ -60,7 +52,7 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
60
52
  | `timeout` | number | 180000 | API 请求超时时间(毫秒) |
61
53
  | `videoSendTimeout` | number | 60000 | 视频消息发送超时时间(毫秒,0 为不限制) |
62
54
  | `userAgent` | string | `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36` | API 请求使用的 User-Agent |
63
- | `proxy` | object | `{ protocol: "http", host: "127.0.0.1", port: 7890, auth: { username: "", password: "" } }` | HTTP 代理设置,支持认证。不填 `host` 则不启用代理 |
55
+ | `proxy` | object | `{ enabled: false, protocol: "http", host: "127.0.0.1", port: 7890, auth: { username: "", password: "" } }` | HTTP/HTTPS 代理设置。`enabled` 开关(默认关闭),`protocol` 下拉选择 `http` 或 `https`。需开启 `enabled` 并填写 `host` 后生效 |
64
56
  | `customHeaders` | array | [] | 自定义请求头,会附加到所有 API 请求中。每项包含 `name`(头名称)和 `value`(头值) |
65
57
 
66
58
  ### API 选择与回退设置 (API Selection & Fallback)
@@ -68,9 +60,9 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
68
60
  |--------|------|--------|------|
69
61
  | `primaryApiUrl` | string | `https://api.bugpk.com/api/short_videos` | 主 API 地址,解析时优先使用 |
70
62
  | `backupApiUrl` | string | `https://api.bugpk.com/api/svparse` | 备用主 API 地址,仅支持抖音、小红书、Instagram、即梦平台解析 |
71
- | `platformDedicatedFirst` | object | 各平台均为 `false` | 各平台独立开关:是否优先使用平台专属 API。对象键为平台标识(英文),值为布尔值。支持的键:`bilibili`、`douyin`、`kuaishou`、`xiaohongshu`、`weibo`、`xigua`、`youtube`、`tiktok`、`acfun`、`zhihu`、`weishi`、`huya`、`haokan`、`meipai`、`twitter`、`instagram`、`doubao`、`oasis`、`wechat_channel` |
63
+ | `platformDedicatedFirst` | object | 各平台均为 `false` | 各平台独立开关:是否优先使用平台专属 API。对象键为平台标识(英文),值为布尔值。支持的键:`bilibili`、`douyin`、`kuaishou`、`xiaohongshu`、`weibo`、`xigua`、`youtube`、`tiktok`、`acfun`、`zhihu`、`weishi`、`huya`、`haokan`、`meipai`、`twitter`、`instagram`、`doubao`、`doubao_chat`、`oasis`、`wechat_channel` |
72
64
  | `customApis` | array | [] | 自定义平台专属 API 列表。每项包含:`platform`(平台类型)、`apiUrl`(API 地址)、`apiKey`(API Key,可选)、`authHeaderType`(认证头类型,可选:`Bearer` / `X-API-Key` / `Custom`)、`customHeaderName`(自定义 Header 名称,仅当 `authHeaderType` 为 `Custom` 时有效)、`fieldMapping`(字段映射 JSON 字符串,用于适配非标准 API 响应,支持点号路径) |
73
- | `globalFieldMapping` | string | `{}` | 全局字段映射 JSON 字符串,优先级低于专属 API 映射。用于统一适配所有平台的 API 响应格式,例如 `{"title":"data.info.title"}` |
65
+ | `globalFieldMapping` | string | 预设完整字段映射JSON(见下方示例) | 全局字段映射 JSON,优先级低于专属 API 映射。用于统一适配所有平台的 API 响应格式,默认已包含常用路径示例 |
74
66
 
75
67
  ### 错误与重试设置 (Error & Retry Settings)
76
68
  | 配置项 | 类型 | 默认值 | 说明 |
@@ -116,8 +108,11 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
116
108
  | `${发布时间}` | 发布时间(格式化) | 所有平台 |
117
109
  | `${图片数量}` | 图集/实况图片数量 | 图集/实况 |
118
110
  | `${作者ID}` | 作者唯一标识ID | 部分平台 |
119
- | `${封面}` | 封面图片地址 | 所有平台 |
120
111
  | `${视频链接}` | 视频原始链接 | 视频 |
112
+ | `${音乐标题}` | 音乐标题 | 部分平台 |
113
+ | `${音乐作者}` | 音乐作者 | 部分平台 |
114
+ | `${音乐封面}` | 音乐封面图片地址 | 部分平台 |
115
+ | `${音乐链接}` | 音乐原始链接 | 部分平台 |
121
116
 
122
117
  > 注:部分变量可能因平台API返回数据不同而显示为空,某行所有变量为空(或为"0")时该行会自动隐藏。
123
118
 
@@ -143,7 +138,8 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
143
138
  | 全民直播 | quanmin (quanmin.tv) | 直播 |
144
139
  | Twitter / X | twitter, x.com | 视频、图文 |
145
140
  | Instagram | instagram, instagram.com | 图文、Reels |
146
- | 豆包 | doubao (doubao.com) | 视频 |
141
+ | 豆包 | doubao (doubao.com/video) | 视频 |
142
+ | 豆包图片 | doubao (doubao.com/thread) | 图片 |
147
143
  | 皮皮搞笑 | pipigx, h5.pipigx.com | 短视频 |
148
144
  | 皮皮虾 | pipixia, h5.pipix.com | 短视频 |
149
145
  | 最右 | zuiyou, xiaochuankeji.cn | 短视频 |
@@ -158,6 +154,9 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
158
154
  |----------------------|-------------------------|
159
155
  | Minecraft-1314 | 插件完整开发 (Complete plugin development) |
160
156
  | ShiraiKuroko003 | 修复消息格式设置问题并且PR-1.2.5版本已修复 |
157
+ | cyavb | 提交功能建议-给自定义API添加KEY认证-已修复 |
158
+ | Keep785 | 提交Bug-无法正常关闭发送封面-已修复 |
159
+ | dzt2008 + Apricityx | 提交Bug-会对非支持视频平台URL进行误解析-已修复 |
161
160
  | JH-Ahua | BugPk-Api 支持 |
162
161
  | shangxue | 灵感来源 |
163
162