baiduwangpan-cli 1.0.2 → 1.1.1
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 +47 -14
- package/bin/bdp.js +119 -11
- package/lib/browser-login.js +5 -10
- package/lib/config.js +64 -16
- package/lib/group.js +389 -64
- package/package.json +2 -2
- package/scripts/postinstall.js +110 -65
package/scripts/postinstall.js
CHANGED
|
@@ -4,8 +4,15 @@
|
|
|
4
4
|
* postinstall.js — 自动下载 BaiduPCS-Go 二进制
|
|
5
5
|
*
|
|
6
6
|
* 跨平台支持: Windows / macOS / Linux (x64, arm64, 386)
|
|
7
|
-
* 下载加速:
|
|
7
|
+
* 下载加速: 镜像(ghfast/ghproxy...) 优先 → GitHub 兜底(大陆网络 GitHub 常 DNS 污染)
|
|
8
8
|
* 解压方式: Windows (PowerShell) / Unix (unzip / python3 / tar)
|
|
9
|
+
*
|
|
10
|
+
* 1.1.0 已知问题修复:
|
|
11
|
+
* - 镜像顺序: 国内网络优先用 ghfast/ghproxy,GitHub 放最后
|
|
12
|
+
* - download() 补 file stream error 处理:第一个镜像部分下载失败时不再直接崩溃,
|
|
13
|
+
* 确保 5 个源按顺序 fallback(此前"只跑 1 行就抛出")
|
|
14
|
+
* - 全部失败时打印每个源的完整下载地址,便于手动下载
|
|
15
|
+
* - 发现版本子目录(BaiduPCS-Go-vX/)里的二进制时提升到固定路径(修复后无需手改 config)
|
|
9
16
|
*/
|
|
10
17
|
|
|
11
18
|
const https = require("https");
|
|
@@ -19,13 +26,13 @@ const PKG_ROOT = path.join(__dirname, "..");
|
|
|
19
26
|
const REPO = "qjfoidnh/BaiduPCS-Go";
|
|
20
27
|
const VERSION = "v4.0.1";
|
|
21
28
|
|
|
22
|
-
// GitHub
|
|
29
|
+
// GitHub 下载加速镜像(按优先级排列):大陆网络优先镜像,GitHub 放最后兜底
|
|
23
30
|
const MIRRORS = [
|
|
24
|
-
(asset) => `https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
25
|
-
(asset) => `https://ghproxy.net/https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
26
31
|
(asset) => `https://ghfast.top/https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
32
|
+
(asset) => `https://ghproxy.net/https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
27
33
|
(asset) => `https://mirror.ghproxy.com/https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
28
34
|
(asset) => `https://gh-proxy.com/https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
35
|
+
(asset) => `https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
29
36
|
];
|
|
30
37
|
|
|
31
38
|
// ── 平台检测 ────────────────────────────────────────────
|
|
@@ -84,67 +91,69 @@ function download(url, dest, timeout = 60000) {
|
|
|
84
91
|
const timer = setTimeout(() => {
|
|
85
92
|
if (!settled) {
|
|
86
93
|
settled = true;
|
|
87
|
-
file.close();
|
|
94
|
+
try { file.close(); } catch {}
|
|
88
95
|
fs.unlink(dest, () => {});
|
|
89
96
|
reject(new Error("timeout"));
|
|
90
97
|
}
|
|
91
98
|
}, timeout);
|
|
92
99
|
|
|
100
|
+
// 统一失败路径:清定时器 + 关流 + 删残留文件。file stream 的 error 也走这里,
|
|
101
|
+
// 防止第一个镜像部分下载失败后 file 抛 EPIPE/ENOSPC 未捕获导致整个 postinstall 崩溃
|
|
102
|
+
// (1.1.0 实测"只跑 1 行就抛出",fallback 没机会执行)。
|
|
103
|
+
const fail = (err) => {
|
|
104
|
+
if (settled) return;
|
|
105
|
+
settled = true;
|
|
106
|
+
clearTimeout(timer);
|
|
107
|
+
try { file.close(); } catch {}
|
|
108
|
+
fs.unlink(dest, () => {});
|
|
109
|
+
reject(err);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
file.on("error", (e) => fail(e));
|
|
113
|
+
|
|
93
114
|
const req = (url, redirects = 0) => {
|
|
94
115
|
if (redirects > 5) {
|
|
95
|
-
|
|
116
|
+
fail(new Error("too many redirects"));
|
|
96
117
|
return;
|
|
97
118
|
}
|
|
98
119
|
|
|
99
120
|
const client = url.startsWith("https") ? https : http;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
res.resume();
|
|
109
|
-
if (!settled) {
|
|
110
|
-
settled = true;
|
|
111
|
-
clearTimeout(timer);
|
|
112
|
-
file.close();
|
|
113
|
-
fs.unlink(dest, () => {});
|
|
114
|
-
reject(new Error(`HTTP ${res.statusCode}`));
|
|
121
|
+
let r;
|
|
122
|
+
try {
|
|
123
|
+
r = client.get(url, { timeout: 15000 }, (res) => {
|
|
124
|
+
// 处理重定向
|
|
125
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
126
|
+
res.resume();
|
|
127
|
+
req(res.headers.location, redirects + 1);
|
|
128
|
+
return;
|
|
115
129
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
if (res.statusCode !== 200) {
|
|
131
|
+
res.resume();
|
|
132
|
+
fail(new Error(`HTTP ${res.statusCode}`));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
res.pipe(file);
|
|
136
|
+
file.on("finish", () => {
|
|
137
|
+
file.close(() => {
|
|
138
|
+
if (!settled) {
|
|
139
|
+
settled = true;
|
|
140
|
+
clearTimeout(timer);
|
|
141
|
+
resolve();
|
|
142
|
+
}
|
|
143
|
+
});
|
|
126
144
|
});
|
|
127
145
|
});
|
|
128
|
-
})
|
|
146
|
+
} catch (e) {
|
|
147
|
+
fail(e);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
129
150
|
|
|
130
|
-
r.on("error", (e) =>
|
|
131
|
-
if (!settled) {
|
|
132
|
-
settled = true;
|
|
133
|
-
clearTimeout(timer);
|
|
134
|
-
file.close();
|
|
135
|
-
fs.unlink(dest, () => {});
|
|
136
|
-
reject(e);
|
|
137
|
-
}
|
|
138
|
-
});
|
|
151
|
+
r.on("error", (e) => fail(e));
|
|
139
152
|
|
|
140
153
|
r.on("timeout", () => {
|
|
141
154
|
if (!settled) {
|
|
142
|
-
settled = true;
|
|
143
|
-
clearTimeout(timer);
|
|
144
155
|
r.destroy();
|
|
145
|
-
|
|
146
|
-
fs.unlink(dest, () => {});
|
|
147
|
-
reject(new Error("connection timeout"));
|
|
156
|
+
fail(new Error("connection timeout"));
|
|
148
157
|
}
|
|
149
158
|
});
|
|
150
159
|
};
|
|
@@ -154,20 +163,29 @@ function download(url, dest, timeout = 60000) {
|
|
|
154
163
|
}
|
|
155
164
|
|
|
156
165
|
async function downloadWithMirrors(assetName, dest) {
|
|
166
|
+
const errors = [];
|
|
157
167
|
for (let i = 0; i < MIRRORS.length; i++) {
|
|
158
168
|
const url = MIRRORS[i](assetName);
|
|
159
|
-
const label = i ===
|
|
169
|
+
const label = i === MIRRORS.length - 1 ? "GitHub" : new URL(MIRRORS[i]("x")).hostname;
|
|
160
170
|
process.stdout.write(` bdp: trying ${label}...`);
|
|
161
171
|
try {
|
|
162
172
|
await download(url, dest, 90000);
|
|
163
173
|
console.log(" OK");
|
|
164
|
-
return true;
|
|
174
|
+
return { ok: true, url, label };
|
|
165
175
|
} catch (e) {
|
|
166
|
-
|
|
167
|
-
|
|
176
|
+
const msg = e.message || String(e);
|
|
177
|
+
errors.push(`${label}: ${msg}`);
|
|
178
|
+
console.log(` failed (${msg})`);
|
|
179
|
+
if (fs.existsSync(dest)) {
|
|
180
|
+
try { fs.unlinkSync(dest); } catch {}
|
|
181
|
+
}
|
|
182
|
+
// GitHub DNS 污染提示
|
|
183
|
+
if (/ENOTFOUND|EAI_AGAIN|ETIMEDOUT/i.test(msg) && label === "GitHub") {
|
|
184
|
+
console.log(" bdp: (GitHub 解析失败——大陆网络常见 DNS 污染,前面的镜像通常可用)");
|
|
185
|
+
}
|
|
168
186
|
}
|
|
169
187
|
}
|
|
170
|
-
return false;
|
|
188
|
+
return { ok: false, errors };
|
|
171
189
|
}
|
|
172
190
|
|
|
173
191
|
// ── 解压 ────────────────────────────────────────────────
|
|
@@ -213,13 +231,39 @@ function extractZip(zipPath, destDir) {
|
|
|
213
231
|
|
|
214
232
|
// ── 主逻辑 ──────────────────────────────────────────────
|
|
215
233
|
|
|
234
|
+
function findExistingBinary(binName) {
|
|
235
|
+
const binPath = path.join(PKG_ROOT, binName);
|
|
236
|
+
if (fs.existsSync(binPath)) return { path: binPath, versioned: false };
|
|
237
|
+
// 版本子目录(上次 postinstall 失败后手动解压的常见位置)
|
|
238
|
+
try {
|
|
239
|
+
for (const entry of fs.readdirSync(PKG_ROOT, { withFileTypes: true })) {
|
|
240
|
+
if (entry.isDirectory() && entry.name.includes("BaiduPCS-Go")) {
|
|
241
|
+
const p = path.join(PKG_ROOT, entry.name, binName);
|
|
242
|
+
if (fs.existsSync(p)) return { path: p, versioned: true };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} catch {}
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
|
|
216
249
|
async function main() {
|
|
217
250
|
const binName = getBinaryName();
|
|
218
251
|
const binPath = path.join(PKG_ROOT, binName);
|
|
219
252
|
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
253
|
+
// 已存在则跳过;版本子目录里的二进制提升到固定路径(CLI 固定路径优先,且不依赖版本号)
|
|
254
|
+
const existing = findExistingBinary(binName);
|
|
255
|
+
if (existing) {
|
|
256
|
+
if (existing.versioned) {
|
|
257
|
+
try {
|
|
258
|
+
fs.copyFileSync(existing.path, binPath);
|
|
259
|
+
if (os.platform() !== "win32") { try { fs.chmodSync(binPath, 0o755); } catch {} }
|
|
260
|
+
console.log(` bdp: ✅ BaiduPCS-Go promoted from ${path.basename(path.dirname(existing.path))} to fixed path.`);
|
|
261
|
+
} catch (e) {
|
|
262
|
+
console.log(` bdp: ⚠️ 版本子目录已发现但提升失败: ${e.message}`);
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
console.log(" bdp: BaiduPCS-Go already exists, skipping.");
|
|
266
|
+
}
|
|
223
267
|
return;
|
|
224
268
|
}
|
|
225
269
|
|
|
@@ -229,14 +273,15 @@ async function main() {
|
|
|
229
273
|
console.log("");
|
|
230
274
|
console.log(" bdp: Installing BaiduPCS-Go (百度网盘 CLI 引擎)...");
|
|
231
275
|
|
|
232
|
-
//
|
|
233
|
-
const
|
|
234
|
-
if (!ok) {
|
|
235
|
-
console.warn(" bdp: ⚠️
|
|
236
|
-
console.warn(` bdp:
|
|
237
|
-
console.warn(` bdp:
|
|
238
|
-
console.warn(` bdp:
|
|
239
|
-
console.warn(" bdp:
|
|
276
|
+
// 下载(镜像优先 → GitHub 兜底)
|
|
277
|
+
const result = await downloadWithMirrors(assetName, zipPath);
|
|
278
|
+
if (!result.ok) {
|
|
279
|
+
console.warn(" bdp: ⚠️ 所有下载源失败(大陆网络常见:GitHub DNS 污染 / 镜像暂时抽风)。");
|
|
280
|
+
console.warn(` bdp: 请手动下载 ${assetName}(任一地址均可):`);
|
|
281
|
+
for (const m of MIRRORS) console.warn(` bdp: ${m(assetName)}`);
|
|
282
|
+
console.warn(` bdp: 解压后把 ${binName} 放到: ${PKG_ROOT}`);
|
|
283
|
+
console.warn(" bdp: (或版本子目录,如 BaiduPCS-Go-v4.0.1-windows-x64/,CLI 会自动发现)");
|
|
284
|
+
console.warn(" bdp: 也可直接确保 BaiduPCS-Go 在 PATH 中(包仍可正常使用)。");
|
|
240
285
|
console.warn("");
|
|
241
286
|
process.exit(0); // 不阻断 npm install
|
|
242
287
|
}
|
|
@@ -244,7 +289,7 @@ async function main() {
|
|
|
244
289
|
// 解压
|
|
245
290
|
console.log(" bdp: Extracting...");
|
|
246
291
|
if (!extractZip(zipPath, PKG_ROOT)) {
|
|
247
|
-
console.warn(` bdp: ⚠️
|
|
292
|
+
console.warn(` bdp: ⚠️ 解压失败。请手动解压: ${zipPath}`);
|
|
248
293
|
process.exit(0);
|
|
249
294
|
}
|
|
250
295
|
|
|
@@ -273,8 +318,8 @@ async function main() {
|
|
|
273
318
|
}
|
|
274
319
|
console.log(` bdp: ✅ BaiduPCS-Go installed.`);
|
|
275
320
|
} else {
|
|
276
|
-
console.warn(" bdp: ⚠️
|
|
277
|
-
console.warn(` bdp:
|
|
321
|
+
console.warn(" bdp: ⚠️ 解压后未找到二进制。");
|
|
322
|
+
console.warn(` bdp: 请手动解压并把 ${binName} 放到: ${PKG_ROOT}`);
|
|
278
323
|
}
|
|
279
324
|
|
|
280
325
|
// 清理 zip 和解压目录
|