koishi-plugin-video-parser-all 0.6.4 → 0.6.6

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 -67
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -38,13 +38,9 @@ IP属地:${'${IP属地}'}
38
38
  在线人数:${'${在线人数}'}
39
39
  关注数:${'${关注数}'}
40
40
  文件大小:${'${文件大小}'}
41
- 分辨率:${'${分辨率}'}
42
- 音乐作者:${'${音乐作者}'}
43
- 音乐标题:${'${音乐标题}'}
44
41
  直播间地址:${'${直播间地址}'}
45
42
  直播间ID:${'${直播间ID}'}
46
43
  直播间状态:${'${直播间状态}'}
47
- 默认画质:${'${默认画质}'}
48
44
  图片数量:${'${图片数量}'}
49
45
  作者ID:${'${作者ID}'}`).description('统一消息格式'),
50
46
  }).description('统一消息格式'),
@@ -145,35 +141,31 @@ const API_CONFIG = {
145
141
  weibo: 'https://api.bugpk.com/api/weibo',
146
142
  toutiao: 'https://api.bugpk.com/api/toutiao',
147
143
  pipigx: 'https://api.bugpk.com/api/pipigx',
148
- pipixia: 'https://api.bugpk.com/api/ppx',
144
+ pipixia: 'https://api.bugpk.com/api/pipixia',
149
145
  zuiyou: 'https://api.bugpk.com/api/zuiyou'
150
146
  };
151
147
  const VARIABLE_MAPPING = {
152
- '标题': ['title', 'Title', 'TITLE', 'note_title', 'content_title', 'item.title', 'data.title', 'video.title', 'live.title'],
153
- '作者': ['author.name', 'author', 'name', 'Author', 'Name', 'owner.name', 'nickname', 'user_name', 'data.author', 'item.author', 'user.name', 'live.author'],
154
- '简介': ['desc', 'description', 'Desc', 'Description', 'content', 'Content', 'note_desc', 'text', 'data.desc', 'item.description', 'live.desc'],
155
- '视频时长': ['duration', 'Duration', 'time', 'Time', 'video_duration', 'item.duration', 'stat.duration'],
156
- '点赞数': ['like', 'Like', 'attitudes_count', 'digg_count', 'praise', 'stat.like', 'liked_count', 'data.like', 'data.attitudes_count', 'item.attitudes_count'],
148
+ '标题': ['title', 'Title', 'TITLE', 'note_title', 'content_title', 'item.title', 'data.title', 'video.title', 'live.title', 'data.item.title'],
149
+ '作者': ['author.name', 'author', 'name', 'Author', 'Name', 'owner.name', 'nickname', 'user_name', 'data.author', 'item.author', 'user.name', 'live.author', 'data.user.name', 'data.author.name'],
150
+ '简介': ['desc', 'description', 'Desc', 'Description', 'content', 'Content', 'note_desc', 'text', 'data.desc', 'item.description', 'live.desc', 'data.item.description'],
151
+ '视频时长': ['duration', 'Duration', 'time', 'Time', 'video_duration', 'item.duration', 'stat.duration', 'data.item.duration'],
152
+ '点赞数': ['like', 'Like', 'attitudes_count', 'digg_count', 'praise', 'stat.like', 'liked_count', 'data.like', 'data.attitudes_count', 'item.attitudes_count', 'data.item.attitudes_count'],
157
153
  '投币数': ['coin', 'Coin', 'bi', 'Bi', 'stat.coin', 'stast.coin'],
158
- '收藏数': ['collect', 'Collect', 'favorite', 'Favorite', 'star', 'Star', 'stat.collect', 'collected_count', 'stast.favorite', 'data.favorite'],
159
- '转发数': ['share', 'Share', 'forward', 'Forward', 'repost', 'stat.share', 'reposts_count', 'shared_count', 'stast.share', 'data.reposts_count'],
160
- '播放数': ['view', 'View', 'play_count', 'PlayCount', 'play', 'stat.view', 'play_times', 'stast.view', 'data.play_count', 'item.play_count'],
161
- '评论数': ['comment', 'Comment', 'comments_count', 'comment_count', 'discuss', 'stat.comment', 'stast.reply', 'data.comments_count', 'item.comments_count'],
162
- 'IP属地': ['ip_info_str', 'data.ip_info_str', 'item.ip_info'],
163
- '发布时间': ['date', 'time', 'publish_time', 'data.date', 'item.publish_time', 'live.time', 'stast.publish_time'],
164
- '粉丝数': ['followers_count', 'data.followers_count', 'item.followers', 'author.fans'],
165
- '在线人数': ['online', 'data.online', 'live.online', 'room.online'],
166
- '关注数': ['attention', 'data.attention', 'live.attention', 'stast.attention'],
167
- '文件大小': ['size', 'size_str', 'item.size', 'item.size_str', 'data.size'],
168
- '分辨率': ['height', 'width', 'h_w', 'item.h_w', 'data.resolution', 'item.height', 'item.width'],
169
- '音乐作者': ['music.author', 'item.music.author', 'data.music.author', 'music.artist'],
170
- '音乐标题': ['music.title', 'item.music.title', 'data.music.title', 'music.name'],
171
- '直播间地址': ['room_url', 'live.room_url', 'data.room_url', 'live.url'],
172
- '直播间ID': ['room_id', 'live.room_id', 'data.room_id', 'live.room_id'],
173
- '直播间状态': ['status', 'live.status', 'data.status', 'room.status'],
174
- '默认画质': ['default_quality', 'data.default_quality', 'item.default_quality'],
175
- '图片数量': ['count', 'data.count', 'item.count', 'images.length', 'data.images.length'],
176
- '作者ID': ['userId', 'userID', 'author_id', 'data.userId', 'item.userID', 'author.mid', 'user.mid'],
154
+ '收藏数': ['collect', 'Collect', 'favorite', 'Favorite', 'star', 'Star', 'stat.collect', 'collected_count', 'stast.favorite', 'data.favorite', 'stast.favorite'],
155
+ '转发数': ['share', 'Share', 'forward', 'Forward', 'repost', 'stat.share', 'reposts_count', 'shared_count', 'stast.share', 'data.reposts_count', 'data.item.reposts_count'],
156
+ '播放数': ['view', 'View', 'play_count', 'PlayCount', 'play', 'stat.view', 'play_times', 'stast.view', 'data.play_count', 'item.play_count', 'data.item.play_count'],
157
+ '评论数': ['comment', 'Comment', 'comments_count', 'comment_count', 'discuss', 'stat.comment', 'stast.reply', 'data.comments_count', 'item.comments_count', 'data.item.comments_count'],
158
+ 'IP属地': ['ip_info_str', 'data.ip_info_str', 'item.ip_info', 'data.item.ip_info_str'],
159
+ '发布时间': ['date', 'time', 'publish_time', 'data.date', 'item.publish_time', 'live.time', 'stast.publish_time', 'stat.time', 'data.time.publish_time', 'data.live.time'],
160
+ '粉丝数': ['followers_count', 'data.followers_count', 'item.followers', 'author.fans', 'data.item.followers_count'],
161
+ '在线人数': ['online', 'data.online', 'live.online', 'room.online', 'data.live.online'],
162
+ '关注数': ['attention', 'data.attention', 'live.attention', 'stast.attention', 'data.live.attention'],
163
+ '文件大小': ['size', 'size_str', 'item.size', 'item.size_str', 'data.size', 'data.item.size_str'],
164
+ '直播间地址': ['room_url', 'live.room_url', 'data.room_url', 'live.url', 'data.live.room_url'],
165
+ '直播间ID': ['room_id', 'live.room_id', 'data.room_id', 'live.room_id', 'data.live.room_id'],
166
+ '直播间状态': ['status', 'live.status', 'data.status', 'room.status', 'data.live.status'],
167
+ '图片数量': ['count', 'data.count', 'item.count', 'images.length', 'data.images.length', 'data.item.count'],
168
+ '作者ID': ['userId', 'userID', 'author_id', 'data.userId', 'item.userID', 'author.mid', 'user.mid', 'data.item.userID', 'data.author_id', 'data.user.mid'],
177
169
  };
178
170
  function getErrorInfo(code, detail) {
179
171
  const baseMsg = exports.ErrorMessageMap[code] || exports.ErrorMessageMap[ErrorCode.UNKNOWN_ERROR];
@@ -393,6 +385,39 @@ function formatDuration(input) {
393
385
  const secs = Math.floor(seconds % 60);
394
386
  return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
395
387
  }
388
+ function formatPublishTime(value) {
389
+ if (!value)
390
+ return '';
391
+ const str = String(value).trim();
392
+ if (/^\d{10,}$/.test(str) && Number(str) > 1e12) {
393
+ if (Number(str) > 1e15) {
394
+ value = Number(str) / 1000;
395
+ }
396
+ }
397
+ try {
398
+ const d = new Date(/^\d+$/.test(str) ? Number(str) * 1000 : str);
399
+ if (isNaN(d.getTime()))
400
+ return '';
401
+ const y = d.getFullYear();
402
+ const m = (d.getMonth() + 1).toString().padStart(2, '0');
403
+ const d_ = d.getDate().toString().padStart(2, '0');
404
+ const H = d.getHours().toString().padStart(2, '0');
405
+ const i = d.getMinutes().toString().padStart(2, '0');
406
+ const parts = [];
407
+ if (y > 2000)
408
+ parts.push(`${y}年`);
409
+ if (m)
410
+ parts.push(`${m}月`);
411
+ if (d_)
412
+ parts.push(`${d_}日`);
413
+ if (H && i)
414
+ parts.push(`${H}:${i}`);
415
+ return parts.join(' ').trim();
416
+ }
417
+ catch {
418
+ return str;
419
+ }
420
+ }
396
421
  function getNestedValue(obj, path) {
397
422
  if (!obj || typeof obj !== 'object' || !path)
398
423
  return undefined;
@@ -436,15 +461,10 @@ function parseData(rawResponse, maxDescLength) {
436
461
  Object.entries(VARIABLE_MAPPING).forEach(([varName, keys]) => {
437
462
  let value = findValueInObject(data, keys) || findValueInObject(rootData, keys);
438
463
  if (varName === '图片数量' && value === undefined) {
439
- value = Array.isArray(data.images) ? data.images.length : (Array.isArray(rootData.images) ? rootData.images.length : undefined);
440
- }
441
- if (varName === '分辨率' && value === undefined) {
442
- const h = findValueInObject(data, ['height', 'item.height']) || findValueInObject(rootData, ['height', 'item.height']);
443
- const w = findValueInObject(data, ['width', 'item.width']) || findValueInObject(rootData, ['width', 'item.width']);
444
- if (h && w)
445
- value = `${w}x${h}`;
446
- else if (data.h_w && Array.isArray(data.h_w) && data.h_w.length)
447
- value = data.h_w.join(', ');
464
+ value = Array.isArray(data.images) ? data.images.length :
465
+ Array.isArray(rootData.images) ? rootData.images.length :
466
+ Array.isArray(data.imgurl) ? data.imgurl.length :
467
+ Array.isArray(rootData.imgurl) ? rootData.imgurl.length : undefined;
448
468
  }
449
469
  if (value !== undefined && value !== null && value !== '') {
450
470
  stat[varName] = value;
@@ -459,33 +479,62 @@ function parseData(rawResponse, maxDescLength) {
459
479
  type = 'cv';
460
480
  else if (rootData.msg === 'live')
461
481
  type = 'live';
462
- else if ((data.images && data.images.length > 1) || (rootData.images && rootData.images.length > 1))
482
+ else if ((data.images && data.images.length > 1) || (rootData.images && rootData.images.length > 1) ||
483
+ (data.imgurl && data.imgurl.length > 1) || (rootData.imgurl && rootData.imgurl.length > 1))
463
484
  type = '图集';
464
- const title = stat['标题'] || (data.note_title || data.title || data.content_title || '无标题');
465
- const author = stat['作者'] || (data.author?.name || data.nickname || data.user_name || '未知作者');
466
- const rawDesc = stat['简介'] || data.note_desc || data.content || data.text || data.description || '';
485
+ const title = stat['标题'] || data.note_title || data.title || data.content_title || data.item?.title || rootData.title || '无标题';
486
+ let author = stat['作者'] || data.author?.name || data.nickname || data.user_name || data.item?.author ||
487
+ rootData.author || data.user?.name || data.owner?.name || '未知作者';
488
+ if (typeof author === 'object' && author.name)
489
+ author = author.name;
490
+ const rawDesc = stat['简介'] || data.note_desc || data.content || data.text || data.description ||
491
+ data.item?.description || rootData.desc || rootData.description || '';
467
492
  const desc = rawDesc.length > 0 ? rawDesc.slice(0, maxDescLength) : (title.length > 0 ? title : '暂无简介');
468
- const cover = data.cover ?? data.imgurl ?? data.pic ?? data.thumbnail ?? data.cover_url ?? (Array.isArray(data.images) && data.images[0] ? data.images[0] : '');
493
+ const cover = data.cover || data.imgurl || data.pic || data.thumbnail || data.cover_url ||
494
+ data.item?.cover || rootData.cover || (Array.isArray(data.images) && data.images[0]) ||
495
+ (Array.isArray(rootData.images) && rootData.images[0]) || '';
469
496
  let images = [];
470
- const imgRaw = data.images ?? data.pics ?? data.pic_urls ?? data.image_list ?? [];
471
- if (Array.isArray(imgRaw))
472
- images = imgRaw.filter(i => i && typeof i === 'string');
473
- else if (imgRaw)
474
- images = [String(imgRaw)];
475
- let video = data.video?.url ?? data.item?.url ?? data.url ?? data.download_url ?? data.playUrl ?? data.video_url ?? '';
476
- const durationValue = stat['视频时长'] || 0;
497
+ const imgSources = [
498
+ data.images, data.pics, data.pic_urls, data.image_list, data.imgurl,
499
+ rootData.images, rootData.pics, rootData.pic_urls, rootData.image_list, rootData.imgurl,
500
+ data.item?.images
501
+ ];
502
+ for (const source of imgSources) {
503
+ if (Array.isArray(source) && source.length > 0) {
504
+ images = source.filter(i => i && typeof i === 'string');
505
+ break;
506
+ }
507
+ }
508
+ let video = data.video?.url || data.item?.url || data.url || data.download_url || data.playUrl ||
509
+ data.video_url || rootData.url || data.item?.url || '';
510
+ const durationValue = stat['视频时长'] || data.item?.duration || data.duration || 0;
477
511
  const duration = typeof durationValue === 'number' ? durationValue : parseInt(durationValue) || 0;
478
512
  const durationFormatted = formatDuration(durationValue);
479
- const live_photo = data.live_photo ?? [];
480
- const music = stat['音乐名'] || '';
481
- const h_w = data.item?.h_w ?? [];
482
- const quality_urls = data.quality_urls ?? {};
483
- const default_quality = data.default_quality ?? '';
484
- const download_url = data.download_url ?? video;
485
- const play_count = stat['播放数'] ?? '';
486
- const reposts_count = Number(stat['转发数']) || 0;
487
- const attitudes_count = Number(stat['点赞数']) || 0;
488
- const comments_count = Number(stat['评论数']) || 0;
513
+ const pubTime = formatPublishTime(stat['发布时间']);
514
+ if (pubTime)
515
+ stat['发布时间'] = pubTime;
516
+ else
517
+ delete stat['发布时间'];
518
+ const durShow = durationFormatted === '00:00:00' && (String(durationValue).length > 12) ? '' : durationFormatted;
519
+ if (durShow)
520
+ stat['视频时长'] = durShow;
521
+ else
522
+ delete stat['视频时长'];
523
+ const sizeVal = stat['文件大小'];
524
+ if (sizeVal && !String(sizeVal).includes('MB')) {
525
+ const num = Number(sizeVal);
526
+ if (!isNaN(num) && num > 0)
527
+ stat['文件大小'] = `${num.toFixed(2)} MB`;
528
+ }
529
+ const live_photo = data.live_photo || rootData.live_photo || [];
530
+ const h_w = data.item?.h_w || rootData.h_w || [];
531
+ const quality_urls = data.quality_urls || rootData.quality_urls || {};
532
+ const default_quality = data.default_quality || rootData.default_quality || '';
533
+ const download_url = data.download_url || video;
534
+ const play_count = stat['播放数'] || '';
535
+ const reposts_count = Number(stat['转发数']) || data.reposts_count || rootData.reposts_count || 0;
536
+ const attitudes_count = Number(stat['点赞数']) || data.attitudes_count || rootData.attitudes_count || 0;
537
+ const comments_count = Number(stat['评论数']) || data.comments_count || rootData.comments_count || 0;
489
538
  return {
490
539
  type: type,
491
540
  rawData: rawResponse,
@@ -499,9 +548,8 @@ function parseData(rawResponse, maxDescLength) {
499
548
  durationFormatted,
500
549
  stat,
501
550
  live_photo,
502
- music: String(music),
503
551
  h_w,
504
- jx: data.jx ?? null,
552
+ jx: data.jx || null,
505
553
  quality_urls,
506
554
  default_quality,
507
555
  download_url,
@@ -635,7 +683,7 @@ function apply(ctx, config) {
635
683
  }
636
684
  const isSuccess = resData.code === 0 || resData.code === 200 || resData.code === 1 ||
637
685
  (resData.msg && (resData.msg.includes('解析成功') || resData.msg.includes('success') || resData.msg.includes('请求成功'))) ||
638
- !!resData.data || !!resData.result || !!resData.video || !!resData.images;
686
+ !!resData.data || !!resData.result || !!resData.video || !!resData.images || !!resData.imgurl;
639
687
  if (!isSuccess) {
640
688
  const apiErrorMsg = resData.msg || resData.error || '解析失败';
641
689
  const code = ErrorCode.API_RETURN_ERROR;
@@ -699,7 +747,6 @@ function apply(ctx, config) {
699
747
  video: parseData.video,
700
748
  type: parseData.type,
701
749
  live_photo: parseData.live_photo,
702
- music: parseData.music,
703
750
  h_w: parseData.h_w,
704
751
  quality_urls: parseData.quality_urls,
705
752
  default_quality: parseData.default_quality,
@@ -784,7 +831,7 @@ function apply(ctx, config) {
784
831
  forwardMessages.push(buildForwardNode(session, koishi_1.h.file(dl.filePath), botName));
785
832
  }
786
833
  else {
787
- forwardMessages.push(buildForwardNode(session, koishi_1.h.text(`视频:${item.video}`), botName));
834
+ forwardMessages.push(buildForwardNode(session, koishi_1.h.video(item.video), botName));
788
835
  }
789
836
  }
790
837
  else {
@@ -792,7 +839,7 @@ function apply(ctx, config) {
792
839
  }
793
840
  }
794
841
  catch (e) {
795
- forwardMessages.push(buildForwardNode(session, koishi_1.h.text(`视频:${item.video}`), botName));
842
+ forwardMessages.push(buildForwardNode(session, koishi_1.h.video(item.video), botName));
796
843
  }
797
844
  }
798
845
  }
@@ -816,7 +863,7 @@ function apply(ctx, config) {
816
863
  await sendTimeout(session, koishi_1.h.video(item.video));
817
864
  }
818
865
  catch (e) {
819
- await sendTimeout(session, `视频:${item.video}`);
866
+ await sendTimeout(session, koishi_1.h.video(item.video));
820
867
  }
821
868
  await delay(500);
822
869
  }
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.4",
4
+ "version": "0.6.6",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [