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.
Files changed (2) hide show
  1. package/lib/index.js +126 -50
  2. 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 responseElements = []; // 用于存储所有要发送的元素
467
+ let videoElements = []; // 用于存储视频相关元素
468
+ let textElements = []; // 用于存储图文解析元素
468
469
  let shouldPerformTextParsing = config.linktextParsing; // 默认根据配置决定是否进行图文解析
469
- //let videoTooLong = false; // 标记视频是否太长
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
- //videoTooLong = true;
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
- await responseElements.push(h.text(config.Maximumduration_tip.tipcontent))
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
- const videoUrl = video.url;
511
- logInfo(videoUrl);
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 (videoUrl) {
579
+ if (videoData) {
514
580
  if (options.link) {
515
- responseElements.push(h.text(videoUrl));
581
+ // 如果是链接选项,仍然使用原始URL
582
+ videoElements.push(h.text(video.url));
516
583
  } else if (options.audio) {
517
- responseElements.push(h.audio(videoUrl));
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
- responseElements.push(h.video(videoUrl));
590
+ videoElements.push(h.video(videoData));
524
591
  break;
525
592
  case '3':
526
- responseElements.push(h.text(videoUrl));
593
+ videoElements.push(h.text(video.url));
527
594
  break;
528
595
  case '4':
529
- responseElements.push(h.text(videoUrl));
530
- responseElements.push(h.video(videoUrl));
596
+ videoElements.push(h.text(video.url));
597
+ videoElements.push(h.video(videoData));
531
598
  break;
532
599
  case '5':
533
- logger.info(videoUrl);
534
- responseElements.push(h.video(videoUrl));
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
- // 图文解析 - 根据 shouldPerformTextParsing 决定是否执行
556
- if (shouldPerformTextParsing) {
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
- // 添加 message 元素到 responseElements
582
- responseElements.push(messageElement);
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 (responseElements.length === 0) {
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: responseElements // 直接使用 responseElements
646
+ children: allElements
599
647
  });
600
- logInfo(JSON.stringify(figureContent, null, 2));
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 responseElements) {
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.20",
5
+ "version": "1.1.22",
6
6
  "main": "lib/index.js",
7
7
  "typings": "lib/index.d.ts",
8
8
  "files": [