dsh-shlr-bilitoolkit 0.1.9 → 0.1.11

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/AGENTS.md ADDED
@@ -0,0 +1,43 @@
1
+ # AGENTS.md — dsh-bili-toolkit 使用约定(Agent 必读)
2
+
3
+ > 本文件面向使用本插件的 agent。**处理任何「B 站登录」相关请求前,必须先读这里,并按下面的规则执行。**
4
+
5
+ ## 登录(最重要,务必遵守)
6
+
7
+ 当用户说「登录 B 站」「扫码登录」「登陆一下」,或任何需要登录的操作返回未登录
8
+ (业务码 `-101` / `CookieError` / 提示「未登录 / 请先登录」)时,按顺序做:
9
+
10
+ 1. **必须调用 `bili_gen_qr`** —— 这是登录 B 站的唯一入口。它会返回二维码图片:
11
+ `qrDataUrl`(base64 data URL)、`qrImageUrl`(`file://` 链接)、`qrImagePath`(本地 PNG 绝对路径)。
12
+ 2. **必须把二维码图片原样展示给用户**:用 Markdown 图片 `![B站登录二维码](<qrDataUrl>)`
13
+ (或引用 `qrImageUrl` / `qrImagePath`),让用户能直接扫。
14
+ 3. 提示用户用「哔哩哔哩」App 扫描该二维码,并在手机上点「确认登录」。
15
+ 4. 用户确认后,调用 `bili_login_status` 轮询确认——成功后会自动把 Cookie 保存到
16
+ `bili_data/bili_cookies.json`。
17
+
18
+ **禁止事项:**
19
+ - 不要用 ASCII / 文本二维码代替图片。
20
+ - 不要只扔一个链接给用户、不展示图片。
21
+ - 不要让用户自己去终端跑 `npm run login`(除非明确处于终端 / CLI 环境)。
22
+ - 不要在未展示二维码的情况下就回复「请登录」。
23
+
24
+ ## 数据位置
25
+
26
+ 统一放在数据目录(默认 `bili_data/`,相对 dsh 工作目录,可用 `BILI_DATA_DIR` 改):
27
+
28
+ | 文件 | 用途 |
29
+ | --- | --- |
30
+ | `bili_cookies.json` | 登录 Cookie(SESSDATA / bili_jct) |
31
+ | `bili_cache.json` | WBI 签名密钥 + bvid→aid 缓存 |
32
+ | `bili_qrcode.png` | 最近一次生成的登录二维码 |
33
+ | `bili_device.json` | 私信设备号 dev_id(跨重启稳定,勿频繁变动) |
34
+
35
+ ## 写操作需确认
36
+
37
+ 点赞 / 收藏 / 投币 / 关注 / 评论 / 私信 / 三连 / 发动态 / 改资料等会**真实修改账号状态**,
38
+ 执行前应先与用户确认。投币不可退回。
39
+
40
+ ## 遇到签名失效
41
+
42
+ 若请求报 `-403` / `-352`(WBI 签名失效),可调用 `bili_cache_clear` 清空缓存后重试;
43
+ 不影响 Cookie / 登录态。
package/README.md CHANGED
@@ -75,10 +75,12 @@ const [ups, _] = await client.space.videos(574115689, 1, 10);
75
75
  - 写操作:`bili_like` / `bili_follow` / `bili_favorite` / `bili_send_comment` / `bili_send_message` / `bili_triple` / `bili_dynamic_publish` / `bili_dynamic_repost` / `bili_coin` / `bili_unfavorite` / `bili_fav_folder_create` / `bili_fav_folder_delete` / `bili_dynamic_like` / `bili_dynamic_delete` / `bili_comment_send` / `bili_comment_reply` / `bili_comment_delete` / `bili_message_recall` / `bili_profile_update_sign` / `bili_profile_update`(均会真实修改账号状态,需登录)
76
76
  - 辅助:`bili_login_status`(查登录态)/ `bili_gen_qr`(生成扫码登录二维码)/ `bili_cache_clear`(清空本地缓存)
77
77
  - 工具读取 `BILI_COOKIE_FILE`(默认 `bili_data/bili_cookies.json`)作为登录态。
78
- - **数据目录**:Cookie / 缓存 / 二维码统一放在一个目录里,默认 `bili_data/`(相对 dsh 工作目录),避免散落污染工作目录。可用 `BILI_DATA_DIR` 改目录;`BILI_COOKIE_FILE` / `BILI_CACHE_FILE` / `BILI_QR_FILE` 可精确指定单个文件。兼容旧版:若新目录还没有 Cookie、而旧位置(`./bili_cookies.json`)有,会继续沿用旧的。
78
+ - **数据目录**:Cookie / 缓存 / 二维码 / 设备号统一放在一个目录里,默认 `bili_data/`(相对 dsh 工作目录),避免散落污染工作目录。可用 `BILI_DATA_DIR` 改目录;`BILI_COOKIE_FILE` / `BILI_CACHE_FILE` / `BILI_QR_FILE` / `BILI_DEVICE_FILE` 可精确指定单个文件。设备号(私信 `dev_id`)会落盘到 `bili_data/bili_device.json`,跨重启保持稳定,避免被 B 站当成新设备触发风控。兼容旧版:若新目录还没有 Cookie、而旧位置(`./bili_cookies.json`)有,会继续沿用旧的。
79
79
  - **扫码登录(独立获取 Cookie)**:运行 `npm run login`,终端会打印 ASCII 二维码,用「哔哩哔哩」App 扫码并确认后,Cookie 自动写入 `bili_data/bili_cookies.json`。也可在对话里先调 `bili_login_status` 查登录态、调 `bili_gen_qr` 拿二维码链接与可直接展示的 `ascii` 二维码。写操作(点赞 / 收藏 / 投币 / 关注 / 评论 / 私信 / 三连)都依赖该 Cookie 中的 `SESSDATA` / `bili_jct`。
80
80
  - **缓存持久化**:除 Cookie 外,客户端还会把 WBI 签名密钥(`B 站每天轮换`)、`bvid→aid` 映射这类稳定 / 带 TTL 的数据写入本地 JSON 缓存(`BILI_CACHE_FILE`,默认 `bili_data/bili_cache.json`),用临时文件 + 原子替换落盘、文件损坏会自动自愈。冷启动或跨进程时直接复用,避免每次都请求 `nav` 接口;密钥过期或失效时 `refresh()` 会重新拉取并覆盖缓存。若签名反复报 `-403/-352`,可调用 `bili_cache_clear` 强制清空缓存后重试(不影响 Cookie / 登录态)。
81
81
 
82
+ > **给 Agent 的约定**:仓库根目录的 [`AGENTS.md`](./AGENTS.md) 写明了登录流程——需要登录时必须调用 `bili_gen_qr` 并把二维码**图片**展示给用户,而不是只给链接或 ASCII。把这份 `AGENTS.md` 放到 dsh 的工作目录(或确保你的 dsh 会读取它),agent 就会按约定输出登录二维码。
83
+
82
84
  安装到 dsh(任选其一,取决于你的发行方式):
83
85
 
84
86
  ```bash
@@ -6,6 +6,13 @@ web 端私信要求带一个 UUID 形式的 msg[dev_id];同一 client 实例
6
6
  import type { BiliClient } from "../client.js";
7
7
  import { PrivateMessage } from "../models.js";
8
8
  export declare function generateDevId(): string;
9
+ /** 读取或生成一个稳定的设备号(dev_id)并落盘。
10
+ *
11
+ * B 站私信要求带设备号;同一设备应保持稳定,频繁变化易被判定为异常 / 触发风控。
12
+ * 传入文件路径时:存在则读取(JSON `{ devId }` 或 JSON 字符串),否则生成并写入;
13
+ * 读取 / 解析失败则重新生成并覆盖。不传路径时退化为内存生成(不落盘)。
14
+ */
15
+ export declare function resolveDevId(file?: string): string;
9
16
  export declare class MessageAPI {
10
17
  private client;
11
18
  constructor(client: BiliClient, devId?: string);
@@ -4,6 +4,8 @@ web 端私信要求带一个 UUID 形式的 msg[dev_id];同一 client 实例
4
4
  避免每次都被当成新设备。dev_id 生成本次会话内稳定即可(不落盘)。
5
5
  */
6
6
  import { randomInt } from "node:crypto";
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
+ import { dirname, resolve } from "node:path";
7
9
  import * as endpoints from "../endpoints.js";
8
10
  import { BiliApiError, CookieError } from "../errors.js";
9
11
  import { PrivateMessage } from "../models.js";
@@ -28,6 +30,39 @@ export function generateDevId() {
28
30
  }
29
31
  return out;
30
32
  }
33
+ /** 读取或生成一个稳定的设备号(dev_id)并落盘。
34
+ *
35
+ * B 站私信要求带设备号;同一设备应保持稳定,频繁变化易被判定为异常 / 触发风控。
36
+ * 传入文件路径时:存在则读取(JSON `{ devId }` 或 JSON 字符串),否则生成并写入;
37
+ * 读取 / 解析失败则重新生成并覆盖。不传路径时退化为内存生成(不落盘)。
38
+ */
39
+ export function resolveDevId(file) {
40
+ if (!file)
41
+ return generateDevId();
42
+ try {
43
+ if (existsSync(file)) {
44
+ const text = readFileSync(file, "utf-8").trim();
45
+ if (text) {
46
+ const parsed = JSON.parse(text);
47
+ const id = typeof parsed === "string" ? parsed : parsed?.devId;
48
+ if (typeof id === "string" && id.trim())
49
+ return id.trim();
50
+ }
51
+ }
52
+ }
53
+ catch {
54
+ // 读取 / 解析失败 → 重新生成并覆盖
55
+ }
56
+ const id = generateDevId();
57
+ try {
58
+ mkdirSync(dirname(resolve(file)), { recursive: true });
59
+ writeFileSync(file, JSON.stringify({ devId: id }, null, 2), "utf-8");
60
+ }
61
+ catch {
62
+ // 只读 / 无权限:忽略,仍返回内存 id
63
+ }
64
+ return id;
65
+ }
31
66
  export class MessageAPI {
32
67
  client;
33
68
  constructor(client, devId) {
package/dist/client.d.ts CHANGED
@@ -28,6 +28,7 @@ export declare const DEFAULT_HEADERS: Record<string, string>;
28
28
  export interface BiliClientOptions {
29
29
  cookieFile?: string;
30
30
  cacheFile?: string;
31
+ deviceFile?: string;
31
32
  timeout?: number;
32
33
  minInterval?: number;
33
34
  jitter?: number;
package/dist/client.js CHANGED
@@ -18,7 +18,7 @@ import { VideoAPI } from "./apis/video.js";
18
18
  import { SearchAPI } from "./apis/search.js";
19
19
  import { SpaceAPI } from "./apis/space.js";
20
20
  import { CommentAPI } from "./apis/comment.js";
21
- import { MessageAPI } from "./apis/message.js";
21
+ import { MessageAPI, resolveDevId } from "./apis/message.js";
22
22
  import { NotifyAPI } from "./apis/notify.js";
23
23
  import { InteractAPI } from "./apis/interact.js";
24
24
  import { RelationAPI } from "./apis/relation.js";
@@ -77,7 +77,7 @@ export class BiliClient {
77
77
  this.search = new SearchAPI(this);
78
78
  this.space = new SpaceAPI(this);
79
79
  this.comment = new CommentAPI(this);
80
- this.message = new MessageAPI(this);
80
+ this.message = new MessageAPI(this, resolveDevId(opts.deviceFile ?? "bili_device.json"));
81
81
  this.notify = new NotifyAPI(this);
82
82
  this.interact = new InteractAPI(this);
83
83
  this.relation = new RelationAPI(this);
package/dist/dsh.js CHANGED
@@ -43,6 +43,7 @@ async function getClient() {
43
43
  cached = new BiliClient({
44
44
  cookieFile: resolveCookieFile(),
45
45
  cacheFile: process.env.BILI_CACHE_FILE ?? resolve(dataDir(), "bili_cache.json"),
46
+ deviceFile: process.env.BILI_DEVICE_FILE ?? resolve(dataDir(), "bili_device.json"),
46
47
  });
47
48
  // 没有 Cookie 文件(或为空 / 损坏)= 未登录(匿名)。
48
49
  // 不能因此让所有工具崩掉——公开接口、以及最关键的扫码登录入口都依赖这里。
@@ -961,7 +962,7 @@ export const TOOLS = [
961
962
  // ---- 登录状态 ----
962
963
  {
963
964
  id: "bili_login_status",
964
- description: "查询当前是否已登录 B 站(返回用户名)。若此前调用过 bili_gen_qr,本工具会顺带轮询扫码状态:用户扫码并在手机确认后,这里返回登录成功并自动保存 Cookie。",
965
+ description: "查询当前是否已登录 B 站(返回用户名)。【用户想登录、或任何需登录操作报未登录(-101/CookieError)时,先调用本工具】;若返回未登录,必须立即调用 bili_gen_qr 向用户展示登录二维码图片。若此前调用过 bili_gen_qr,本工具会顺带轮询扫码状态:用户扫码并在手机确认后,返回登录成功并自动保存 Cookie。",
965
966
  parameters: { type: "object", properties: {} },
966
967
  handler: async () => {
967
968
  const c = await getClient();
@@ -1010,7 +1011,7 @@ export const TOOLS = [
1010
1011
  },
1011
1012
  {
1012
1013
  id: "bili_gen_qr",
1013
- description: "生成 B 站扫码登录二维码图片。返回二维码内容链接 url、轮询用的 qrcodeKey,以及可供 dsh 自行获取/渲染的二维码图片:qrDataUrl(base64 data URL)、qrImageUrl(file:// 链接)、qrImagePath(本地 PNG 绝对路径)。用户扫码确认后,调用 bili_login_status 完成登录并保存 Cookie。",
1014
+ description: "【B 站登录唯一入口】生成 B 站扫码登录二维码图片。调用后必须把返回的二维码图片展示给用户扫码(用 qrDataUrl / qrImageUrl / qrImagePath 渲染成图片),不要只给链接、不要让用户手动跑命令。返回:url(二维码内容链接)、qrcodeKey(轮询用)、qrDataUrl(base64 data URL)、qrImageUrl(file:// 链接)、qrImagePath(本地 PNG 绝对路径)。用户扫码确认后,调用 bili_login_status 完成登录并保存 Cookie。",
1014
1015
  parameters: { type: "object", properties: {} },
1015
1016
  handler: async () => {
1016
1017
  const c = await getClient();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-shlr-bilitoolkit",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "深海猎人专用B站接口工具箱 dsh 插件。",
5
5
  "type": "module",
6
6
  "main": "dist/dsh.js",
@@ -11,7 +11,8 @@
11
11
  },
12
12
  "files": [
13
13
  "dist",
14
- "cordis.patch.yml"
14
+ "cordis.patch.yml",
15
+ "AGENTS.md"
15
16
  ],
16
17
  "scripts": {
17
18
  "build": "tsc -p tsconfig.json",