koishi-plugin-video-parser-all 0.5.4 → 0.5.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 +140 -44
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -124,8 +124,8 @@ const PLATFORM_KEYWORDS = {
124
124
  zuiyou: ['zuiyou', '最右', 'xiaochuankeji.cn', 'izuiyou.com', 'izuiyou.com/topic']
125
125
  };
126
126
  const API_CONFIG = {
127
- bilibili: 'https://api.bugpk.com/api/bilibili',
128
- douyin: 'https://api.bugpk.com/api/dyjx',
127
+ bilibili: 'https://api.xingzhige.com/API/b_parse',
128
+ douyin: 'https://api.xingzhige.com/API/douyin/',
129
129
  kuaishou: 'https://api.bugpk.com/api/ksjx',
130
130
  xiaohongshu: 'https://api.bugpk.com/api/xhsjx',
131
131
  weibo: 'https://api.bugpk.com/api/weibo',
@@ -147,16 +147,16 @@ const PLATFORM_ERROR_CODE_MAP = {
147
147
  };
148
148
  const VARIABLE_MAPPING = {
149
149
  '标题': ['title', 'Title', 'TITLE'],
150
- '作者': ['author.name', 'author', 'name', 'Author', 'Name'],
150
+ '作者': ['author.name', 'author', 'name', 'Author', 'Name', 'owner.name'],
151
151
  '简介': ['desc', 'description', 'Desc', 'Description', 'content', 'Content'],
152
152
  '视频时长': ['duration', 'Duration', 'time', 'Time'],
153
- '点赞数': ['like', 'Like', 'attitudes_count', 'digg_count', 'praise'],
153
+ '点赞数': ['like', 'Like', 'attitudes_count', 'digg_count', 'praise', 'stat.like'],
154
154
  '投币数': ['coin', 'Coin', 'bi', 'Bi'],
155
- '收藏数': ['collect', 'Collect', 'favorite', 'Favorite', 'star', 'Star'],
156
- '转发数': ['share', 'Share', 'forward', 'Forward', 'repost'],
155
+ '收藏数': ['collect', 'Collect', 'favorite', 'Favorite', 'star', 'Star', 'stat.collect'],
156
+ '转发数': ['share', 'Share', 'forward', 'Forward', 'repost', 'stat.share', 'reposts_count'],
157
157
  '播放数': ['view', 'View', 'play_count', 'PlayCount', 'play'],
158
- '评论数': ['comment', 'Comment', 'comments_count', 'comment_count', 'discuss'],
159
- '音乐名': ['music.title', 'music_name', 'audio_name', 'sound_name']
158
+ '评论数': ['comment', 'Comment', 'comments_count', 'comment_count', 'discuss', 'stat.comment'],
159
+ '音乐名': ['music.title', 'music_name', 'audio_name', 'sound_name', 'muisic', 'music']
160
160
  };
161
161
  function getErrorInfo(code, detail) {
162
162
  const baseMsg = exports.ErrorMessageMap[code] || exports.ErrorMessageMap[ErrorCode.UNKNOWN_ERROR];
@@ -321,7 +321,6 @@ function getPlatformType(url) {
321
321
  }
322
322
  function cleanUrl(url) {
323
323
  try {
324
- // 处理HTML实体编码
325
324
  url = url.replace(/&/g, '&');
326
325
  const urlObj = new URL(url);
327
326
  if (urlObj.hostname.includes('xiaohongshu.com')) {
@@ -329,7 +328,7 @@ function cleanUrl(url) {
329
328
  urlObj.searchParams.delete('xhsshare');
330
329
  urlObj.searchParams.delete('xsec_token');
331
330
  urlObj.searchParams.delete('xsec_source');
332
- return urlObj.origin + urlObj.pathname + urlObj.search;
331
+ return urlObj.origin + urlObj.pathname;
333
332
  }
334
333
  if (urlObj.hostname.includes('douyin.com') || urlObj.hostname.includes('v.douyin.com')) {
335
334
  return urlObj.origin + urlObj.pathname;
@@ -337,7 +336,6 @@ function cleanUrl(url) {
337
336
  return url;
338
337
  }
339
338
  catch (e) {
340
- // 处理HTML实体编码
341
339
  return url.replace(/&/g, '&');
342
340
  }
343
341
  }
@@ -410,7 +408,13 @@ function findValueInObject(obj, keys) {
410
408
  }
411
409
  function parseData(rawResponse, maxDescLength, platform) {
412
410
  let data = rawResponse;
413
- if (data.data) {
411
+ if (platform === 'bilibili' && rawResponse.data) {
412
+ data = rawResponse.data;
413
+ }
414
+ else if (platform === 'douyin' && rawResponse.data) {
415
+ data = rawResponse.data;
416
+ }
417
+ else if (data.data) {
414
418
  data = data.data;
415
419
  }
416
420
  const stat = {};
@@ -420,30 +424,87 @@ function parseData(rawResponse, maxDescLength, platform) {
420
424
  stat[varName] = value;
421
425
  }
422
426
  });
423
- let type = data.type || 'video';
424
- const title = findValueInObject(data, ['title']) || '无标题';
425
- const author = findValueInObject(data, ['author.name', 'author']) || '未知作者';
426
- const desc = (findValueInObject(data, ['desc', 'description', 'content']) || title).toString().slice(0, maxDescLength);
427
- const cover = findValueInObject(data, ['cover', 'imgurl', 'pic', 'thumbnail']) || '';
428
- let images = findValueInObject(data, ['imgurl', 'images', 'pics']) || [];
427
+ let type = 'video';
428
+ if (platform === 'douyin' && data.jx && data.jx.type) {
429
+ type = data.jx.type;
430
+ }
431
+ else if (data.type) {
432
+ type = data.type;
433
+ }
434
+ let title = '无标题';
435
+ if (platform === 'bilibili' && data.video && data.video.title) {
436
+ title = data.video.title;
437
+ }
438
+ else if (platform === 'douyin' && data.item && data.item.title) {
439
+ title = data.item.title;
440
+ }
441
+ else {
442
+ title = findValueInObject(data, ['title']) || '无标题';
443
+ }
444
+ let author = '未知作者';
445
+ if (platform === 'bilibili' && data.owner && data.owner.name) {
446
+ author = data.owner.name;
447
+ }
448
+ else if (platform === 'douyin' && data.author && data.author.name) {
449
+ author = data.author.name;
450
+ }
451
+ else {
452
+ author = findValueInObject(data, ['author.name', 'author', 'name', 'auther']) || '未知作者';
453
+ }
454
+ let desc = title;
455
+ if (platform === 'bilibili' && data.video && data.video.desc) {
456
+ desc = data.video.desc;
457
+ }
458
+ else if (platform === 'douyin') {
459
+ desc = title;
460
+ }
461
+ else {
462
+ desc = findValueInObject(data, ['desc', 'description', 'content']) || title;
463
+ }
464
+ desc = desc.toString().slice(0, maxDescLength);
465
+ let cover = '';
466
+ if (platform === 'bilibili' && data.video && data.video.fm) {
467
+ cover = data.video.fm;
468
+ }
469
+ else if (platform === 'douyin' && data.item && data.item.cover) {
470
+ cover = data.item.cover;
471
+ }
472
+ else {
473
+ cover = findValueInObject(data, ['cover', 'imgurl', 'pic', 'thumbnail']) || '';
474
+ }
475
+ let images = [];
476
+ if (platform === 'douyin' && data.item && data.item.images) {
477
+ images = data.item.images;
478
+ }
479
+ else {
480
+ images = findValueInObject(data, ['imgurl', 'images', 'pics']) || [];
481
+ }
429
482
  if (!Array.isArray(images))
430
483
  images = [images];
431
- const videoUrls = [
432
- findValueInObject(data, ['url']),
433
- findValueInObject(data, ['download_url']),
434
- findValueInObject(data, ['video_backup']),
435
- findValueInObject(data, ['playUrl']),
436
- findValueInObject(data, ['video_url'])
437
- ];
438
484
  let video = '';
439
- if (Array.isArray(videoUrls[2])) {
440
- video = videoUrls[2][0]?.url || '';
485
+ if (platform === 'bilibili' && data.video && data.video.url) {
486
+ video = data.video.url;
487
+ }
488
+ else if (platform === 'douyin' && data.item && data.item.url) {
489
+ video = data.item.url;
441
490
  }
442
491
  else {
443
- for (const url of videoUrls) {
444
- if (url && typeof url === 'string' && url.trim() !== '') {
445
- video = url;
446
- break;
492
+ const videoUrls = [
493
+ findValueInObject(data, ['url']),
494
+ findValueInObject(data, ['download_url']),
495
+ findValueInObject(data, ['video_backup']),
496
+ findValueInObject(data, ['playUrl']),
497
+ findValueInObject(data, ['video_url'])
498
+ ];
499
+ if (Array.isArray(videoUrls[2])) {
500
+ video = videoUrls[2][0]?.url || '';
501
+ }
502
+ else {
503
+ for (const url of videoUrls) {
504
+ if (url && typeof url === 'string' && url.trim() !== '') {
505
+ video = url;
506
+ break;
507
+ }
447
508
  }
448
509
  }
449
510
  }
@@ -451,6 +512,15 @@ function parseData(rawResponse, maxDescLength, platform) {
451
512
  const duration = typeof durationValue === 'number' ? durationValue : parseInt(durationValue) || 0;
452
513
  const durationFormatted = formatDuration(durationValue || 0);
453
514
  const live_photo = data.live_photo || [];
515
+ const music = findValueInObject(data, ['music', 'muisic']) || '';
516
+ const h_w = platform === 'douyin' && data.item && data.item.h_w ? data.item.h_w : [];
517
+ const quality_urls = data.quality_urls || {};
518
+ const default_quality = data.default_quality || '';
519
+ const download_url = data.download_url || '';
520
+ const play_count = data.play_count || '';
521
+ const reposts_count = data.reposts_count || 0;
522
+ const attitudes_count = data.attitudes_count || 0;
523
+ const comments_count = data.comments_count || 0;
454
524
  return {
455
525
  type: type,
456
526
  rawData: rawResponse,
@@ -463,7 +533,17 @@ function parseData(rawResponse, maxDescLength, platform) {
463
533
  duration,
464
534
  durationFormatted,
465
535
  stat,
466
- live_photo
536
+ live_photo,
537
+ music,
538
+ h_w,
539
+ jx: data.jx || null,
540
+ quality_urls,
541
+ default_quality,
542
+ download_url,
543
+ play_count,
544
+ reposts_count,
545
+ attitudes_count,
546
+ comments_count
467
547
  };
468
548
  }
469
549
  function generateFormattedText(platform, parseData, config) {
@@ -542,8 +622,9 @@ function apply(ctx, config) {
542
622
  let lastError = null;
543
623
  for (let i = 0; i <= retryTimes; i++) {
544
624
  try {
625
+ const params = { url };
545
626
  const res = await http.get(API_CONFIG[platform], {
546
- params: { url },
627
+ params,
547
628
  timeout: config.timeout
548
629
  });
549
630
  return res.data;
@@ -576,9 +657,14 @@ function apply(ctx, config) {
576
657
  }
577
658
  try {
578
659
  const resData = await parseWithRetry(realUrl, platform, config.retryTimes);
579
- // 正确的成功判断逻辑:code为200或0,或者msg包含"解析成功"
580
- const isSuccess = resData.code === 200 || resData.code === 0 ||
581
- (resData.msg && resData.msg.includes('解析成功'));
660
+ let isSuccess = false;
661
+ if (platform === 'bilibili' || platform === 'douyin') {
662
+ isSuccess = resData.code === 0 || (resData.msg && (resData.msg.includes('解析成功') || resData.msg === 'video'));
663
+ }
664
+ else {
665
+ isSuccess = resData.code === 200 || resData.code === 0 ||
666
+ (resData.msg && resData.msg.includes('解析成功'));
667
+ }
582
668
  if (!isSuccess) {
583
669
  const apiErrorMsg = resData.msg || '解析失败';
584
670
  const platformCode = PLATFORM_ERROR_CODE_MAP[platform] || ErrorCode.API_RETURN_ERROR;
@@ -593,11 +679,11 @@ function apply(ctx, config) {
593
679
  }
594
680
  try {
595
681
  const parseResult = parseData(resData, config.maxDescLength, platform);
596
- // 修正内容判断逻辑:支持live类型和live_photo
597
682
  const hasValidContent = parseResult.video ||
598
683
  (parseResult.images && parseResult.images.length > 0) ||
599
684
  (parseResult.live_photo && parseResult.live_photo.length > 0) ||
600
- parseResult.type === 'live';
685
+ parseResult.type === 'live' ||
686
+ parseResult.type === '图集';
601
687
  if (!hasValidContent) {
602
688
  const code = ErrorCode.NO_VIDEO_FOUND;
603
689
  const msg = getErrorInfo(code, '链接有效但未找到视频/图片内容(可能是直播、私密内容或已删除)');
@@ -658,7 +744,12 @@ function apply(ctx, config) {
658
744
  images: parseData.images,
659
745
  video: parseData.video,
660
746
  type: parseData.type,
661
- live_photo: parseData.live_photo
747
+ live_photo: parseData.live_photo,
748
+ music: parseData.music,
749
+ h_w: parseData.h_w,
750
+ quality_urls: parseData.quality_urls,
751
+ default_quality: parseData.default_quality,
752
+ download_url: parseData.download_url
662
753
  },
663
754
  code: ErrorCode.SUCCESS,
664
755
  msg: getErrorInfo(ErrorCode.SUCCESS)
@@ -728,6 +819,11 @@ function apply(ctx, config) {
728
819
  forwardMessages.push(buildForwardNode(session, item.text, botName));
729
820
  if (item.cover && forwardMessages.length < 100)
730
821
  forwardMessages.push(buildForwardNode(session, koishi_1.h.image(item.cover), botName));
822
+ if (item.type === '图集' && item.images?.length) {
823
+ for (let i = 0; i < item.images.length && forwardMessages.length < 100; i++) {
824
+ forwardMessages.push(buildForwardNode(session, koishi_1.h.image(item.images[i]), botName));
825
+ }
826
+ }
731
827
  if (item.type === 'image' && item.images?.length) {
732
828
  for (let i = 0; i < item.images.length && forwardMessages.length < 100; i++) {
733
829
  forwardMessages.push(buildForwardNode(session, koishi_1.h.image(item.images[i]), botName));
@@ -795,7 +891,11 @@ function apply(ctx, config) {
795
891
  await sendTimeout(session, item.text);
796
892
  await delay(300);
797
893
  }
798
- if (item.type === 'live' || item.type === 'live_photo') {
894
+ if (item.type === '图集' && item.images?.length) {
895
+ const imgMsg = (0, koishi_1.h)('message', ...item.images.map((url) => koishi_1.h.image(url)));
896
+ await sendTimeout(session, imgMsg);
897
+ }
898
+ else if (item.type === 'live' || item.type === 'live_photo') {
799
899
  if (item.live_photo?.length) {
800
900
  for (const liveItem of item.live_photo) {
801
901
  await sendTimeout(session, koishi_1.h.image(liveItem.image));
@@ -975,9 +1075,5 @@ function apply(ctx, config) {
975
1075
  logger.info(getErrorInfo(ErrorCode.SUCCESS, '自动清理缓存完成'));
976
1076
  }, config.autoClearCacheInterval * 60000);
977
1077
  }
978
- process.on('exit', () => {
979
- clearAllCache();
980
- logger.info(getErrorInfo(ErrorCode.SUCCESS, '进程退出,已清理缓存'));
981
- });
982
1078
  logger.info(getErrorInfo(ErrorCode.SUCCESS, '视频解析插件已加载'));
983
1079
  }
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.5.4",
4
+ "version": "0.5.6",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [