Download scripts/build/copy_reader_vendor.mjs from VoiceOfML/Search: direct link, hf CLI and curl.
- Browser
- Download file 4.75 kB
-
https://huggingface.co/spaces/VoiceOfML/Search/resolve/main/scripts/build/copy_reader_vendor.mjs
- Command line
-
hf download hf://spaces/VoiceOfML/Search/scripts/build/copy_reader_vendor.mjs
-
curl -L -o copy_reader_vendor.mjs https://huggingface.co/spaces/VoiceOfML/Search/resolve/main/scripts/build/copy_reader_vendor.mjs
4.75 kB
| import { createHash } from "node:crypto"; | |
| import { mkdirSync, rmSync, writeFileSync } from "node:fs"; | |
| import { get } from "node:https"; | |
| import { dirname, join } from "node:path"; | |
| import { gunzipSync } from "node:zlib"; | |
| import { createRequire } from "node:module"; | |
| const resources = createRequire(import.meta.url)(join(process.cwd(), "static/reader-resources.js")); | |
| const output = process.argv[2] || "static/vendor"; | |
| const foliateOutputArgument = process.argv.indexOf("--foliate-output"); | |
| if (foliateOutputArgument >= 0 && !process.argv[foliateOutputArgument + 1]) | |
| throw new Error("--foliate-output requires a directory"); | |
| const foliateOutput = foliateOutputArgument >= 0 | |
| ? process.argv[foliateOutputArgument + 1] | |
| : process.argv.includes("--refresh-foliate") | |
| ? join(process.cwd(), "static/foliate-reader/vendor") : null; | |
| mkdirSync(output, { recursive: true }); | |
| function download(url, redirects = 0) { | |
| return new Promise((resolve, reject) => { | |
| const request = get(url, (response) => { | |
| if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location && redirects < 5) { | |
| response.resume(); | |
| return download(new URL(response.headers.location, url), redirects + 1).then(resolve, reject); | |
| } | |
| if (response.statusCode !== 200) { | |
| response.resume(); | |
| return reject(new Error(`${url}: HTTP ${response.statusCode}`)); | |
| } | |
| const chunks = []; | |
| response.on("data", (chunk) => chunks.push(chunk)); | |
| response.on("end", () => resolve(Buffer.concat(chunks))); | |
| response.on("error", reject); | |
| }); | |
| request.setTimeout(180000, () => request.destroy(new Error(`${url}: request timed out`))); | |
| request.on("error", reject); | |
| }); | |
| } | |
| async function downloadWithRetry(url) { | |
| let lastError; | |
| for (let attempt = 0; attempt < 4; attempt++) { | |
| try { return await download(url); } | |
| catch (error) { | |
| lastError = error; | |
| if (attempt < 3) await new Promise((resolve) => setTimeout(resolve, 1000 * (2 ** attempt))); | |
| } | |
| } | |
| throw lastError; | |
| } | |
| async function main() { | |
| const pdfArchive = await downloadWithRetry(resources.pdfArchive.url); | |
| const pdfArchiveHash = createHash("sha256").update(pdfArchive).digest("hex"); | |
| if (pdfArchiveHash !== resources.pdfArchive.sha256) throw new Error(`pdfjs-dist archive SHA-256 ${pdfArchiveHash} does not match`); | |
| const tar = gunzipSync(pdfArchive); | |
| for (let offset = 0; offset + 512 <= tar.length;) { | |
| const header = tar.subarray(offset, offset + 512), name = header.subarray(0, 100).toString().replace(/\0.*$/, ""); | |
| if (!name) break; | |
| const size = parseInt(header.subarray(124, 136).toString().replace(/\0.*$/, "").trim() || "0", 8); | |
| const relative = name.replace(/^package\//, ""); | |
| if ((relative.startsWith("cmaps/") || relative.startsWith("standard_fonts/") || relative.startsWith("wasm/")) && !relative.endsWith("/")) { | |
| const target = join(output, relative); | |
| mkdirSync(dirname(target), { recursive: true }); | |
| writeFileSync(target, tar.subarray(offset + 512, offset + 512 + size)); | |
| if (foliateOutput) { | |
| const foliateTarget = join(foliateOutput, "pdfjs", relative); | |
| mkdirSync(dirname(foliateTarget), { recursive: true }); | |
| writeFileSync(foliateTarget, tar.subarray(offset + 512, offset + 512 + size)); | |
| } | |
| } | |
| offset += 512 + Math.ceil(size / 512) * 512; | |
| } | |
| for (const [name, {url, file: target, sha256: expected, path}] of Object.entries(resources.vendors)) { | |
| const bytes = await downloadWithRetry(url); | |
| const actual = createHash("sha256").update(bytes).digest("hex"); | |
| if (actual !== expected) throw new Error(`${url}: SHA-256 ${actual} does not match ${expected}`); | |
| mkdirSync(dirname(join(output, target)), { recursive: true }); | |
| const versioned = path.slice("vendor/".length); | |
| mkdirSync(dirname(join(output, versioned)), { recursive: true }); | |
| writeFileSync(join(output, versioned), bytes); | |
| if (foliateOutput && (name === "pdf" || name === "pdfWorker")) { | |
| const filename = name === "pdf" ? "pdf.mjs" : "pdf.worker.mjs"; | |
| mkdirSync(join(foliateOutput, "pdfjs"), { recursive: true }); | |
| writeFileSync(join(foliateOutput, "pdfjs", filename), bytes); | |
| rmSync(join(foliateOutput, "pdfjs", filename + ".map"), { force: true }); | |
| } | |
| } | |
| if (foliateOutput) for (const {url, file, sha256: expected} of Object.values(resources.foliateVendors)) { | |
| const bytes = await downloadWithRetry(url); | |
| const actual = createHash("sha256").update(bytes).digest("hex"); | |
| if (actual !== expected) throw new Error(`${url}: SHA-256 ${actual} does not match ${expected}`); | |
| const target = join(foliateOutput, file); | |
| mkdirSync(dirname(target), { recursive: true }); | |
| writeFileSync(target, bytes); | |
| } | |
| } | |
| main().catch((error) => { console.error(error); process.exitCode = 1; }); | |