baiduwangpan-cli 1.0.0 → 1.0.2
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/README.md +66 -3
- package/bin/bdp.js +247 -24
- package/lib/browser-login.js +432 -0
- package/lib/config.js +18 -2
- package/lib/group.js +345 -56
- package/lib/http.js +38 -6
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -65,13 +65,25 @@ npm link # 全局注册 bdp 命令
|
|
|
65
65
|
|
|
66
66
|
### 2. 配置认证
|
|
67
67
|
|
|
68
|
+
**方式一:浏览器自动登录(推荐)**
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
bdp login
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
自动启动 Chrome/Edge → 打开百度网盘登录页 → **手机扫码** → 在页面会话内验证登录 → 自动同步引擎。无需 F12。
|
|
75
|
+
|
|
76
|
+
扫码产生的新会话可能被百度限制为只能在原浏览器上下文中使用。因此 `bdp` 会保留专用 profile,并在登录后将浏览器最小化;PCS API 继续使用 BDUSS/STOKEN,网页和群聊 API 通过该浏览器的 CDP 会话调用。浏览器被关闭后,下次网页 API 调用会使用同一 profile 自动重启。
|
|
77
|
+
|
|
78
|
+
**方式二:手动凭证**
|
|
79
|
+
|
|
68
80
|
```bash
|
|
69
81
|
bdp login --bduss <你的BDUSS> --stoken <你的STOKEN>
|
|
70
82
|
bdp whoami # 验证
|
|
71
83
|
```
|
|
72
84
|
|
|
73
85
|
<details>
|
|
74
|
-
<summary>📋 如何获取 BDUSS 和 STOKEN
|
|
86
|
+
<summary>📋 如何获取 BDUSS 和 STOKEN(手动方式)</summary>
|
|
75
87
|
|
|
76
88
|
1. 浏览器打开 [pan.baidu.com](https://pan.baidu.com) 并登录
|
|
77
89
|
2. 按 `F12` → **Application** → **Cookies** → `https://pan.baidu.com`
|
|
@@ -79,6 +91,8 @@ bdp whoami # 验证
|
|
|
79
91
|
|
|
80
92
|
> ⚠️ STOKEN 必须在百度网盘页面获取(不是百度首页),值中应包含大写字母。
|
|
81
93
|
|
|
94
|
+
> 💡 推荐直接运行 `bdp login`,全程自动化,无需手动操作。
|
|
95
|
+
|
|
82
96
|
</details>
|
|
83
97
|
|
|
84
98
|
### 3. 开始使用
|
|
@@ -183,7 +197,7 @@ const results = await group.searchFiles('539478953581833690', '倪海厦');
|
|
|
183
197
|
│ lib/pan.js │ lib/group.js │
|
|
184
198
|
│ 全盘文件操作 │ 群聊文件浏览 │
|
|
185
199
|
├──────────────────┼──────────────────────────────────┤
|
|
186
|
-
│ BaiduPCS-Go │
|
|
200
|
+
│ BaiduPCS-Go │ lib/http.js (curl / browser) │
|
|
187
201
|
│ (BDUSS 认证) │ mbox API (逆向) │
|
|
188
202
|
│ locate → dlink │ /mbox/group/listshare │
|
|
189
203
|
│ upload/download │ /mbox/msg/shareinfo │
|
|
@@ -237,14 +251,63 @@ baiduwangpan-cli/
|
|
|
237
251
|
├── lib/
|
|
238
252
|
│ ├── index.js # 库导出
|
|
239
253
|
│ ├── config.js # 配置管理 (~/.bdp/config.json)
|
|
240
|
-
│ ├── http.js #
|
|
254
|
+
│ ├── http.js # 网页 API 双传输 (curl / browser)
|
|
255
|
+
│ ├── browser-login.js # 浏览器登录、持久 profile 与 CDP 请求
|
|
241
256
|
│ ├── pan.js # 网盘操作 (BaiduPCS-Go 桥接)
|
|
242
257
|
│ └── group.js # 群聊操作 (逆向 mbox API)
|
|
258
|
+
├── test/ # Node.js 回归测试
|
|
259
|
+
├── skills/
|
|
260
|
+
│ └── baiduwangpan/ # Agent Skill 源文件 (SKILL.md + reference + scripts)
|
|
261
|
+
├── baiduwangpan-skill.zip # Agent Skill 打包 (Releases 附件)
|
|
243
262
|
├── bdp.js # 早期独立版 (保留参考)
|
|
244
263
|
├── bdp-group.js # 早期独立版 (保留参考)
|
|
245
264
|
└── bdp.py # Python 版 (备用)
|
|
246
265
|
```
|
|
247
266
|
|
|
267
|
+
## 🤖 Agent Skill 使用
|
|
268
|
+
|
|
269
|
+
本仓库附带一个标准格式的 Agent Skill,让 Claude Code / Codex / OpenClaw / Cursor 等 Agent 通过自然语言操作百度网盘。
|
|
270
|
+
|
|
271
|
+
### 安装 Skill
|
|
272
|
+
|
|
273
|
+
从 [Releases](https://github.com/NkAntony777/baiduwangpan-cli/releases) 下载 `baiduwangpan-skill.zip`,或直接复制仓库 `skills/baiduwangpan/` 文件夹:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
# 各平台 skills 目录
|
|
277
|
+
~/.claude/skills/ # Claude Code
|
|
278
|
+
~/.codex/skills/ # Codex CLI
|
|
279
|
+
~/.config/opencode/skills/ # OpenCode
|
|
280
|
+
# 或对应 Agent 的 skills 目录
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Skill 使用
|
|
284
|
+
|
|
285
|
+
Agent 加载 skill 后,自然语言即可驱动(skill 会自动触发):
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
用户: 看看我网盘里有什么
|
|
289
|
+
用户: 在群里找倪海厦的资料
|
|
290
|
+
用户: 读一下 /文档/data.csv 前几行
|
|
291
|
+
用户: 搜索网盘里所有报告文件
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
skill 会自动执行 `bdp` 命令并返回结构化结果(含 `--json` 输出)。
|
|
295
|
+
|
|
296
|
+
### Skill 内容
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
skills/baiduwangpan/
|
|
300
|
+
├── SKILL.md # 技能定义(触发规则 + 命令规范 + 安全边界)
|
|
301
|
+
├── reference/
|
|
302
|
+
│ ├── commands.md # 完整命令参考
|
|
303
|
+
│ ├── authentication.md # 凭证获取与配置
|
|
304
|
+
│ ├── examples.md # Agent 使用示例 + JSON 输出格式
|
|
305
|
+
│ └── troubleshooting.md # 故障排查
|
|
306
|
+
└── scripts/
|
|
307
|
+
├── setup.sh # macOS/Linux 自动安装
|
|
308
|
+
└── setup.ps1 # Windows 自动安装
|
|
309
|
+
```
|
|
310
|
+
|
|
248
311
|
## ⚠️ 注意事项
|
|
249
312
|
|
|
250
313
|
- **BDUSS 有效期**:Cookie 会过期,失效后重新执行 `bdp login`
|
package/bin/bdp.js
CHANGED
|
@@ -52,12 +52,38 @@ function output(data, jsonFlag, formatter) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
function emitJson(data, args) {
|
|
56
|
+
const json = JSON.stringify(data, null, 2);
|
|
57
|
+
if (args.flags.jsonFile) {
|
|
58
|
+
require("fs").writeFileSync(args.flags.jsonFile, json, "utf-8");
|
|
59
|
+
console.log(args.flags.jsonFile);
|
|
60
|
+
} else {
|
|
61
|
+
console.log(json);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function verboseLog(args, msg) {
|
|
66
|
+
if (args.flags.verbose) process.stderr.write(`[verbose] ${msg}\n`);
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
function parseArgs(argv) {
|
|
56
70
|
const opts = { _: [], flags: {} };
|
|
57
71
|
for (let i = 0; i < argv.length; i++) {
|
|
58
72
|
const arg = argv[i];
|
|
59
73
|
if (arg === "--json") {
|
|
60
74
|
opts.flags.json = true;
|
|
75
|
+
} else if (arg === "--legacy-json") {
|
|
76
|
+
opts.flags.legacyJson = true;
|
|
77
|
+
} else if (arg === "--json-file") {
|
|
78
|
+
opts.flags.jsonFile = argv[++i];
|
|
79
|
+
} else if (arg === "--verbose") {
|
|
80
|
+
opts.flags.verbose = true;
|
|
81
|
+
} else if (arg === "--unique") {
|
|
82
|
+
opts.flags.unique = true;
|
|
83
|
+
} else if (arg === "--no-unique") {
|
|
84
|
+
opts.flags.unique = false;
|
|
85
|
+
} else if (arg === "--all") {
|
|
86
|
+
opts.flags.all = true;
|
|
61
87
|
} else if (arg === "-n" || arg === "--lines") {
|
|
62
88
|
opts.flags.n = parseInt(argv[++i], 10) || 20;
|
|
63
89
|
} else if (arg === "-p" || arg === "--path") {
|
|
@@ -76,6 +102,22 @@ function parseArgs(argv) {
|
|
|
76
102
|
opts.flags.stoken = argv[++i];
|
|
77
103
|
} else if (arg === "--page") {
|
|
78
104
|
opts.flags.page = parseInt(argv[++i], 10) || 1;
|
|
105
|
+
} else if (arg === "--page-size") {
|
|
106
|
+
opts.flags.pageSize = parseInt(argv[++i], 10) || 50;
|
|
107
|
+
} else if (arg === "--limit") {
|
|
108
|
+
opts.flags.limit = parseInt(argv[++i], 10) || 50;
|
|
109
|
+
} else if (arg === "--concurrency") {
|
|
110
|
+
opts.flags.concurrency = parseInt(argv[++i], 10) || 4;
|
|
111
|
+
} else if (arg === "--depth") {
|
|
112
|
+
opts.flags.depth = parseInt(argv[++i], 10) || 2;
|
|
113
|
+
} else if (arg === "--max-nodes") {
|
|
114
|
+
opts.flags.maxNodes = parseInt(argv[++i], 10) || 2000;
|
|
115
|
+
} else if (arg === "--from-uk") {
|
|
116
|
+
opts.flags.fromUk = argv[++i];
|
|
117
|
+
} else if (arg === "--msg-id") {
|
|
118
|
+
opts.flags.msgId = argv[++i];
|
|
119
|
+
} else if (arg === "--parent-fs-id") {
|
|
120
|
+
opts.flags.parentFsId = argv[++i];
|
|
79
121
|
} else if (arg.startsWith("-")) {
|
|
80
122
|
opts.flags[arg.replace(/^-+/, "")] = true;
|
|
81
123
|
} else {
|
|
@@ -90,14 +132,77 @@ function parseArgs(argv) {
|
|
|
90
132
|
const cmds = {};
|
|
91
133
|
|
|
92
134
|
cmds.login = async (args, json) => {
|
|
93
|
-
|
|
94
|
-
if (args.flags.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
135
|
+
// 方式 1: 手动传入凭证
|
|
136
|
+
if (args.flags.bduss || args.flags.stoken) {
|
|
137
|
+
if (!args.flags.bduss || !args.flags.stoken) {
|
|
138
|
+
throw new Error("Manual login requires both --bduss and --stoken");
|
|
139
|
+
}
|
|
140
|
+
config.setAuth({
|
|
141
|
+
bduss: args.flags.bduss,
|
|
142
|
+
stoken: args.flags.stoken,
|
|
143
|
+
webTransport: "curl",
|
|
144
|
+
});
|
|
145
|
+
const cfg = config.get();
|
|
146
|
+
output(
|
|
147
|
+
{ success: true, bduss: cfg.bduss ? "***set***" : "missing", stoken: cfg.stoken ? "***set***" : "missing" },
|
|
148
|
+
json,
|
|
149
|
+
() => console.log("Credentials saved to " + config.CONFIG_FILE)
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 方式 2: 浏览器自动登录(扫码,Agent 代劳)
|
|
155
|
+
const { browserLogin } = require("../lib/browser-login");
|
|
156
|
+
const status = (msg) => {
|
|
157
|
+
if (!json) console.log(msg);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
status("🔐 bdp login: 未提供 --bduss/--stoken,启动浏览器扫码登录...");
|
|
161
|
+
try {
|
|
162
|
+
const previous = config.get();
|
|
163
|
+
const creds = await browserLogin({
|
|
164
|
+
onStatus: status,
|
|
165
|
+
profileDir: previous.browserProfile || undefined,
|
|
166
|
+
port: previous.webTransport === "browser" ? previous.browserPort : undefined,
|
|
167
|
+
});
|
|
168
|
+
config.setAuth({
|
|
169
|
+
bduss: creds.bduss,
|
|
170
|
+
stoken: creds.stoken,
|
|
171
|
+
webTransport: "browser",
|
|
172
|
+
browserProfile: creds.browserProfile,
|
|
173
|
+
browserPort: creds.browserPort,
|
|
174
|
+
});
|
|
175
|
+
status("✅ 登录成功,凭证已保存到 " + config.CONFIG_FILE);
|
|
176
|
+
|
|
177
|
+
// 同步登录 BaiduPCS-Go 引擎(全盘操作依赖)
|
|
178
|
+
try {
|
|
179
|
+
const { spawnSync } = require("child_process");
|
|
180
|
+
const cfg = config.get();
|
|
181
|
+
const loginResult = spawnSync(cfg.pcsPath, ["login", `-bduss=${creds.bduss}`, `-stoken=${creds.stoken}`], {
|
|
182
|
+
encoding: "utf-8",
|
|
183
|
+
timeout: 30000,
|
|
184
|
+
});
|
|
185
|
+
if (loginResult.stdout && loginResult.stdout.includes("登录成功")) {
|
|
186
|
+
status("✅ BaiduPCS-Go 引擎已同步登录");
|
|
187
|
+
} else {
|
|
188
|
+
status("⚠️ BaiduPCS-Go 引擎登录失败: " + (loginResult.stdout || loginResult.stderr || "未知错误").trim().substring(0, 100));
|
|
189
|
+
}
|
|
190
|
+
} catch (e) {
|
|
191
|
+
status("⚠️ BaiduPCS-Go 引擎登录异常: " + e.message);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (json) {
|
|
195
|
+
console.log(JSON.stringify({ success: true, method: "browser-qr", bduss: "***set***", stoken: "***set***" }));
|
|
196
|
+
}
|
|
197
|
+
} catch (e) {
|
|
198
|
+
if (json) {
|
|
199
|
+
console.log(JSON.stringify({ error: e.message }));
|
|
200
|
+
} else {
|
|
201
|
+
console.error(`[ERROR] ${e.message}`);
|
|
202
|
+
console.error(" 提示: 也可手动方式 bdp login --bduss <值> --stoken <值>");
|
|
203
|
+
}
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
101
206
|
};
|
|
102
207
|
|
|
103
208
|
cmds.whoami = async (args, json) => {
|
|
@@ -107,6 +212,7 @@ cmds.whoami = async (args, json) => {
|
|
|
107
212
|
loggedIn: !!(cfg.bduss && cfg.stoken),
|
|
108
213
|
bduss: cfg.bduss ? "***set***" : "missing",
|
|
109
214
|
stoken: cfg.stoken ? "***set***" : "missing",
|
|
215
|
+
webTransport: cfg.webTransport,
|
|
110
216
|
pcsPath: cfg.pcsPath,
|
|
111
217
|
configFile: config.CONFIG_FILE,
|
|
112
218
|
},
|
|
@@ -115,6 +221,7 @@ cmds.whoami = async (args, json) => {
|
|
|
115
221
|
console.log(`Status: ${d.loggedIn ? "✅ Logged in" : "❌ Not logged in"}`);
|
|
116
222
|
console.log(`BDUSS: ${d.bduss}`);
|
|
117
223
|
console.log(`STOKEN: ${d.stoken}`);
|
|
224
|
+
console.log(`Web API: ${d.webTransport}`);
|
|
118
225
|
console.log(`PCS Path: ${d.pcsPath}`);
|
|
119
226
|
console.log(`Config: ${d.configFile}`);
|
|
120
227
|
}
|
|
@@ -127,6 +234,7 @@ cmds.config = async (args, json) => {
|
|
|
127
234
|
console.log("Configuration:");
|
|
128
235
|
console.log(` bduss: ${d.bduss ? d.bduss.substring(0, 10) + "..." : "(not set)"}`);
|
|
129
236
|
console.log(` stoken: ${d.stoken ? d.stoken.substring(0, 10) + "..." : "(not set)"}`);
|
|
237
|
+
console.log(` web API: ${d.webTransport}`);
|
|
130
238
|
console.log(` pcsPath: ${d.pcsPath}`);
|
|
131
239
|
console.log(` ua: ${d.ua.substring(0, 40)}...`);
|
|
132
240
|
console.log(` maxBytes: ${d.maxBytes}`);
|
|
@@ -284,29 +392,119 @@ cmds.gshares = async (args, json) => {
|
|
|
284
392
|
cmds.gls = async (args, json) => {
|
|
285
393
|
const gid = args._[0];
|
|
286
394
|
const fsId = args._[1];
|
|
287
|
-
if (!gid || !fsId) { console.error("Usage: bdp gls <gid> <fs_id>"); process.exit(1); }
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
395
|
+
if (!gid || !fsId) { console.error("Usage: bdp gls <gid> <fs_id> [--page N] [--page-size N]"); process.exit(1); }
|
|
396
|
+
|
|
397
|
+
const opts = {
|
|
398
|
+
page: args.flags.page || 1,
|
|
399
|
+
pageSize: args.flags.pageSize || 50,
|
|
400
|
+
};
|
|
401
|
+
if (args.flags.fromUk) opts.fromUk = args.flags.fromUk;
|
|
402
|
+
if (args.flags.msgId) opts.msgId = args.flags.msgId;
|
|
403
|
+
if (args.flags.parentFsId) opts.parentFsId = args.flags.parentFsId;
|
|
404
|
+
|
|
405
|
+
verboseLog(args, `gls gid=${gid} fsId=${fsId} page=${opts.page} pageSize=${opts.pageSize}`);
|
|
406
|
+
const result = await group.listFiles(gid, fsId, opts);
|
|
407
|
+
|
|
408
|
+
if (args.flags.legacyJson) {
|
|
409
|
+
emitJson(result.files, args);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (result.fallback) {
|
|
414
|
+
verboseLog(args, `fallback: ${result.fallback.reason} -> ${result.fallback.resolvedFsId} (${result.fallback.level})`);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (args.flags.jsonFile || json) {
|
|
418
|
+
emitJson(result, args);
|
|
419
|
+
} else {
|
|
420
|
+
if (result.fallback) {
|
|
421
|
+
console.log(`⚠️ fallback: ${result.fallback.reason} — 已回退到 ${result.fallback.resolvedFsId} (${result.fallback.level})`);
|
|
422
|
+
}
|
|
423
|
+
console.log(`${result.files.length} items${result.hasMore ? " (has more — use --page)" : ""}:\n`);
|
|
424
|
+
result.files.forEach((f) => {
|
|
292
425
|
const dir = f.isDir ? "[DIR] " : " ";
|
|
293
426
|
console.log(` ${dir}${f.name} ${formatSize(f.size)} fs_id:${f.fsId}`);
|
|
294
427
|
});
|
|
295
|
-
}
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
cmds.gtree = async (args, json) => {
|
|
432
|
+
const gid = args._[0];
|
|
433
|
+
if (!gid) { console.error("Usage: bdp gtree <gid> [--depth N] [--concurrency N] [--max-nodes N]"); process.exit(1); }
|
|
434
|
+
|
|
435
|
+
const opts = {
|
|
436
|
+
depth: args.flags.depth || 2,
|
|
437
|
+
concurrency: args.flags.concurrency || 4,
|
|
438
|
+
maxNodes: args.flags.maxNodes || 2000,
|
|
439
|
+
};
|
|
440
|
+
verboseLog(args, `gtree gid=${gid} depth=${opts.depth} concurrency=${opts.concurrency} maxNodes=${opts.maxNodes}`);
|
|
441
|
+
const result = await group.treeFiles(gid, opts);
|
|
442
|
+
|
|
443
|
+
if (args.flags.jsonFile || json) {
|
|
444
|
+
emitJson(result, args);
|
|
445
|
+
} else {
|
|
446
|
+
console.log(`${result.tree.length} nodes (depth ${result.depth}, ${result.failed.length} failed${result.truncated ? ", truncated" : ""}):\n`);
|
|
447
|
+
result.tree.forEach((n) => {
|
|
448
|
+
const dir = n.isDir ? "[DIR] " : " ";
|
|
449
|
+
console.log(` ${dir}${n.path || n.name} ${formatSize(n.size)} fs_id:${n.fsId}`);
|
|
450
|
+
});
|
|
451
|
+
}
|
|
296
452
|
};
|
|
297
453
|
|
|
298
454
|
cmds.gsearch = async (args, json) => {
|
|
299
455
|
const gid = args._[0];
|
|
300
456
|
const keyword = args._[1];
|
|
301
|
-
if (!gid || !keyword) { console.error("Usage: bdp gsearch <gid> <keyword>"); process.exit(1); }
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
457
|
+
if (!gid || !keyword) { console.error("Usage: bdp gsearch <gid> <keyword> [--page N] [--limit N]"); process.exit(1); }
|
|
458
|
+
|
|
459
|
+
const opts = {
|
|
460
|
+
page: args.flags.page || 1,
|
|
461
|
+
limit: args.flags.limit || 50,
|
|
462
|
+
concurrency: args.flags.concurrency || 4,
|
|
463
|
+
unique: args.flags.unique !== false,
|
|
464
|
+
all: args.flags.all === true,
|
|
465
|
+
depth: args.flags.depth || 1,
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
verboseLog(args, `gsearch gid=${gid} keyword="${keyword}" page=${opts.page} limit=${opts.limit} concurrency=${opts.concurrency} unique=${opts.unique} all=${opts.all}`);
|
|
469
|
+
const result = await group.searchFiles(gid, keyword, opts);
|
|
470
|
+
|
|
471
|
+
if (result.partial) {
|
|
472
|
+
verboseLog(args, `partial: ${result.failedShares}/${result.totalShares} shares failed`);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (args.flags.legacyJson) {
|
|
476
|
+
emitJson(result.results, args);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (args.flags.jsonFile || json) {
|
|
481
|
+
emitJson(result, args);
|
|
482
|
+
} else {
|
|
483
|
+
console.log(`${result.returned} matches for "${keyword}"${result.hasMore ? " (has more — use --page " + (result.nextPage || "?") + ")" : ""}:\n`);
|
|
484
|
+
result.results.forEach((r) => {
|
|
306
485
|
const dir = r.isDir ? "[DIR] " : " ";
|
|
307
486
|
console.log(` ${dir}${r.path || r.name} ${formatSize(r.size)} fs_id:${r.fsId}`);
|
|
308
487
|
});
|
|
309
|
-
|
|
488
|
+
if (result.partial) {
|
|
489
|
+
console.error(`[verbose] ${result.failedShares} shares failed (partial result)`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
cmds.error = async (args, json) => {
|
|
495
|
+
const code = args._[0] || "-3";
|
|
496
|
+
const ERRORS = {
|
|
497
|
+
"-3": "群分享 API 拒绝请求。已观察到大目录、错误的 msgId/fromUk、过期分享都可能触发。\n" +
|
|
498
|
+
"处理:减小 --page-size(自动重试 50→20→10),或携带 gsearch 返回的 fromUk/msgId/parentFsId 信息重试;\n" +
|
|
499
|
+
" 若回退到父目录(fallback level=parent),Agent 应从父目录换路径继续遍历。",
|
|
500
|
+
"-6": "接口鉴权失败。通常为 access_token/cookie 失效,请重新执行 bdp login。",
|
|
501
|
+
};
|
|
502
|
+
const msg = ERRORS[code] || `未知错误码 ${code},请提交 Issue: https://github.com/NkAntony777/baiduwangpan-cli/issues`;
|
|
503
|
+
if (args.flags.jsonFile || json) {
|
|
504
|
+
emitJson({ code, description: msg }, args);
|
|
505
|
+
} else {
|
|
506
|
+
console.log(msg);
|
|
507
|
+
}
|
|
310
508
|
};
|
|
311
509
|
|
|
312
510
|
// ── Main ───────────────────────────────────────────────
|
|
@@ -332,22 +530,38 @@ PAN FILE OPERATIONS (全盘)
|
|
|
332
530
|
GROUP CHAT OPERATIONS (群聊)
|
|
333
531
|
groups List all groups
|
|
334
532
|
gshares <gid> List share libraries in group
|
|
533
|
+
gtree <gid> Build directory tree (BFS)
|
|
534
|
+
[--depth N] [--concurrency N] [--max-nodes N]
|
|
335
535
|
gls <gid> <fs_id> Browse files in a share
|
|
536
|
+
[--page N] [--page-size N] [--from-uk X] [--msg-id Y] [--parent-fs-id Z]
|
|
336
537
|
gsearch <gid> <keyword> Search group file names
|
|
538
|
+
[--page N] [--limit N] [--depth N] [--concurrency N] [--no-unique] [--all]
|
|
539
|
+
error <code> Explain an error code (e.g. -3)
|
|
337
540
|
|
|
338
541
|
CONFIGURATION
|
|
339
|
-
login
|
|
542
|
+
login Browser QR login (auto-detect cookies)
|
|
543
|
+
login --bduss X --stoken Y Save credentials manually
|
|
340
544
|
whoami Check login status
|
|
341
545
|
config Show configuration
|
|
342
546
|
|
|
343
547
|
OPTIONS
|
|
344
548
|
--json Output JSON (for Agent consumption)
|
|
549
|
+
--json-file <path> Write JSON to file (UTF-8, bypasses console encoding)
|
|
550
|
+
--legacy-json Output bare array (gls/gsearch legacy format)
|
|
551
|
+
--verbose Write progress/log to stderr only
|
|
345
552
|
-n <N> Number of lines (head/tail)
|
|
346
553
|
-p <path> Search path (search)
|
|
347
554
|
-i Ignore case (grep)
|
|
348
555
|
-N Show line numbers (cat/grep)
|
|
349
556
|
-o <dir> Output directory (get)
|
|
350
|
-
--page <N> Page number (gls)
|
|
557
|
+
--page <N> Page number (gls/gsearch)
|
|
558
|
+
--page-size <N> Page size for gls (default 50, max 100)
|
|
559
|
+
--limit <N> Page size for gsearch (default 50)
|
|
560
|
+
--depth <N> Recursive search/tree depth (gsearch default 1, gtree default 2)
|
|
561
|
+
--max-nodes <N> Tree node cap (gtree default 2000)
|
|
562
|
+
--concurrency <N> Parallel share scans for gsearch/gtree (default 4)
|
|
563
|
+
--no-unique Keep duplicates from different msgId (gsearch)
|
|
564
|
+
--all Fetch all results, no paging (gsearch, not Agent default)
|
|
351
565
|
|
|
352
566
|
EXAMPLES
|
|
353
567
|
bdp login --bduss abc123 --stoken def456
|
|
@@ -357,7 +571,10 @@ EXAMPLES
|
|
|
357
571
|
bdp groups --json
|
|
358
572
|
bdp gshares 539478953581833690
|
|
359
573
|
bdp gls 539478953581833690 742474845517885 --json
|
|
360
|
-
bdp
|
|
574
|
+
bdp gls 539478953581833690 292608024165826 --from-uk 2642611875 --msg-id 5069931974377329661 --json
|
|
575
|
+
bdp gsearch 539478953581833690 "倪海厦" --limit 20 --json
|
|
576
|
+
bdp gsearch 539478953581833690 "古籍" --page 2 --limit 20 --json-file result.json
|
|
577
|
+
bdp error -3`;
|
|
361
578
|
|
|
362
579
|
async function main() {
|
|
363
580
|
const argv = process.argv.slice(2);
|
|
@@ -372,6 +589,7 @@ async function main() {
|
|
|
372
589
|
process.exit(0);
|
|
373
590
|
}
|
|
374
591
|
|
|
592
|
+
let exitCode = 0;
|
|
375
593
|
try {
|
|
376
594
|
await handler(args, json);
|
|
377
595
|
} catch (e) {
|
|
@@ -380,8 +598,13 @@ async function main() {
|
|
|
380
598
|
} else {
|
|
381
599
|
console.error(`[ERROR] ${e.message}`);
|
|
382
600
|
}
|
|
383
|
-
|
|
601
|
+
exitCode = 1;
|
|
602
|
+
} finally {
|
|
603
|
+
try {
|
|
604
|
+
require("../lib/browser-login").disconnectBrowserSession();
|
|
605
|
+
} catch {}
|
|
384
606
|
}
|
|
607
|
+
process.exit(exitCode);
|
|
385
608
|
}
|
|
386
609
|
|
|
387
610
|
main();
|