baiduwangpan-cli 1.0.0
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/LICENSE +21 -0
- package/README.md +263 -0
- package/bin/bdp.js +387 -0
- package/lib/config.js +59 -0
- package/lib/group.js +123 -0
- package/lib/http.js +90 -0
- package/lib/index.js +5 -0
- package/lib/pan.js +204 -0
- package/package.json +44 -0
- package/scripts/postinstall.js +295 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* postinstall.js — 自动下载 BaiduPCS-Go 二进制
|
|
5
|
+
*
|
|
6
|
+
* 跨平台支持: Windows / macOS / Linux (x64, arm64, 386)
|
|
7
|
+
* 下载加速: GitHub → ghproxy 镜像 → ghfast 镜像 → 降级提示
|
|
8
|
+
* 解压方式: Windows (PowerShell) / Unix (unzip / python3 / tar)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const https = require("https");
|
|
12
|
+
const http = require("http");
|
|
13
|
+
const fs = require("fs");
|
|
14
|
+
const path = require("path");
|
|
15
|
+
const os = require("os");
|
|
16
|
+
const { spawnSync, execSync } = require("child_process");
|
|
17
|
+
|
|
18
|
+
const PKG_ROOT = path.join(__dirname, "..");
|
|
19
|
+
const REPO = "qjfoidnh/BaiduPCS-Go";
|
|
20
|
+
const VERSION = "v4.0.1";
|
|
21
|
+
|
|
22
|
+
// GitHub 下载加速镜像(按优先级排列)
|
|
23
|
+
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
|
+
(asset) => `https://ghfast.top/https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
27
|
+
(asset) => `https://mirror.ghproxy.com/https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
28
|
+
(asset) => `https://gh-proxy.com/https://github.com/${REPO}/releases/download/${VERSION}/${asset}`,
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
// ── 平台检测 ────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
function getAssetName() {
|
|
34
|
+
const platform = os.platform();
|
|
35
|
+
const arch = os.arch();
|
|
36
|
+
|
|
37
|
+
let osName, archName;
|
|
38
|
+
|
|
39
|
+
switch (platform) {
|
|
40
|
+
case "win32": osName = "windows"; break;
|
|
41
|
+
case "darwin": osName = "darwin-osx"; break;
|
|
42
|
+
case "linux": osName = "linux"; break;
|
|
43
|
+
case "freebsd": osName = "freebsd"; break;
|
|
44
|
+
default: throw new Error(`Unsupported platform: ${platform}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
switch (arch) {
|
|
48
|
+
case "x64":
|
|
49
|
+
archName = osName === "windows" ? "x64" : "amd64";
|
|
50
|
+
break;
|
|
51
|
+
case "arm64":
|
|
52
|
+
case "aarch64":
|
|
53
|
+
archName = "arm64";
|
|
54
|
+
break;
|
|
55
|
+
case "ia32":
|
|
56
|
+
case "x32":
|
|
57
|
+
case "arm":
|
|
58
|
+
archName = (osName === "windows") ? "x86" : "386";
|
|
59
|
+
break;
|
|
60
|
+
case "mips":
|
|
61
|
+
archName = osName === "linux" ? "mips" : arch;
|
|
62
|
+
break;
|
|
63
|
+
case "mipsel":
|
|
64
|
+
archName = osName === "linux" ? "mipsle" : arch;
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
throw new Error(`Unsupported arch: ${arch}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { assetName: `BaiduPCS-Go-${VERSION}-${osName}-${archName}.zip`, osName, archName };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getBinaryName() {
|
|
74
|
+
return os.platform() === "win32" ? "BaiduPCS-Go.exe" : "BaiduPCS-Go";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ── 下载 ────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
function download(url, dest, timeout = 60000) {
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
const file = fs.createWriteStream(dest);
|
|
82
|
+
let settled = false;
|
|
83
|
+
|
|
84
|
+
const timer = setTimeout(() => {
|
|
85
|
+
if (!settled) {
|
|
86
|
+
settled = true;
|
|
87
|
+
file.close();
|
|
88
|
+
fs.unlink(dest, () => {});
|
|
89
|
+
reject(new Error("timeout"));
|
|
90
|
+
}
|
|
91
|
+
}, timeout);
|
|
92
|
+
|
|
93
|
+
const req = (url, redirects = 0) => {
|
|
94
|
+
if (redirects > 5) {
|
|
95
|
+
if (!settled) { settled = true; clearTimeout(timer); reject(new Error("too many redirects")); }
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const client = url.startsWith("https") ? https : http;
|
|
100
|
+
const r = client.get(url, { timeout: 15000 }, (res) => {
|
|
101
|
+
// 处理重定向
|
|
102
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
103
|
+
res.resume();
|
|
104
|
+
req(res.headers.location, redirects + 1);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (res.statusCode !== 200) {
|
|
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}`));
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
res.pipe(file);
|
|
119
|
+
file.on("finish", () => {
|
|
120
|
+
file.close(() => {
|
|
121
|
+
if (!settled) {
|
|
122
|
+
settled = true;
|
|
123
|
+
clearTimeout(timer);
|
|
124
|
+
resolve();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
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
|
+
});
|
|
139
|
+
|
|
140
|
+
r.on("timeout", () => {
|
|
141
|
+
if (!settled) {
|
|
142
|
+
settled = true;
|
|
143
|
+
clearTimeout(timer);
|
|
144
|
+
r.destroy();
|
|
145
|
+
file.close();
|
|
146
|
+
fs.unlink(dest, () => {});
|
|
147
|
+
reject(new Error("connection timeout"));
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
req(url);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function downloadWithMirrors(assetName, dest) {
|
|
157
|
+
for (let i = 0; i < MIRRORS.length; i++) {
|
|
158
|
+
const url = MIRRORS[i](assetName);
|
|
159
|
+
const label = i === 0 ? "GitHub" : new URL(MIRRORS[i]("x")).hostname;
|
|
160
|
+
process.stdout.write(` bdp: trying ${label}...`);
|
|
161
|
+
try {
|
|
162
|
+
await download(url, dest, 90000);
|
|
163
|
+
console.log(" OK");
|
|
164
|
+
return true;
|
|
165
|
+
} catch (e) {
|
|
166
|
+
console.log(` failed (${e.message})`);
|
|
167
|
+
if (fs.existsSync(dest)) fs.unlinkSync(dest);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ── 解压 ────────────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
function extractZip(zipPath, destDir) {
|
|
176
|
+
const platform = os.platform();
|
|
177
|
+
|
|
178
|
+
// Windows: PowerShell
|
|
179
|
+
if (platform === "win32") {
|
|
180
|
+
try {
|
|
181
|
+
execSync(
|
|
182
|
+
`powershell -NoProfile -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${destDir}' -Force"`,
|
|
183
|
+
{ stdio: "ignore", timeout: 30000 }
|
|
184
|
+
);
|
|
185
|
+
return true;
|
|
186
|
+
} catch { /* fall through */ }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Unix: unzip
|
|
190
|
+
const unzip = spawnSync("unzip", ["-o", "-q", zipPath, "-d", destDir], { stdio: "ignore", timeout: 30000 });
|
|
191
|
+
if (unzip.status === 0) return true;
|
|
192
|
+
|
|
193
|
+
// Fallback: python3
|
|
194
|
+
try {
|
|
195
|
+
execSync(
|
|
196
|
+
`python3 -c "import zipfile,sys; zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])" "${zipPath}" "${destDir}"`,
|
|
197
|
+
{ stdio: "ignore", timeout: 30000 }
|
|
198
|
+
);
|
|
199
|
+
return true;
|
|
200
|
+
} catch { /* fall through */ }
|
|
201
|
+
|
|
202
|
+
// Fallback: python
|
|
203
|
+
try {
|
|
204
|
+
execSync(
|
|
205
|
+
`python -c "import zipfile,sys; zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])" "${zipPath}" "${destDir}"`,
|
|
206
|
+
{ stdio: "ignore", timeout: 30000 }
|
|
207
|
+
);
|
|
208
|
+
return true;
|
|
209
|
+
} catch { /* fall through */ }
|
|
210
|
+
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ── 主逻辑 ──────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
async function main() {
|
|
217
|
+
const binName = getBinaryName();
|
|
218
|
+
const binPath = path.join(PKG_ROOT, binName);
|
|
219
|
+
|
|
220
|
+
// 已存在则跳过
|
|
221
|
+
if (fs.existsSync(binPath)) {
|
|
222
|
+
console.log(" bdp: BaiduPCS-Go already exists, skipping.");
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const { assetName } = getAssetName();
|
|
227
|
+
const zipPath = path.join(PKG_ROOT, assetName);
|
|
228
|
+
|
|
229
|
+
console.log("");
|
|
230
|
+
console.log(" bdp: Installing BaiduPCS-Go (百度网盘 CLI 引擎)...");
|
|
231
|
+
|
|
232
|
+
// 下载
|
|
233
|
+
const ok = await downloadWithMirrors(assetName, zipPath);
|
|
234
|
+
if (!ok) {
|
|
235
|
+
console.warn(" bdp: ⚠️ All download mirrors failed.");
|
|
236
|
+
console.warn(` bdp: Please manually download ${assetName}`);
|
|
237
|
+
console.warn(` bdp: from https://github.com/${REPO}/releases/tag/${VERSION}`);
|
|
238
|
+
console.warn(` bdp: and extract ${binName} to: ${PKG_ROOT}`);
|
|
239
|
+
console.warn(" bdp: (the package still works if BaiduPCS-Go is in your PATH)");
|
|
240
|
+
console.warn("");
|
|
241
|
+
process.exit(0); // 不阻断 npm install
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// 解压
|
|
245
|
+
console.log(" bdp: Extracting...");
|
|
246
|
+
if (!extractZip(zipPath, PKG_ROOT)) {
|
|
247
|
+
console.warn(` bdp: ⚠️ Cannot extract. Please manually unzip: ${zipPath}`);
|
|
248
|
+
process.exit(0);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// 查找并移动二进制
|
|
252
|
+
let found = false;
|
|
253
|
+
function searchDir(dir) {
|
|
254
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
255
|
+
if (entry.name === binName) {
|
|
256
|
+
const src = path.join(dir, entry.name);
|
|
257
|
+
if (!found) {
|
|
258
|
+
fs.copyFileSync(src, binPath);
|
|
259
|
+
found = true;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (entry.isDirectory() && entry.name.includes("BaiduPCS-Go")) {
|
|
263
|
+
searchDir(path.join(dir, entry.name));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
searchDir(PKG_ROOT);
|
|
268
|
+
|
|
269
|
+
if (found) {
|
|
270
|
+
// Unix 设置可执行权限
|
|
271
|
+
if (os.platform() !== "win32") {
|
|
272
|
+
try { fs.chmodSync(binPath, 0o755); } catch {}
|
|
273
|
+
}
|
|
274
|
+
console.log(` bdp: ✅ BaiduPCS-Go installed.`);
|
|
275
|
+
} else {
|
|
276
|
+
console.warn(" bdp: ⚠️ Binary not found after extraction.");
|
|
277
|
+
console.warn(` bdp: Please manually extract and place ${binName} in: ${PKG_ROOT}`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// 清理 zip 和解压目录
|
|
281
|
+
try { fs.unlinkSync(zipPath); } catch {}
|
|
282
|
+
for (const entry of fs.readdirSync(PKG_ROOT, { withFileTypes: true })) {
|
|
283
|
+
if (entry.isDirectory() && entry.name.includes("BaiduPCS-Go-v")) {
|
|
284
|
+
try { fs.rmSync(path.join(PKG_ROOT, entry.name), { recursive: true }); } catch {}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
console.log("");
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
main().catch((e) => {
|
|
292
|
+
console.warn(` bdp: ⚠️ Post-install error: ${e.message}`);
|
|
293
|
+
console.warn(" bdp: The package will still work if BaiduPCS-Go is in your PATH.");
|
|
294
|
+
process.exit(0); // 永不阻断 npm install
|
|
295
|
+
});
|