From 05ee2316e9fb0e5d130ef59b71b0bf24fe44fee1 Mon Sep 17 00:00:00 2001 From: share121 <2854631158@qq.com> Date: Thu, 6 Feb 2025 20:58:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E8=AF=86=E5=88=AB=E6=96=87=E4=BB=B6=E5=90=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.ts | 59 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/main.ts b/main.ts index a7f5846..f0eb892 100644 --- a/main.ts +++ b/main.ts @@ -1,47 +1,40 @@ -import { dirname, join, basename } from "jsr:@std/path"; +import { basename, join } from "jsr:@std/path"; import { Mutex } from "npm:async-mutex"; import { downloadChunk } from "./workerpool.ts"; export async function download( url: string, - filename: string, + dirpath: string, threads: number, chunkSize = 5 * 1024 * 1024, headers: HeadersInit = {} ) { - async function writeFile(buf: ArrayBuffer, pos: number) { - const release = await mutex.acquire(); - while (true) { - try { - await file.seek(pos, Deno.SeekMode.Start); - await file.write(new Uint8Array(buf)); - break; - } catch (e) { - console.error("%c" + e, "color: red"); - } - } - release(); - } - - async function getContentLength() { + async function getURLInfo() { const r = await fetch(url, { method: "HEAD", headers: headers, }); - return +r.headers.get("content-length")!; + const contentLength = +r.headers.get("content-length")!; + const disposition = r.headers.get("content-disposition"); + const filename = ( + disposition + ?.split(";") + .map((s) => s.trim()) + .find((s) => s.startsWith("filename=")) + ?.split("=")[1] ?? basename(url) + ).replace(/[\\/:*?"<>|]/g, "_"); + return { filename, contentLength }; } - // 初始化文件 - const dirpath = dirname(filename); - await Deno.mkdir(dirpath, { recursive: true }); - const file = await Deno.open(filename, { write: true, create: true }); - - // 读写锁 const mutex = new Mutex(); + const { contentLength, filename } = await getURLInfo(); + await Deno.mkdir(dirpath, { recursive: true }); + const file = await Deno.open(join(dirpath, filename), { + write: true, + create: true, + }); try { - // 获取文件长度 - const contentLength = await getContentLength(); const chunkCount = Math.ceil(contentLength / chunkSize); const chunks: Chunk[] = Array.from({ length: chunkCount }, (_, i) => ({ start: i * chunkSize, @@ -53,7 +46,17 @@ export async function download( headers, chunks, async (i) => { - await writeFile(i.data, i.origin.start); + const release = await mutex.acquire(); + while (true) { + try { + await file.seek(i.origin.start, Deno.SeekMode.Start); + await file.write(new Uint8Array(i.data)); + break; + } catch (e) { + console.error("%c" + e, "color: red"); + } + } + release(); console.log(`chunk ${i.origin.start} - ${i.origin.end} done`); }, Infinity @@ -73,5 +76,5 @@ if (import.meta.main) { const url = Deno.args[0]; const threads = +Deno.args[1] || 32; const dirpath = Deno.args[2] || "."; - await download(url, join(dirpath, basename(url)), threads); + await download(url, join(Deno.cwd(), dirpath), threads); }