UNPKG

@guoyunhe/downloader

Version:

Download large files with minimum RAM usage. Support tar.gz and zip extraction.

141 lines (137 loc) 5.49 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { download: () => download }); module.exports = __toCommonJS(src_exports); var import_fs = require("fs"); var import_promises2 = require("fs/promises"); var import_http = __toESM(require("http")); var import_https = __toESM(require("https")); var import_node_stream_zip = __toESM(require("node-stream-zip")); var import_os = require("os"); var import_path2 = require("path"); var import_tar = __toESM(require("tar")); // src/stripDirectory.ts var import_promises = require("fs/promises"); var import_path = require("path"); async function stripDirectory(dir, strip = 1) { if (strip < 1) return; const items = await scanDirectory(dir, strip + 1); const tmpDir = dir + "__old__"; await (0, import_promises.rename)(dir, tmpDir); await (0, import_promises.mkdir)(dir); await Promise.all( Object.entries(items).map(async ([from, to]) => { (0, import_promises.rename)((0, import_path.join)(tmpDir, from), (0, import_path.join)(dir, to)); }) ); await (0, import_promises.rm)(tmpDir, { recursive: true }); } async function scanDirectory(dir, depth = 1, prefix = "") { const result = {}; if (depth < 1) return result; const items = await (0, import_promises.readdir)(dir, { withFileTypes: true }); for (let i = 0; i < items.length; i++) { const item = items[i]; if (item.isDirectory() && depth > 1) { Object.assign( result, await scanDirectory((0, import_path.join)(dir, item.name), depth - 1, (0, import_path.join)(prefix, item.name)) ); } else { result[(0, import_path.join)(prefix, item.name)] = item.name; } } return result; } // src/index.ts function download(url, dist, options = {}) { const { maxRedirects = 5, extract = false, strip = 0 } = options; return new Promise((resolve, reject) => { const get = url.startsWith("https://") ? import_https.default.get : import_http.default.get; get(url, async (res) => { if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { let output; let zipFile; if (extract && [ "application/tar", "application/tar+gzip", "application/x-tar", "application/x-gzip" ].includes(res.headers["content-type"] || "")) { await (0, import_promises2.mkdir)(dist, { recursive: true }); output = import_tar.default.x({ strip, cwd: dist }); } else if (extract && res.headers["content-type"] === "application/zip") { const tmpPrefix = (0, import_path2.join)((0, import_os.tmpdir)(), "guoyunhe-downloader"); const temp = await (0, import_promises2.mkdtemp)(tmpPrefix); zipFile = (0, import_path2.join)(temp, "archive.zip"); output = (0, import_fs.createWriteStream)(zipFile); } else { await (0, import_promises2.mkdir)((0, import_path2.dirname)(dist), { recursive: true }); output = (0, import_fs.createWriteStream)(dist); } res.pipe(output, { end: false }); res.on("end", async function() { output.end(); if (zipFile) { const zip = new import_node_stream_zip.default.async({ file: zipFile }); await zip.extract(null, dist); await stripDirectory(dist, strip); } resolve(); }); } else if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { if (maxRedirects > 0) { const newUrl = res.headers.location; download(newUrl, dist, { ...options, maxRedirects: maxRedirects - 1 }).then(resolve).catch(reject); } else { reject( new Error( `Too many redirects when downloading ${url}. Use maxRedirects option to increase the limit.` ) ); } } else { reject(new Error("Failed to download " + url)); } }); }); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { download });