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

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 +99 -58
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -42,7 +42,8 @@ IP属地:${'${IP属地}'}
42
42
  直播间ID:${'${直播间ID}'}
43
43
  直播间状态:${'${直播间状态}'}
44
44
  图片数量:${'${图片数量}'}
45
- 作者ID:${'${作者ID}'}`).description('统一消息格式'),
45
+ 作者ID:${'${作者ID}'}
46
+ 视频备用链接:${'${视频备用链接}'}`).description('统一消息格式'),
46
47
  }).description('统一消息格式'),
47
48
  koishi_1.Schema.object({
48
49
  showImageText: koishi_1.Schema.boolean().default(true).description('显示图文内容'),
@@ -145,18 +146,18 @@ const API_CONFIG = {
145
146
  zuiyou: 'https://api.bugpk.com/api/zuiyou'
146
147
  };
147
148
  const VARIABLE_MAPPING = {
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'],
153
- '投币数': ['coin', 'Coin', 'bi', 'Bi', 'stat.coin', 'stast.coin'],
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'],
149
+ '标题': ['title', 'note_title', 'content_title', 'item.title', 'data.title', 'video.title', 'live.title', 'data.item.title', 'data.live.title'],
150
+ '作者': ['author', 'author.name', 'name', 'nickname', 'user_name', 'owner.name', 'data.author', 'item.author', 'user.name', 'live.author', 'data.user.name', 'data.author.name'],
151
+ '简介': ['desc', 'description', 'content', 'note_desc', 'text', 'data.desc', 'item.description', 'live.desc', 'data.item.description'],
152
+ '视频时长': ['duration', 'time', 'video_duration', 'item.duration', 'stat.duration', 'data.item.duration'],
153
+ '点赞数': ['like', 'attitudes_count', 'digg_count', 'praise', 'stat.like', 'liked_count', 'data.like', 'data.attitudes_count', 'item.attitudes_count', 'data.item.attitudes_count'],
154
+ '投币数': ['coin', 'bi', 'stat.coin', 'stast.coin'],
155
+ '收藏数': ['collect', 'favorite', 'star', 'stat.collect', 'collected_count', 'stast.favorite', 'data.favorite'],
156
+ '转发数': ['share', 'forward', 'repost', 'stat.share', 'reposts_count', 'shared_count', 'stast.share', 'data.reposts_count', 'data.item.reposts_count'],
157
+ '播放数': ['view', 'play_count', 'play', 'stat.view', 'play_times', 'stast.view', 'data.play_count', 'item.play_count', 'data.item.play_count'],
158
+ '评论数': ['comment', 'comments_count', 'comment_count', 'discuss', 'stat.comment', 'stast.reply', 'data.comments_count', 'item.comments_count', 'data.item.comments_count', 'stat.reply'],
158
159
  '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
+ '发布时间': ['date', 'time', 'publish_time', 'data.date', 'item.publish_time', 'live.time', 'stast.publish_time', 'stat.time', 'data.time.publish_time', 'data.live.time', 'stat.ctime'],
160
161
  '粉丝数': ['followers_count', 'data.followers_count', 'item.followers', 'author.fans', 'data.item.followers_count'],
161
162
  '在线人数': ['online', 'data.online', 'live.online', 'room.online', 'data.live.online'],
162
163
  '关注数': ['attention', 'data.attention', 'live.attention', 'stast.attention', 'data.live.attention'],
@@ -165,7 +166,8 @@ const VARIABLE_MAPPING = {
165
166
  '直播间ID': ['room_id', 'live.room_id', 'data.room_id', 'live.room_id', 'data.live.room_id'],
166
167
  '直播间状态': ['status', 'live.status', 'data.status', 'room.status', 'data.live.status'],
167
168
  '图片数量': ['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'],
169
+ '作者ID': ['userId', 'userID', 'author_id', 'data.userId', 'item.userID', 'author.mid', 'user.mid', 'data.item.userID', 'data.author_id', 'data.user.mid', 'author.id', 'uid', 'short_id', 'data.author.id'],
170
+ '视频备用链接': ['data.video_backup', 'video_backup']
169
171
  };
170
172
  function getErrorInfo(code, detail) {
171
173
  const baseMsg = exports.ErrorMessageMap[code] || exports.ErrorMessageMap[ErrorCode.UNKNOWN_ERROR];
@@ -389,15 +391,20 @@ function formatPublishTime(value) {
389
391
  if (!value)
390
392
  return '';
391
393
  const str = String(value).trim();
394
+ if (value === 'ctime')
395
+ return '';
396
+ if (/^\d{10}$/.test(str)) {
397
+ value = Number(str) * 1000;
398
+ }
392
399
  if (/^\d{10,}$/.test(str) && Number(str) > 1e12) {
393
400
  if (Number(str) > 1e15) {
394
401
  value = Number(str) / 1000;
395
402
  }
396
403
  }
397
404
  try {
398
- const d = new Date(/^\d+$/.test(str) ? Number(str) * 1000 : str);
405
+ const d = new Date(/^\d+$/.test(str) ? Number(str) : str);
399
406
  if (isNaN(d.getTime()))
400
- return '';
407
+ return str;
401
408
  const y = d.getFullYear();
402
409
  const m = (d.getMonth() + 1).toString().padStart(2, '0');
403
410
  const d_ = d.getDate().toString().padStart(2, '0');
@@ -455,18 +462,19 @@ function findValueInObject(obj, keys) {
455
462
  return undefined;
456
463
  }
457
464
  function parseData(rawResponse, maxDescLength) {
458
- const rootData = rawResponse || {};
459
- const data = rootData.data || rootData.result || rootData || {};
465
+ const root = rawResponse || {};
466
+ const data = root.data || root.result || root || {};
460
467
  const stat = {};
461
468
  Object.entries(VARIABLE_MAPPING).forEach(([varName, keys]) => {
462
- let value = findValueInObject(data, keys) || findValueInObject(rootData, keys);
469
+ let value = findValueInObject(data, keys) || findValueInObject(root, keys);
463
470
  if (varName === '图片数量' && value === undefined) {
464
471
  value = Array.isArray(data.images) ? data.images.length :
465
- Array.isArray(rootData.images) ? rootData.images.length :
472
+ Array.isArray(root.images) ? root.images.length :
466
473
  Array.isArray(data.imgurl) ? data.imgurl.length :
467
- Array.isArray(rootData.imgurl) ? rootData.imgurl.length : undefined;
474
+ Array.isArray(root.imgurl) ? root.imgurl.length :
475
+ data.count || root.count || undefined;
468
476
  }
469
- if (value !== undefined && value !== null && value !== '') {
477
+ if (value !== undefined && value !== null && value !== '' && value !== 0) {
470
478
  stat[varName] = value;
471
479
  }
472
480
  });
@@ -475,28 +483,32 @@ function parseData(rawResponse, maxDescLength) {
475
483
  type = data.jx.type;
476
484
  else if (data.type)
477
485
  type = data.type;
478
- else if (rootData.msg === 'cv')
486
+ else if (root.msg === 'cv')
479
487
  type = 'cv';
480
- else if (rootData.msg === 'live')
488
+ else if (root.msg === 'live')
481
489
  type = 'live';
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))
490
+ else if ((data.images && data.images.length > 1) || (root.images && root.images.length > 1) ||
491
+ (data.imgurl && data.imgurl.length > 1) || (root.imgurl && root.imgurl.length > 1))
484
492
  type = '图集';
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 || '未知作者';
493
+ const title = stat['标题'] || data.note_title || data.title || data.content_title || data.video?.title ||
494
+ data.item?.title || root.title || data.live?.title || '无标题';
495
+ let author = stat['作者'] || data.author?.name || data.nickname || data.user_name || data.owner?.name ||
496
+ data.item?.author || root.author || data.user?.name || data.live?.author || '未知作者';
488
497
  if (typeof author === 'object' && author.name)
489
498
  author = author.name;
490
499
  const rawDesc = stat['简介'] || data.note_desc || data.content || data.text || data.description ||
491
- data.item?.description || rootData.desc || rootData.description || '';
492
- const desc = rawDesc.length > 0 ? rawDesc.slice(0, maxDescLength) : (title.length > 0 ? title : '暂无简介');
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]) || '';
500
+ data.video?.desc || data.item?.description || root.desc || root.description ||
501
+ data.live?.desc || (title !== '无标题' ? title : '') || '暂无简介';
502
+ const desc = rawDesc.length > 0 ? rawDesc.slice(0, maxDescLength) : '暂无简介';
503
+ const cover = data.cover || data.video?.fm || data.imgurl || data.pic || data.thumbnail || data.cover_url ||
504
+ data.item?.cover || root.cover || data.live?.cover || data.live?.keyframe ||
505
+ (Array.isArray(data.images) && data.images[0]) ||
506
+ (Array.isArray(root.images) && root.images[0]) ||
507
+ (Array.isArray(data.imgurl) && data.imgurl[0]) || '';
496
508
  let images = [];
497
509
  const imgSources = [
498
510
  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,
511
+ root.images, root.pics, root.pic_urls, root.image_list, root.imgurl,
500
512
  data.item?.images
501
513
  ];
502
514
  for (const source of imgSources) {
@@ -505,8 +517,9 @@ function parseData(rawResponse, maxDescLength) {
505
517
  break;
506
518
  }
507
519
  }
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 || '';
520
+ let video = data.video?.url || data.url || data.download_url || data.playUrl ||
521
+ data.video_url || root.url || data.item?.url || data.live?.url ||
522
+ (data.live?.url && Array.isArray(data.live.url) ? data.live.url[0] : '') || '';
510
523
  const durationValue = stat['视频时长'] || data.item?.duration || data.duration || 0;
511
524
  const duration = typeof durationValue === 'number' ? durationValue : parseInt(durationValue) || 0;
512
525
  const durationFormatted = formatDuration(durationValue);
@@ -515,26 +528,40 @@ function parseData(rawResponse, maxDescLength) {
515
528
  stat['发布时间'] = pubTime;
516
529
  else
517
530
  delete stat['发布时间'];
518
- const durShow = durationFormatted === '00:00:00' && (String(durationValue).length > 12) ? '' : durationFormatted;
519
- if (durShow)
520
- stat['视频时长'] = durShow;
521
- else
531
+ if (durationFormatted !== '00:00:00') {
532
+ stat['视频时长'] = durationFormatted;
533
+ }
534
+ else {
522
535
  delete stat['视频时长'];
536
+ }
523
537
  const sizeVal = stat['文件大小'];
524
538
  if (sizeVal && !String(sizeVal).includes('MB')) {
525
539
  const num = Number(sizeVal);
526
540
  if (!isNaN(num) && num > 0)
527
541
  stat['文件大小'] = `${num.toFixed(2)} MB`;
528
542
  }
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 || '';
543
+ const live_photo = data.live_photo || root.live_photo || [];
544
+ const h_w = data.item?.h_w || root.h_w || [];
545
+ const quality_urls = data.quality_urls || root.quality_urls || {};
546
+ const default_quality = data.default_quality || root.default_quality || '';
533
547
  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;
548
+ const play_count = stat['播放数'] || data.play_count || root.play_count || '';
549
+ const reposts_count = Number(stat['转发数']) || data.reposts_count || root.reposts_count || 0;
550
+ const attitudes_count = Number(stat['点赞数']) || data.attitudes_count || root.attitudes_count || data.like || root.like || 0;
551
+ const comments_count = Number(stat['评论数']) || data.comments_count || root.comments_count || 0;
552
+ if (data.live) {
553
+ stat['直播间地址'] = data.live.room_url || '';
554
+ stat['直播间ID'] = data.live.room_id || '';
555
+ stat['直播间状态'] = data.live.status === 1 ? '直播中' : (data.live.status === 0 ? '未开播' : data.live.status || '未知');
556
+ stat['在线人数'] = data.live.online || '';
557
+ stat['关注数'] = data.live.attention || '';
558
+ }
559
+ if (data.followers_count)
560
+ stat['粉丝数'] = data.followers_count;
561
+ if (data.ip_info_str)
562
+ stat['IP属地'] = data.ip_info_str;
563
+ if (data.video_backup)
564
+ stat['视频备用链接'] = data.video_backup;
538
565
  return {
539
566
  type: type,
540
567
  rawData: rawResponse,
@@ -571,7 +598,8 @@ function generateFormattedText(parseData, config) {
571
598
  收藏:${'${收藏数}'}
572
599
  转发:${'${转发数}'}
573
600
  播放:${'${播放数}'}
574
- 评论:${'${评论数}'}`;
601
+ 评论:${'${评论数}'}
602
+ 视频备用链接:${'${视频备用链接}'}`;
575
603
  }
576
604
  let result = format;
577
605
  const varMatches = result.match(/\$\{([^}]+)\}/g) || [];
@@ -637,14 +665,27 @@ function apply(ctx, config) {
637
665
  for (let i = 0; i <= retryTimes; i++) {
638
666
  try {
639
667
  const params = { url, proxyurl: '' };
640
- const res = await http.get(API_CONFIG[platform], {
641
- params,
642
- timeout: config.timeout,
643
- headers: {
644
- 'X-Requested-With': 'XMLHttpRequest',
645
- 'Origin': platform === 'xiaohongshu' ? 'https://api.bugpk.com' : 'https://www.baidu.com'
646
- }
647
- });
668
+ let res;
669
+ if (platform === 'xiaohongshu') {
670
+ res = await http.post(API_CONFIG[platform], new URLSearchParams(params), {
671
+ timeout: config.timeout,
672
+ headers: {
673
+ 'X-Requested-With': 'XMLHttpRequest',
674
+ 'Origin': 'https://api.bugpk.com',
675
+ 'Content-Type': 'application/x-www-form-urlencoded'
676
+ }
677
+ });
678
+ }
679
+ else {
680
+ res = await http.get(API_CONFIG[platform], {
681
+ params,
682
+ timeout: config.timeout,
683
+ headers: {
684
+ 'X-Requested-With': 'XMLHttpRequest',
685
+ 'Origin': 'https://www.baidu.com'
686
+ }
687
+ });
688
+ }
648
689
  return res.data;
649
690
  }
650
691
  catch (error) {
@@ -682,7 +723,7 @@ function apply(ctx, config) {
682
723
  return { data: null, code, msg };
683
724
  }
684
725
  const isSuccess = resData.code === 0 || resData.code === 200 || resData.code === 1 ||
685
- (resData.msg && (resData.msg.includes('解析成功') || resData.msg.includes('success') || resData.msg.includes('请求成功'))) ||
726
+ (resData.msg && (resData.msg.includes('解析成功') || resData.msg.includes('success') || resData.msg.includes('请求成功') || resData.msg === 'video' || resData.msg === 'cv' || resData.msg === 'live')) ||
686
727
  !!resData.data || !!resData.result || !!resData.video || !!resData.images || !!resData.imgurl;
687
728
  if (!isSuccess) {
688
729
  const apiErrorMsg = resData.msg || resData.error || '解析失败';
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.6",
4
+ "version": "0.6.8",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [