From d0e9cbcaa6a6f517a1e3995c2bb92af005da96d6 Mon Sep 17 00:00:00 2001 From: ztimson Date: Sun, 21 Apr 2024 21:33:38 -0400 Subject: [PATCH] Added download utilities --- package.json | 2 +- src/download.ts | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 1 + src/xhr.ts | 18 +----------------- 4 files changed, 49 insertions(+), 18 deletions(-) create mode 100644 src/download.ts diff --git a/package.json b/package.json index 207cf92..c995707 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ztimson/utils", - "version": "0.5.0", + "version": "0.6.0", "description": "Utility library", "author": "Zak Timson", "license": "MIT", diff --git a/src/download.ts b/src/download.ts new file mode 100644 index 0000000..e1810bc --- /dev/null +++ b/src/download.ts @@ -0,0 +1,46 @@ +import {TypedEmitter, TypedEvents} from './emitter.ts'; + +export type downloadEvents = TypedEvents & { + complete: (blob: Blob) => any; + progress: (progress: number) => any; +} + +export function download(href: any, name: string) { + const a = document.createElement('a'); + a.href = href; + a.download = name; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); +} + +export function downloadStream(url: string, name?: string) { + const emitter = new TypedEmitter(); + fetch(url).then(response => { + const contentLength = response.headers.get('Content-Length') || '0'; + const total = parseInt(contentLength, 10); + let chunks: any[] = [], loaded = 0; + const reader = response.body?.getReader(); + reader?.read().then(function processResult(result) { + if(result.done) { + const blob = new Blob(chunks); + emitter.emit('progress', 1); + if(name) { + const url = URL.createObjectURL(blob); + download(url, name); + URL.revokeObjectURL(url); + } + emitter.emit('complete', blob); + return; + } else { + const chunk = result.value; + chunks.push(chunk); + loaded += chunk.length; + const progress = Math.round((loaded / total) * 100); + emitter.emit('progress', progress); + reader.read().then(processResult); + } + }); + }); + return emitter; +} diff --git a/src/index.ts b/src/index.ts index ba3acb0..bf9ae54 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ export * from './array'; export * from './aset'; +export * from './download.ts'; export * from './emitter'; export * from './errors'; export * from './logger'; diff --git a/src/xhr.ts b/src/xhr.ts index d70d83c..7fa4132 100644 --- a/src/xhr.ts +++ b/src/xhr.ts @@ -1,3 +1,4 @@ +import {TypedEmitter, TypedEvents} from './emitter.ts'; import {clean} from './objects'; export type Interceptor = (request: Response, next: () => void) => void; @@ -45,14 +46,6 @@ export class XHR { return () => { this.interceptors[key] = null; } } - download(opts: RequestOptions & {url: string}) { - this.request({...opts, skipConverting: true}).then(async resp => { - const blob = await resp.blob(); - download(URL.createObjectURL(blob), opts.url.split('/').pop()); - URL.revokeObjectURL(opts.url); - }); - } - async request(opts: RequestOptions = {}): Promise { if(!this.opts.url && !opts.url) throw new Error('URL needs to be set'); const url = (opts.url?.startsWith('http') ? opts.url : (this.opts.url || '') + (opts.url || '')).replace(/([^:]\/)\/+/g, '$1'); @@ -82,12 +75,3 @@ export class XHR { }); } } - -export function download(href: any, name: string) { - const a = document.createElement('a'); - a.href = href; - a.download = name; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); -}