koishi-plugin-video-parser-all 0.6.3 → 0.6.5
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 +72 -57
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -32,27 +32,17 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
32
32
|
转发:${'${转发数}'}
|
|
33
33
|
播放:${'${播放数}'}
|
|
34
34
|
评论:${'${评论数}'}
|
|
35
|
-
音乐:${'${音乐名}'}
|
|
36
35
|
IP属地:${'${IP属地}'}
|
|
37
36
|
发布时间:${'${发布时间}'}
|
|
38
37
|
粉丝数:${'${粉丝数}'}
|
|
39
38
|
在线人数:${'${在线人数}'}
|
|
40
39
|
关注数:${'${关注数}'}
|
|
41
|
-
视频质量:${'${视频质量}'}
|
|
42
|
-
帧率:${'${帧率}'}
|
|
43
|
-
码率:${'${码率}'}
|
|
44
40
|
文件大小:${'${文件大小}'}
|
|
45
|
-
分辨率:${'${分辨率}'}
|
|
46
|
-
音乐作者:${'${音乐作者}'}
|
|
47
|
-
音乐标题:${'${音乐标题}'}
|
|
48
41
|
直播间地址:${'${直播间地址}'}
|
|
49
42
|
直播间ID:${'${直播间ID}'}
|
|
50
43
|
直播间状态:${'${直播间状态}'}
|
|
51
|
-
默认画质:${'${默认画质}'}
|
|
52
44
|
图片数量:${'${图片数量}'}
|
|
53
|
-
作者ID:${'${作者ID}'}
|
|
54
|
-
封面链接:${'${封面链接}'}
|
|
55
|
-
视频链接:${'${视频链接}'}`).description('统一消息格式(无法获取的变量会自动隐藏)'),
|
|
45
|
+
作者ID:${'${作者ID}'}`).description('统一消息格式'),
|
|
56
46
|
}).description('统一消息格式'),
|
|
57
47
|
koishi_1.Schema.object({
|
|
58
48
|
showImageText: koishi_1.Schema.boolean().default(true).description('显示图文内容'),
|
|
@@ -75,10 +65,10 @@ IP属地:${'${IP属地}'}
|
|
|
75
65
|
enableForward: koishi_1.Schema.boolean().default(false).description('启用合并转发(仅OneBot平台)'),
|
|
76
66
|
downloadVideoBeforeSend: koishi_1.Schema.boolean().default(false).description('发送前先下载视频'),
|
|
77
67
|
maxVideoSize: koishi_1.Schema.number().min(0).default(0).description('最大视频大小限制(MB,0为不限制)'),
|
|
78
|
-
downloadThreads: koishi_1.Schema.number().min(0).max(10).default(0).description('多线程下载线程数(0
|
|
68
|
+
downloadThreads: koishi_1.Schema.number().min(0).max(10).default(0).description('多线程下载线程数(0为不使用多线程)'),
|
|
79
69
|
}).description('发送方式设置'),
|
|
80
70
|
koishi_1.Schema.object({
|
|
81
|
-
messageBufferDelay: koishi_1.Schema.number().min(0).default(0).description('
|
|
71
|
+
messageBufferDelay: koishi_1.Schema.number().min(0).default(0).description('消息缓冲延迟(毫秒)'),
|
|
82
72
|
}).description('消息处理设置'),
|
|
83
73
|
koishi_1.Schema.object({
|
|
84
74
|
autoClearCacheInterval: koishi_1.Schema.number().min(0).default(0).description('自动清理缓存间隔(分钟,0为关闭)'),
|
|
@@ -114,7 +104,7 @@ exports.ErrorMessageMap = {
|
|
|
114
104
|
[ErrorCode.PLATFORM_API_NOT_CONFIGURED]: '该平台暂未配置解析接口',
|
|
115
105
|
[ErrorCode.REQUEST_TIMEOUT]: '请求超时',
|
|
116
106
|
[ErrorCode.NETWORK_ERROR]: '网络请求失败',
|
|
117
|
-
[ErrorCode.DUPLICATE_PARSE]: '
|
|
107
|
+
[ErrorCode.DUPLICATE_PARSE]: '请勿重复解析',
|
|
118
108
|
[ErrorCode.INVALID_URL]: '无效的链接格式',
|
|
119
109
|
[ErrorCode.API_RETURN_ERROR]: 'API返回错误',
|
|
120
110
|
[ErrorCode.API_DATA_PARSE_FAILED]: '数据解析异常',
|
|
@@ -165,27 +155,17 @@ const VARIABLE_MAPPING = {
|
|
|
165
155
|
'转发数': ['share', 'Share', 'forward', 'Forward', 'repost', 'stat.share', 'reposts_count', 'shared_count', 'stast.share', 'data.reposts_count'],
|
|
166
156
|
'播放数': ['view', 'View', 'play_count', 'PlayCount', 'play', 'stat.view', 'play_times', 'stast.view', 'data.play_count', 'item.play_count'],
|
|
167
157
|
'评论数': ['comment', 'Comment', 'comments_count', 'comment_count', 'discuss', 'stat.comment', 'stast.reply', 'data.comments_count', 'item.comments_count'],
|
|
168
|
-
'音乐名': ['music.title', 'music_name', 'audio_name', 'sound_name', 'muisic', 'music', 'bgm_name', 'data.music.name', 'item.music.title', 'music.author', 'music.albumName'],
|
|
169
158
|
'IP属地': ['ip_info_str', 'data.ip_info_str', 'item.ip_info'],
|
|
170
159
|
'发布时间': ['date', 'time', 'publish_time', 'data.date', 'item.publish_time', 'live.time', 'stast.publish_time'],
|
|
171
160
|
'粉丝数': ['followers_count', 'data.followers_count', 'item.followers', 'author.fans'],
|
|
172
161
|
'在线人数': ['online', 'data.online', 'live.online', 'room.online'],
|
|
173
162
|
'关注数': ['attention', 'data.attention', 'live.attention', 'stast.attention'],
|
|
174
|
-
'视频质量': ['quality', 'max_qxd', 'data.quality', 'item.quality', 'quality_urls'],
|
|
175
|
-
'帧率': ['fps', 'item.fps', 'data.fps'],
|
|
176
|
-
'码率': ['bitrate', 'item.bitrate', 'data.bitrate', 'br', 'item.br'],
|
|
177
163
|
'文件大小': ['size', 'size_str', 'item.size', 'item.size_str', 'data.size'],
|
|
178
|
-
'分辨率': ['height', 'width', 'h_w', 'item.h_w', 'data.resolution', 'item.height', 'item.width'],
|
|
179
|
-
'音乐作者': ['music.author', 'item.music.author', 'data.music.author', 'music.artist'],
|
|
180
|
-
'音乐标题': ['music.title', 'item.music.title', 'data.music.title', 'music.name'],
|
|
181
164
|
'直播间地址': ['room_url', 'live.room_url', 'data.room_url', 'live.url'],
|
|
182
165
|
'直播间ID': ['room_id', 'live.room_id', 'data.room_id', 'live.room_id'],
|
|
183
166
|
'直播间状态': ['status', 'live.status', 'data.status', 'room.status'],
|
|
184
|
-
'默认画质': ['default_quality', 'data.default_quality', 'item.default_quality'],
|
|
185
167
|
'图片数量': ['count', 'data.count', 'item.count', 'images.length', 'data.images.length'],
|
|
186
168
|
'作者ID': ['userId', 'userID', 'author_id', 'data.userId', 'item.userID', 'author.mid', 'user.mid'],
|
|
187
|
-
'封面链接': ['cover', 'imgurl', 'pic', 'thumbnail', 'cover_url', 'data.cover', 'item.cover', 'live.cover'],
|
|
188
|
-
'视频链接': ['url', 'video_url', 'playUrl', 'download_url', 'data.url', 'item.url', 'live.url', 'quality_urls.*'],
|
|
189
169
|
};
|
|
190
170
|
function getErrorInfo(code, detail) {
|
|
191
171
|
const baseMsg = exports.ErrorMessageMap[code] || exports.ErrorMessageMap[ErrorCode.UNKNOWN_ERROR];
|
|
@@ -375,7 +355,6 @@ async function resolveShortUrl(url) {
|
|
|
375
355
|
headers: {
|
|
376
356
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
377
357
|
'Referer': 'https://www.baidu.com/',
|
|
378
|
-
'Cookie': 'xhsTrackerId=xxx; xhs_sessionId=xxx'
|
|
379
358
|
}
|
|
380
359
|
});
|
|
381
360
|
return cleanUrl(res.request.res?.responseUrl || url);
|
|
@@ -386,21 +365,55 @@ async function resolveShortUrl(url) {
|
|
|
386
365
|
}
|
|
387
366
|
function formatDuration(input) {
|
|
388
367
|
if (!input || input === 0 || input === '0' || input === '00:00')
|
|
389
|
-
return '00:00';
|
|
368
|
+
return '00:00:00';
|
|
390
369
|
if (typeof input === 'string') {
|
|
391
|
-
if (input.includes(':'))
|
|
392
|
-
|
|
370
|
+
if (input.includes(':')) {
|
|
371
|
+
const parts = input.split(':');
|
|
372
|
+
if (parts.length === 2)
|
|
373
|
+
return `00:${parts[0].padStart(2, '0')}:${parts[1].padStart(2, '0')}`;
|
|
374
|
+
if (parts.length === 3)
|
|
375
|
+
return `${parts[0].padStart(2, '0')}:${parts[1].padStart(2, '0')}:${parts[2].padStart(2, '0')}`;
|
|
376
|
+
return '00:00:00';
|
|
377
|
+
}
|
|
393
378
|
input = Number(input);
|
|
394
379
|
}
|
|
395
380
|
const seconds = Math.floor(Number(input));
|
|
396
|
-
if (isNaN(seconds) || seconds <= 0)
|
|
397
|
-
return '00:00';
|
|
381
|
+
if (isNaN(seconds) || seconds <= 0 || seconds > 315360000)
|
|
382
|
+
return '00:00:00';
|
|
398
383
|
const hours = Math.floor(seconds / 3600);
|
|
399
384
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
400
385
|
const secs = Math.floor(seconds % 60);
|
|
401
|
-
return hours
|
|
402
|
-
|
|
403
|
-
|
|
386
|
+
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
|
387
|
+
}
|
|
388
|
+
function formatPublishTime(value) {
|
|
389
|
+
if (!value)
|
|
390
|
+
return '';
|
|
391
|
+
const str = String(value).trim();
|
|
392
|
+
if (/^\d{10,}$/.test(str) && Number(str) > 1e12)
|
|
393
|
+
return '';
|
|
394
|
+
try {
|
|
395
|
+
const d = new Date(/^\d+$/.test(str) ? Number(str) * 1000 : str);
|
|
396
|
+
if (isNaN(d.getTime()))
|
|
397
|
+
return '';
|
|
398
|
+
const y = d.getFullYear();
|
|
399
|
+
const m = (d.getMonth() + 1).toString().padStart(2, '0');
|
|
400
|
+
const d_ = d.getDate().toString().padStart(2, '0');
|
|
401
|
+
const H = d.getHours().toString().padStart(2, '0');
|
|
402
|
+
const i = d.getMinutes().toString().padStart(2, '0');
|
|
403
|
+
const parts = [];
|
|
404
|
+
if (y > 2000)
|
|
405
|
+
parts.push(`${y}年`);
|
|
406
|
+
if (m)
|
|
407
|
+
parts.push(`${m}月`);
|
|
408
|
+
if (d_)
|
|
409
|
+
parts.push(`${d_}日`);
|
|
410
|
+
if (H && i)
|
|
411
|
+
parts.push(`${H}:${i}`);
|
|
412
|
+
return parts.join(' ').trim();
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
return '';
|
|
416
|
+
}
|
|
404
417
|
}
|
|
405
418
|
function getNestedValue(obj, path) {
|
|
406
419
|
if (!obj || typeof obj !== 'object' || !path)
|
|
@@ -447,17 +460,6 @@ function parseData(rawResponse, maxDescLength) {
|
|
|
447
460
|
if (varName === '图片数量' && value === undefined) {
|
|
448
461
|
value = Array.isArray(data.images) ? data.images.length : (Array.isArray(rootData.images) ? rootData.images.length : undefined);
|
|
449
462
|
}
|
|
450
|
-
if (varName === '分辨率' && value === undefined) {
|
|
451
|
-
const h = findValueInObject(data, ['height', 'item.height']) || findValueInObject(rootData, ['height', 'item.height']);
|
|
452
|
-
const w = findValueInObject(data, ['width', 'item.width']) || findValueInObject(rootData, ['width', 'item.width']);
|
|
453
|
-
if (h && w)
|
|
454
|
-
value = `${w}x${h}`;
|
|
455
|
-
else if (data.h_w && Array.isArray(data.h_w) && data.h_w.length)
|
|
456
|
-
value = data.h_w.join(', ');
|
|
457
|
-
}
|
|
458
|
-
if (varName === '视频链接' && value === undefined) {
|
|
459
|
-
value = data.url || data.video || data.download_url || rootData.url || rootData.video;
|
|
460
|
-
}
|
|
461
463
|
if (value !== undefined && value !== null && value !== '') {
|
|
462
464
|
stat[varName] = value;
|
|
463
465
|
}
|
|
@@ -471,12 +473,13 @@ function parseData(rawResponse, maxDescLength) {
|
|
|
471
473
|
type = 'cv';
|
|
472
474
|
else if (rootData.msg === 'live')
|
|
473
475
|
type = 'live';
|
|
474
|
-
else if (data.images && data.images.length >
|
|
476
|
+
else if ((data.images && data.images.length > 1) || (rootData.images && rootData.images.length > 1))
|
|
475
477
|
type = '图集';
|
|
476
|
-
const title = stat['标题'] || '无标题';
|
|
477
|
-
const author = stat['作者'] || '未知作者';
|
|
478
|
-
const
|
|
479
|
-
const
|
|
478
|
+
const title = stat['标题'] || (data.note_title || data.title || data.content_title || '无标题');
|
|
479
|
+
const author = stat['作者'] || (data.author?.name || data.nickname || data.user_name || '未知作者');
|
|
480
|
+
const rawDesc = stat['简介'] || data.note_desc || data.content || data.text || data.description || '';
|
|
481
|
+
const desc = rawDesc.length > 0 ? rawDesc.slice(0, maxDescLength) : (title.length > 0 ? title : '暂无简介');
|
|
482
|
+
const cover = data.cover ?? data.imgurl ?? data.pic ?? data.thumbnail ?? data.cover_url ?? (Array.isArray(data.images) && data.images[0] ? data.images[0] : '');
|
|
480
483
|
let images = [];
|
|
481
484
|
const imgRaw = data.images ?? data.pics ?? data.pic_urls ?? data.image_list ?? [];
|
|
482
485
|
if (Array.isArray(imgRaw))
|
|
@@ -487,8 +490,23 @@ function parseData(rawResponse, maxDescLength) {
|
|
|
487
490
|
const durationValue = stat['视频时长'] || 0;
|
|
488
491
|
const duration = typeof durationValue === 'number' ? durationValue : parseInt(durationValue) || 0;
|
|
489
492
|
const durationFormatted = formatDuration(durationValue);
|
|
493
|
+
const pubTime = formatPublishTime(stat['发布时间']);
|
|
494
|
+
if (pubTime)
|
|
495
|
+
stat['发布时间'] = pubTime;
|
|
496
|
+
else
|
|
497
|
+
delete stat['发布时间'];
|
|
498
|
+
const durShow = durationFormatted === '00:00:00' && (String(durationValue).length > 12) ? '' : durationFormatted;
|
|
499
|
+
if (durShow)
|
|
500
|
+
stat['视频时长'] = durShow;
|
|
501
|
+
else
|
|
502
|
+
delete stat['视频时长'];
|
|
503
|
+
const sizeVal = stat['文件大小'];
|
|
504
|
+
if (sizeVal && !String(sizeVal).includes('MB')) {
|
|
505
|
+
const num = Number(sizeVal);
|
|
506
|
+
if (!isNaN(num) && num > 0)
|
|
507
|
+
stat['文件大小'] = `${num.toFixed(2)} MB`;
|
|
508
|
+
}
|
|
490
509
|
const live_photo = data.live_photo ?? [];
|
|
491
|
-
const music = stat['音乐名'] || '';
|
|
492
510
|
const h_w = data.item?.h_w ?? [];
|
|
493
511
|
const quality_urls = data.quality_urls ?? {};
|
|
494
512
|
const default_quality = data.default_quality ?? '';
|
|
@@ -510,7 +528,6 @@ function parseData(rawResponse, maxDescLength) {
|
|
|
510
528
|
durationFormatted,
|
|
511
529
|
stat,
|
|
512
530
|
live_photo,
|
|
513
|
-
music: String(music),
|
|
514
531
|
h_w,
|
|
515
532
|
jx: data.jx ?? null,
|
|
516
533
|
quality_urls,
|
|
@@ -534,8 +551,7 @@ function generateFormattedText(parseData, config) {
|
|
|
534
551
|
收藏:${'${收藏数}'}
|
|
535
552
|
转发:${'${转发数}'}
|
|
536
553
|
播放:${'${播放数}'}
|
|
537
|
-
评论:${'${评论数}'}
|
|
538
|
-
音乐:${'${音乐名}'}`;
|
|
554
|
+
评论:${'${评论数}'}`;
|
|
539
555
|
}
|
|
540
556
|
let result = format;
|
|
541
557
|
const varMatches = result.match(/\$\{([^}]+)\}/g) || [];
|
|
@@ -711,7 +727,6 @@ function apply(ctx, config) {
|
|
|
711
727
|
video: parseData.video,
|
|
712
728
|
type: parseData.type,
|
|
713
729
|
live_photo: parseData.live_photo,
|
|
714
|
-
music: parseData.music,
|
|
715
730
|
h_w: parseData.h_w,
|
|
716
731
|
quality_urls: parseData.quality_urls,
|
|
717
732
|
default_quality: parseData.default_quality,
|
|
@@ -796,7 +811,7 @@ function apply(ctx, config) {
|
|
|
796
811
|
forwardMessages.push(buildForwardNode(session, koishi_1.h.file(dl.filePath), botName));
|
|
797
812
|
}
|
|
798
813
|
else {
|
|
799
|
-
forwardMessages.push(buildForwardNode(session, koishi_1.h.
|
|
814
|
+
forwardMessages.push(buildForwardNode(session, koishi_1.h.video(item.video), botName));
|
|
800
815
|
}
|
|
801
816
|
}
|
|
802
817
|
else {
|
|
@@ -804,7 +819,7 @@ function apply(ctx, config) {
|
|
|
804
819
|
}
|
|
805
820
|
}
|
|
806
821
|
catch (e) {
|
|
807
|
-
forwardMessages.push(buildForwardNode(session, koishi_1.h.
|
|
822
|
+
forwardMessages.push(buildForwardNode(session, koishi_1.h.video(item.video), botName));
|
|
808
823
|
}
|
|
809
824
|
}
|
|
810
825
|
}
|
|
@@ -828,7 +843,7 @@ function apply(ctx, config) {
|
|
|
828
843
|
await sendTimeout(session, koishi_1.h.video(item.video));
|
|
829
844
|
}
|
|
830
845
|
catch (e) {
|
|
831
|
-
await sendTimeout(session,
|
|
846
|
+
await sendTimeout(session, koishi_1.h.video(item.video));
|
|
832
847
|
}
|
|
833
848
|
await delay(500);
|
|
834
849
|
}
|
package/package.json
CHANGED