koishi-plugin-bilibili-videolink-analysis 1.1.20 → 1.1.22
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 +126 -50
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -118,6 +118,7 @@ exports.Config = Schema.intersect([
|
|
|
118
118
|
|
|
119
119
|
Schema.object({
|
|
120
120
|
isfigure: Schema.boolean().default(false).description("是否开启合并转发 `仅支持 onebot 适配器` 其他平台开启 无效").experimental(),
|
|
121
|
+
filebuffer: Schema.boolean().default(true).description("是否将视频链接下载后再发送 (以解决部分onebot协议端的问题)<br>否则使用视频直链发送").experimental(),
|
|
121
122
|
middleware: Schema.boolean().default(false).description("前置中间件模式"),
|
|
122
123
|
userAgent: Schema.string().description("所有 API 请求所用的 User-Agent").default("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"),
|
|
123
124
|
}).description("调试设置"),
|
|
@@ -455,7 +456,6 @@ display: none !important;
|
|
|
455
456
|
return false; // 没有处理过
|
|
456
457
|
}
|
|
457
458
|
|
|
458
|
-
//解析视频并返回
|
|
459
459
|
async function processVideoFromLink(session, config, ctx, lastProcessedUrls, logger, ret, options = { video: true }) {
|
|
460
460
|
const lastretUrl = extractLastUrl(ret);
|
|
461
461
|
|
|
@@ -464,11 +464,44 @@ display: none !important;
|
|
|
464
464
|
await session.send(config.waitTip_Switch);
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
-
let
|
|
467
|
+
let videoElements = []; // 用于存储视频相关元素
|
|
468
|
+
let textElements = []; // 用于存储图文解析元素
|
|
468
469
|
let shouldPerformTextParsing = config.linktextParsing; // 默认根据配置决定是否进行图文解析
|
|
469
|
-
|
|
470
|
+
let isLongVideo = false; // 标记视频是否过长
|
|
470
471
|
|
|
471
|
-
//
|
|
472
|
+
// 先进行图文解析
|
|
473
|
+
if (shouldPerformTextParsing) {
|
|
474
|
+
let fullText;
|
|
475
|
+
if (config.bVideoShowLink) {
|
|
476
|
+
fullText = ret; // 发送完整信息
|
|
477
|
+
} else {
|
|
478
|
+
// 去掉最后一个链接
|
|
479
|
+
fullText = ret.replace(lastretUrl, '');
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// 分割文本
|
|
483
|
+
const textParts = fullText.split('${~~~}');
|
|
484
|
+
|
|
485
|
+
// 循环处理每个分割后的部分
|
|
486
|
+
for (const part of textParts) {
|
|
487
|
+
const trimmedPart = part.trim(); // 去除首尾空格
|
|
488
|
+
if (trimmedPart) { // 确保不是空字符串
|
|
489
|
+
// 使用 h.parse 解析文本为消息元素
|
|
490
|
+
const parsedElements = h.parse(trimmedPart);
|
|
491
|
+
|
|
492
|
+
// 创建 message 元素
|
|
493
|
+
const messageElement = h('message', {
|
|
494
|
+
userId: session.userId,
|
|
495
|
+
nickname: session.author?.nickname || session.username,
|
|
496
|
+
}, parsedElements);
|
|
497
|
+
|
|
498
|
+
// 添加 message 元素到 textElements
|
|
499
|
+
textElements.push(messageElement);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// 视频/链接解析
|
|
472
505
|
if (config.VideoParsing_ToLink) {
|
|
473
506
|
const fullAPIurl = `http://api.xingzhige.cn/API/b_parse/?url=${encodeURIComponent(lastretUrl)}`;
|
|
474
507
|
|
|
@@ -487,7 +520,7 @@ display: none !important;
|
|
|
487
520
|
const videoDurationMinutes = videoDurationSeconds / 60;
|
|
488
521
|
|
|
489
522
|
if (videoDurationMinutes > config.Maximumduration) {
|
|
490
|
-
|
|
523
|
+
isLongVideo = true;
|
|
491
524
|
|
|
492
525
|
// 根据 Maximumduration_tip 的值决定行为
|
|
493
526
|
if (config.Maximumduration_tip === 'return') {
|
|
@@ -497,41 +530,75 @@ display: none !important;
|
|
|
497
530
|
// 返回文字提示
|
|
498
531
|
if (config.Maximumduration_tip.tipcontent) {
|
|
499
532
|
if (config.Maximumduration_tip.tipanalysis) {
|
|
500
|
-
|
|
533
|
+
videoElements.push(h.text(config.Maximumduration_tip.tipcontent));
|
|
501
534
|
} else {
|
|
502
535
|
await session.send(config.Maximumduration_tip.tipcontent);
|
|
503
536
|
}
|
|
504
537
|
}
|
|
538
|
+
|
|
505
539
|
// 决定是否进行图文解析
|
|
506
540
|
shouldPerformTextParsing = config.Maximumduration_tip.tipanalysis === true;
|
|
541
|
+
|
|
542
|
+
// 如果不进行图文解析,清空已准备的文本元素
|
|
543
|
+
if (!shouldPerformTextParsing) {
|
|
544
|
+
textElements = [];
|
|
545
|
+
}
|
|
507
546
|
}
|
|
508
547
|
} else {
|
|
509
548
|
// 视频时长在允许范围内,处理视频
|
|
510
|
-
|
|
511
|
-
logInfo(
|
|
549
|
+
let videoData = video.url; // 使用新变量名,避免覆盖原始URL
|
|
550
|
+
logInfo(videoData);
|
|
551
|
+
|
|
552
|
+
if (config.filebuffer) {
|
|
553
|
+
try {
|
|
554
|
+
const videoFileBuffer = await ctx.http.file(video.url);
|
|
555
|
+
logInfo(videoFileBuffer);
|
|
556
|
+
|
|
557
|
+
// 检查文件类型
|
|
558
|
+
if (videoFileBuffer && videoFileBuffer.data) {
|
|
559
|
+
// 将ArrayBuffer转换为Buffer
|
|
560
|
+
const buffer = Buffer.from(videoFileBuffer.data);
|
|
561
|
+
|
|
562
|
+
// 获取MIME类型
|
|
563
|
+
const mimeType = videoFileBuffer.type || videoFileBuffer.mime || 'video/mp4';
|
|
564
|
+
|
|
565
|
+
// 创建data URI
|
|
566
|
+
const base64Data = buffer.toString('base64');
|
|
567
|
+
videoData = `data:${mimeType};base64,${base64Data}`;
|
|
568
|
+
|
|
569
|
+
logInfo("成功使用 ctx.http.file 将视频URL 转换为data URI格式");
|
|
570
|
+
} else {
|
|
571
|
+
logInfo("文件数据无效,使用原始URL");
|
|
572
|
+
}
|
|
573
|
+
} catch (error) {
|
|
574
|
+
logger.error("获取视频文件失败:", error);
|
|
575
|
+
// 出错时继续使用原始URL
|
|
576
|
+
}
|
|
577
|
+
}
|
|
512
578
|
|
|
513
|
-
if (
|
|
579
|
+
if (videoData) {
|
|
514
580
|
if (options.link) {
|
|
515
|
-
|
|
581
|
+
// 如果是链接选项,仍然使用原始URL
|
|
582
|
+
videoElements.push(h.text(video.url));
|
|
516
583
|
} else if (options.audio) {
|
|
517
|
-
|
|
584
|
+
videoElements.push(h.audio(videoData));
|
|
518
585
|
} else {
|
|
519
586
|
switch (config.VideoParsing_ToLink) {
|
|
520
587
|
case '1':
|
|
521
588
|
break;
|
|
522
589
|
case '2':
|
|
523
|
-
|
|
590
|
+
videoElements.push(h.video(videoData));
|
|
524
591
|
break;
|
|
525
592
|
case '3':
|
|
526
|
-
|
|
593
|
+
videoElements.push(h.text(video.url));
|
|
527
594
|
break;
|
|
528
595
|
case '4':
|
|
529
|
-
|
|
530
|
-
|
|
596
|
+
videoElements.push(h.text(video.url));
|
|
597
|
+
videoElements.push(h.video(videoData));
|
|
531
598
|
break;
|
|
532
599
|
case '5':
|
|
533
|
-
logger.info(
|
|
534
|
-
|
|
600
|
+
logger.info(video.url);
|
|
601
|
+
videoElements.push(h.video(videoData));
|
|
535
602
|
break;
|
|
536
603
|
default:
|
|
537
604
|
break;
|
|
@@ -540,6 +607,7 @@ display: none !important;
|
|
|
540
607
|
} else {
|
|
541
608
|
throw new Error("解析视频直链失败");
|
|
542
609
|
}
|
|
610
|
+
|
|
543
611
|
}
|
|
544
612
|
} else {
|
|
545
613
|
throw new Error("获取播放数据失败");
|
|
@@ -552,40 +620,20 @@ display: none !important;
|
|
|
552
620
|
}
|
|
553
621
|
}
|
|
554
622
|
|
|
555
|
-
//
|
|
556
|
-
|
|
557
|
-
let fullText;
|
|
558
|
-
if (config.bVideoShowLink) {
|
|
559
|
-
fullText = ret; // 发送完整信息
|
|
560
|
-
} else {
|
|
561
|
-
// 去掉最后一个链接
|
|
562
|
-
fullText = ret.replace(lastretUrl, '');
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// 分割文本
|
|
566
|
-
const textParts = fullText.split('${~~~}');
|
|
567
|
-
|
|
568
|
-
// 循环处理每个分割后的部分
|
|
569
|
-
for (const part of textParts) {
|
|
570
|
-
const trimmedPart = part.trim(); // 去除首尾空格
|
|
571
|
-
if (trimmedPart) { // 确保不是空字符串
|
|
572
|
-
// 使用 h.parse 解析文本为消息元素
|
|
573
|
-
const parsedElements = h.parse(trimmedPart);
|
|
574
|
-
|
|
575
|
-
// 创建 message 元素
|
|
576
|
-
const messageElement = h('message', {
|
|
577
|
-
userId: session.userId,
|
|
578
|
-
nickname: session.author?.nickname || session.username,
|
|
579
|
-
}, parsedElements);
|
|
623
|
+
// 准备发送的所有元素
|
|
624
|
+
let allElements = [];
|
|
580
625
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
626
|
+
// 根据视频是否过长决定发送顺序
|
|
627
|
+
if (isLongVideo) {
|
|
628
|
+
// 过长视频:先发送过长提示(已在上面处理),然后是图文解析(如果启用)
|
|
629
|
+
allElements = [...textElements, ...videoElements];
|
|
630
|
+
} else {
|
|
631
|
+
// 正常视频:先发送图文解析,然后是视频元素
|
|
632
|
+
allElements = [...textElements, ...videoElements];
|
|
585
633
|
}
|
|
586
634
|
|
|
587
635
|
// 如果没有任何元素要发送,则直接返回
|
|
588
|
-
if (
|
|
636
|
+
if (allElements.length === 0) {
|
|
589
637
|
return;
|
|
590
638
|
}
|
|
591
639
|
|
|
@@ -595,15 +643,43 @@ display: none !important;
|
|
|
595
643
|
|
|
596
644
|
// 创建 figure 元素
|
|
597
645
|
const figureContent = h('figure', {
|
|
598
|
-
children:
|
|
646
|
+
children: allElements
|
|
599
647
|
});
|
|
600
|
-
|
|
648
|
+
|
|
649
|
+
// 创建一个用于日志的深拷贝对象,避免修改原始对象
|
|
650
|
+
const logObject = JSON.parse(JSON.stringify(figureContent));
|
|
651
|
+
|
|
652
|
+
// 递归处理对象,截断长字符串
|
|
653
|
+
function truncateLongStrings(obj, maxLength = 150) {
|
|
654
|
+
if (!obj) return obj;
|
|
655
|
+
|
|
656
|
+
if (typeof obj === 'string' && obj.length > maxLength) {
|
|
657
|
+
return obj.substring(0, maxLength) + '... [截断剩余' + (obj.length - maxLength) + '字符]';
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
if (Array.isArray(obj)) {
|
|
661
|
+
return obj.map(item => truncateLongStrings(item, maxLength));
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
if (typeof obj === 'object') {
|
|
665
|
+
const newObj = {};
|
|
666
|
+
for (const key in obj) {
|
|
667
|
+
newObj[key] = truncateLongStrings(obj[key], maxLength);
|
|
668
|
+
}
|
|
669
|
+
return newObj;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
return obj;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// 截断长字符串后再打印
|
|
676
|
+
logInfo(JSON.stringify(truncateLongStrings(logObject), null, 2));
|
|
601
677
|
|
|
602
678
|
// 发送合并转发消息
|
|
603
679
|
await session.send(figureContent);
|
|
604
680
|
} else {
|
|
605
681
|
// 没有启用合并转发,按顺序发送所有元素
|
|
606
|
-
for (const element of
|
|
682
|
+
for (const element of allElements) {
|
|
607
683
|
await session.send(element);
|
|
608
684
|
}
|
|
609
685
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "koishi-plugin-bilibili-videolink-analysis",
|
|
3
3
|
"description": "[<ruby>Bilibili视频解析<rp>(</rp><rt>点我查看食用方法</rt><rp>)</rp></ruby>](https://www.npmjs.com/package/koishi-plugin-bilibili-videolink-analysis)解析B站链接(支持小程序卡片)支持搜索点播功能!灵感来自完美的 [bili-parser](/market?keyword=bili-parser) !",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "1.1.
|
|
5
|
+
"version": "1.1.22",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
8
8
|
"files": [
|