Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	
		coyotte508
		
	commited on
		
		
					Commit 
							
							·
						
						075be5d
	
1
								Parent(s):
							
							e5bdcf2
								
structure
Browse files- .vscode/settings.json +3 -0
 - src/lib/WebBlob.ts +111 -0
 - src/lib/check-dduf.ts +3 -0
 - src/routes/+page.svelte +36 -2
 
    	
        .vscode/settings.json
    ADDED
    
    | 
         @@ -0,0 +1,3 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            {
         
     | 
| 2 | 
         
            +
              "editor.formatOnSave": true
         
     | 
| 3 | 
         
            +
            }
         
     | 
    	
        src/lib/WebBlob.ts
    ADDED
    
    | 
         @@ -0,0 +1,111 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            /**
         
     | 
| 2 | 
         
            +
             * WebBlob is a Blob implementation for web resources that supports range requests.
         
     | 
| 3 | 
         
            +
             */
         
     | 
| 4 | 
         
            +
             
     | 
| 5 | 
         
            +
            interface WebBlobCreateOptions {
         
     | 
| 6 | 
         
            +
            	/**
         
     | 
| 7 | 
         
            +
            	 * @default 1_000_000
         
     | 
| 8 | 
         
            +
            	 *
         
     | 
| 9 | 
         
            +
            	 * Objects below that size will immediately be fetched and put in RAM, rather
         
     | 
| 10 | 
         
            +
            	 * than streamed ad-hoc
         
     | 
| 11 | 
         
            +
            	 */
         
     | 
| 12 | 
         
            +
            	cacheBelow?: number;
         
     | 
| 13 | 
         
            +
            	/**
         
     | 
| 14 | 
         
            +
            	 * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
         
     | 
| 15 | 
         
            +
            	 */
         
     | 
| 16 | 
         
            +
            	fetch?: typeof fetch;
         
     | 
| 17 | 
         
            +
            }
         
     | 
| 18 | 
         
            +
             
     | 
