koishi-plugin-video-parser-all 0.6.1 → 0.6.3

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 (2) hide show
  1. package/lib/index.js +114 -18
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -22,7 +22,37 @@ exports.Config = koishi_1.Schema.intersect([
22
22
  sameLinkInterval: koishi_1.Schema.number().min(0).default(180).description('相同链接重复解析间隔(秒)'),
23
23
  }).description('基础设置'),
24
24
  koishi_1.Schema.object({
25
- unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default('标题:${标题}\n作者:${作者}\n简介:${简介}\n时长:${视频时长}\n点赞:${点赞数}\n投币:${投币数}\n收藏:${收藏数}\n转发:${转发数}\n播放:${播放数}\n评论:${评论数}\n音乐:${音乐名}').description('统一消息格式(无法获取的变量会自动隐藏)\n变量介绍:\n${标题} - 内容标题\n${作者} - 作者名称\n${简介} - 内容简介\n${视频时长} - 视频时长\n${点赞数} - 点赞数量\n${投币数} - 投币数(仅B站)\n收藏数 - 收藏数量\n${转发数} - 转发/分享数量\n${播放数} - 播放数量\n${评论数} - 评论数量\n${音乐名} - 背景音乐名称'),
25
+ unifiedMessageFormat: koishi_1.Schema.string().role('textarea').default(`标题:${'${标题}'}
26
+ 作者:${'${作者}'}
27
+ 简介:${'${简介}'}
28
+ 时长:${'${视频时长}'}
29
+ 点赞:${'${点赞数}'}
30
+ 投币:${'${投币数}'}
31
+ 收藏:${'${收藏数}'}
32
+ 转发:${'${转发数}'}
33
+ 播放:${'${播放数}'}
34
+ 评论:${'${评论数}'}
35
+ 音乐:${'${音乐名}'}
36
+ IP属地:${'${IP属地}'}
37
+ 发布时间:${'${发布时间}'}
38
+ 粉丝数:${'${粉丝数}'}
39
+ 在线人数:${'${在线人数}'}
40
+ 关注数:${'${关注数}'}
41
+ 视频质量:${'${视频质量}'}
42
+ 帧率:${'${帧率}'}
43
+ 码率:${'${码率}'}
44
+ 文件大小:${'${文件大小}'}
45
+ 分辨率:${'${分辨率}'}
46
+ 音乐作者:${'${音乐作者}'}
47
+ 音乐标题:${'${音乐标题}'}
48
+ 直播间地址:${'${直播间地址}'}
49
+ 直播间ID:${'${直播间ID}'}
50
+ 直播间状态:${'${直播间状态}'}
51
+ 默认画质:${'${默认画质}'}
52
+ 图片数量:${'${图片数量}'}
53
+ 作者ID:${'${作者ID}'}
54
+ 封面链接:${'${封面链接}'}
55
+ 视频链接:${'${视频链接}'}`).description('统一消息格式(无法获取的变量会自动隐藏)'),
26
56
  }).description('统一消息格式'),
