koishi-plugin-video-parser-all 0.5.5 → 0.5.7

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 +35 -38
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -123,7 +123,6 @@ const PLATFORM_KEYWORDS = {
123
123
  douyin: ['douyin', '抖音', 'v.douyin.com', 'douyinpic.com', 'douyinvod.com', 'douyin.com/video', 'douyin.com/note', 'www.douyin.com', 'tiktok.com'],
124
124
  zuiyou: ['zuiyou', '最右', 'xiaochuankeji.cn', 'izuiyou.com', 'izuiyou.com/topic']
125
125
  };
126
- // 更新API配置:B站和抖音使用新的api.xingzhige.com,其他平台保持不变
127
126
  const API_CONFIG = {
128
127
  bilibili: 'https://api.xingzhige.com/API/b_parse',
129
128
  douyin: 'https://api.xingzhige.com/API/douyin/',
@@ -154,10 +153,10 @@ const VARIABLE_MAPPING = {
154
153
  '点赞数': ['like', 'Like', 'attitudes_count', 'digg_count', 'praise', 'stat.like'],
155
154
  '投币数': ['coin', 'Coin', 'bi', 'Bi'],
156
155
  '收藏数': ['collect', 'Collect', 'favorite', 'Favorite', 'star', 'Star', 'stat.collect'],
157
- '转发数': ['share', 'Share', 'forward', 'Forward', 'repost', 'stat.share'],
156
+ '转发数': ['share', 'Share', 'forward', 'Forward', 'repost', 'stat.share', 'reposts_count'],
158
157
  '播放数': ['view', 'View', 'play_count', 'PlayCount', 'play'],
159
158
  '评论数': ['comment', 'Comment', 'comments_count', 'comment_count', 'discuss', 'stat.comment'],
160
- '音乐名': ['music.title', 'music_name', 'audio_name', 'sound_name', 'muisic']
159
+ '音乐名': ['music.title', 'music_name', 'audio_name', 'sound_name', 'muisic', 'music']
161
160
  };
162
161
  function getErrorInfo(code, detail) {
163
162
  const baseMsg = exports.ErrorMessageMap[code] || exports.ErrorMessageMap[ErrorCode.UNKNOWN_ERROR];
@@ -322,7 +321,6 @@ function getPlatformType(url) {
322
321
  }
323
322
  function cleanUrl(url) {
324
323
  try {
325
- // 处理HTML实体编码
326
324
  url = url.replace(/&/g, '&');
327
325
  const urlObj = new URL(url);
328
326
  if (urlObj.hostname.includes('xiaohongshu.com')) {
@@ -330,7 +328,7 @@ function cleanUrl(url) {
330
328
  urlObj.searchParams.delete('xhsshare');
331
329
  urlObj.searchParams.delete('xsec_token');
332
330
  urlObj.searchParams.delete('xsec_source');
333
- return urlObj.origin + urlObj.pathname + urlObj.search;
331
+ return urlObj.origin + urlObj.pathname;
334
332
  }
335
333
  if (urlObj.hostname.includes('douyin.com') || urlObj.hostname.includes('v.douyin.com')) {
336
334
  return urlObj.origin + urlObj.pathname;
@@ -338,7 +336,6 @@ function cleanUrl(url) {
338
336
  return url;
339
337
  }
340
338
  catch (e) {
341
- // 处理HTML实体编码
342
339
  return url.replace(/&/g, '&');
343
340
  }
344
341
  }
@@ -409,39 +406,31 @@ function findValueInObject(obj, keys) {
409
406
  }
410
407
  return undefined;
411
408
  }
412
- // 适配新的API返回格式
413
409
  function parseData(rawResponse, maxDescLength, platform) {
414
410
  let data = rawResponse;
415
- // 处理不同平台的返回结构差异
416
411
  if (platform === 'bilibili' && rawResponse.data) {
417
- // 适配api.xingzhige.com的B站返回格式
418
412
  data = rawResponse.data;
419
413
  }
420
414
  else if (platform === 'douyin' && rawResponse.data) {
421
- // 适配api.xingzhige.com的抖音返回格式
422
415
  data = rawResponse.data;
423
416
  }
424
417
  else if (data.data) {
425
- // 其他平台保持原有逻辑
426
418
  data = data.data;
427
419
  }
428
420
  const stat = {};
429
- // 适配新的字段映射
430
421
  Object.entries(VARIABLE_MAPPING).forEach(([varName, keys]) => {
431
422
  const value = findValueInObject(data, keys);
432
423
  if (value !== undefined) {
433
424
  stat[varName] = value;
434
425
  }
435
426
  });
436
- // 处理不同平台的类型字段
437
427
  let type = 'video';
438
428
  if (platform === 'douyin' && data.jx && data.jx.type) {
439
- type = data.jx.type; // 抖音的图集类型
429
+ type = data.jx.type;
440
430
  }
441
431
  else if (data.type) {
442
432
  type = data.type;
443
433
  }
444
- // 适配不同平台的标题字段
445
434
  let title = '无标题';
446
435
  if (platform === 'bilibili' && data.video && data.video.title) {
447
436
  title = data.video.title;
@@ -452,7 +441,6 @@ function parseData(rawResponse, maxDescLength, platform) {
452
441
  else {
453
442
  title = findValueInObject(data, ['title']) || '无标题';
454
443
  }
455
- // 适配不同平台的作者字段
456
444
  let author = '未知作者';
457
445
  if (platform === 'bilibili' && data.owner && data.owner.name) {
458
446
  author = data.owner.name;
@@ -463,19 +451,17 @@ function parseData(rawResponse, maxDescLength, platform) {
463
451
  else {
464
452
  author = findValueInObject(data, ['author.name', 'author', 'name', 'auther']) || '未知作者';
465
453
  }
466
- // 适配不同平台的描述字段
467
454
  let desc = title;
468
455
  if (platform === 'bilibili' && data.video && data.video.desc) {
469
456
  desc = data.video.desc;
470
457
  }
471
458
  else if (platform === 'douyin') {
472
- desc = title; // 抖音没有单独的描述字段
459
+ desc = title;
473
460
  }
474
461
  else {
475
462
  desc = findValueInObject(data, ['desc', 'description', 'content']) || title;
476
463
  }
477
464
  desc = desc.toString().slice(0, maxDescLength);
478
- // 适配不同平台的封面字段
479
465
  let cover = '';
480
466
  if (platform === 'bilibili' && data.video && data.video.fm) {
481
467
  cover = data.video.fm;
@@ -486,7 +472,6 @@ function parseData(rawResponse, maxDescLength, platform) {
486
472
  else {
487
473
  cover = findValueInObject(data, ['cover', 'imgurl', 'pic', 'thumbnail']) || '';
488
474
  }
489
- // 适配不同平台的图片字段
490
475
  let images = [];
491
476
  if (platform === 'douyin' && data.item && data.item.images) {
492
477
  images = data.item.images;
@@ -496,13 +481,12 @@ function parseData(rawResponse, maxDescLength, platform) {
496
481
  }
497
482
  if (!Array.isArray(images))
498
483
  images = [images];
499
- // 适配不同平台的视频链接字段
500
484
  let video = '';
501
485
  if (platform === 'bilibili' && data.video && data.video.url) {
502
486
  video = data.video.url;
503
487
  }
504
- else if (platform === 'douyin') {
505
- video = ''; // 抖音图集没有视频链接
488
+ else if (platform === 'douyin' && data.item && data.item.url) {
489
+ video = data.item.url;
506
490
  }
507
491
  else {
508
492
  const videoUrls = [
@@ -524,12 +508,19 @@ function parseData(rawResponse, maxDescLength, platform) {
524
508
  }
525
509
  }
526
510
  }
527
- // 适配不同平台的时长字段
528
511
  const durationValue = findValueInObject(data, ['duration']);
529
512
  const duration = typeof durationValue === 'number' ? durationValue : parseInt(durationValue) || 0;
530
513
  const durationFormatted = formatDuration(durationValue || 0);
531
- // 处理live_photo字段
532
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;
533
524
  return {
534
525
  type: type,
535
526
  rawData: rawResponse,
@@ -542,7 +533,17 @@ function parseData(rawResponse, maxDescLength, platform) {
542
533
  duration,
543
534
  durationFormatted,
544
535
  stat,
545
- 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
546
547
  };
547
548
  }
548
549
  function generateFormattedText(platform, parseData, config) {
@@ -621,8 +622,9 @@ function apply(ctx, config) {
621
622
  let lastError = null;
622
623
  for (let i = 0; i <= retryTimes; i++) {
623
624
  try {
625
+ const params = { url };
624
626
  const res = await http.get(API_CONFIG[platform], {
625
- params: { url },
627
+ params,
626
628
  timeout: config.timeout
627
629
  });
628
630
  return res.data;
@@ -655,14 +657,11 @@ function apply(ctx, config) {
655
657
  }
656
658
  try {
657
659
  const resData = await parseWithRetry(realUrl, platform, config.retryTimes);
658
- // 适配不同平台的成功判断逻辑
659
660
  let isSuccess = false;
660
- // B站和抖音使用新的判断逻辑(code=0表示成功)
661
661
  if (platform === 'bilibili' || platform === 'douyin') {
662
662
  isSuccess = resData.code === 0 || (resData.msg && (resData.msg.includes('解析成功') || resData.msg === 'video'));
663
663
  }
664
664
  else {
665
- // 其他平台保持原有逻辑
666
665
  isSuccess = resData.code === 200 || resData.code === 0 ||
667
666
  (resData.msg && resData.msg.includes('解析成功'));
668
667
  }
@@ -680,7 +679,6 @@ function apply(ctx, config) {
680
679
  }
681
680
  try {
682
681
  const parseResult = parseData(resData, config.maxDescLength, platform);
683
- // 修正内容判断逻辑:支持抖音图集、live类型和live_photo
684
682
  const hasValidContent = parseResult.video ||
685
683
  (parseResult.images && parseResult.images.length > 0) ||
686
684
  (parseResult.live_photo && parseResult.live_photo.length > 0) ||
@@ -746,7 +744,12 @@ function apply(ctx, config) {
746
744
  images: parseData.images,
747
745
  video: parseData.video,
748
746
  type: parseData.type,
749
- 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
750
753
  },
751
754
  code: ErrorCode.SUCCESS,
752
755
  msg: getErrorInfo(ErrorCode.SUCCESS)
@@ -816,7 +819,6 @@ function apply(ctx, config) {
816
819
  forwardMessages.push(buildForwardNode(session, item.text, botName));
817
820
  if (item.cover && forwardMessages.length < 100)
818
821
  forwardMessages.push(buildForwardNode(session, koishi_1.h.image(item.cover), botName));
819
- // 处理抖音图集
820
822
  if (item.type === '图集' && item.images?.length) {
821
823
  for (let i = 0; i < item.images.length && forwardMessages.length < 100; i++) {
822
824
  forwardMessages.push(buildForwardNode(session, koishi_1.h.image(item.images[i]), botName));
@@ -889,7 +891,6 @@ function apply(ctx, config) {
889
891
  await sendTimeout(session, item.text);
890
892
  await delay(300);
891
893
  }
892
- // 处理抖音图集
893
894
  if (item.type === '图集' && item.images?.length) {
894
895
  const imgMsg = (0, koishi_1.h)('message', ...item.images.map((url) => koishi_1.h.image(url)));
895
896
  await sendTimeout(session, imgMsg);
@@ -1074,9 +1075,5 @@ function apply(ctx, config) {
1074
1075
  logger.info(getErrorInfo(ErrorCode.SUCCESS, '自动清理缓存完成'));
1075
1076
  }, config.autoClearCacheInterval * 60000);
1076
1077
  }
1077
- process.on('exit', () => {
1078
- clearAllCache();
1079
- logger.info(getErrorInfo(ErrorCode.SUCCESS, '进程退出,已清理缓存'));
1080
- });
1081
1078
  logger.info(getErrorInfo(ErrorCode.SUCCESS, '视频解析插件已加载'));
1082
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.5",
4
+ "version": "0.5.7",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [