koishi-plugin-bilibili-videolink-analysis 1.1.2 → 1.1.3
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 +200 -252
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -54,6 +54,7 @@ exports.usage = `
|
|
|
54
54
|
|
|
55
55
|
exports.Config = Schema.intersect([
|
|
56
56
|
Schema.object({
|
|
57
|
+
demand: Schema.boolean().default(true).description("开启点播指令功能"),
|
|
57
58
|
timeout: Schema.number().role('slider').min(1).max(300).step(1).default(60).description('指定播放视频的输入时限。`单位 秒`'),
|
|
58
59
|
point: Schema.tuple([Number, Number]).description('序号标注位置。分别表示`距离顶部 距离左侧`的百分比').default([50, 50]),
|
|
59
60
|
enable: Schema.boolean().description('是否开启自动解析`选择对应视频 会自动解析视频内容`').default(true),
|
|
@@ -126,95 +127,232 @@ function apply(ctx, config) {
|
|
|
126
127
|
}
|
|
127
128
|
return next();
|
|
128
129
|
});
|
|
130
|
+
if (config.demand) {
|
|
131
|
+
ctx.command('B站点播')
|
|
132
|
+
ctx.command('B站点播/退出登录', '退出B站账号')
|
|
133
|
+
.action(async ({ session }) => {
|
|
134
|
+
const page = await ctx.puppeteer.page();
|
|
135
|
+
await page.goto('https://www.bilibili.com/', { waitUntil: 'networkidle2' });
|
|
129
136
|
|
|
130
|
-
|
|
131
|
-
|
|
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;
|
|
137
|
+
const loginButtonSelector = '.right-entry__outside.go-login-btn';
|
|
138
|
+
const isLoggedIn = await page.$(loginButtonSelector) === null;
|
|
138
139
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
if (!isLoggedIn) {
|
|
141
|
+
await page.close();
|
|
142
|
+
await session.send(h.text('您尚未登录。'))
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
144
145
|
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
const avatarLinkSelector = '.header-entry-mini';
|
|
147
|
+
const logoutButtonSelector = '.logout-item';
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
try {
|
|
150
|
+
const avatarElement = await page.$(avatarLinkSelector);
|
|
151
|
+
if (avatarElement) {
|
|
152
|
+
await avatarElement.hover();
|
|
153
|
+
await page.waitForSelector(logoutButtonSelector, { visible: true });
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
await page.click(logoutButtonSelector);
|
|
155
156
|
|
|
156
|
-
|
|
157
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
157
158
|
|
|
159
|
+
await page.close();
|
|
160
|
+
await session.send(h.text('已成功退出登录。'))
|
|
161
|
+
return;
|
|
162
|
+
} else {
|
|
163
|
+
await page.close();
|
|
164
|
+
await session.send(h.text('找不到用户头像,无法退出登录。'))
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
158
168
|
await page.close();
|
|
159
|
-
|
|
169
|
+
logger.error('Error during logout:', error);
|
|
170
|
+
await session.send(h.text('退出登录时出错。'))
|
|
160
171
|
return;
|
|
161
|
-
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
ctx.command('B站点播/登录', '登录B站账号')
|
|
176
|
+
.alias("登陆")
|
|
177
|
+
.action(async ({ session }) => {
|
|
178
|
+
const page = await ctx.puppeteer.page();
|
|
179
|
+
await page.goto('https://www.bilibili.com/', { waitUntil: 'networkidle2' });
|
|
180
|
+
|
|
181
|
+
const loginButtonSelector = '.right-entry__outside.go-login-btn';
|
|
182
|
+
const isLoggedIn = await page.$(loginButtonSelector) === null;
|
|
183
|
+
|
|
184
|
+
if (isLoggedIn) {
|
|
162
185
|
await page.close();
|
|
163
|
-
await session.send(h.text('
|
|
186
|
+
await session.send(h.text('您已经登录了。'))
|
|
164
187
|
return;
|
|
165
188
|
}
|
|
166
|
-
} catch (error) {
|
|
167
|
-
await page.close();
|
|
168
|
-
logger.error('Error during logout:', error);
|
|
169
|
-
await session.send(h.text('退出登录时出错。'))
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
189
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
190
|
+
await page.click(loginButtonSelector);
|
|
191
|
+
|
|
192
|
+
const qrCodeSelector = '.login-scan-box img';
|
|
193
|
+
await page.waitForSelector(qrCodeSelector);
|
|
194
|
+
const qrCodeUrl = await page.$eval(qrCodeSelector, img => img.src);
|
|
195
|
+
|
|
196
|
+
await session.send(h.image(qrCodeUrl, 'image/png'));
|
|
197
|
+
await session.send('请扫描二维码进行登录。');
|
|
198
|
+
|
|
199
|
+
let attempts = 0;
|
|
200
|
+
let loginSuccessful = false;
|
|
201
|
+
|
|
202
|
+
while (attempts < 6) {
|
|
203
|
+
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait
|
|
204
|
+
const isStillLoggedIn = await page.$(loginButtonSelector) === null;
|
|
205
|
+
|
|
206
|
+
if (isStillLoggedIn) {
|
|
207
|
+
loginSuccessful = true;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
179
210
|
|
|
180
|
-
|
|
181
|
-
|
|
211
|
+
attempts++;
|
|
212
|
+
}
|
|
182
213
|
|
|
183
|
-
if (isLoggedIn) {
|
|
184
214
|
await page.close();
|
|
185
|
-
await session.send(h.text('
|
|
215
|
+
await session.send(h.text(loginSuccessful ? '登录成功!' : '登录失败,请重试。'))
|
|
186
216
|
return;
|
|
187
|
-
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
ctx.command('B站点播/点播 [keyword]', '点播B站视频')
|
|
220
|
+
.option('video', '-v 解析返回视频')
|
|
221
|
+
.option('audio', '-a 解析返回语音')
|
|
222
|
+
.option('link', '-l 解析返回链接')
|
|
223
|
+
.option('page', '-p <page:number> 指定页数', { fallback: '1' })
|
|
224
|
+
.example('点播 遠い空へ -v')
|
|
225
|
+
.action(async ({ options, session }, keyword) => {
|
|
226
|
+
if (!keyword) {
|
|
227
|
+
await session.execute('点播 -h')
|
|
228
|
+
await session.send(h.text('没输入点播内容'))
|
|
229
|
+
return
|
|
230
|
+
}
|
|
188
231
|
|
|
189
|
-
await page.click(loginButtonSelector);
|
|
190
232
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
233
|
+
const url = `https://search.bilibili.com/video?keyword=${encodeURIComponent(keyword)}&page=${options.page}&o=30`
|
|
234
|
+
const page = await ctx.puppeteer.page()
|
|
235
|
+
|
|
236
|
+
await page.goto(url, {
|
|
237
|
+
waitUntil: 'networkidle2'
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
await page.addStyleTag({
|
|
241
|
+
content: `
|
|
242
|
+
div.bili-header,
|
|
243
|
+
div.login-tip,
|
|
244
|
+
div.v-popover,
|
|
245
|
+
div.right-entry__outside {
|
|
246
|
+
display: none !important;
|
|
247
|
+
}
|
|
248
|
+
`
|
|
249
|
+
})
|
|
250
|
+
// 获取视频列表并为每个视频元素添加序号
|
|
251
|
+
const videos = await page.evaluate((point) => {
|
|
252
|
+
const items = Array.from(document.querySelectorAll('.video-list-item:not([style*="display: none"])'))
|
|
253
|
+
return items.map((item, index) => {
|
|
254
|
+
const link = item.querySelector('a')
|
|
255
|
+
const href = link?.getAttribute('href') || ''
|
|
256
|
+
const idMatch = href.match(/\/video\/(BV\w+)\//)
|
|
257
|
+
const id = idMatch ? idMatch[1] : ''
|
|
194
258
|
|
|
195
|
-
|
|
196
|
-
|
|
259
|
+
if (!id) {
|
|
260
|
+
// 如果没有提取到视频ID,隐藏这个元素
|
|
261
|
+
//const htmlElement = item as HTMLElement
|
|
262
|
+
const htmlElement = item
|
|
263
|
+
htmlElement.style.display = 'none'
|
|
264
|
+
} else {
|
|
265
|
+
// 创建一个包含序号的元素,并将其插入到视频元素的正中央
|
|
266
|
+
const overlay = document.createElement('div')
|
|
267
|
+
overlay.style.position = 'absolute'
|
|
268
|
+
overlay.style.top = `${point[0]}%`
|
|
269
|
+
overlay.style.left = `${point[1]}%`
|
|
270
|
+
overlay.style.transform = 'translate(-50%, -50%)'
|
|
271
|
+
overlay.style.fontSize = '48px'
|
|
272
|
+
overlay.style.fontWeight = 'bold'
|
|
273
|
+
overlay.style.color = 'black'
|
|
274
|
+
overlay.style.zIndex = '10'
|
|
275
|
+
overlay.style.backgroundColor = 'rgba(255, 255, 255, 0.7)' // 半透明白色背景,确保数字清晰可见
|
|
276
|
+
overlay.style.padding = '10px'
|
|
277
|
+
overlay.style.borderRadius = '8px'
|
|
278
|
+
overlay.textContent = `${index + 1}` // 序号
|
|
279
|
+
|
|
280
|
+
// 确保父元素有 `position: relative` 以正确定位
|
|
281
|
+
//const videoElement = item as HTMLElement
|
|
282
|
+
const videoElement = item
|
|
283
|
+
videoElement.style.position = 'relative'
|
|
284
|
+
videoElement.appendChild(overlay)
|
|
285
|
+
}
|
|
197
286
|
|
|
198
|
-
|
|
199
|
-
|
|
287
|
+
return { id }
|
|
288
|
+
}).filter(video => video.id)
|
|
289
|
+
}, config.point) // 传递配置的 point 参数
|
|
200
290
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
291
|
+
// 如果开启了日志调试模式,打印获取到的视频信息
|
|
292
|
+
if (config.loggerinfo) {
|
|
293
|
+
ctx.logger.info(options)
|
|
294
|
+
ctx.logger.info(`共找到 ${videos.length} 个视频:`)
|
|
295
|
+
videos.forEach((video, index) => {
|
|
296
|
+
ctx.logger.info(`序号 ${index + 1}: ID - ${video.id}`)
|
|
297
|
+
})
|
|
298
|
+
}
|
|
204
299
|
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
|
|
300
|
+
if (videos.length === 0) {
|
|
301
|
+
await page.close()
|
|
302
|
+
await session.send(h.text('未找到相关视频。'))
|
|
303
|
+
return
|
|
208
304
|
}
|
|
209
305
|
|
|
210
|
-
|
|
211
|
-
|
|
306
|
+
// 动态调整窗口大小以适应视频数量
|
|
307
|
+
const viewportHeight = 200 + videos.length * 100
|
|
308
|
+
await page.setViewport({
|
|
309
|
+
width: 1440,
|
|
310
|
+
height: viewportHeight
|
|
311
|
+
})
|
|
312
|
+
let msg;
|
|
313
|
+
// 截图
|
|
314
|
+
const videoListElement = await page.$('.video-list.row')
|
|
315
|
+
if (videoListElement) {
|
|
316
|
+
const imgBuf = await videoListElement.screenshot({
|
|
317
|
+
captureBeyondViewport: false
|
|
318
|
+
})
|
|
319
|
+
msg = h.image(imgBuf, 'image/png')
|
|
320
|
+
}
|
|
212
321
|
|
|
213
|
-
|
|
214
|
-
await session.send(h.text(loginSuccessful ? '登录成功!' : '登录失败,请重试。'))
|
|
215
|
-
return;
|
|
216
|
-
});
|
|
322
|
+
await page.close()
|
|
217
323
|
|
|
324
|
+
// 发送截图
|
|
325
|
+
await session.send(msg)
|
|
326
|
+
|
|
327
|
+
// 提示用户输入
|
|
328
|
+
await session.send(`请选择视频的序号:`)
|
|
329
|
+
|
|
330
|
+
// 等待用户输入
|
|
331
|
+
const userChoice = await session.prompt(config.timeout * 1000)
|
|
332
|
+
const choiceIndex = parseInt(userChoice) - 1
|
|
333
|
+
if (isNaN(choiceIndex) || choiceIndex < 0 || choiceIndex >= videos.length) {
|
|
334
|
+
await session.send(h.text('输入无效,请输入正确的序号。'))
|
|
335
|
+
return
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// 返回用户选择的视频ID
|
|
339
|
+
const chosenVideo = videos[choiceIndex]
|
|
340
|
+
|
|
341
|
+
// 如果开启了日志调试模式,打印用户选择的视频信息
|
|
342
|
+
if (config.loggerinfo) {
|
|
343
|
+
ctx.logger.info(`渲染序号设置\noverlay.style.top = ${config.point[0]}% \noverlay.style.left = ${config.point[1]}%`)
|
|
344
|
+
ctx.logger.info(`用户选择了序号 ${choiceIndex + 1}: ID - ${chosenVideo.id}`)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (config.enable) { // 开启自动解析了
|
|
348
|
+
session.content = `https://www.bilibili.com/video/${chosenVideo.id}`
|
|
349
|
+
const ret = await extractLinks(session, config, ctx, lastProcessedUrls, logger); // 提取链接
|
|
350
|
+
if (ret && !isLinkProcessedRecently(ret, lastProcessedUrls, config, logger)) {
|
|
351
|
+
await processVideoFromLink(session, config, ctx, lastProcessedUrls, logger, ret, options); // 解析视频并返回
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
})
|
|
355
|
+
}
|
|
218
356
|
if (config.loggerinfo) {
|
|
219
357
|
ctx.command('B站点播/调试点播 [keyword]', '调试时点播B站视频')
|
|
220
358
|
.option('video', '-v 解析返回视频')
|
|
@@ -322,196 +460,6 @@ function apply(ctx, config) {
|
|
|
322
460
|
}
|
|
323
461
|
});
|
|
324
462
|
}
|
|
325
|
-
ctx.command('B站点播/点播 [keyword]', '点播B站视频')
|
|
326
|
-
.option('video', '-v 解析返回视频')
|
|
327
|
-
.option('audio', '-a 解析返回语音')
|
|
328
|
-
.option('link', '-l 解析返回链接')
|
|
329
|
-
.option('page', '-p <page:number> 指定页数', { fallback: '1' })
|
|
330
|
-
.example('点播 遠い空へ -v')
|
|
331
|
-
.action(async ({ options, session }, keyword) => {
|
|
332
|
-
if (!keyword) {
|
|
333
|
-
await session.execute('点播 -h')
|
|
334
|
-
await session.send(h.text('没输入点播内容'))
|
|
335
|
-
return
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const url = `https://search.bilibili.com/video?keyword=${encodeURIComponent(keyword)}&page=${options.page}&o=30`
|
|
340
|
-
const page = await ctx.puppeteer.page()
|
|
341
|
-
|
|
342
|
-
await page.goto(url, {
|
|
343
|
-
waitUntil: 'networkidle2'
|
|
344
|
-
})
|
|
345
|
-
|
|
346
|
-
await page.addStyleTag({
|
|
347
|
-
content: `
|
|
348
|
-
div.bili-header,
|
|
349
|
-
div.login-tip,
|
|
350
|
-
div.v-popover,
|
|
351
|
-
div.right-entry__outside {
|
|
352
|
-
display: none !important;
|
|
353
|
-
}
|
|
354
|
-
`
|
|
355
|
-
})
|
|
356
|
-
// 获取视频列表并为每个视频元素添加序号
|
|
357
|
-
const videos = await page.evaluate((point) => {
|
|
358
|
-
const items = Array.from(document.querySelectorAll('.video-list-item:not([style*="display: none"])'))
|
|
359
|
-
return items.map((item, index) => {
|
|
360
|
-
const link = item.querySelector('a')
|
|
361
|
-
const href = link?.getAttribute('href') || ''
|
|
362
|
-
const idMatch = href.match(/\/video\/(BV\w+)\//)
|
|
363
|
-
const id = idMatch ? idMatch[1] : ''
|
|
364
|
-
|
|
365
|
-
if (!id) {
|
|
366
|
-
// 如果没有提取到视频ID,隐藏这个元素
|
|
367
|
-
//const htmlElement = item as HTMLElement
|
|
368
|
-
const htmlElement = item
|
|
369
|
-
htmlElement.style.display = 'none'
|
|
370
|
-
} else {
|
|
371
|
-
// 创建一个包含序号的元素,并将其插入到视频元素的正中央
|
|
372
|
-
const overlay = document.createElement('div')
|
|
373
|
-
overlay.style.position = 'absolute'
|
|
374
|
-
overlay.style.top = `${point[0]}%`
|
|
375
|
-
overlay.style.left = `${point[1]}%`
|
|
376
|
-
overlay.style.transform = 'translate(-50%, -50%)'
|
|
377
|
-
overlay.style.fontSize = '48px'
|
|
378
|
-
overlay.style.fontWeight = 'bold'
|
|
379
|
-
overlay.style.color = 'black'
|
|
380
|
-
overlay.style.zIndex = '10'
|
|
381
|
-
overlay.style.backgroundColor = 'rgba(255, 255, 255, 0.7)' // 半透明白色背景,确保数字清晰可见
|
|
382
|
-
overlay.style.padding = '10px'
|
|
383
|
-
overlay.style.borderRadius = '8px'
|
|
384
|
-
overlay.textContent = `${index + 1}` // 序号
|
|
385
|
-
|
|
386
|
-
// 确保父元素有 `position: relative` 以正确定位
|
|
387
|
-
//const videoElement = item as HTMLElement
|
|
388
|
-
const videoElement = item
|
|
389
|
-
videoElement.style.position = 'relative'
|
|
390
|
-
videoElement.appendChild(overlay)
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return { id }
|
|
394
|
-
}).filter(video => video.id)
|
|
395
|
-
}, config.point) // 传递配置的 point 参数
|
|
396
|
-
|
|
397
|
-
// 如果开启了日志调试模式,打印获取到的视频信息
|
|
398
|
-
if (config.loggerinfo) {
|
|
399
|
-
ctx.logger.info(options)
|
|
400
|
-
ctx.logger.info(`共找到 ${videos.length} 个视频:`)
|
|
401
|
-
videos.forEach((video, index) => {
|
|
402
|
-
ctx.logger.info(`序号 ${index + 1}: ID - ${video.id}`)
|
|
403
|
-
})
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
if (videos.length === 0) {
|
|
407
|
-
await page.close()
|
|
408
|
-
await session.send(h.text('未找到相关视频。'))
|
|
409
|
-
return
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// 动态调整窗口大小以适应视频数量
|
|
413
|
-
const viewportHeight = 200 + videos.length * 100
|
|
414
|
-
await page.setViewport({
|
|
415
|
-
width: 1440,
|
|
416
|
-
height: viewportHeight
|
|
417
|
-
})
|
|
418
|
-
let msg;
|
|
419
|
-
// 截图
|
|
420
|
-
const videoListElement = await page.$('.video-list.row')
|
|
421
|
-
if (videoListElement) {
|
|
422
|
-
const imgBuf = await videoListElement.screenshot({
|
|
423
|
-
captureBeyondViewport: false
|
|
424
|
-
})
|
|
425
|
-
msg = h.image(imgBuf, 'image/png')
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
await page.close()
|
|
429
|
-
|
|
430
|
-
// 发送截图
|
|
431
|
-
await session.send(msg)
|
|
432
|
-
|
|
433
|
-
// 提示用户输入
|
|
434
|
-
await session.send(`请选择视频的序号:`)
|
|
435
|
-
|
|
436
|
-
// 等待用户输入
|
|
437
|
-
const userChoice = await session.prompt(config.timeout * 1000)
|
|
438
|
-
const choiceIndex = parseInt(userChoice) - 1
|
|
439
|
-
if (isNaN(choiceIndex) || choiceIndex < 0 || choiceIndex >= videos.length) {
|
|
440
|
-
await session.send(h.text('输入无效,请输入正确的序号。'))
|
|
441
|
-
return
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// 返回用户选择的视频ID
|
|
445
|
-
const chosenVideo = videos[choiceIndex]
|
|
446
|
-
|
|
447
|
-
// 如果开启了日志调试模式,打印用户选择的视频信息
|
|
448
|
-
if (config.loggerinfo) {
|
|
449
|
-
ctx.logger.info(`渲染序号设置\noverlay.style.top = ${config.point[0]}% \noverlay.style.left = ${config.point[1]}%`)
|
|
450
|
-
ctx.logger.info(`用户选择了序号 ${choiceIndex + 1}: ID - ${chosenVideo.id}`)
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (config.enable) { // 开启自动解析了
|
|
454
|
-
session.content = `https://www.bilibili.com/video/${chosenVideo.id}`
|
|
455
|
-
const ret = await extractLinks(session, config, ctx, lastProcessedUrls, logger); // 提取链接
|
|
456
|
-
if (ret && !isLinkProcessedRecently(ret, lastProcessedUrls, config, logger)) {
|
|
457
|
-
await processVideoFromLink(session, config, ctx, lastProcessedUrls, logger, ret, options); // 解析视频并返回
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
})
|
|
461
|
-
/*async function handleBilibiliMedia(config, session, lastretUrl) {
|
|
462
|
-
const fullAPIurl = `https://api.xingzhige.com/API/b_parse/?url=${encodeURIComponent(lastretUrl)}`;
|
|
463
|
-
|
|
464
|
-
try {
|
|
465
|
-
// 发起请求,解析 Bilibili 视频信息
|
|
466
|
-
const responseData = await ctx.http.get(fullAPIurl);
|
|
467
|
-
|
|
468
|
-
// 检查返回状态码是否为0且为视频内容
|
|
469
|
-
if (responseData.code === 0 && responseData.msg === "video" && responseData.data) {
|
|
470
|
-
const { bvid, cid } = responseData.data;
|
|
471
|
-
|
|
472
|
-
// 请求 Bilibili 播放 URL,获取视频信息
|
|
473
|
-
const bilibiliUrl = `https://api.bilibili.com/x/player/playurl?fnval=80&cid=${cid}&bvid=${bvid}`;
|
|
474
|
-
const playData = await ctx.http.get(bilibiliUrl);
|
|
475
|
-
//////
|
|
476
|
-
ctx.logger.info(bilibiliUrl)
|
|
477
|
-
// 检查返回的状态码是否为0,表示请求成功
|
|
478
|
-
if (playData.code === 0 && playData.data && playData.data.dash.duration) {
|
|
479
|
-
const videoDurationSeconds = playData.data.dash.duration; // 视频时长,单位为秒
|
|
480
|
-
const videoDurationMinutes = videoDurationSeconds / 60; // 转换为分钟
|
|
481
|
-
|
|
482
|
-
// 检查视频时长是否超过配置的最大允许时长
|
|
483
|
-
if (videoDurationMinutes > config.Maximumduration) {
|
|
484
|
-
// 视频时长超过最大限制,返回提示
|
|
485
|
-
if (config.Maximumduration_tip !== '不返回文字提示') {
|
|
486
|
-
await session.send(config.Maximumduration_tip)
|
|
487
|
-
return next()
|
|
488
|
-
} else {
|
|
489
|
-
return null; // 不返回提示信息
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// 视频时长符合要求,继续解析并返回视频直链
|
|
494
|
-
const videoUrl = responseData.data.video.url;
|
|
495
|
-
//////
|
|
496
|
-
ctx.logger.info(videoUrl)
|
|
497
|
-
if (videoUrl) {
|
|
498
|
-
return videoUrl; // 返回视频直链
|
|
499
|
-
} else {
|
|
500
|
-
throw new Error("解析视频直链失败");
|
|
501
|
-
}
|
|
502
|
-
} else {
|
|
503
|
-
throw new Error("获取播放数据失败");
|
|
504
|
-
}
|
|
505
|
-
} else {
|
|
506
|
-
throw new Error("解析视频信息失败或非视频类型内容");
|
|
507
|
-
}
|
|
508
|
-
} catch (error) {
|
|
509
|
-
logger.error("请求解析 API 失败或处理出错:", error);
|
|
510
|
-
return null;
|
|
511
|
-
}
|
|
512
|
-
}*/
|
|
513
|
-
|
|
514
|
-
|
|
515
463
|
//判断是否需要解析
|
|
516
464
|
async function isProcessLinks(session, config, ctx, lastProcessedUrls, logger) {
|
|
517
465
|
// 解析内容中的链接
|
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.3",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
8
8
|
"files": [
|