27
57
  koishi_1.Schema.object({
28
58
  showImageText: koishi_1.Schema.boolean().default(true).description('显示图文内容'),
@@ -125,17 +155,37 @@ const API_CONFIG = {
125
155
  zuiyou: 'https://api.bugpk.com/api/zuiyou'
126
156
  };
127
157
  const VARIABLE_MAPPING = {
128
- '标题': ['title', 'Title', 'TITLE', 'note_title', 'content_title'],
129
- '作者': ['author.name', 'author', 'name', 'Author', 'Name', 'owner.name', 'nickname', 'user_name'],
130
- '简介': ['desc', 'description', 'Desc', 'Description', 'content', 'Content', 'note_desc', 'text'],
131
- '视频时长': ['duration', 'Duration', 'time', 'Time', 'video_duration'],
132
- '点赞数': ['like', 'Like', 'attitudes_count', 'digg_count', 'praise', 'stat.like', 'liked_count'],
133
- '投币数': ['coin', 'Coin', 'bi', 'Bi', 'stat.coin'],
134
- '收藏数': ['collect', 'Collect', 'favorite', 'Favorite', 'star', 'Star', 'stat.collect', 'collected_count'],
135
- '转发数': ['share', 'Share', 'forward', 'Forward', 'repost', 'stat.share', 'reposts_count', 'shared_count'],
136
- '播放数': ['view', 'View', 'play_count', 'PlayCount', 'play', 'stat.view', 'play_times'],
137
- '评论数': ['comment', 'Comment', 'comments_count', 'comment_count', 'discuss', 'stat.comment'],
138
- '音乐名': ['music.title', 'music_name', 'audio_name', 'sound_name', 'muisic', 'music', 'bgm_name']
158
+ '标题': ['title', 'Title', 'TITLE', 'note_title', 'content_title', 'item.title', 'data.title', 'video.title', 'live.title'],
159
+ '作者': ['author.name', 'author', 'name', 'Author', 'Name', 'owner.name', 'nickname', 'user_name', 'data.author', 'item.author', 'user.name', 'live.author'],
160
+ '简介': ['desc', 'description', 'Desc', 'Description', 'content', 'Content', 'note_desc', 'text', 'data.desc', 'item.description', 'live.desc'],
161
+ '视频时长': ['duration', 'Duration', 'time', 'Time', 'video_duration', 'item.duration', 'stat.duration'],
162
+ '点赞数': ['like', 'Like', 'attitudes_count', 'digg_count', 'praise', 'stat.like', 'liked_count', 'data.like', 'data.attitudes_count', 'item.attitudes_count'],
163
+ '投币数': ['coin', 'Coin', 'bi', 'Bi', 'stat.coin', 'stast.coin'],
164
+ '收藏数': ['collect', 'Collect', 'favorite', 'Favorite', 'star', 'Star', 'stat.collect', 'collected_count', 'stast.favorite', 'data.favorite'],
165
+ '转发数': ['share', 'Share', 'forward', 'Forward', 'repost', 'stat.share', 'reposts_count', 'shared_count', 'stast.share', 'data.reposts_count'],
166
+ '播放数': ['view', 'View', 'play_count', 'PlayCount', 'play', 'stat.view', 'play_times', 'stast.view', 'data.play_count', 'item.play_count'],
167
+ '评论数': ['comment', 'Comment', 'comments_count', 'comment_count', 'discuss', 'stat.comment', 'stast.reply', 'data.comments_count', 'item.comments_count'],
168
+ '音乐名': ['music.title', 'music_name', 'audio_name', 'sound_name', 'muisic', 'music', 'bgm_name', 'data.music.name', 'item.music.title', 'music.author', 'music.albumName'],
169
+ 'IP属地': ['ip_info_str', 'data.ip_info_str', 'item.ip_info'],
170
+ '发布时间': ['date', 'time', 'publish_time', 'data.date', 'item.publish_time', 'live.time', 'stast.publish_time'],
171
+ '粉丝数': ['followers_count', 'data.followers_count', 'item.followers', 'author.fans'],
172
+ '在线人数': ['online', 'data.online', 'live.online', 'room.online'],
173
+ '关注数': ['attention', 'data.attention', 'live.attention', 'stast.attention'],
174
+ '视频质量': ['quality', 'max_qxd', 'data.quality', 'item.quality', 'quality_urls'],
175
+ '帧率': ['fps', 'item.fps', 'data.fps'],
176
+ '码率': ['bitrate', 'item.bitrate', 'data.bitrate', 'br', 'item.br'],
177
+ '文件大小': ['size', 'size_str', 'item.size', 'item.size_str', 'data.size'],
178
+ '分辨率': ['height', 'width', 'h_w', 'item.h_w', 'data.resolution', 'item.height', 'item.width'],
179
+ '音乐作者': ['music.author', 'item.music.author', 'data.music.author', 'music.artist'],
180
+ '音乐标题': ['music.title', 'item.music.title', 'data.music.title', 'music.name'],
181
+ '直播间地址': ['room_url', 'live.room_url', 'data.room_url', 'live.url'],
182
+ '直播间ID': ['room_id', 'live.room_id', 'data.room_id', 'live.room_id'],
183
+ '直播间状态': ['status', 'live.status', 'data.status', 'room.status'],
184
+ '默认画质': ['default_quality', 'data.default_quality', 'item.default_quality'],
185
+ '图片数量': ['count', 'data.count', 'item.count', 'images.length', 'data.images.length'],
186
+ '作者ID': ['userId', 'userID', 'author_id', 'data.userId', 'item.userID', 'author.mid', 'user.mid'],
187
+ '封面链接': ['cover', 'imgurl', 'pic', 'thumbnail', 'cover_url', 'data.cover', 'item.cover', 'live.cover'],
188
+ '视频链接': ['url', 'video_url', 'playUrl', 'download_url', 'data.url', 'item.url', 'live.url', 'quality_urls.*'],
139
189
  };
140
190
  function getErrorInfo(code, detail) {
141
191
  const baseMsg = exports.ErrorMessageMap[code] || exports.ErrorMessageMap[ErrorCode.UNKNOWN_ERROR];
@@ -393,14 +443,36 @@ function parseData(rawResponse, maxDescLength) {
393
443
  const data = rootData.data || rootData.result || rootData || {};
394
444
  const stat = {};
395
445
  Object.entries(VARIABLE_MAPPING).forEach(([varName, keys]) => {
396
- const value = findValueInObject(data, keys) || findValueInObject(rootData, keys);
397
- stat[varName] = value ?? '';
446
+ let value = findValueInObject(data, keys) || findValueInObject(rootData, keys);
447
+ if (varName === '图片数量' && value === undefined) {
448
+ value = Array.isArray(data.images) ? data.images.length : (Array.isArray(rootData.images) ? rootData.images.length : undefined);
449
+ }
450
+ if (varName === '分辨率' && value === undefined) {
451
+ const h = findValueInObject(data, ['height', 'item.height']) || findValueInObject(rootData, ['height', 'item.height']);
452
+ const w = findValueInObject(data, ['width', 'item.width']) || findValueInObject(rootData, ['width', 'item.width']);
453
+ if (h && w)
454
+ value = `${w}x${h}`;
455
+ else if (data.h_w && Array.isArray(data.h_w) && data.h_w.length)
456
+ value = data.h_w.join(', ');
457
+ }
458
+ if (varName === '视频链接' && value === undefined) {
459
+ value = data.url || data.video || data.download_url || rootData.url || rootData.video;
460
+ }
461
+ if (value !== undefined && value !== null && value !== '') {
462
+ stat[varName] = value;
463
+ }
398
464
  });
399
465
  let type = 'video';
400
466
  if (data.jx?.type)
401
467
  type = data.jx.type;
402
468
  else if (data.type)
403
469
  type = data.type;
470
+ else if (rootData.msg === 'cv')
471
+ type = 'cv';
472
+ else if (rootData.msg === 'live')
473
+ type = 'live';
474
+ else if (data.images && data.images.length > 0 && !data.url)
475
+ type = '图集';
404
476
  const title = stat['标题'] || '无标题';
405
477
  const author = stat['作者'] || '未知作者';
406
478
  const desc = (stat['简介'] || title).slice(0, maxDescLength);
@@ -451,14 +523,32 @@ function parseData(rawResponse, maxDescLength) {
451
523
  };
452
524
  }
453
525
  function generateFormattedText(parseData, config) {
454
- let format = config.unifiedMessageFormat || '标题:${标题}\n作者:${作者}\n简介:${简介}';
526
+ let format = config.unifiedMessageFormat || '';
527
+ if (!format) {
528
+ format = `标题:${'${标题}'}
529
+ 作者:${'${作者}'}
530
+ 简介:${'${简介}'}
531
+ 时长:${'${视频时长}'}
532
+ 点赞:${'${点赞数}'}
533
+ 投币:${'${投币数}'}
534
+ 收藏:${'${收藏数}'}
535
+ 转发:${'${转发数}'}
536
+ 播放:${'${播放数}'}
537
+ 评论:${'${评论数}'}
538
+ 音乐:${'${音乐名}'}`;
539
+ }
455
540
  let result = format;
456
541
  const varMatches = result.match(/\$\{([^}]+)\}/g) || [];
457
542
  varMatches.forEach((varMatch) => {
458
543
  const varName = varMatch.replace(/\$\{|\}/g, '');
459
544
  const value = parseData.stat[varName];
460
- const showValue = value ?? '';
461
- result = result.replace(varMatch, String(showValue));
545
+ if (value === undefined || value === null || value === '') {
546
+ const lines = result.split('\n');
547
+ result = lines.filter((line) => !line.includes(varMatch)).join('\n');
548
+ }
549
+ else {
550
+ result = result.replace(varMatch, String(value));
551
+ }
462
552
  });
463
553
  return result.trim() || `标题:${parseData.title}\n作者:${parseData.author}\n简介:${parseData.desc}`;
464
554
  }
@@ -556,7 +646,7 @@ function apply(ctx, config) {
556
646
  return { data: null, code, msg };
557
647
  }
558
648
  const isSuccess = resData.code === 0 || resData.code === 200 || resData.code === 1 ||
559
- (resData.msg && (resData.msg.includes('解析成功') || resData.msg.includes('success'))) ||
649
+ (resData.msg && (resData.msg.includes('解析成功') || resData.msg.includes('success') || resData.msg.includes('请求成功'))) ||
560
650
  !!resData.data || !!resData.result || !!resData.video || !!resData.images;
561
651
  if (!isSuccess) {
562
652
  const apiErrorMsg = resData.msg || resData.error || '解析失败';
@@ -783,5 +873,11 @@ function apply(ctx, config) {
783
873
  const now = Date.now();
784
874
  processed.forEach((t, h) => now - t > 86400000 && processed.delete(h));
785
875
  }, 3600000);
876
+ if (config.autoClearCacheInterval > 0) {
877
+ setInterval(() => {
878
+ clearAllCache();
879
+ logger.info('自动清理缓存完成');
880
+ }, config.autoClearCacheInterval * 60 * 1000);
881
+ }
786
882
  logger.info('✅ 视频解析插件已启动');
787
883
  }
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.6.1",
4
+ "version": "0.6.3",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [