81 lines
1.9 KiB
TypeScript
81 lines
1.9 KiB
TypeScript
import type { AssetRef } from '@tts/shared';
|
|
|
|
/** Guess a MIME type from a URL's file extension. */
|
|
export function guessMimeType(url: string): string {
|
|
const ext = url.split('?')[0]!.split('.').pop()!.toLowerCase();
|
|
switch (ext) {
|
|
case 'png':
|
|
return 'image/png';
|
|
case 'jpg':
|
|
case 'jpeg':
|
|
return 'image/jpeg';
|
|
case 'gif':
|
|
return 'image/gif';
|
|
case 'webp':
|
|
return 'image/webp';
|
|
case 'pdf':
|
|
return 'application/pdf';
|
|
default:
|
|
return 'application/octet-stream';
|
|
}
|
|
}
|
|
|
|
/** Download a single asset as a `Blob`. */
|
|
export async function downloadAsset(url: string): Promise<Blob> {
|
|
const res = await fetch(url);
|
|
if (!res.ok) {
|
|
throw new Error(`Failed to download asset (${res.status}): ${url}`);
|
|
}
|
|
return res.blob();
|
|
}
|
|
|
|
export interface DownloadProgress {
|
|
done: number;
|
|
total: number;
|
|
url: string;
|
|
}
|
|
|
|
export interface DownloadOptions {
|
|
concurrency?: number;
|
|
onProgress?: (p: DownloadProgress) => void;
|
|
}
|
|
|
|
export interface DownloadedAsset {
|
|
ref: AssetRef;
|
|
blob: Blob;
|
|
}
|
|
|
|
/**
|
|
* Download multiple assets with limited concurrency and a progress callback.
|
|
*/
|
|
export async function downloadAll(
|
|
refs: AssetRef[],
|
|
options: DownloadOptions = {},
|
|
): Promise<DownloadedAsset[]> {
|
|
const concurrency = options.concurrency ?? 4;
|
|
const results: DownloadedAsset[] = [];
|
|
let done = 0;
|
|
|
|
const worker = async (ref: AssetRef): Promise<void> => {
|
|
const blob = await downloadAsset(ref.url);
|
|
results.push({ ref, blob });
|
|
done += 1;
|
|
options.onProgress?.({ done, total: refs.length, url: ref.url });
|
|
};
|
|
|
|
const queue = [...refs];
|
|
const workers: Promise<void>[] = [];
|
|
for (let i = 0; i < Math.min(concurrency, queue.length); i++) {
|
|
workers.push(
|
|
(async () => {
|
|
while (queue.length > 0) {
|
|
const ref = queue.shift()!;
|
|
await worker(ref);
|
|
}
|
|
})(),
|
|
);
|
|
}
|
|
|
|
await Promise.all(workers);
|
|
return results;
|
|
} |