koishi-plugin-bilibili-videolink-analysis 0.6.2 → 1.0.0

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 (3) hide show
  1. package/lib/index.js +270 -273
  2. package/package.json +4 -6
  3. package/readme.md +7 -0
package/lib/index.js CHANGED
@@ -7,7 +7,7 @@ const logger = new Logger('bilibili-videolink-analysis');
7
7
  exports.name = 'bilibili-videolink-analysis';
8
8
  exports.inject = {
9
9
  optional: ['puppeteer'],
10
- required: ['BiliBiliVideo']
10
+ //required: ['BiliBiliVideo']
11
11
  }
12
12
  exports.usage = `
13
13
 
@@ -24,7 +24,6 @@ exports.usage = `
24
24
  #### ⚠️ **如果你使用不了本项目,请优先检查:** ⚠️
25
25
  #### 若无注册的指令,请关开一下[command插件](/market?keyword=commands+email:shigma10826@gmail.com)(没有指令也不影响解析别人的链接)
26
26
  #### 视频内容是否为B站的大会员专属视频/付费视频/充电专属视频
27
- #### 是否正确配置并启动了[bilibili-login插件](/market?keyword=bilibili-login) (启动即可,不是必须登录)
28
27
  #### 接入方法是否支持获取网址链接/小程序卡片消息
29
28
  #### 接入方法是否支持视频元素的发送
30
29
  #### 发送视频超时/其他网络问题
@@ -48,7 +47,6 @@ exports.usage = `
48
47
  特别鸣谢以下项目的支持:
49
48
 
50
49
  - [@summonhim/koishi-plugin-bili-parser](/market?keyword=bili-parser)
51
- - [koishi-plugin-iirose-media-request](/market?keyword=iirose-media-request)
52
50
 
53
51
  ---
54
52
 
@@ -74,16 +72,16 @@ exports.Config = Schema.intersect([
74
72
  Schema.const('4').description('返回视频和视频直链'),
75
73
  Schema.const('5').description('返回视频,仅在日志记录视频直链'),
76
74
  ]).role('radio').default('2').description("是否返回` 视频/视频直链 `"),
77
- Video_ClarityPriority: Schema.union([
78
- Schema.const('1').description('低清晰度优先(低清晰度的视频发得快一点)'),
79
- Schema.const('2').description('高清晰度优先(清晰的还是去B站看吧)'),
80
- ]).role('radio').default('1').description("发送的视频清晰度优先策略"),
75
+ //Video_ClarityPriority: Schema.union([
76
+ // Schema.const('1').description('低清晰度优先(低清晰度的视频发得快一点)'),
77
+ // Schema.const('2').description('高清晰度优先(清晰的还是去B站看吧)'),
78
+ //]).role('radio').default('1').description("发送的视频清晰度优先策略"),
81
79
  BVnumberParsing: Schema.boolean().default(true).description("是否允许根据`独立的BV号`解析视频 `开启后,可以通过视频的BV号解析视频。` <br> [触发说明见README](https://www.npmjs.com/package/koishi-plugin-bilibili-videolink-analysis)"),
82
- Maximumduration: Schema.number().default(25).description("允许解析的视频最大时长(分钟)`超过这个时长 就不会发视频`").min(1),
83
- Maximumduration_tip: Schema.union([
84
- Schema.const('不返回文字提示').description('不返回文字提示'),
85
- Schema.string().description('返回文字提示(请在右侧填写文字内容)').default('视频太长啦!还是去B站看吧~'),
86
- ]).description("对过长视频的文字提示内容").default('视频太长啦!还是去B站看吧~'),
80
+ //Maximumduration: Schema.number().default(25).description("允许解析的视频最大时长(分钟)`超过这个时长 就不会发视频`").min(1),
81
+ //Maximumduration_tip: Schema.union([
82
+ // Schema.const('不返回文字提示').description('不返回文字提示'),
83
+ // Schema.string().description('返回文字提示(请在右侧填写文字内容)').default('视频太长啦!还是去B站看吧~'),
84
+ //]).description("对过长视频的文字提示内容").default('视频太长啦!还是去B站看吧~'),
87
85
  MinimumTimeInterval: Schema.number().default(180).description("若干`秒`内 不再处理相同链接 `防止多bot互相触发 导致的刷屏/性能浪费`").min(1),
88
86
  }).description("基础设置"),
89
87
 
@@ -110,8 +108,15 @@ exports.Config = Schema.intersect([
110
108
  ]);
111
109
 
112
110
  function apply(ctx, config) {
113
- const bilibiliVideo = ctx.BiliBiliVideo;
111
+
114
112
  ctx.middleware(async (session, next) => {
113
+ // 如果允许解析 BV 号,则进行解析
114
+ if (config.BVnumberParsing) {
115
+ const bvUrls = convertBVToUrl(session.content);
116
+ if (bvUrls.length > 0) {
117
+ session.content += '\n' + bvUrls.join('\n');
118
+ }
119
+ }
115
120
  const links = await isProcessLinks(session, config, ctx, lastProcessedUrls, logger); // 判断是否需要解析
116
121
  if (links) {
117
122
  const ret = await extractLinks(session, config, ctx, lastProcessedUrls, logger); // 提取链接
@@ -122,7 +127,197 @@ function apply(ctx, config) {
122
127
  return next();
123
128
  });
124
129
 
125
- ctx.command('点播 [keyword]', '点播B站视频')
130
+ ctx.command('B站点播')
131
+ ctx.command('退出登录', '退出B站账号')
132
+ .action(async ({ session }) => {
133
+ const page = await ctx.puppeteer.page();
134
+ await page.goto('https://www.bilibili.com/', { waitUntil: 'networkidle2' });
135
+
136
+ const loginButtonSelector = '.right-entry__outside.go-login-btn';
137
+ const isLoggedIn = await page.$(loginButtonSelector) === null;
138
+
139
+ if (!isLoggedIn) {
140
+ await page.close();
141
+ return '您尚未登录。';
142
+ }
143
+
144
+ const avatarLinkSelector = '.header-entry-mini';
145
+ const logoutButtonSelector = '.logout-item';
146
+
147
+ try {
148
+ const avatarElement = await page.$(avatarLinkSelector);
149
+ if (avatarElement) {
150
+ await avatarElement.hover();
151
+ await page.waitForSelector(logoutButtonSelector, { visible: true });
152
+
153
+ await page.click(logoutButtonSelector);
154
+
155
+ await new Promise(resolve => setTimeout(resolve, 1000));
156
+
157
+ await page.close();
158
+ return '已成功退出登录。';
159
+ } else {
160
+ await page.close();
161
+ return '找不到用户头像,无法退出登录。';
162
+ }
163
+ } catch (error) {
164
+ await page.close();
165
+ console.error('Error during logout:', error);
166
+ return '退出登录时出错。';
167
+ }
168
+ });
169
+
170
+ ctx.command('B站点播/登录', '登录B站账号')
171
+ .alias("登陆")
172
+ .action(async ({ session }) => {
173
+ const page = await ctx.puppeteer.page();
174
+ await page.goto('https://www.bilibili.com/', { waitUntil: 'networkidle2' });
175
+
176
+ const loginButtonSelector = '.right-entry__outside.go-login-btn';
177
+ const isLoggedIn = await page.$(loginButtonSelector) === null;
178
+
179
+ if (isLoggedIn) {
180
+ await page.close();
181
+ return '您已经登录了。';
182
+ }
183
+
184
+ await page.click(loginButtonSelector);
185
+
186
+ const qrCodeSelector = '.login-scan-box img';
187
+ await page.waitForSelector(qrCodeSelector);
188
+ const qrCodeUrl = await page.$eval(qrCodeSelector, img => img.src);
189
+
190
+ await session.send(h.image(qrCodeUrl, 'image/png'));
191
+ await session.send('请扫描二维码进行登录。');
192
+
193
+ let attempts = 0;
194
+ let loginSuccessful = false;
195
+
196
+ while (attempts < 6) {
197
+ await new Promise(resolve => setTimeout(resolve, 5000)); // Wait
198
+ const isStillLoggedIn = await page.$(loginButtonSelector) === null;
199
+
200
+ if (isStillLoggedIn) {
201
+ loginSuccessful = true;
202
+ break;
203
+ }
204
+
205
+ attempts++;
206
+ }
207
+
208
+ await page.close();
209
+
210
+ return loginSuccessful ? '登录成功!' : '登录失败,请重试。';
211
+ });
212
+
213
+ if (config.loggerinfo) {
214
+ ctx.command('B站点播/调试点播 [keyword]', '调试时点播B站视频')
215
+ .option('video', '-v 解析返回视频')
216
+ .option('audio', '-a 解析返回语音')
217
+ .option('link', '-l 解析返回链接')
218
+ .option('page', '-p <page:number> 指定页数', { fallback: '1' })
219
+ .example('调试点播 遠い空へ -v')
220
+ .action(async ({ options, session }, keyword) => {
221
+ if (!keyword) {
222
+ await session.execute('调试点播 -h');
223
+ return '没输入keyword';
224
+ }
225
+ const url = `https://search.bilibili.com/video?keyword=${encodeURIComponent(keyword)}&page=${options.page}&o=30`;
226
+ const page = await ctx.puppeteer.page();
227
+ await page.goto(url, {
228
+ waitUntil: 'networkidle2',
229
+ });
230
+
231
+ // 获取视频列表并为每个视频元素添加序号
232
+ const videos = await page.evaluate((point) => {
233
+ const items = Array.from(document.querySelectorAll('.video-list-item:not([style*="display: none"])'));
234
+ return items.map((item, index) => {
235
+ const link = item.querySelector('a');
236
+ const href = link?.getAttribute('href') || '';
237
+ const idMatch = href.match(/\/video\/(BV\w+)\//);
238
+ const id = idMatch ? idMatch[1] : '';
239
+ if (!id) {
240
+ const htmlElement = item;
241
+ htmlElement.style.display = 'none';
242
+ } else {
243
+ const overlay = document.createElement('div');
244
+ overlay.style.position = 'absolute';
245
+ overlay.style.top = `${point[0]}%`;
246
+ overlay.style.left = `${point[1]}%`;
247
+ overlay.style.transform = 'translate(-50%, -50%)';
248
+ overlay.style.fontSize = '48px';
249
+ overlay.style.fontWeight = 'bold';
250
+ overlay.style.color = 'black';
251
+ overlay.style.zIndex = '10';
252
+ overlay.style.backgroundColor = 'rgba(255, 255, 255, 0.7)';
253
+ overlay.style.padding = '10px';
254
+ overlay.style.borderRadius = '8px';
255
+ overlay.textContent = `${index + 1}`;
256
+ const videoElement = item;
257
+ videoElement.style.position = 'relative';
258
+ videoElement.appendChild(overlay);
259
+ }
260
+ return { id };
261
+ }).filter(video => video.id);
262
+ }, config.point);
263
+
264
+ // 如果开启了日志调试模式,打印获取到的视频信息
265
+ if (config.loggerinfo) {
266
+ ctx.logger.info(options);
267
+ ctx.logger.info(`共找到 ${videos.length} 个视频:`);
268
+ videos.forEach((video, index) => {
269
+ ctx.logger.info(`序号 ${index + 1}: ID - ${video.id}`);
270
+ });
271
+ }
272
+ if (videos.length === 0) {
273
+ await page.close();
274
+ return '未找到相关视频。';
275
+ }
276
+
277
+ // 动态调整窗口大小以适应视频数量
278
+ const viewportHeight = 200 + videos.length * 100;
279
+ await page.setViewport({
280
+ width: 1440,
281
+ height: viewportHeight,
282
+ });
283
+
284
+ let msg;
285
+ // 截取整个页面
286
+ const imgBuf = await page.screenshot({ fullPage: true });
287
+ msg = h.image(imgBuf, 'image/png');
288
+
289
+ await page.close();
290
+
291
+ // 发送截图
292
+ await session.send(msg);
293
+ // 提示用户输入
294
+ await session.send(`请选择视频的序号:`);
295
+ // 等待用户输入
296
+ const userChoice = await session.prompt(config.timeout * 1000);
297
+ const choiceIndex = parseInt(userChoice) - 1;
298
+ if (isNaN(choiceIndex) || choiceIndex < 0 || choiceIndex >= videos.length) {
299
+ return '输入无效,请输入正确的序号。';
300
+ }
301
+
302
+ // 返回用户选择的视频ID
303
+ const chosenVideo = videos[choiceIndex];
304
+ // 如果开启了日志调试模式,打印用户选择的视频信息
305
+ if (config.loggerinfo) {
306
+ ctx.logger.info(`渲染序号设置\noverlay.style.top = ${config.point[0]}% \noverlay.style.left = ${config.point[1]}%`);
307
+ ctx.logger.info(`用户选择了序号 ${choiceIndex + 1}: ID - ${chosenVideo.id}`);
308
+ }
309
+
310
+ if (config.enable) {
311
+ // 开启自动解析了
312
+ session.content = `https://www.bilibili.com/video/${chosenVideo.id}`;
313
+ const ret = await extractLinks(session, config, ctx, lastProcessedUrls, logger);
314
+ if (ret && !isLinkProcessedRecently(ret, lastProcessedUrls, config, logger)) {
315
+ await processVideoFromLink(session, config, ctx, lastProcessedUrls, logger, ret, options);
316
+ }
317
+ }
318
+ });
319
+ }
320
+ ctx.command('B站点播/点播 [keyword]', '点播B站视频')
126
321
  .option('video', '-v 解析返回视频')
