koishi-plugin-video-parser-all 0.7.4 → 0.7.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 (3) hide show
  1. package/lib/index.js +49 -138
  2. package/package.json +2 -3
  3. package/readme.md +1 -2
package/lib/index.js CHANGED
@@ -31,18 +31,7 @@ exports.Config = koishi_1.Schema.intersect([
31
31
  收藏:${'${收藏数}'}
32
32
  转发:${'${转发数}'}
33
33
  播放:${'${播放数}'}
34
- 评论:${'${评论数}'}
35
- IP属地:${'${IP属地}'}
36
- 发布时间:${'${发布时间}'}
37
- 粉丝数:${'${粉丝数}'}
38
- 在线人数:${'${在线人数}'}
39
- 关注数:${'${关注数}'}
40
- 文件大小:${'${文件大小}'}
41
- 直播间地址:${'${直播间地址}'}
42
- 直播间ID:${'${直播间ID}'}
43
- 直播间状态:${'${直播间状态}'}
44
- 图片数量:${'${图片数量}'}
45
- 作者ID:${'${作者ID}'}`).description('统一消息格式'),
34
+ 评论:${'${评论数}'}`).description('统一消息格式'),
46
35
  }).description('统一消息格式'),
47
36
  koishi_1.Schema.object({
48
37
  showImageText: koishi_1.Schema.boolean().default(true).description('显示图文内容'),
@@ -80,7 +69,6 @@ const logger = new koishi_1.Logger(exports.name);
80
69
  const PLATFORM_KEYWORDS = {
81
70
  bilibili: ['bilibili', 'b23', 'B站', 'www.bilibili.com', 'm.bilibili.com', '哔哩哔哩', 'bilibili.com/opus', 'bilibili.com/video', 'b23.tv', 't.bilibili.com', 'bilibili.com/bangumi'],
82
71
  kuaishou: ['kuaishou', '快手', 'v.kuaishou.com', 'www.kuaishou.com', 'kwimgs.com', 'kuaishou.com/app'],
83
- xiaohongshu: ['xiaohongshu', '小红书', 'xhslink.com', 'xiaohongshu.com', 'xhscdn.com', 'xiaohongshu.com/explore', 'xhslink.com/', 'xiaohongshu.com/discovery/item'],
84
72
  weibo: ['weibo', '微博', 'weibo.com', 'video.weibo.com', 'm.weibo.cn', 'weibo.com/tv/show', 'weibo.com/feed'],
85
73
  toutiao: ['toutiao', '今日头条', 'm.toutiao.com', 'toutiao.com', 'ixigua.com', 'toutiao.com/video', 'ixigua.com/i'],
86
74
  pipigx: ['pipigx', '皮皮搞笑', 'h5.pipigx.com', 'ippzone.com', 'pipigx.com/share'],
@@ -92,7 +80,6 @@ const API_CONFIG = {
92
80
  bilibili: 'https://api.xingzhige.com/API/b_parse',
93
81
  douyin: 'https://api.xingzhige.com/API/douyin/',
94
82
  kuaishou: 'https://api.bugpk.com/api/ksjx',
95
- xiaohongshu: 'https://api.bugpk.com/api/xhsjx',
96
83
  weibo: 'https://api.bugpk.com/api/weibo',
97
84
  toutiao: 'https://api.bugpk.com/api/toutiao',
98
85
  pipigx: 'https://api.bugpk.com/api/pipigx',
@@ -264,8 +251,6 @@ function getPlatformType(url) {
264
251
  return 'bilibili';
265
252
  if (PLATFORM_KEYWORDS.kuaishou.some(k => lower.includes(k)))
266
253
  return 'kuaishou';
267
- if (PLATFORM_KEYWORDS.xiaohongshu.some(k => lower.includes(k)))
268
- return 'xiaohongshu';
269
254
  if (PLATFORM_KEYWORDS.weibo.some(k => lower.includes(k)))
270
255
  return 'weibo';
271
256
  if (PLATFORM_KEYWORDS.toutiao.some(k => lower.includes(k)))
@@ -284,9 +269,6 @@ function cleanUrl(url) {
284
269
  try {
285
270
  url = url.replace(/&/g, '&');
286
271
  const urlObj = new URL(url);
287
- if (urlObj.hostname.includes('xiaohongshu.com') || urlObj.hostname.includes('xhslink.com')) {
288
- return urlObj.href;
289
- }
290
272
  if (urlObj.hostname.includes('douyin.com') || urlObj.hostname.includes('v.douyin.com')) {
291
273
  urlObj.searchParams.delete('source');
292
274
  urlObj.searchParams.delete('share_type');
@@ -414,20 +396,17 @@ function findValueInObject(obj, keys) {
414
396
  }
415
397
  function parseData(rawResponse, maxDescLength) {
416
398
  const root = rawResponse || {};
417
- const data = root.data || root.result || root || {};
418
- // 小红书特殊处理:API返回数据在 root 根节点而非 data 子节点
419
- const isXiaohongshu = root.note_title || root.note_desc || root.author_name || root.cover;
420
- const parseRoot = isXiaohongshu ? root : data;
399
+ const data = root.data || root;
421
400
  const stat = {};
422
401
  let totalImageCount = 0;
423
402
  Object.entries(VARIABLE_MAPPING).forEach(([varName, keys]) => {
424
- let value = findValueInObject(parseRoot, keys) || findValueInObject(root, keys);
403
+ let value = findValueInObject(data, keys) || findValueInObject(root, keys);
425
404
  if (varName === '图片数量' && value === undefined) {
426
405
  let imgCount = 0;
427
406
  const imgSources = [
428
- parseRoot.images, parseRoot.pics, parseRoot.pic_urls, parseRoot.image_list, parseRoot.imgurl,
407
+ data.images, data.pics, data.pic_urls, data.image_list, data.imgurl,
429
408
  root.images, root.pics, root.pic_urls, root.image_list, root.imgurl,
430
- parseRoot.item?.images
409
+ data.item?.images
431
410
  ];
432
411
  for (const source of imgSources) {
433
412
  if (Array.isArray(source) && source.length > 0) {
@@ -436,8 +415,8 @@ function parseData(rawResponse, maxDescLength) {
436
415
  }
437
416
  }
438
417
  totalImageCount = imgCount;
439
- const cover = parseRoot.cover || parseRoot.video?.fm || parseRoot.imgurl || parseRoot.pic || parseRoot.thumbnail || parseRoot.cover_url ||
440
- parseRoot.item?.cover || root.cover || parseRoot.live?.cover || parseRoot.live?.keyframe || '';
418
+ const cover = data.cover || data.video?.fm || data.imgurl || data.pic || data.thumbnail || data.cover_url ||
419
+ data.item?.cover || root.cover || data.live?.cover || data.live?.keyframe || '';
441
420
  if (cover && imgCount > 0) {
442
421
  imgCount = imgSources.find(source => Array.isArray(source))?.filter(i => i && typeof i === 'string' && i !== cover).length || 0;
443
422
  }
@@ -447,118 +426,58 @@ function parseData(rawResponse, maxDescLength) {
447
426
  stat[varName] = value;
448
427
  }
449
428
  });
450
- // 小红书字段兜底
451
- if (isXiaohongshu) {
452
- if (!stat['标题'])
453
- stat['标题'] = root.note_title || root.title || '';
454
- if (!stat['作者'])
455
- stat['作者'] = root.author_name || root.nickname || root.author || '';
456
- if (!stat['简介'])
457
- stat['简介'] = root.note_desc || root.desc || root.content || '';
458
- if (!stat['播放数'])
459
- stat['播放数'] = root.play_count || root.view_count || '';
460
- if (!stat['点赞数'])
461
- stat['点赞数'] = root.like_count || root.attitudes_count || '';
462
- if (!stat['评论数'])
463
- stat['评论数'] = root.comment_count || root.comments_count || '';
464
- if (!stat['收藏数'])
465
- stat['收藏数'] = root.collect_count || root.favorite_count || '';
466
- if (!stat['转发数'])
467
- stat['转发数'] = root.share_count || root.repost_count || '';
468
- if (!stat['发布时间'])
469
- stat['发布时间'] = root.create_time || root.publish_time || '';
470
- if (!stat['IP属地'])
471
- stat['IP属地'] = root.ip_location || root.ip_info_str || '';
472
- }
473
429
  let type = 'video';
474
- if (parseRoot.jx?.type)
475
- type = parseRoot.jx.type;
476
- else if (parseRoot.type)
477
- type = parseRoot.type;
430
+ if (data.jx?.type)
431
+ type = data.jx.type;
432
+ else if (data.type)
433
+ type = data.type;
478
434
  else if (root.msg === 'cv')
479
435
  type = 'cv';
480
436
  else if (root.msg === 'live')
481
437
  type = 'live';
482
- else if ((parseRoot.images && parseRoot.images.length > 1) || (root.images && root.images.length > 1) ||
483
- (parseRoot.imgurl && parseRoot.imgurl.length > 1) || (root.imgurl && root.imgurl.length > 1))
438
+ else if ((data.images && data.images.length > 1) || (root.images && root.images.length > 1) ||
439
+ (data.imgurl && data.imgurl.length > 1) || (root.imgurl && root.imgurl.length > 1))
484
440
  type = '图集';
485
- const title = stat['标题'] || parseRoot.note_title || parseRoot.title || parseRoot.content_title || parseRoot.video?.title ||
486
- parseRoot.item?.title || root.title || parseRoot.live?.title || '无标题';
487
- let author = stat['作者'] || parseRoot.author?.name || parseRoot.nickname || parseRoot.user_name || parseRoot.owner?.name ||
488
- parseRoot.item?.author || root.author || parseRoot.user?.name || parseRoot.live?.author || '';
489
- if (typeof author === 'object') {
490
- author = '';
441
+ const title = data.title || '无标题';
442
+ let author = '';
443
+ if (data.author && typeof data.author === 'object') {
444
+ author = data.author.name || '';
491
445
  }
492
446
  else {
493
- author = author || '未知作者';
494
- }
495
- const rawDesc = stat['简介'] || parseRoot.note_desc || parseRoot.content || parseRoot.text || parseRoot.description ||
496
- parseRoot.video?.desc || parseRoot.item?.description || root.desc || root.description ||
497
- parseRoot.live?.desc || (title !== '无标题' ? title : '') || '暂无简介';
498
- const desc = rawDesc.length > 0 ? rawDesc.slice(0, maxDescLength) : '暂无简介';
499
- const cover = parseRoot.cover || parseRoot.video?.fm || parseRoot.imgurl || parseRoot.pic || parseRoot.thumbnail || parseRoot.cover_url ||
500
- parseRoot.item?.cover || root.cover || parseRoot.live?.cover || parseRoot.live?.keyframe ||
501
- (Array.isArray(parseRoot.images) && parseRoot.images[0]) ||
502
- (Array.isArray(root.images) && root.images[0]) ||
503
- (Array.isArray(parseRoot.imgurl) && parseRoot.imgurl[0]) || '';
504
- let images = [];
505
- const imgSources = [
506
- parseRoot.images, parseRoot.pics, parseRoot.pic_urls, parseRoot.image_list, parseRoot.imgurl,
507
- root.images, root.pics, root.pic_urls, root.image_list, root.imgurl,
508
- parseRoot.item?.images
509
- ];
510
- for (const source of imgSources) {
511
- if (Array.isArray(source) && source.length > 0) {
512
- images = source.filter(i => i && typeof i === 'string' && i !== cover);
513
- break;
514
- }
515
- }
516
- let video = parseRoot.video?.url || parseRoot.url || parseRoot.download_url || parseRoot.playUrl ||
517
- parseRoot.video_url || root.url || parseRoot.item?.url || parseRoot.live?.url ||
518
- (parseRoot.live?.url && Array.isArray(parseRoot.live.url) ? parseRoot.live.url[0] : '') || '';
519
- const durationValue = stat['视频时长'] || parseRoot.item?.duration || parseRoot.duration || 0;
447
+ author = data.author || '';
448
+ }
449
+ author = author || '未知作者';
450
+ const rawDesc = data.desc || data.content || '暂无简介';
451
+ const desc = rawDesc.slice(0, maxDescLength);
452
+ const cover = data.cover || '';
453
+ const images = Array.isArray(data.images) ? data.images : [];
454
+ const video = data.url || data.video_backup || '';
455
+ const durationValue = data.duration || 0;
520
456
  const duration = typeof durationValue === 'number' ? durationValue : parseInt(durationValue) || 0;
521
457
  const durationFormatted = formatDuration(durationValue);
522
- const pubTime = formatPublishTime(stat['发布时间']);
458
+ const pubTime = formatPublishTime(data.create_time || data.publish_time);
523
459
  if (pubTime)
524
460
  stat['发布时间'] = pubTime;
525
- else
526
- delete stat['发布时间'];
527
- if (durationFormatted !== '00:00:00') {
461
+ if (durationFormatted !== '00:00:00')
528
462
  stat['视频时长'] = durationFormatted;
529
- }
530
- else {
531
- delete stat['视频时长'];
532
- }
533
- if (stat['图片数量'] === 0) {
463
+ if (stat['图片数量'] === 0)
534
464
  delete stat['图片数量'];
465
+ const live_photo = data.live_photo || [];
466
+ const h_w = data.item?.h_w || [];
467
+ const quality_urls = data.quality_urls || {};
468
+ const default_quality = data.default_quality || '';
469
+ const download_url = video;
470
+ const play_count = stat['播放数'] || '';
471
+ const reposts_count = Number(stat['转发数']) || 0;
472
+ const attitudes_count = Number(stat['点赞数']) || 0;
473
+ const comments_count = Number(stat['评论数']) || 0;
474
+ if (data.live) {
475
+ stat['直播间地址'] = data.live.room_url || '';
476
+ stat['直播间ID'] = data.live.room_id || '';
477
+ stat['直播间状态'] = data.live.status === 1 ? '直播中' : (data.live.status === 0 ? '未开播' : '未知');
478
+ stat['在线人数'] = data.live.online || '';
479
+ stat['关注数'] = data.live.attention || '';
535
480
  }
536
- const sizeVal = stat['文件大小'];
537
- if (sizeVal && !String(sizeVal).includes('MB')) {
538
- const num = Number(sizeVal);
539
- if (!isNaN(num) && num > 0)
540
- stat['文件大小'] = `${num.toFixed(2)} MB`;
541
- }
542
- const live_photo = parseRoot.live_photo || root.live_photo || [];
543
- const h_w = parseRoot.item?.h_w || root.h_w || [];
544
- const quality_urls = parseRoot.quality_urls || root.quality_urls || {};
545
- const default_quality = parseRoot.default_quality || root.default_quality || '';
546
- const download_url = parseRoot.download_url || video;
547
- const play_count = stat['播放数'] || parseRoot.play_count || root.play_count || '';
548
- const reposts_count = Number(stat['转发数']) || parseRoot.reposts_count || root.reposts_count || 0;
549
- const attitudes_count = Number(stat['点赞数']) || parseRoot.attitudes_count || root.attitudes_count || parseRoot.like || root.like || 0;
550
- const comments_count = Number(stat['评论数']) || parseRoot.comments_count || root.comments_count || 0;
551
- if (parseRoot.live) {
552
- stat['直播间地址'] = parseRoot.live.room_url || '';
553
- stat['直播间ID'] = parseRoot.live.room_id || '';
554
- stat['直播间状态'] = parseRoot.live.status === 1 ? '直播中' : (parseRoot.live.status === 0 ? '未开播' : parseRoot.live.status || '未知');
555
- stat['在线人数'] = parseRoot.live.online || '';
556
- stat['关注数'] = parseRoot.live.attention || '';
557
- }
558
- if (parseRoot.followers_count)
559
- stat['粉丝数'] = parseRoot.followers_count;
560
- if (parseRoot.ip_info_str)
561
- stat['IP属地'] = parseRoot.ip_info_str;
562
481
  return {
563
482
  type: type,
564
483
  rawData: rawResponse,
@@ -574,7 +493,7 @@ function parseData(rawResponse, maxDescLength) {
574
493
  totalImageCount,
575
494
  live_photo,
576
495
  h_w,
577
- jx: parseRoot.jx || null,
496
+ jx: data.jx || null,
578
497
  quality_urls,
579
498
  default_quality,
580
499
  download_url,
@@ -664,18 +583,10 @@ function apply(ctx, config) {
664
583
  for (let i = 0; i <= retryTimes; i++) {
665
584
  try {
666
585
  const params = { url };
667
- let res;
668
- if (platform === 'xiaohongshu') {
669
- res = await http.post(API_CONFIG[platform], new URLSearchParams(params), {
670
- timeout: config.timeout
671
- });
672
- }
673
- else {
674
- res = await http.get(API_CONFIG[platform], {
675
- params,
676
- timeout: config.timeout
677
- });
678
- }
586
+ const res = await http.get(API_CONFIG[platform], {
587
+ params,
588
+ timeout: config.timeout
589
+ });
679
590
  return res.data;
680
591
  }
681
592
  catch (error) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-video-parser-all",
3
- "description": "Koishi 全平台视频解析插件,支持抖音/快手/B站/小红书/微博/今日头条/皮皮搞笑/皮皮虾/最右视频链接解析",
4
- "version": "0.7.4",
3
+ "description": "Koishi 全平台视频解析插件,支持抖音/快手/B站/微博/今日头条/皮皮搞笑/皮皮虾/最右视频链接解析",
4
+ "version": "0.7.6",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -26,7 +26,6 @@
26
26
  "bv",
27
27
  "douyin",
28
28
  "kuaishou",
29
- "xiaohongshu",
30
29
  "weibo",
31
30
  "toutiao",
32
31
  "pipigx",
package/readme.md CHANGED
@@ -3,7 +3,7 @@
3
3
  ## 项目介绍 (Project Introduction)
4
4
 
5
5
  ### 中文
6
- 这是一个为 Koishi 机器人框架开发的**多平台视频/图集解析插件**,支持自动识别并解析抖音、快手、B站、小红书、微博、今日头条、皮皮搞笑、皮皮虾、最右等主流平台的短视频/图集链接。核心特性:
6
+ 这是一个为 Koishi 机器人框架开发的**多平台视频/图集解析插件**,支持自动识别并解析抖音、快手、B站、微博、今日头条、皮皮搞笑、皮皮虾、最右等主流平台的短视频/图集链接。核心特性:
7
7
  - 🚀 自动识别多平台链接,无需手动指定平台
8
8
  - 🎨 自定义解析结果格式,支持丰富的变量替换
9
9
  - ⚡ 内置防重复解析、接口重试、自动缓存清理等实用功能
@@ -119,7 +119,6 @@ This is a **multi-platform video/image parsing plugin** developed for the Koishi
119
119
  | 哔哩哔哩 (B站) | bilibili、b23、B站 | 视频、番剧、直播、图集 |
120
120
  | 抖音 | douyin、v.douyin.com | 短视频、图集、直播 |
121
121
  | 快手 | kuaishou、v.kuaishou.com | 短视频、图集 |
122
- | 小红书 | xiaohongshu、xhslink.com | 笔记、图集、视频 |
123
122
  | 微博 | weibo、video.weibo.com | 视频、图集 |
124
123
  | 今日头条 | toutiao、ixigua.com | 短视频 |
125
124
  | 皮皮搞笑 | pipigx、h5.pipigx.com | 短视频 |