koishi-plugin-bilibili-videolink-analysis 1.1.2 → 1.1.4
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/LICENSE.txt +21 -0
- package/lib/index.js +199 -252
- package/package.json +1 -1
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 shangxue
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
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,231 @@ function apply(ctx, config) {
|
|
|
126
127
|
}
|
|
127
128
|
return next();
|
|
128
129
|
});
|
|
130
|
+
if (config.demand) {
|
|
131
|
+
ctx.command('B站点播/退出登录', '退出B站账号')
|
|
132
|
+
.action(async ({ session }) => {
|
|
133
|
+
const page = await ctx.puppeteer.page();
|
|
134
|
+
await page.goto('https://www.bilibili.com/', { waitUntil: 'networkidle2' });
|
|
129
135
|
|
|
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;
|
|
136
|
+
const loginButtonSelector = '.right-entry__outside.go-login-btn';
|
|
137
|
+
const isLoggedIn = await page.$(loginButtonSelector) === null;
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
if (!isLoggedIn) {
|
|
140
|
+
await page.close();
|
|
141
|
+
await session.send(h.text('您尚未登录。'))
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
const avatarLinkSelector = '.header-entry-mini';
|
|
146
|
+
const logoutButtonSelector = '.logout-item';
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
try {
|
|
149
|
+
const avatarElement = await page.$(avatarLinkSelector);
|
|
150
|
+
if (avatarElement) {
|
|
151
|
+
await avatarElement.hover();
|
|
152
|
+
await page.waitForSelector(logoutButtonSelector, { visible: true });
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
await page.click(logoutButtonSelector);
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
157
157
|
|
|
158
|
+
await page.close();
|
|
159
|
+
await session.send(h.text('已成功退出登录。'))
|
|
160
|
+
return;
|
|
161
|
+
} else {
|
|
162
|
+
await page.close();
|
|
163
|
+
await session.send(h.text('找不到用户头像,无法退出登录。'))
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
158
167
|
await page.close();
|
|
159
|
-
|
|
168
|
+
logger.error('Error during logout:', error);
|
|
169
|
+
await session.send(h.text('退出登录时出错。'))
|
|
160
170
|
return;
|
|
161
|
-
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
ctx.command('B站点播/登录', '登录B站账号')
|
|
175
|
+
.alias("登陆")
|
|
176
|
+
.action(async ({ session }) => {
|
|
177
|
+
const page = await ctx.puppeteer.page();
|
|
178
|
+
await page.goto('https://www.bilibili.com/', { waitUntil: 'networkidle2' });
|
|
179
|
+
|
|
180
|
+
const loginButtonSelector = '.right-entry__outside.go-login-btn';
|
|
181
|
+
const isLoggedIn = await page.$(loginButtonSelector) === null;
|
|
182
|
+
|
|
183
|
+
if (isLoggedIn) {
|
|
162
184
|
await page.close();
|
|
163
|
-
await session.send(h.text('
|
|
185
|
+
await session.send(h.text('您已经登录了。'))
|
|
164
186
|
return;
|
|
165
187
|
}
|
|
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
188
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
189
|
+
await page.click(loginButtonSelector);
|
|
190
|
+
|
|
191
|
+
const qrCodeSelector = '.login-scan-box img';
|
|
192
|
+
await page.waitForSelector(qrCodeSelector);
|
|
193
|
+
const qrCodeUrl = await page.$eval(qrCodeSelector, img => img.src);
|
|
194
|
+
|
|
195
|
+
await session.send(h.image(qrCodeUrl, 'image/png'));
|
|
196
|
+
await session.send('请扫描二维码进行登录。');
|
|
197
|
+
|
|
198
|
+
let attempts = 0;
|
|
199
|
+
let loginSuccessful = false;
|
|
200
|
+
|
|
201
|
+
while (attempts < 6) {
|
|
202
|
+
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait
|
|
203
|
+
const isStillLoggedIn = await page.$(loginButtonSelector) === null;
|
|
204
|
+
|
|
205
|
+
if (isStillLoggedIn) {
|
|
206
|
+
loginSuccessful = true;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
179
209
|
|
|
180
|
-
|
|
181
|
-
|
|
210
|
+
attempts++;
|
|
211
|
+
}
|
|
182
212
|
|
|
183
|
-
if (isLoggedIn) {
|
|
184
213
|
await page.close();
|
|
185
|
-
await session.send(h.text('
|
|
214
|
+
await session.send(h.text(loginSuccessful ? '登录成功!' : '登录失败,请重试。'))
|
|
186
215
|
return;
|
|
187
|
-
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
ctx.command('B站点播 [keyword]', '点播B站视频')
|
|
219
|
+
.option('video', '-v 解析返回视频')
|
|
220
|
+
.option('audio', '-a 解析返回语音')
|
|
221
|
+
.option('link', '-l 解析返回链接')
|
|
222
|
+
.option('page', '-p <page:number> 指定页数', { fallback: '1' })
|
|
223
|
+
.example('点播 遠い空へ -v')
|
|
224
|
+
.action(async ({ options, session }, keyword) => {
|
|
225
|
+
if (!keyword) {
|
|
226
|
+
await session.execute('点播 -h')
|
|
227
|
+
await session.send(h.text('没输入点播内容'))
|
|
228
|
+
return
|
|
229
|
+
}
|
|
188
230
|
|
|
189
|
-
await page.click(loginButtonSelector);
|
|
190
231
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
232
|
+
const url = `https://search.bilibili.com/video?keyword=${encodeURIComponent(keyword)}&page=${options.page}&o=30`
|
|
233
|
+
const page = await ctx.puppeteer.page()
|
|
234
|
+
|
|
235
|
+
await page.goto(url, {
|
|
236
|
+
waitUntil: 'networkidle2'
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
await page.addStyleTag({
|
|
240
|
+
content: `
|
|
241
|
+
div.bili-header,
|
|
242
|
+
div.login-tip,
|
|
243
|
+
div.v-popover,
|
|
244
|
+
div.right-entry__outside {
|
|
245
|
+
display: none !important;
|
|
246
|
+
}
|
|
247
|
+
`
|
|
248
|
+
})
|
|
249
|
+
// 获取视频列表并为每个视频元素添加序号
|
|
250
|
+
const videos = await page.evaluate((point) => {
|
|
251
|
+
const items = Array.from(document.querySelectorAll('.video-list-item:not([style*="display: none"])'))
|
|
252
|
+
return items.map((item, index) => {
|
|
253
|
+
const link = item.querySelector('a')
|
|
254
|
+
const href = link?.getAttribute('href') || ''
|
|
255
|
+
const idMatch = href.match(/\/video\/(BV\w+)\//)
|
|
256
|
+
const id = idMatch ? idMatch[1] : ''
|
|
194
257
|
|
|
195
|
-
|
|
196
|
-
|
|
258
|
+
if (!id) {
|
|
259
|
+
// 如果没有提取到视频ID,隐藏这个元素
|
|
260
|
+
//const htmlElement = item as HTMLElement
|
|
261
|
+
const htmlElement = item
|
|
262
|
+
htmlElement.style.display = 'none'
|
|
263
|
+
} else {
|
|
264
|
+
// 创建一个包含序号的元素,并将其插入到视频元素的正中央
|
|
265
|
+
const overlay = document.createElement('div')
|
|
266
|
+
overlay.style.position = 'absolute'
|
|
267
|
+
overlay.style.top = `${point[0]}%`
|
|
268
|
+
overlay.style.left = `${point[1]}%`
|
|
269
|
+
overlay.style.transform = 'translate(-50%, -50%)'
|
|
270
|
+
overlay.style.fontSize = '48px'
|
|
271
|
+
overlay.style.fontWeight = 'bold'
|
|
272
|
+
overlay.style.color = 'black'
|
|
273
|
+
overlay.style.zIndex = '10'
|
|
274
|
+
overlay.style.backgroundColor = 'rgba(255, 255, 255, 0.7)' // 半透明白色背景,确保数字清晰可见
|
|
275
|
+
overlay.style.padding = '10px'
|
|
276
|
+
overlay.style.borderRadius = '8px'
|
|
277
|
+
overlay.textContent = `${index + 1}` // 序号
|
|
278
|
+
|
|
279
|
+
// 确保父元素有 `position: relative` 以正确定位
|
|
280
|
+
//const videoElement = item as HTMLElement
|
|
281
|
+
const videoElement = item
|
|
282
|
+
videoElement.style.position = 'relative'
|
|
283
|
+
videoElement.appendChild(overlay)
|
|
284
|
+
}
|
|
197
285
|
|
|
198
|
-
|
|
199
|
-
|
|
286
|
+
return { id }
|
|
287
|
+
}).filter(video => video.id)
|
|
288
|
+
}, config.point) // 传递配置的 point 参数
|
|
200
289
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
290
|
+
// 如果开启了日志调试模式,打印获取到的视频信息
|
|
291
|
+
if (config.loggerinfo) {
|
|
292
|
+
ctx.logger.info(options)
|
|
293
|
+
ctx.logger.info(`共找到 ${videos.length} 个视频:`)
|
|
294
|
+
videos.forEach((video, index) => {
|
|
295
|
+
ctx.logger.info(`序号 ${index + 1}: ID - ${video.id}`)
|
|
296
|
+
})
|
|
297
|
+
}
|
|
204
298
|
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
|
|
299
|
+
if (videos.length === 0) {
|
|
300
|
+
await page.close()
|
|
301
|
+
await session.send(h.text('未找到相关视频。'))
|
|
302
|
+
return
|
|
208
303
|
}
|
|
209
304
|
|
|
210
|
-
|
|
211
|
-
|
|
305
|
+
// 动态调整窗口大小以适应视频数量
|
|
306
|
+
const viewportHeight = 200 + videos.length * 100
|
|
307
|
+
await page.setViewport({
|
|
308
|
+
width: 1440,
|
|
309
|
+
height: viewportHeight
|
|
310
|
+
})
|
|
311
|
+
let msg;
|
|
312
|
+
// 截图
|
|
313
|
+
const videoListElement = await page.$('.video-list.row')
|
|
314
|
+
if (videoListElement) {
|
|
315
|
+
const imgBuf = await videoListElement.screenshot({
|
|
316
|
+
captureBeyondViewport: false
|
|
317
|
+
})
|
|
318
|
+
msg = h.image(imgBuf, 'image/png')
|
|
319
|
+
}
|
|
212
320
|
|
|
213
|
-
|
|
214
|
-
await session.send(h.text(loginSuccessful ? '登录成功!' : '登录失败,请重试。'))
|
|
215
|
-
return;
|
|
216
|
-
});
|
|
321
|
+
await page.close()
|
|
217
322
|
|
|
323
|
+
// 发送截图
|
|
324
|
+
await session.send(msg)
|
|
325
|
+
|
|
326
|
+
// 提示用户输入
|
|
327
|
+
await session.send(`请选择视频的序号:`)
|
|
328
|
+
|
|
329
|
+
// 等待用户输入
|
|
330
|
+
const userChoice = await session.prompt(config.timeout * 1000)
|
|
331
|
+
const choiceIndex = parseInt(userChoice) - 1
|
|
332
|
+
if (isNaN(choiceIndex) || choiceIndex < 0 || choiceIndex >= videos.length) {
|
|
333
|
+
await session.send(h.text('输入无效,请输入正确的序号。'))
|
|
334
|
+
return
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// 返回用户选择的视频ID
|
|
338
|
+
const chosenVideo = videos[choiceIndex]
|
|
339
|
+
|
|
340
|
+
// 如果开启了日志调试模式,打印用户选择的视频信息
|
|
341
|
+
if (config.loggerinfo) {
|
|
342
|
+
ctx.logger.info(`渲染序号设置\noverlay.style.top = ${config.point[0]}% \noverlay.style.left = ${config.point[1]}%`)
|
|
343
|
+
ctx.logger.info(`用户选择了序号 ${choiceIndex + 1}: ID - ${chosenVideo.id}`)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (config.enable) { // 开启自动解析了
|
|
347
|
+
session.content = `https://www.bilibili.com/video/${chosenVideo.id}`
|
|
348
|
+
const ret = await extractLinks(session, config, ctx, lastProcessedUrls, logger); // 提取链接
|
|
349
|
+
if (ret && !isLinkProcessedRecently(ret, lastProcessedUrls, config, logger)) {
|
|
350
|
+
await processVideoFromLink(session, config, ctx, lastProcessedUrls, logger, ret, options); // 解析视频并返回
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
})
|
|
354
|
+
}
|
|
218
355
|
if (config.loggerinfo) {
|
|
219
356
|
ctx.command('B站点播/调试点播 [keyword]', '调试时点播B站视频')
|
|
220
357
|
.option('video', '-v 解析返回视频')
|
|
@@ -322,196 +459,6 @@ function apply(ctx, config) {
|
|
|
322
459
|
}
|
|
323
460
|
});
|
|
324
461
|
}
|
|
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
462
|
//判断是否需要解析
|
|
516
463
|
async function isProcessLinks(session, config, ctx, lastProcessedUrls, logger) {
|
|
517
464
|
// 解析内容中的链接
|
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.4",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
8
8
|
"files": [
|