baiduwangpan-cli 1.1.1 → 1.1.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 +2 -1
- package/bin/bdp.js +33 -11
- package/lib/partial.js +54 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -146,7 +146,7 @@ bdp gtree <gid> [--depth N] [--concurrency N] [--max-nodes N]
|
|
|
146
146
|
bdp gsearch <gid> <keyword> 搜索群文件名 (全量遍历目录)
|
|
147
147
|
[--page N] [--limit N] [--depth N] [--concurrency N]
|
|
148
148
|
[--max-pages N] [--max-requests N] [--no-unique]
|
|
149
|
-
[--all|--all-results] [--timeout N] [--no-cache]
|
|
149
|
+
[--all|--all-results] [--timeout N] [--save-partial] [--no-cache]
|
|
150
150
|
bdp cache [clear] 查看 / 清空会话缓存 (~/.bdp/cache/)
|
|
151
151
|
```
|
|
152
152
|
|
|
@@ -174,6 +174,7 @@ bdp cache [clear] 查看 / 清空会话缓存 (~/.bdp/cache/)
|
|
|
174
174
|
--no-unique 保留不同 msgId 的重复项 (gsearch)
|
|
175
175
|
--all, --all-results 忽略分页获取全部结果 (gsearch; 不限时, 慢但完整)
|
|
176
176
|
--timeout <N> 超时秒数,到点返回已扫到的部分结果 (gsearch; 0=不限时, 默认 0)
|
|
177
|
+
--save-partial 未完整时自动把已搜到的结果存为 JSON 并打印路径 (gsearch; 配 --json-file 时写该文件)
|
|
177
178
|
--no-cache 禁用会话缓存 (gsearch/gtree/gshares/gls)
|
|
178
179
|
```
|
|
179
180
|
|
package/bin/bdp.js
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
const { config } = require("../lib");
|
|
35
35
|
const pan = require("../lib/pan");
|
|
36
36
|
const group = require("../lib/group");
|
|
37
|
+
const partial = require("../lib/partial");
|
|
37
38
|
|
|
38
39
|
// ── Utils ──────────────────────────────────────────────
|
|
39
40
|
|
|
@@ -88,6 +89,8 @@ function parseArgs(argv) {
|
|
|
88
89
|
opts.flags.timeout = parseInt(argv[++i], 10) || 0;
|
|
89
90
|
} else if (arg === "--timeout-ms") {
|
|
90
91
|
opts.flags.timeoutMs = parseInt(argv[++i], 10) || 0;
|
|
92
|
+
} else if (arg === "--save-partial") {
|
|
93
|
+
opts.flags.savePartial = true;
|
|
91
94
|
} else if (arg === "-n" || arg === "--lines") {
|
|
92
95
|
opts.flags.n = parseInt(argv[++i], 10) || 20;
|
|
93
96
|
} else if (arg === "-p" || arg === "--path") {
|
|
@@ -487,20 +490,26 @@ cmds.gsearch = async (args, json) => {
|
|
|
487
490
|
cache: args.flags.noCache !== true,
|
|
488
491
|
};
|
|
489
492
|
|
|
490
|
-
// --
|
|
493
|
+
// --save-partial:未完整(超时/限流/预算/失败)时自动把已搜到的结果落盘;
|
|
494
|
+
// 未指定 --json-file 时自动生成路径(bdp-gsearch-<gid>-<kw>-partial-<ts>.json)
|
|
495
|
+
const savePartial = args.flags.savePartial === true;
|
|
491
496
|
const jsonFile = args.flags.jsonFile;
|
|
497
|
+
const partialFile = jsonFile || (savePartial ? partial.defaultPartialFile(gid, keyword) : null);
|
|
492
498
|
const fsMod = require("fs");
|
|
499
|
+
|
|
500
|
+
// 扫描过程中持续写部分结果(--json-file 或 --save-partial 自动文件),
|
|
501
|
+
// 即使被外部超时/杀掉,已搜到的结果也已落盘
|
|
493
502
|
let lastProgressWrite = 0;
|
|
494
|
-
if (
|
|
495
|
-
fsMod.writeFileSync(
|
|
503
|
+
if (partialFile) {
|
|
504
|
+
fsMod.writeFileSync(partialFile, JSON.stringify({ running: true, results: [], complete: false, partial: true }, null, 2), "utf-8");
|
|
496
505
|
}
|
|
497
506
|
opts.onProgress = (snap) => {
|
|
498
|
-
if (!
|
|
507
|
+
if (!partialFile) return;
|
|
499
508
|
const now = Date.now();
|
|
500
509
|
if (snap.running && now - lastProgressWrite < 400) return; // 节流,避免频繁写盘
|
|
501
510
|
lastProgressWrite = now;
|
|
502
511
|
fsMod.writeFileSync(
|
|
503
|
-
|
|
512
|
+
partialFile,
|
|
504
513
|
JSON.stringify(
|
|
505
514
|
{
|
|
506
515
|
running: snap.running,
|
|
@@ -527,7 +536,7 @@ cmds.gsearch = async (args, json) => {
|
|
|
527
536
|
);
|
|
528
537
|
};
|
|
529
538
|
|
|
530
|
-
verboseLog(args, `gsearch gid=${gid} keyword="${keyword}" page=${opts.page} limit=${opts.limit} concurrency=${opts.concurrency} unique=${opts.unique} all=${opts.all} timeoutMs=${opts.timeoutMs} depth=${opts.depth} maxPages=${opts.maxPages} maxRequests=${opts.maxRequests} cache=${opts.cache}`);
|
|
539
|
+
verboseLog(args, `gsearch gid=${gid} keyword="${keyword}" page=${opts.page} limit=${opts.limit} concurrency=${opts.concurrency} unique=${opts.unique} all=${opts.all} timeoutMs=${opts.timeoutMs} savePartial=${savePartial} depth=${opts.depth} maxPages=${opts.maxPages} maxRequests=${opts.maxRequests} cache=${opts.cache}`);
|
|
531
540
|
const result = await group.searchFiles(gid, keyword, opts);
|
|
532
541
|
|
|
533
542
|
if (result.partial) {
|
|
@@ -542,10 +551,7 @@ cmds.gsearch = async (args, json) => {
|
|
|
542
551
|
|
|
543
552
|
if (args.flags.legacyJson) {
|
|
544
553
|
emitJson(result.results, args);
|
|
545
|
-
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
if (args.flags.jsonFile || json) {
|
|
554
|
+
} else if (args.flags.jsonFile || json) {
|
|
549
555
|
emitJson(result, args);
|
|
550
556
|
} else {
|
|
551
557
|
console.log(`${result.returned} matches for "${keyword}"${result.hasMore ? " (has more — use --page " + (result.nextPage || "?") + ")" : ""}:\n`);
|
|
@@ -561,6 +567,21 @@ cmds.gsearch = async (args, json) => {
|
|
|
561
567
|
console.error(`[verbose] ${result.failedShares} shares failed (partial result)`);
|
|
562
568
|
}
|
|
563
569
|
}
|
|
570
|
+
|
|
571
|
+
// --save-partial:未完整时把已搜到的结果写盘并告知路径(stderr,不污染 JSON stdout)
|
|
572
|
+
if (savePartial && partialFile && result.partial) {
|
|
573
|
+
if (!jsonFile) {
|
|
574
|
+
fsMod.writeFileSync(
|
|
575
|
+
partialFile,
|
|
576
|
+
JSON.stringify(partial.buildPartialPayload(result, { gid, keyword }), null, 2),
|
|
577
|
+
"utf-8"
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
console.error(`💾 部分结果已保存: ${partialFile}`);
|
|
581
|
+
} else if (savePartial && partialFile && !result.partial && !jsonFile) {
|
|
582
|
+
// 自动生成的文件且搜索完整 → 清理占位文件,避免留下垃圾
|
|
583
|
+
try { fsMod.unlinkSync(partialFile); } catch {}
|
|
584
|
+
}
|
|
564
585
|
};
|
|
565
586
|
|
|
566
587
|
cmds.cache = async (args, json) => {
|
|
@@ -638,7 +659,7 @@ GROUP CHAT OPERATIONS (群聊)
|
|
|
638
659
|
gsearch <gid> <keyword> Search group file names (全量遍历目录, 缓存命中秒回)
|
|
639
660
|
[--page N] [--limit N] [--depth N] [--concurrency N]
|
|
640
661
|
[--max-pages N] [--max-requests N] [--no-unique]
|
|
641
|
-
[--all|--all-results] [--timeout N] [--no-cache]
|
|
662
|
+
[--all|--all-results] [--timeout N] [--save-partial] [--no-cache]
|
|
642
663
|
cache [clear] Show cache info or clear session cache
|
|
643
664
|
error <code> Explain an error code (e.g. -3)
|
|
644
665
|
|
|
@@ -670,6 +691,7 @@ OPTIONS
|
|
|
670
691
|
--no-unique Keep duplicates from different msgId (gsearch)
|
|
671
692
|
--all, --all-results Fetch all results, no paging (gsearch; slow but never truncates)
|
|
672
693
|
--timeout <N> Abort after N seconds and return partial results (gsearch; 0=unlimited)
|
|
694
|
+
--save-partial Auto-save partial results to JSON when scan is incomplete (gsearch)
|
|
673
695
|
|
|
674
696
|
EXAMPLES
|
|
675
697
|
bdp login --bduss abc123 --stoken def456
|
package/lib/partial.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/partial.js — gsearch --save-partial 的纯工具函数
|
|
3
|
+
*
|
|
4
|
+
* 用途:搜索未完整(超时/限流/预算耗尽/失败)时,自动把已搜到的部分结果
|
|
5
|
+
* 落盘到 JSON 文件,避免"跑完了才发现只有 partial:true、结果却没保存"。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require("path");
|
|
9
|
+
|
|
10
|
+
// 非法文件名字符(Windows/Linux 通用)
|
|
11
|
+
const ILLEGAL = /[\\/:*?"<>|]/g;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* --save-partial 未指定 --json-file 时的默认保存路径:
|
|
15
|
+
* <cwd>/bdp-gsearch-<gid>-<keyword>-partial-<timestamp>.json
|
|
16
|
+
*/
|
|
17
|
+
function defaultPartialFile(gid, keyword, options = {}) {
|
|
18
|
+
const cwd = options.cwd || process.cwd();
|
|
19
|
+
const date = options.date || new Date();
|
|
20
|
+
const safeKw = String(keyword == null ? "" : keyword).replace(ILLEGAL, "_").slice(0, 40) || "search";
|
|
21
|
+
const ts = date.toISOString().replace(/[:.]/g, "-");
|
|
22
|
+
return path.join(cwd, `bdp-gsearch-${String(gid)}-${safeKw}-partial-${ts}.json`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 部分结果落盘对象:results 为已搜到的全部匹配(不翻页切片),
|
|
27
|
+
* 附带扫描诊断(scannedShares/totalShares/failedShares/stoppedReason 等),
|
|
28
|
+
* 供 Agent / 用户超时后直接读取。
|
|
29
|
+
*/
|
|
30
|
+
function buildPartialPayload(result, meta = {}) {
|
|
31
|
+
return {
|
|
32
|
+
saved: "partial",
|
|
33
|
+
partial: true,
|
|
34
|
+
complete: false,
|
|
35
|
+
timedOut: !!result.timedOut,
|
|
36
|
+
stoppedReason: result.stoppedReason || null,
|
|
37
|
+
gid: meta.gid,
|
|
38
|
+
keyword: meta.keyword,
|
|
39
|
+
page: result.page,
|
|
40
|
+
pageSize: result.pageSize,
|
|
41
|
+
total: result.results.length,
|
|
42
|
+
results: result.results,
|
|
43
|
+
scannedShares: result.scannedShares,
|
|
44
|
+
totalShares: result.totalShares,
|
|
45
|
+
failedShares: result.failedShares,
|
|
46
|
+
throttledShares: result.throttledShares,
|
|
47
|
+
cachedDirs: result.cachedDirs,
|
|
48
|
+
budgetUsed: result.budgetUsed,
|
|
49
|
+
depth: result.depth,
|
|
50
|
+
maxPages: result.maxPages,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = { defaultPartialFile, buildPartialPayload };
|