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.
- package/lib/index.js +49 -138
- package/package.json +2 -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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
440
|
-
|
|
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 (
|
|
475
|
-
type =
|
|
476
|
-
else if (
|
|
477
|
-
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 ((
|
|
483
|
-
(
|
|
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 =
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
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
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
|
|
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(
|
|
458
|
+
const pubTime = formatPublishTime(data.create_time || data.publish_time);
|
|
523
459
|
if (pubTime)
|
|
524
460
|
stat['发布时间'] = pubTime;
|
|
525
|
-
|
|
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:
|
|
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
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
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.
|
|
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 | 短视频 |
|