koishi-plugin-video-parser-all 0.6.5 → 0.6.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.
- package/lib/index.js +109 -60
- 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}'}
|
|
45
|
+
作者ID:${'${作者ID}'}
|
|
46
|
+
视频备用链接:${'${视频备用链接}'}`).description('统一消息格式'),
|
|
46
47
|
}).description('统一消息格式'),
|
|
47
48
|
koishi_1.Schema.object({
|
|
48
49
|
showImageText: koishi_1.Schema.boolean().default(true).description('显示图文内容'),
|
|
@@ -141,31 +142,32 @@ const API_CONFIG = {
|
|
|
141
142
|
weibo: 'https://api.bugpk.com/api/weibo',
|
|
142
143
|
toutiao: 'https://api.bugpk.com/api/toutiao',
|
|
143
144
|
pipigx: 'https://api.bugpk.com/api/pipigx',
|
|
144
|
-
pipixia: 'https://api.bugpk.com/api/
|
|
145
|
+
pipixia: 'https://api.bugpk.com/api/pipixia',
|
|
145
146
|
zuiyou: 'https://api.bugpk.com/api/zuiyou'
|
|
146
147
|
};
|
|
147
148
|
const VARIABLE_MAPPING = {
|
|
148
|
-
'标题': ['title', '
|
|
149
|
-
'作者': ['author
|
|
150
|
-
'简介': ['desc', 'description', '
|
|
151
|
-
'视频时长': ['duration', '
|
|
152
|
-
'点赞数': ['like', '
|
|
153
|
-
'投币数': ['coin', '
|
|
154
|
-
'收藏数': ['collect', '
|
|
155
|
-
'转发数': ['share', '
|
|
156
|
-
'播放数': ['view', '
|
|
157
|
-
'评论数': ['comment', '
|
|
158
|
-
'IP属地': ['ip_info_str', 'data.ip_info_str', 'item.ip_info'],
|
|
159
|
-
'发布时间': ['date', 'time', 'publish_time', 'data.date', 'item.publish_time', 'live.time', 'stast.publish_time'],
|
|
160
|
-
'粉丝数': ['followers_count', 'data.followers_count', 'item.followers', 'author.fans'],
|
|
161
|
-
'在线人数': ['online', 'data.online', 'live.online', 'room.online'],
|
|
162
|
-
'关注数': ['attention', 'data.attention', 'live.attention', 'stast.attention'],
|
|
163
|
-
'文件大小': ['size', 'size_str', 'item.size', 'item.size_str', 'data.size'],
|
|
164
|
-
'直播间地址': ['room_url', 'live.room_url', 'data.room_url', 'live.url'],
|
|
165
|
-
'直播间ID': ['room_id', 'live.room_id', 'data.room_id', 'live.room_id'],
|
|
166
|
-
'直播间状态': ['status', 'live.status', 'data.status', 'room.status'],
|
|
167
|
-
'图片数量': ['count', 'data.count', 'item.count', 'images.length', 'data.images.length'],
|
|
168
|
-
'作者ID': ['userId', 'userID', 'author_id', 'data.userId', 'item.userID', 'author.mid', 'user.mid'],
|
|
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'],
|
|
159
|
+
'IP属地': ['ip_info_str', 'data.ip_info_str', 'item.ip_info', 'data.item.ip_info_str'],
|
|
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'],
|
|
161
|
+
'粉丝数': ['followers_count', 'data.followers_count', 'item.followers', 'author.fans', 'data.item.followers_count'],
|
|
162
|
+
'在线人数': ['online', 'data.online', 'live.online', 'room.online', 'data.live.online'],
|
|
163
|
+
'关注数': ['attention', 'data.attention', 'live.attention', 'stast.attention', 'data.live.attention'],
|
|
164
|
+
'文件大小': ['size', 'size_str', 'item.size', 'item.size_str', 'data.size', 'data.item.size_str'],
|
|
165
|
+
'直播间地址': ['room_url', 'live.room_url', 'data.room_url', 'live.url', 'data.live.room_url'],
|
|
166
|
+
'直播间ID': ['room_id', 'live.room_id', 'data.room_id', 'live.room_id', 'data.live.room_id'],
|
|
167
|
+
'直播间状态': ['status', 'live.status', 'data.status', 'room.status', 'data.live.status'],
|
|
168
|
+
'图片数量': ['count', 'data.count', 'item.count', 'images.length', 'data.images.length', 'data.item.count'],
|
|
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,12 +391,21 @@ function formatPublishTime(value) {
|
|
|
389
391
|
if (!value)
|
|
390
392
|
return '';
|
|
391
393
|
const str = String(value).trim();
|
|
392
|
-
|
|
394
|
+
// 适配B站的 ctime 时间戳字段名(避免直接传入字符串"ctime")
|
|
395
|
+
if (value === 'ctime')
|
|
393
396
|
return '';
|
|
397
|
+
if (/^\d{10}$/.test(str)) {
|
|
398
|
+
value = Number(str) * 1000;
|
|
399
|
+
}
|
|
400
|
+
if (/^\d{10,}$/.test(str) && Number(str) > 1e12) {
|
|
401
|
+
if (Number(str) > 1e15) {
|
|
402
|
+
value = Number(str) / 1000;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
394
405
|
try {
|
|
395
|
-
const d = new Date(/^\d+$/.test(str) ? Number(str)
|
|
406
|
+
const d = new Date(/^\d+$/.test(str) ? Number(str) : str);
|
|
396
407
|
if (isNaN(d.getTime()))
|
|
397
|
-
return
|
|
408
|
+
return str;
|
|
398
409
|
const y = d.getFullYear();
|
|
399
410
|
const m = (d.getMonth() + 1).toString().padStart(2, '0');
|
|
400
411
|
const d_ = d.getDate().toString().padStart(2, '0');
|
|
@@ -412,7 +423,7 @@ function formatPublishTime(value) {
|
|
|
412
423
|
return parts.join(' ').trim();
|
|
413
424
|
}
|
|
414
425
|
catch {
|
|
415
|
-
return
|
|
426
|
+
return str;
|
|
416
427
|
}
|
|
417
428
|
}
|
|
418
429
|
function getNestedValue(obj, path) {
|
|
@@ -452,15 +463,19 @@ function findValueInObject(obj, keys) {
|
|
|
452
463
|
return undefined;
|
|
453
464
|
}
|
|
454
465
|
function parseData(rawResponse, maxDescLength) {
|
|
455
|
-
const
|
|
456
|
-
const data =
|
|
466
|
+
const root = rawResponse || {};
|
|
467
|
+
const data = root.data || root.result || root || {};
|
|
457
468
|
const stat = {};
|
|
458
469
|
Object.entries(VARIABLE_MAPPING).forEach(([varName, keys]) => {
|
|
459
|
-
let value = findValueInObject(data, keys) || findValueInObject(
|
|
470
|
+
let value = findValueInObject(data, keys) || findValueInObject(root, keys);
|
|
460
471
|
if (varName === '图片数量' && value === undefined) {
|
|
461
|
-
value = Array.isArray(data.images) ? data.images.length :
|
|
472
|
+
value = Array.isArray(data.images) ? data.images.length :
|
|
473
|
+
Array.isArray(root.images) ? root.images.length :
|
|
474
|
+
Array.isArray(data.imgurl) ? data.imgurl.length :
|
|
475
|
+
Array.isArray(root.imgurl) ? root.imgurl.length :
|
|
476
|
+
data.count || root.count || undefined;
|
|
462
477
|
}
|
|
463
|
-
if (value !== undefined && value !== null && value !== '') {
|
|
478
|
+
if (value !== undefined && value !== null && value !== '' && value !== 0) {
|
|
464
479
|
stat[varName] = value;
|
|
465
480
|
}
|
|
466
481
|
});
|
|
@@ -469,25 +484,44 @@ function parseData(rawResponse, maxDescLength) {
|
|
|
469
484
|
type = data.jx.type;
|
|
470
485
|
else if (data.type)
|
|
471
486
|
type = data.type;
|
|
472
|
-
else if (
|
|
487
|
+
else if (root.msg === 'cv')
|
|
473
488
|
type = 'cv';
|
|
474
|
-
else if (
|
|
489
|
+
else if (root.msg === 'live')
|
|
475
490
|
type = 'live';
|
|
476
|
-
else if ((data.images && data.images.length > 1) || (
|
|
491
|
+
else if ((data.images && data.images.length > 1) || (root.images && root.images.length > 1) ||
|
|
492
|
+
(data.imgurl && data.imgurl.length > 1) || (root.imgurl && root.imgurl.length > 1))
|
|
477
493
|
type = '图集';
|
|
478
|
-
const title = stat['标题'] ||
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
494
|
+
const title = stat['标题'] || data.note_title || data.title || data.content_title || data.video?.title ||
|
|
495
|
+
data.item?.title || root.title || data.live?.title || '无标题';
|
|
496
|
+
let author = stat['作者'] || data.author?.name || data.nickname || data.user_name || data.owner?.name ||
|
|
497
|
+
data.item?.author || root.author || data.user?.name || data.live?.author || '未知作者';
|
|
498
|
+
if (typeof author === 'object' && author.name)
|
|
499
|
+
author = author.name;
|
|
500
|
+
const rawDesc = stat['简介'] || data.note_desc || data.content || data.text || data.description ||
|
|
501
|
+
data.video?.desc || data.item?.description || root.desc || root.description ||
|
|
502
|
+
data.live?.desc || (title !== '无标题' ? title : '') || '暂无简介';
|
|
503
|
+
const desc = rawDesc.length > 0 ? rawDesc.slice(0, maxDescLength) : '暂无简介';
|
|
504
|
+
const cover = data.cover || data.video?.fm || data.imgurl || data.pic || data.thumbnail || data.cover_url ||
|
|
505
|
+
data.item?.cover || root.cover || data.live?.cover || data.live?.keyframe ||
|
|
506
|
+
(Array.isArray(data.images) && data.images[0]) ||
|
|
507
|
+
(Array.isArray(root.images) && root.images[0]) ||
|
|
508
|
+
(Array.isArray(data.imgurl) && data.imgurl[0]) || '';
|
|
483
509
|
let images = [];
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
images
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
510
|
+
const imgSources = [
|
|
511
|
+
data.images, data.pics, data.pic_urls, data.image_list, data.imgurl,
|
|
512
|
+
root.images, root.pics, root.pic_urls, root.image_list, root.imgurl,
|
|
513
|
+
data.item?.images
|
|
514
|
+
];
|
|
515
|
+
for (const source of imgSources) {
|
|
516
|
+
if (Array.isArray(source) && source.length > 0) {
|
|
517
|
+
images = source.filter(i => i && typeof i === 'string');
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
let video = data.video?.url || data.url || data.download_url || data.playUrl ||
|
|
522
|
+
data.video_url || root.url || data.item?.url || data.live?.url ||
|
|
523
|
+
(data.live?.url && Array.isArray(data.live.url) ? data.live.url[0] : '') || '';
|
|
524
|
+
const durationValue = stat['视频时长'] || data.item?.duration || data.duration || 0;
|
|
491
525
|
const duration = typeof durationValue === 'number' ? durationValue : parseInt(durationValue) || 0;
|
|
492
526
|
const durationFormatted = formatDuration(durationValue);
|
|
493
527
|
const pubTime = formatPublishTime(stat['发布时间']);
|
|
@@ -506,15 +540,29 @@ function parseData(rawResponse, maxDescLength) {
|
|
|
506
540
|
if (!isNaN(num) && num > 0)
|
|
507
541
|
stat['文件大小'] = `${num.toFixed(2)} MB`;
|
|
508
542
|
}
|
|
509
|
-
const live_photo = data.live_photo
|
|
510
|
-
const h_w = data.item?.h_w
|
|
511
|
-
const quality_urls = data.quality_urls
|
|
512
|
-
const default_quality = data.default_quality
|
|
513
|
-
const download_url = data.download_url
|
|
514
|
-
const play_count = stat['播放数']
|
|
515
|
-
const reposts_count = Number(stat['转发数']) || 0;
|
|
516
|
-
const attitudes_count = Number(stat['点赞数']) || 0;
|
|
517
|
-
const comments_count = Number(stat['评论数']) || 0;
|
|
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 || '';
|
|
547
|
+
const download_url = data.download_url || video;
|
|
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
|
+
// 处理小红书视频备用链接
|
|
564
|
+
if (data.video_backup)
|
|
565
|
+
stat['视频备用链接'] = data.video_backup;
|
|
518
566
|
return {
|
|
519
567
|
type: type,
|
|
520
568
|
rawData: rawResponse,
|
|
@@ -529,7 +577,7 @@ function parseData(rawResponse, maxDescLength) {
|
|
|
529
577
|
stat,
|
|
530
578
|
live_photo,
|
|
531
579
|
h_w,
|
|
532
|
-
jx: data.jx
|
|
580
|
+
jx: data.jx || null,
|
|
533
581
|
quality_urls,
|
|
534
582
|
default_quality,
|
|
535
583
|
download_url,
|
|
@@ -551,7 +599,8 @@ function generateFormattedText(parseData, config) {
|
|
|
551
599
|
收藏:${'${收藏数}'}
|
|
552
600
|
转发:${'${转发数}'}
|
|
553
601
|
播放:${'${播放数}'}
|
|
554
|
-
评论:${'${评论数}'}
|
|
602
|
+
评论:${'${评论数}'}
|
|
603
|
+
视频备用链接:${'${视频备用链接}'}`;
|
|
555
604
|
}
|
|
556
605
|
let result = format;
|
|
557
606
|
const varMatches = result.match(/\$\{([^}]+)\}/g) || [];
|
|
@@ -662,8 +711,8 @@ function apply(ctx, config) {
|
|
|
662
711
|
return { data: null, code, msg };
|
|
663
712
|
}
|
|
664
713
|
const isSuccess = resData.code === 0 || resData.code === 200 || resData.code === 1 ||
|
|
665
|
-
(resData.msg && (resData.msg.includes('解析成功') || resData.msg.includes('success') || resData.msg.includes('请求成功'))) ||
|
|
666
|
-
!!resData.data || !!resData.result || !!resData.video || !!resData.images;
|
|
714
|
+
(resData.msg && (resData.msg.includes('解析成功') || resData.msg.includes('success') || resData.msg.includes('请求成功') || resData.msg === 'video' || resData.msg === 'cv' || resData.msg === 'live')) ||
|
|
715
|
+
!!resData.data || !!resData.result || !!resData.video || !!resData.images || !!resData.imgurl;
|
|
667
716
|
if (!isSuccess) {
|
|
668
717
|
const apiErrorMsg = resData.msg || resData.error || '解析失败';
|
|
669
718
|
const code = ErrorCode.API_RETURN_ERROR;
|
package/package.json
CHANGED