| 19 | 
         
            +
            export class WebBlob extends Blob {
         
     | 
| 20 | 
         
            +
            	static async create(url: URL, opts?: WebBlobCreateOptions): Promise<Blob> {
         
     | 
| 21 | 
         
            +
            		const customFetch = opts?.fetch ?? fetch;
         
     | 
| 22 | 
         
            +
            		const response = await customFetch(url, { method: "HEAD" });
         
     | 
| 23 | 
         
            +
             
     | 
| 24 | 
         
            +
            		const size = Number(response.headers.get("content-length"));
         
     | 
| 25 | 
         
            +
            		const contentType = response.headers.get("content-type") || "";
         
     | 
| 26 | 
         
            +
            		const supportRange = response.headers.get("accept-ranges") === "bytes";
         
     | 
| 27 | 
         
            +
             
     | 
| 28 | 
         
            +
            		if (!supportRange || size < (opts?.cacheBelow ?? 1_000_000)) {
         
     | 
| 29 | 
         
            +
            			return await (await customFetch(url)).blob();
         
     | 
| 30 | 
         
            +
            		}
         
     | 
| 31 | 
         
            +
             
     | 
| 32 | 
         
            +
            		return new WebBlob(url, 0, size, contentType, true, customFetch);
         
     | 
| 33 | 
         
            +
            	}
         
     | 
| 34 | 
         
            +
             
     | 
| 35 | 
         
            +
            	private url: URL;
         
     | 
| 36 | 
         
            +
            	private start: number;
         
     | 
| 37 | 
         
            +
            	private end: number;
         
     | 
| 38 | 
         
            +
            	private contentType: string;
         
     | 
| 39 | 
         
            +
            	private full: boolean;
         
     | 
| 40 | 
         
            +
            	private fetch: typeof fetch;
         
     | 
| 41 | 
         
            +
             
     | 
| 42 | 
         
            +
            	constructor(url: URL, start: number, end: number, contentType: string, full: boolean, customFetch: typeof fetch) {
         
     | 
| 43 | 
         
            +
            		super([]);
         
     | 
| 44 | 
         
            +
             
     | 
| 45 | 
         
            +
            		this.url = url;
         
     | 
| 46 | 
         
            +
            		this.start = start;
         
     | 
| 47 | 
         
            +
            		this.end = end;
         
     | 
| 48 | 
         
            +
            		this.contentType = contentType;
         
     | 
| 49 | 
         
            +
            		this.full = full;
         
     | 
| 50 | 
         
            +
            		this.fetch = customFetch;
         
     | 
| 51 | 
         
            +
            	}
         
     | 
| 52 | 
         
            +
             
     | 
| 53 | 
         
            +
            	override get size(): number {
         
     | 
| 54 | 
         
            +
            		return this.end - this.start;
         
     | 
| 55 | 
         
            +
            	}
         
     | 
| 56 | 
         
            +
             
     | 
| 57 | 
         
            +
            	override get type(): string {
         
     | 
| 58 | 
         
            +
            		return this.contentType;
         
     | 
| 59 | 
         
            +
            	}
         
     | 
| 60 | 
         
            +
             
     | 
| 61 | 
         
            +
            	override slice(start = 0, end = this.size): WebBlob {
         
     | 
| 62 | 
         
            +
            		if (start < 0 || end < 0) {
         
     | 
| 63 | 
         
            +
            			new TypeError("Unsupported negative start/end on FileBlob.slice");
         
     | 
| 64 | 
         
            +
            		}
         
     | 
| 65 | 
         
            +
             
     | 
| 66 | 
         
            +
            		const slice = new WebBlob(
         
     | 
| 67 | 
         
            +
            			this.url,
         
     | 
| 68 | 
         
            +
            			this.start + start,
         
     | 
| 69 | 
         
            +
            			Math.min(this.start + end, this.end),
         
     | 
| 70 | 
         
            +
            			this.contentType,
         
     | 
| 71 | 
         
            +
            			start === 0 && end === this.size ? this.full : false,
         
     | 
| 72 | 
         
            +
            			this.fetch
         
     | 
| 73 | 
         
            +
            		);
         
     | 
| 74 | 
         
            +
             
     | 
| 75 | 
         
            +
            		return slice;
         
     | 
| 76 | 
         
            +
            	}
         
     | 
| 77 | 
         
            +
             
     | 
| 78 | 
         
            +
            	override async arrayBuffer(): Promise<ArrayBuffer> {
         
     | 
| 79 | 
         
            +
            		const result = await this.fetchRange();
         
     | 
| 80 | 
         
            +
             
     | 
| 81 | 
         
            +
            		return result.arrayBuffer();
         
     | 
| 82 | 
         
            +
            	}
         
     | 
| 83 | 
         
            +
             
     | 
| 84 | 
         
            +
            	override async text(): Promise<string> {
         
     | 
| 85 | 
         
            +
            		const result = await this.fetchRange();
         
     | 
| 86 | 
         
            +
             
     | 
| 87 | 
         
            +
            		return result.text();
         
     | 
| 88 | 
         
            +
            	}
         
     | 
| 89 | 
         
            +
             
     | 
| 90 | 
         
            +
            	override stream(): ReturnType<Blob["stream"]> {
         
     | 
| 91 | 
         
            +
            		const stream = new TransformStream();
         
     | 
| 92 | 
         
            +
             
     | 
| 93 | 
         
            +
            		this.fetchRange()
         
     | 
| 94 | 
         
            +
            			.then((response) => response.body?.pipeThrough(stream))
         
     | 
| 95 | 
         
            +
            			.catch((error) => stream.writable.abort(error.message));
         
     | 
| 96 | 
         
            +
             
     | 
| 97 | 
         
            +
            		return stream.readable;
         
     | 
| 98 | 
         
            +
            	}
         
     | 
| 99 | 
         
            +
             
     | 
| 100 | 
         
            +
            	private fetchRange(): Promise<Response> {
         
     | 
| 101 | 
         
            +
            		const fetch = this.fetch; // to avoid this.fetch() which is bound to the instance instead of globalThis
         
     | 
| 102 | 
         
            +
            		if (this.full) {
         
     | 
| 103 | 
         
            +
            			return fetch(this.url);
         
     | 
| 104 | 
         
            +
            		}
         
     | 
| 105 | 
         
            +
            		return fetch(this.url, {
         
     | 
| 106 | 
         
            +
            			headers: {
         
     | 
| 107 | 
         
            +
            				Range: `bytes=${this.start}-${this.end - 1}`,
         
     | 
| 108 | 
         
            +
            			},
         
     | 
| 109 | 
         
            +
            		});
         
     | 
| 110 | 
         
            +
            	}
         
     | 
| 111 | 
         
            +
            }
         
     | 
    	
        src/lib/check-dduf.ts
    ADDED
    
    | 
         @@ -0,0 +1,3 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            export async function checkDduf(url: string): Promise<string> {
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
            }
         
     | 
    	
        src/routes/+page.svelte
    CHANGED
    
    | 
         @@ -1,2 +1,36 @@ 
     | 
|
| 1 | 
         
            -
            < 
     | 
| 2 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            <script lang="ts">
         
     | 
| 2 | 
         
            +
            	import { goto } from '$app/navigation';
         
     | 
| 3 | 
         
            +
            	import { checkDduf } from '$lib/check-dduf';
         
     | 
| 4 | 
         
            +
             
     | 
| 5 | 
         
            +
            	let url = '';
         
     | 
| 6 | 
         
            +
            	let output = '';
         
     | 
| 7 | 
         
            +
             
     | 
| 8 | 
         
            +
            	async function handleSubmit(event: Event) {
         
     | 
| 9 | 
         
            +
            		event.preventDefault();
         
     | 
| 10 | 
         
            +
             
     | 
| 11 | 
         
            +
            		output = await checkDduf(url);
         
     | 
| 12 | 
         
            +
            	}
         
     | 
| 13 | 
         
            +
            </script>
         
     | 
| 14 | 
         
            +
             
     | 
| 15 | 
         
            +
            <div class="flex flex-col gap-4 p-4">
         
     | 
| 16 | 
         
            +
            	<h1 class="text-xl font-bold">DDUF Check</h1>
         
     | 
| 17 | 
         
            +
             
     | 
| 18 | 
         
            +
            	<form class="flex flex-col gap-4" onsubmit={handleSubmit}>
         
     | 
| 19 | 
         
            +
            		<label class="flex flex-col gap-2">
         
     | 
| 20 | 
         
            +
            			DDUF URL (resolved url)
         
     | 
| 21 | 
         
            +
            			<input
         
     | 
| 22 | 
         
            +
            				type="url"
         
     | 
| 23 | 
         
            +
            				name="url"
         
     | 
| 24 | 
         
            +
            				placeholder="https://huggingface.co/name/repo/main/resolve/file.dduf"
         
     | 
| 25 | 
         
            +
            				bind:value={url}
         
     | 
| 26 | 
         
            +
            				class="w-full rounded-md border border-gray-300 p-2"
         
     | 
| 27 | 
         
            +
            			/>
         
     | 
| 28 | 
         
            +
            		</label>
         
     | 
| 29 | 
         
            +
             
     | 
| 30 | 
         
            +
            		<button type="submit" class="self-start rounded-md bg-blue-500 p-2 text-white">Check</button>
         
     | 
| 31 | 
         
            +
             
     | 
| 32 | 
         
            +
            		<textarea class="w-full rounded-md border border-gray-300 p-2" rows="10" readonly
         
     | 
| 33 | 
         
            +
            			>{output}</textarea
         
     | 
| 34 | 
         
            +
            		>
         
     | 
| 35 | 
         
            +
            	</form>
         
     | 
| 36 | 
         
            +
            </div>
         
     |