dsh-shlr-bilitoolkit 0.1.2 → 0.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/dist/dsh.d.ts +3 -0
- package/dist/dsh.js +141 -19
- package/package.json +2 -2
package/dist/dsh.d.ts
CHANGED
|
@@ -18,6 +18,9 @@ export interface DshTool {
|
|
|
18
18
|
description: string;
|
|
19
19
|
parameters: Record<string, unknown>;
|
|
20
20
|
handler: (args: any) => Promise<unknown>;
|
|
21
|
+
render?: (args: any, value: any) => any[];
|
|
22
|
+
presentationMeta?: (args: any, value: any) => unknown;
|
|
23
|
+
presentResult?: (args: any, result: any) => any;
|
|
21
24
|
}
|
|
22
25
|
export declare const TOOLS: DshTool[];
|
|
23
26
|
export declare function apply(ctx: any): void;
|
package/dist/dsh.js
CHANGED
|
@@ -13,16 +13,29 @@ import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
|
13
13
|
import QRCode from "qrcode";
|
|
14
14
|
import { BiliClient } from "./client.js";
|
|
15
15
|
import { Collection, Page, PlayInfo, Subtitle, User, Video } from "./models.js";
|
|
16
|
-
|
|
16
|
+
import { QR_STATUS_EXPIRED, QR_STATUS_SCANNED, QR_STATUS_SUCCESS, } from "./apis/auth.js";
|
|
17
|
+
// 插件入口必须导出的字段(Cordis 据此识别并注入相应服务)
|
|
17
18
|
export const name = "bili-toolkit";
|
|
18
|
-
|
|
19
|
+
// tools:注册工具;attachments:把二维码等图片登记成可在 UI 渲染的持久附件
|
|
20
|
+
export const inject = ["tools", "attachments"];
|
|
19
21
|
let cached = null;
|
|
22
|
+
// 附件服务(apply 时从 ctx 捕获);缺失时二维码退化为文本
|
|
23
|
+
let attachmentStore = null;
|
|
24
|
+
// 最近一次生成、等待扫码确认的二维码 key(登录完成链路用)
|
|
25
|
+
let pendingQrKey = null;
|
|
20
26
|
async function getClient() {
|
|
21
27
|
if (!cached) {
|
|
22
28
|
cached = new BiliClient({
|
|
23
29
|
cookieFile: process.env.BILI_COOKIE_FILE ?? "bili_cookies.json",
|
|
24
30
|
});
|
|
25
|
-
|
|
31
|
+
// 没有 Cookie 文件(或为空 / 损坏)= 未登录(匿名)。
|
|
32
|
+
// 不能因此让所有工具崩掉——公开接口、以及最关键的扫码登录入口都依赖这里。
|
|
33
|
+
try {
|
|
34
|
+
await cached.loadCookies();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// 按未登录处理:匿名可用公开接口;需要登录的操作会再由接口层报错
|
|
38
|
+
}
|
|
26
39
|
}
|
|
27
40
|
return cached;
|
|
28
41
|
}
|
|
@@ -406,27 +419,127 @@ export const TOOLS = [
|
|
|
406
419
|
// ---- 登录状态 ----
|
|
407
420
|
{
|
|
408
421
|
id: "bili_login_status",
|
|
409
|
-
description: "查询当前是否已登录 B
|
|
422
|
+
description: "查询当前是否已登录 B 站(返回用户名)。若此前调用过 bili_gen_qr,本工具会顺带轮询扫码状态:用户扫码并在手机确认后,这里返回登录成功并自动保存 Cookie。",
|
|
410
423
|
parameters: { type: "object", properties: {} },
|
|
411
424
|
handler: async () => {
|
|
412
425
|
const c = await getClient();
|
|
413
426
|
const account = await c.getAccount();
|
|
427
|
+
if (account) {
|
|
428
|
+
return { isLoggedIn: true, username: account.uname, mid: account.mid };
|
|
429
|
+
}
|
|
430
|
+
// 未登录:若有等待确认的扫码,轮询一次
|
|
431
|
+
if (pendingQrKey) {
|
|
432
|
+
const [code, message] = await c.auth.poll(pendingQrKey);
|
|
433
|
+
if (code === QR_STATUS_SUCCESS) {
|
|
434
|
+
await c.saveCookies();
|
|
435
|
+
pendingQrKey = null;
|
|
436
|
+
const acc = await c.getAccount();
|
|
437
|
+
return {
|
|
438
|
+
isLoggedIn: true,
|
|
439
|
+
justLoggedIn: true,
|
|
440
|
+
username: acc?.uname ?? null,
|
|
441
|
+
mid: acc?.mid ?? null,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
if (code === QR_STATUS_EXPIRED) {
|
|
445
|
+
pendingQrKey = null;
|
|
446
|
+
return {
|
|
447
|
+
isLoggedIn: false,
|
|
448
|
+
qrStatus: "expired",
|
|
449
|
+
hint: "二维码已过期,请重新调用 bili_gen_qr 生成新的二维码。",
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
isLoggedIn: false,
|
|
454
|
+
qrStatus: code === QR_STATUS_SCANNED ? "scanned" : "waiting",
|
|
455
|
+
hint: code === QR_STATUS_SCANNED
|
|
456
|
+
? "已扫码,请在手机上点击「确认登录」,然后再调用一次 bili_login_status。"
|
|
457
|
+
: "请用「哔哩哔哩」App 扫描刚生成的二维码,确认后再调用 bili_login_status。",
|
|
458
|
+
message,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
414
461
|
return {
|
|
415
|
-
isLoggedIn:
|
|
416
|
-
username:
|
|
417
|
-
mid:
|
|
462
|
+
isLoggedIn: false,
|
|
463
|
+
username: null,
|
|
464
|
+
mid: null,
|
|
465
|
+
hint: "未登录,请先调用 bili_gen_qr 生成登录二维码。",
|
|
418
466
|
};
|
|
419
467
|
},
|
|
420
468
|
},
|
|
421
469
|
{
|
|
422
470
|
id: "bili_gen_qr",
|
|
423
|
-
description: "生成 B
|
|
471
|
+
description: "生成 B 站扫码登录二维码,并在对话中以「图片」形式展示(用「哔哩哔哩」App 扫码)。返回二维码内容链接 url 与轮询用的 qrcodeKey。用户扫码确认后,调用 bili_login_status 完成登录并保存 Cookie。",
|
|
424
472
|
parameters: { type: "object", properties: {} },
|
|
425
473
|
handler: async () => {
|
|
426
474
|
const c = await getClient();
|
|
427
475
|
const [url, key] = await c.auth.generate();
|
|
428
|
-
|
|
429
|
-
|
|
476
|
+
pendingQrKey = key;
|
|
477
|
+
// 生成 PNG 二维码并登记为附件,供 UI 以图片渲染
|
|
478
|
+
let qrImage = null;
|
|
479
|
+
try {
|
|
480
|
+
const png = await QRCode.toBuffer(url, {
|
|
481
|
+
type: "png",
|
|
482
|
+
errorCorrectionLevel: "M",
|
|
483
|
+
margin: 2,
|
|
484
|
+
width: 320,
|
|
485
|
+
});
|
|
486
|
+
if (attachmentStore?.saveImage) {
|
|
487
|
+
qrImage = await attachmentStore.saveImage({
|
|
488
|
+
data: new Uint8Array(png),
|
|
489
|
+
mediaType: "image/png",
|
|
490
|
+
name: "bili-login-qr.png",
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
qrImage = null; // 附件不可用时退化为下方 ascii
|
|
496
|
+
}
|
|
497
|
+
// ascii 仅作为附件不可用时的兜底
|
|
498
|
+
let ascii = null;
|
|
499
|
+
if (!qrImage) {
|
|
500
|
+
try {
|
|
501
|
+
ascii = await QRCode.toString(url, { type: "utf8" });
|
|
502
|
+
}
|
|
503
|
+
catch {
|
|
504
|
+
ascii = null;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return { url, qrcodeKey: key, qrImage, ascii };
|
|
508
|
+
},
|
|
509
|
+
// 面向模型的文本:不塞图片 / ascii,给指引即可
|
|
510
|
+
render: (_args, value) => [
|
|
511
|
+
{
|
|
512
|
+
type: "text",
|
|
513
|
+
text: "已生成 B 站登录二维码(已在界面上以图片展示)。请让用户用「哔哩哔哩」App 扫码," +
|
|
514
|
+
"并在手机上确认登录;用户确认后,调用 bili_login_status 查询登录态并保存 Cookie。" +
|
|
515
|
+
`qrcodeKey=${value?.qrcodeKey ?? ""}`,
|
|
516
|
+
},
|
|
517
|
+
],
|
|
518
|
+
// 把图片引用 / ascii / url 透传给 presentResult(仅 UI 用)
|
|
519
|
+
presentationMeta: (_args, value) => ({
|
|
520
|
+
qrImage: value?.qrImage ?? null,
|
|
521
|
+
ascii: value?.ascii ?? null,
|
|
522
|
+
url: value?.url ?? null,
|
|
523
|
+
}),
|
|
524
|
+
// UI 呈现:优先渲染图片二维码;无附件时退化为 ascii 代码块 + 链接
|
|
525
|
+
presentResult: (_args, result) => {
|
|
526
|
+
const meta = (result?.meta ?? {});
|
|
527
|
+
const content = [];
|
|
528
|
+
if (meta.qrImage) {
|
|
529
|
+
content.push({ type: "image", attachment: meta.qrImage });
|
|
530
|
+
content.push({
|
|
531
|
+
type: "text",
|
|
532
|
+
text: "请用「哔哩哔哩」App 扫描上方二维码,并在手机上确认登录。",
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
else if (meta.ascii) {
|
|
536
|
+
content.push({ type: "text", text: "```\n" + meta.ascii + "\n```" });
|
|
537
|
+
content.push({ type: "text", text: `二维码链接:${meta.url ?? ""}` });
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
content.push({ type: "text", text: `二维码链接:${meta.url ?? ""}` });
|
|
541
|
+
}
|
|
542
|
+
return { card: "generic", title: "扫码登录 B 站", content };
|
|
430
543
|
},
|
|
431
544
|
},
|
|
432
545
|
// ---- 缓存维护 ----
|
|
@@ -442,22 +555,31 @@ export const TOOLS = [
|
|
|
442
555
|
},
|
|
443
556
|
];
|
|
444
557
|
export function apply(ctx) {
|
|
558
|
+
// 捕获附件服务,供 bili_gen_qr 把二维码登记成可在 UI 渲染的图片
|
|
559
|
+
attachmentStore = ctx?.attachments ?? null;
|
|
445
560
|
for (const tool of TOOLS) {
|
|
446
|
-
|
|
447
|
-
|
|
561
|
+
const output = {
|
|
562
|
+
schema: { type: "object", additionalProperties: true },
|
|
563
|
+
render: tool.render ??
|
|
564
|
+
((_args, value) => [{ type: "text", text: textOf(value) }]),
|
|
565
|
+
};
|
|
566
|
+
if (tool.presentationMeta) {
|
|
567
|
+
output.presentationMeta = tool.presentationMeta;
|
|
568
|
+
}
|
|
569
|
+
const options = {
|
|
448
570
|
name: tool.id,
|
|
449
571
|
description: tool.description,
|
|
450
572
|
parameters: toDshParameters(tool.parameters),
|
|
451
|
-
output
|
|
452
|
-
schema: { type: "object", additionalProperties: true },
|
|
453
|
-
render: (_args, value) => [
|
|
454
|
-
{ type: "text", text: textOf(value) },
|
|
455
|
-
],
|
|
456
|
-
},
|
|
573
|
+
output,
|
|
457
574
|
async execute(args) {
|
|
458
575
|
return await tool.handler(args);
|
|
459
576
|
},
|
|
460
|
-
}
|
|
577
|
+
};
|
|
578
|
+
if (tool.presentResult) {
|
|
579
|
+
options.presentResult = tool.presentResult;
|
|
580
|
+
}
|
|
581
|
+
// 官方路径:ctx.tools.register(defineTool({...}))
|
|
582
|
+
const def = defineTool(options);
|
|
461
583
|
if (ctx?.tools?.register) {
|
|
462
584
|
ctx.tools.register(def);
|
|
463
585
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-shlr-bilitoolkit",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "B
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "深海猎人专用B站接口工具箱 dsh 插件。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/dsh.js",
|
|
7
7
|
"types": "dist/dsh.d.ts",
|