music-library-tools/src/sendgb.js

103 lines
2.5 KiB
JavaScript

import fs from "fs";
const C = {
info: msg => console.log("\x1b[36m[i]\x1b[0m " + msg),
ok: msg => console.log("\x1b[32m[✓]\x1b[0m " + msg),
warn: msg => console.log("\x1b[33m[!]\x1b[0m " + msg),
err: msg => console.log("\x1b[31m[✗]\x1b[0m " + msg),
};
const base = "https://sendgb.com/";
const url = process.argv[2];
if (!url || !url.startsWith(base)) {
C.err("Usage: node sendgb.js <sendgb-url>");
process.exit(1);
}
C.info(`Fetching page: ${url}`);
const page = await fetch(url);
const html = await page.text();
const sendgb_session = page.headers
.getSetCookie()
.find(c => c.startsWith("sendgb_ses="))
?.split(";")[0]
.split("=")
.at(-1);
if (!sendgb_session) {
C.err("Failed to extract sendgb session cookie");
process.exit(1);
}
const get = (re) => [...html.matchAll(re)][0]?.[1];
const link = get(/<form id="downloadItems" action="([^"]*)"/gm);
const secret = get(/name="secret_code"[^>]*value="([^"]*)"/gm);
const total_files = get(/name="total_files"[^>]*value="(\d+)"/gm);
if (!link || !secret || !total_files) {
C.err("Failed to parse download form");
process.exit(1);
}
C.info(`Files: ${total_files}`);
C.info("Requesting ZIP…");
const res = await fetch(link, {
method: "POST",
body: new URLSearchParams({
action: "download",
secret_code: secret,
private_id: "",
download_id: url.replace(base, ""),
total_files
}),
headers: {
"User-Agent": "Mozilla/5.0"
}
});
if (!res.ok || !res.body) {
C.err(`Download failed (${res.status})`);
process.exit(1);
}
C.info("Content-type: " + res.headers.get("content-type"))
const filename =
res.headers.get("content-disposition")?.match(/filename="?([^"]+)"?/)?.[1]
?? "download.zip";
C.info(`Downloading ${filename}`);
const file = fs.createWriteStream(filename);
const reader = res.body.getReader();
let downloaded = 0;
const total = Number(res.headers.get("content-length")) || 0;
const start = Date.now();
while (true) {
const { done, value } = await reader.read();
if (done) break;
file.write(value);
downloaded += value.length;
if (total) {
const pct = ((downloaded / total) * 100).toFixed(1);
const mb = (downloaded / 1024 / 1024).toFixed(2);
const tmb = (total / 1024 / 1024).toFixed(2);
process.stdout.write(`\r${pct}% ${mb}/${tmb} MB`);
} else {
const mb = (downloaded / 1024 / 1024).toFixed(2);
process.stdout.write(`\r${mb} MB`);
}
}
file.end();
process.stdout.write("\n");
C.ok(`Saved as ${filename} in ${((Date.now() - start) / 1000).toFixed(1)}s`);