127
322
  .option('audio', '-a 解析返回语音')
128
323
  .option('link', '-l 解析返回链接')
@@ -131,7 +326,7 @@ function apply(ctx, config) {
131
326
  .action(async ({ options, session }, keyword) => {
132
327
  if (!keyword) {
133
328
  await session.execute('点播 -h')
134
- return '没输入keyword'
329
+ return '没输入点播内容'
135
330
  }
136
331
 
137
332
 
@@ -144,13 +339,13 @@ function apply(ctx, config) {
144
339
 
145
340
  await page.addStyleTag({
146
341
  content: `
147
- div.bili-header,
148
- div.login-tip,
149
- div.v-popover,
150
- div.right-entry__outside {
151
- display: none !important;
152
- }
153
- `
342
+ div.bili-header,
343
+ div.login-tip,
344
+ div.v-popover,
345
+ div.right-entry__outside {
346
+ display: none !important;
347
+ }
348
+ `
154
349
  })
155
350
  // 获取视频列表并为每个视频元素添加序号
156
351
  const videos = await page.evaluate((point) => {
@@ -256,21 +451,31 @@ function apply(ctx, config) {
256
451
  }
257
452
  })
258
453
 
454
+ async function handleBilibiliMedia(lastretUrl, config) {
455
+ const fullAPIurl = `https://api.xingzhige.com/API/b_parse/?url=${encodeURIComponent(lastretUrl)}`;
259
456
 
260
- //判断是否需要解析
261
- async function isProcessLinks(session, config, ctx, lastProcessedUrls, logger) {
262
- let content = session.content;
263
-
264
- // 如果允许解析 BV 号,则进行解析
265
- if (config.BVnumberParsing) {
266
- const bvUrls = convertBVToUrl(content);
267
- if (bvUrls.length > 0) {
268
- content += '\n' + bvUrls.join('\n');
457
+ try {
458
+ // 发起请求,解析 Bilibili 视频信息
459
+ const data = await ctx.http.get(fullAPIurl);
460
+ // 检查返回的状态码是否为0,表示成功
461
+ if (data.code === 0 && data.msg === "video" && data.data && data.data.video) {
462
+ const videoData = data.data.video;
463
+ const videoUrl = videoData.url; // 视频直链
464
+ // 返回视频直链
465
+ return videoUrl;
466
+ } else {
467
+ throw new Error("解析视频信息失败或非视频类型内容");
269
468
  }
469
+ } catch (error) {
470
+ logger.error("请求解析 API 失败或处理出错:", error);
471
+ return null;
270
472
  }
473
+ }
271
474
 
475
+ //判断是否需要解析
476
+ async function isProcessLinks(session, config, ctx, lastProcessedUrls, logger) {
272
477
  // 解析内容中的链接
273
- const links = link_type_parser(content);
478
+ const links = link_type_parser(session.content);
274
479
  if (links.length === 0) {
275
480
  return false; // 如果没有找到链接,返回 false
276
481
  }
@@ -327,7 +532,7 @@ function apply(ctx, config) {
327
532
  //解析视频并返回
328
533
  async function processVideoFromLink(session, config, ctx, lastProcessedUrls, logger, ret, options = { video: true }) {
329
534
  const lastretUrl = extractLastUrl(ret);
330
- let bilibilimediaDataURL = '';
535
+
331
536
  let mediaData = '';
332
537
 
333
538
  if (config.waitTip_Switch) {
@@ -346,17 +551,8 @@ function apply(ctx, config) {
346
551
  }
347
552
 
348
553
  if (config.VideoParsing_ToLink) {
349
- const mediaDataString = JSON.stringify(await handleBilibiliMedia(bilibiliVideo, lastretUrl, config));
350
- mediaData = JSON.parse(mediaDataString);
351
- bilibilimediaDataURL = mediaData[0].url;
352
- const videoDuration = mediaData[0].duration; // 提取视频时长,单位为秒
353
-
354
- if (videoDuration > config.Maximumduration * 60) {
355
- if (config.Maximumduration_tip) {
356
- await session.send(config.Maximumduration_tip);
357
- }
358
- return;
359
- }
554
+ const bilibilimediaDataURL = await handleBilibiliMedia(lastretUrl);
555
+
360
556
  if (options.link) { // 发送链接
361
557
  await session.send(h.text(bilibilimediaDataURL));
362
558
  return;
@@ -445,10 +641,10 @@ function apply(ctx, config) {
445
641
  this.config = config;
446
642
  }
447
643
  /**
448
- * 解析 ID 类型
449
- * @param id 视频 ID
450
- * @returns type: ID 类型, id: 视频 ID
451
- */
644
+ * 解析 ID 类型
645
+ * @param id 视频 ID
646
+ * @returns type: ID 类型, id: 视频 ID
647
+ */
452
648
  vid_type_parse(id) {
453
649
  var idRegex = [
454
650
  {
@@ -475,10 +671,10 @@ function apply(ctx, config) {
475
671
  };
476
672
  }
477
673
  /**
478
- * 根据视频 ID 查找视频信息
479
- * @param id 视频 ID
480
- * @returns 视频信息 Json
481
- */
674
+ * 根据视频 ID 查找视频信息
675
+ * @param id 视频 ID
676
+ * @returns 视频信息 Json
677
+ */
482
678
  async fetch_video_info(id) {
483
679
  var ret;
484
680
  const vid = this.vid_type_parse(id);
@@ -504,10 +700,10 @@ function apply(ctx, config) {
504
700
  return ret;
505
701
  }
506
702
  /**
507
- * 生成视频信息
508
- * @param id 视频 ID
509
- * @returns 文字视频信息
510
- */
703
+ * 生成视频信息
704
+ * @param id 视频 ID
705
+ * @returns 文字视频信息
706
+ */
511
707
  async gen_context(id) {
512
708
  const info = await this.fetch_video_info(id);
513
709
  if (!info || !info["data"])
@@ -544,10 +740,10 @@ function apply(ctx, config) {
544
740
  }
545
741
 
546
742
  /**
547
- * 链接类型解析
548
- * @param content 传入消息
549
- * @returns type: "链接类型", id :"内容ID"
550
- */
743
+ * 链接类型解析
744
+ * @param content 传入消息
745
+ * @returns type: "链接类型", id :"内容ID"
746
+ */
551
747
  function link_type_parser(content) {
552
748
  var linkRegex = [
553
749
  {
@@ -613,12 +809,12 @@ function apply(ctx, config) {
613
809
  }
614
810
 
615
811
  /**
616
- * 类型执行器
617
- * @param ctx Context
618
- * @param config Config
619
- * @param element 链接列表
620
- * @returns 解析来的文本
621
- */
812
+ * 类型执行器
813
+ * @param ctx Context
814
+ * @param config Config
815
+ * @param element 链接列表
816
+ * @returns 解析来的文本
817
+ */
622
818
  async function type_processer(ctx, config, element) {
623
819
  var ret = "";
624
820
  switch (element["type"]) {
@@ -651,10 +847,10 @@ function apply(ctx, config) {
651
847
  this.config = config;
652
848
  }
653
849
  /**
654
- * 根据短链接重定向获取正常链接
655
- * @param id 短链接 ID
656
- * @returns 正常链接
657
- */
850
+ * 根据短链接重定向获取正常链接
851
+ * @param id 短链接 ID
852
+ * @returns 正常链接
853
+ */
658
854
  async get_redir_url(id) {
659
855
  var data = await this.ctx.http.get("https://b23.tv/" + id, {
660
856
  redirect: "manual",
@@ -673,10 +869,10 @@ function apply(ctx, config) {
673
869
  /////////////////////////////////////////////////////////////////////////////////////////////////////////
674
870
  /////////////////////////////////////////////////////////////////////////////////////////////////////////
675
871
  /**
676
- * 检查看看一个url是否返回403,或者无法访问,主要用在通过bilibili官方api拿到的视频流
677
- * @param url 链接
678
- * @returns boolean
679
- */
872
+ * 检查看看一个url是否返回403,或者无法访问,主要用在通过bilibili官方api拿到的视频流
873
+ * @param url 链接
874
+ * @returns boolean
875
+ */
680
876
  async function checkResponseStatus(url) {
681
877
  try {
682
878
  const response = await ctx.http(url, {
@@ -704,205 +900,6 @@ function apply(ctx, config) {
704
900
  }
705
901
  }
706
902
 
707
- async function handleBilibiliMedia(bilibiliVideo, originUrl) {
708
- const GetVideoStream = async (h5videoStream, pcvideoStream, cid) => {
709
- if (!h5videoStream.data ||
710
- !pcvideoStream.data ||
711
- !h5videoStream.data.accept_quality ||
712
- !pcvideoStream.data.accept_quality ||
713
- !h5videoStream.data.accept_format ||
714
- !pcvideoStream.data.accept_format)
715
- throw new Error('无法获取清晰度信息, 可能该视频为大会员专享或者该视频为付费视频/充电专属视频!或者账号被风控。');
716
- const h5Quality = h5videoStream.data.accept_quality;
717
- const pcQuality = pcvideoStream.data.accept_quality;
718
- if (config.loggerinfo) {
719
- logger.info(`h5Quality清晰度: ` + h5Quality)
720
- logger.info(`pcQuality清晰度: ` + pcQuality)
721
- }
722
- const CombinedQualityInfo = h5Quality
723
- .filter((item, index) => !(h5videoStream.data?.accept_format?.includes('flv') && h5videoStream.data.accept_format.split(',')[index].includes('flv')))
724
- .map(item => ['html5', item])
725
- .concat(pcQuality
726
- .filter((item, index) => !(pcvideoStream.data?.accept_format?.includes('flv') && pcvideoStream.data.accept_format.split(',')[index].includes('flv')))
727
- .map(item => ['pc', item]));
728
- CombinedQualityInfo.sort((a, b) => {
729
- if (b[1] === a[1]) {
730
- // 如果两者数字相等
731
- if (a[0] === 'html5') {
732
- // html5排在前面
733
- return -1;
734
- }
735
- else if (b[0] === 'html5') {
736
- // pc排在前面
737
- return 1;
738
- }
739
- else {
740
- // 如果都是相同类型,则按照原顺序
741
- return 0;
742
- }
743
- }
744
- else {
745
- // 根据配置决定排序顺序
746
- switch (config.Video_ClarityPriority) {
747
- case '1':
748
- //logger.info(`低清晰度优先排序,a[1]: ${a[1]}, b[1]: ${b[1]}`);
749
- return a[1] - b[1]; // 从低到高排序(低清晰度优先)
750
- case '2':
751
- //logger.info(`高清晰度优先排序,a[1]: ${a[1]}, b[1]: ${b[1]}`);
752
- return b[1] - a[1]; // 从高到低排序(高清晰度优先)
753
- default:
754
- //logger.warn(`未知的视频清晰度优先级配置: ${config.Video_ClarityPriority}`);
755
- return 0; // 默认保持原顺序
756
- }
757
- }
758
- });
759
- outerLoop: for (const [index, item] of CombinedQualityInfo.entries()) {
760
-
761
- videoStream = await bilibiliVideo.getBilibiliVideoStream(avid, bvid, cid, item[1], item[0], 1);
762
-
763
- if (!videoStream || !videoStream.data || !videoStream.data.durl) {
764
- continue;
765
- }
766
- if (await checkResponseStatus(videoStream.data.durl[0].url) === true) {
767
- break outerLoop;
768
- }
769
- const isLastItem = index === CombinedQualityInfo.length - 1;
770
- if (isLastItem) {
771
- throw new Error('在尝试了全部清晰度和平台后,无法获取流媒体');
772
- }
773
- }
774
- return videoStream;
775
- };
776
- const duration = [];
777
- const cids = [];
778
- const cover = [];
779
- const name = [];
780
- const type = [];
781
- const singer = [];
782
- const link = [];
783
- const origin = [];
784
- const bitRate = [];
785
- const url = [];
786
- let bvid;
787
- if (originUrl.includes('http') && originUrl.includes('video')) {
788
- originUrl = originUrl.replace(/\?/g, '/');
789
- bvid = originUrl.split('/video/')[1].split('/')[0];
790
- }
791
- else if (originUrl.includes('BV') || originUrl.includes('bv')) {
792
- bvid = originUrl;
793
- }
794
- else {
795
- const mediaData = returnErrorMediaData(['暂不支持']);
796
- return mediaData;
797
- }
798
- const videoInfo = await bilibiliVideo.getBilibiliVideoDetail(null, bvid);
799
- if (!videoInfo || !videoInfo.data) {
800
- const mediaData = returnErrorMediaData(['这个不是正确的bv号']);
801
- return mediaData;
802
- }
803
- videoInfo.data.pages.forEach((page) => {
804
- if (!videoInfo.data)
805
- return;
806
- cids.push(page.cid);
807
- cover.push(videoInfo.data.pic);
808
- type.push('video');
809
- singer.push(videoInfo.data.owner.name);
810
- link.push(`https://www.bilibili.com/video/${bvid}`);
811
- duration.push(page.duration + 1 || videoInfo.data.duration + 1);
812
- origin.push('bilibili');
813
- if (videoInfo.data.pages.length <= 1) {
814
- name.push(videoInfo.data.title);
815
- }
816
- else {
817
- name.push(`${videoInfo.data.title} - P${page.part}`);
818
- }
819
- });
820
- const avid = videoInfo.data.aid;
821
- let videoStream;
822
-
823
- const h5videoStream = await bilibiliVideo.getBilibiliVideoStream(avid, bvid, cids[0], 112, 'html5', 1);
824
- const pcvideoStream = await bilibiliVideo.getBilibiliVideoStream(avid, bvid, cids[0], 112, 'pc', 1);
825
- if (!h5videoStream || !pcvideoStream)
826
- return returnErrorMediaData(['无法获取B站视频流']);
827
-
828
- const cid = cids[0];
829
- videoStream = await GetVideoStream(h5videoStream, pcvideoStream, cid);
830
- if (!videoStream || !videoStream.data || !videoStream.data.quality || !videoStream.data.durl)
831
- return returnErrorMediaData(['无法获取videoStream信息']);
832
- bitRate.push(videoStream.data.quality);
833
- url.push(videoStream.data.durl[0].url);
834
- /*
835
- for (const cid of cids) {
836
- videoStream = await GetVideoStream(h5videoStream, pcvideoStream, cid);
837
- if (!videoStream || !videoStream.data || !videoStream.data.quality || !videoStream.data.durl)
838
- return returnErrorMediaData(['无法获取videoStream信息']);
839
- bitRate.push(videoStream.data.quality);
840
- url.push(videoStream.data.durl[0].url);
841
- }
842
- */
843
- const mediaData = returnCompleteMediaData(type, name, singer, cover, url, duration, bitRate, [], origin, link);
844
- return mediaData;
845
- }
846
-
847
- /**
848
- * 返回包含错误信息的mediaData
849
- * @param errorMsg 错误信息
850
- * @return mediaData
851
- */
852
- function returnErrorMediaData(errorMsgs) {
853
- const errorMediaDataArray = [];
854
- for (const errorMsg of errorMsgs) {
855
- const mediaData = {
856
- type: 'music',
857
- name: '0',
858
- signer: '0',
859
- cover: '0',
860
- link: '0',
861
- url: '0',
862
- duration: 0,
863
- bitRate: 0,
864
- lyrics: null,
865
- origin: null,
866
- error: errorMsg,
867
- };
868
- errorMediaDataArray.push(mediaData);
869
- }
870
- return errorMediaDataArray;
871
- }
872
-
873
- /**
874
- * 返回完整的mediaData
875
- * @param type 类型
876
- * @param name 标题
877
- * @param signer 创作者
878
- * @param cover 封面图url
879
- * @param url 链接
880
- * @param duration 时长
881
- * @param bitRate 比特率
882
- * @return mediaData
883
- */
884
- function returnCompleteMediaData(typeList, nameList, signerList, coverList, urlList, durationList, bitRateList, lyricsList = [], origin = [], linkList = [], commentList) {
885
- const mediaDataArray = [];
886
- for (let i = 0; i < urlList.length; i++) {
887
- const mediaData = {
888
- type: typeList[i],
889
- name: nameList[i],
890
- signer: signerList[i],
891
- cover: coverList[i],
892
- link: linkList[i] || urlList[i],
893
- url: urlList[i],
894
- duration: durationList[i],
895
- bitRate: bitRateList[i],
896
- lyrics: lyricsList[i] || null,
897
- origin: origin[i] || null,
898
- comment: commentList?.[i] || undefined,
899
- error: null,
900
- };
901
-
902
- mediaDataArray.push(mediaData);
903
- }
904
- return mediaDataArray;
905
- }
906
903
 
907
904
  }
908
905
  exports.apply = apply;
package/package.json CHANGED
@@ -1,15 +1,14 @@
1
1
  {
2
2
  "name": "koishi-plugin-bilibili-videolink-analysis",
3
- "description": "[<ruby>Bilibili视频解析<rp>(</rp><rt>点我查看食用方法</rt><rp>)</rp></ruby>](https://www.npmjs.com/package/koishi-plugin-bilibili-videolink-analysis)解析B站链接(支持小程序卡片)支持搜索点播功能!灵感来自强大的 [iirose-media-request](/market?keyword=iirose-media-request) 以及完美的 [bili-parser](/market?keyword=bili-parser) ,十分感谢这两个优秀的项目!",
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": "0.6.2",
5
+ "version": "1.0.0",
6
6
  "main": "lib/index.js",
7
7
  "typings": "lib/index.d.ts",
8
8
  "files": [
9
9
  "lib",
10
10
  "dist"
11
11
  ],
12
- "scripts": {},
13
12
  "homepage": "https://github.com/shangxueink/koishi-shangxue-apps/tree/main/",
14
13
  "bugs": {
15
14
  "url": "https://github.com/shangxueink/koishi-shangxue-apps/issues"
@@ -23,7 +22,6 @@
23
22
  "bilibili-videolink-analysis"
24
23
  ],
25
24
  "peerDependencies": {
26
- "koishi": "^4.16.8",
27
- "koishi-plugin-bilibili-login": "^0.1.50"
25
+ "koishi": "^4.16.8"
28
26
  }
29
- }
27
+ }
package/readme.md CHANGED
@@ -178,6 +178,13 @@ https://www.bilibili.com/video/BV1ii421Q7oj
178
178
  <details>
179
179
  <summary>点击此处 可查看更新日志</summary>
180
180
 
181
+ - **1.0.0**
182
+ - 不想写了
183
+
184
+ - **0.6.3**
185
+ - 修复单独的bv号解析报错
186
+ - 0.6.2更新了点播,忘写了
187
+
181
188
  - **0.6.1**
182
189
  - 支持点播功能,使用puppeteer进行网页截图,并且加以渲染序号,以便选择
183
190
  - 模块化中间件部分内容,方便调用