diff options
Diffstat (limited to '')
-rw-r--r-- | app/src/lib/svelte/Navigation.svelte | 2 | ||||
-rw-r--r-- | app/src/lib/ts/crc32.worker.ts | 10 | ||||
-rw-r--r-- | app/src/lib/ts/download.ts | 33 | ||||
-rw-r--r-- | app/src/lib/ts/truncate.worker.ts | 10 | ||||
-rw-r--r-- | app/src/lib/types/truncate-worker.ts | 8 | ||||
-rw-r--r-- | app/src/routes/crc32/+page.svelte | 55 | ||||
-rw-r--r-- | app/src/routes/truncate/+page.svelte | 75 |
7 files changed, 127 insertions, 66 deletions
diff --git a/app/src/lib/svelte/Navigation.svelte b/app/src/lib/svelte/Navigation.svelte index 20c7d8b..fd3c914 100644 --- a/app/src/lib/svelte/Navigation.svelte +++ b/app/src/lib/svelte/Navigation.svelte @@ -7,5 +7,5 @@ <svelte:fragment slot="lead"> <AppRailAnchor href="/" selected={$page.url.pathname === '/'}>Home!</AppRailAnchor> </svelte:fragment> - <AppRailAnchor href="/crc32" selected={$page.url.pathname === '/crc32'}>CRC32</AppRailAnchor> + <AppRailAnchor href="/truncate" selected={$page.url.pathname === '/truncate'}>Truncate!</AppRailAnchor> </AppRail> diff --git a/app/src/lib/ts/crc32.worker.ts b/app/src/lib/ts/crc32.worker.ts deleted file mode 100644 index 57c1bc9..0000000 --- a/app/src/lib/ts/crc32.worker.ts +++ /dev/null @@ -1,10 +0,0 @@ -// TODO: Think about using a WebAssembly implementation of CRC32 instead of JavaScript. -// WHY? The JavaScript implementation is not very extensible and is not very fast. -import crc32 from 'crc/crc32'; - -onmessage = async (message: MessageEvent<File>) => { - const file = message.data; - const buffer = await file.arrayBuffer(); - const crc = crc32(buffer); - postMessage(crc); -}; diff --git a/app/src/lib/ts/download.ts b/app/src/lib/ts/download.ts new file mode 100644 index 0000000..a6167d7 --- /dev/null +++ b/app/src/lib/ts/download.ts @@ -0,0 +1,33 @@ +// Yoinked from https://web.dev/patterns/files/save-a-file/ for the polyfill + +export default async function saveFile(blob: ArrayBuffer, suggestedName: string | undefined) { + const supportsFSAccess = 'showSaveFilePicker' in window && + (() => { + try { + return window.self === window.top; + } catch { + return false; + } + })(); + + if (supportsFSAccess) { + try { + const handle = await window.showSaveFilePicker({ + suggestedName: suggestedName, + }) + const writable = await handle.createWritable(); + await writable.write(blob); + await writable.close(); + } catch (err: unknown) { + // TypeScript + if ((err as Error)?.name !== 'AbortError') { + console.error(err); + } + } + } else { + const anchor = document.createElement('a'); + anchor.download = suggestedName ?? 'truncated'; + anchor.href = URL.createObjectURL(new Blob([blob])); + anchor.click(); + } +}
\ No newline at end of file diff --git a/app/src/lib/ts/truncate.worker.ts b/app/src/lib/ts/truncate.worker.ts new file mode 100644 index 0000000..52eebb7 --- /dev/null +++ b/app/src/lib/ts/truncate.worker.ts @@ -0,0 +1,10 @@ +import type { TruncateRequest, TruncateResponse } from '../types/truncate-worker'; + + +onmessage = async (message: MessageEvent<TruncateRequest>) => { + const file = message.data.file; + const buffer = await file.arrayBuffer(); + const truncated = buffer.slice(0, message.data.size); + + postMessage({ file: truncated } as TruncateResponse); +}
\ No newline at end of file diff --git a/app/src/lib/types/truncate-worker.ts b/app/src/lib/types/truncate-worker.ts new file mode 100644 index 0000000..9b1872f --- /dev/null +++ b/app/src/lib/types/truncate-worker.ts @@ -0,0 +1,8 @@ +export type TruncateRequest = { + file: File, + size: number, +}; + +export type TruncateResponse = { + file: ArrayBuffer, +}; diff --git a/app/src/routes/crc32/+page.svelte b/app/src/routes/crc32/+page.svelte deleted file mode 100644 index b88e52e..0000000 --- a/app/src/routes/crc32/+page.svelte +++ /dev/null @@ -1,55 +0,0 @@ -<script lang="ts"> - import { FileDropzone, ProgressBar } from '@skeletonlabs/skeleton'; - import { onMount } from 'svelte'; - - let disableInput = false; - let files: FileList; - let form: HTMLFormElement; - let worker: Worker; - - function onUpload() { - disableInput = true; - worker.postMessage(files[0]); - form.reset(); - } - - onMount(async () => { - worker = new Worker(new URL('$lib/ts/crc32.worker.ts', import.meta.url), { type: 'module' }); - worker.onmessage = (e: MessageEvent<number>) => { - disableInput = false; - console.log(e.data); - }; - }); -</script> - -<svelte:head> - <title>CRC32</title> -</svelte:head> - -<div class="container h-full mx-auto flex justify-center items-center"> - <div class="space-y-10 text-center flex flex-col items-center"> - <form bind:this={form} on:submit|preventDefault={onUpload} method="POST" action="?/TODO"> - <FileDropzone - name="checksumMe" - bind:files - on:change={() => form.requestSubmit()} - required - disabled={disableInput} - > - <svelte:fragment slot="lead"> - <h2 class="h2">Drop a file here to get its CRC32 checksum.</h2> - </svelte:fragment> - </FileDropzone> - <br /> - <noscript> - <button type="submit" class="btn variant-filled"> - After adding a file, click to submit! (Not yet implemented) - </button> - </noscript> - {#if disableInput} - <h3 class="h3">Calculating the checksum, this may take time!</h3> <br /> - <ProgressBar /> - {/if} - </form> - </div> -</div> diff --git a/app/src/routes/truncate/+page.svelte b/app/src/routes/truncate/+page.svelte new file mode 100644 index 0000000..9e2545f --- /dev/null +++ b/app/src/routes/truncate/+page.svelte @@ -0,0 +1,75 @@ +<script lang="ts"> + import saveFile from '$lib/ts/download'; + import type { TruncateRequest, TruncateResponse } from '$lib/types/truncate-worker'; + import { FileDropzone, ProgressBar } from '@skeletonlabs/skeleton'; + import { onMount } from 'svelte'; + + let disableInput = false; + let files: FileList; + let form: HTMLFormElement; + let worker: Worker; + $: truncateTo = 1; + let originalName: string; + + function onUpload() { + disableInput = true; + originalName = files[0].name; + worker.postMessage({ + file: files[0], + size: truncateTo, + } as TruncateRequest); + form.reset(); + truncateTo = 1; + } + + onMount(async () => { + worker = new Worker(new URL('$lib/ts/truncate.worker.ts', import.meta.url), { type: 'module' }); + worker.onmessage = (e: MessageEvent<TruncateResponse>) => { + disableInput = false; + saveFile(e.data.file, `trunc-${originalName}`); + + }; + }); +</script> + +<svelte:head> + <title>Truncate</title> +</svelte:head> + +<div class="container h-full mx-auto flex justify-center items-center"> + <div class="space-y-10 text-center flex flex-col items-center"> + <form bind:this={form} on:submit|preventDefault={onUpload} method="POST" action="?/TODO"> + <label class="label" for="truncateMe"> + <FileDropzone + id="truncateMe" + name="truncateMe" + bind:files + on:change={() => form.requestSubmit()} + required + disabled={disableInput} + > + <svelte:fragment slot="lead"> + <h2 class="h2">Drop a file here to truncate it.</h2> + </svelte:fragment> + </FileDropzone> + </label> + <br /> + <label class="label"> + <span>Truncate up to... (in bytes)</span> + <input class="input" type="number" name="truncateTo" bind:value={truncateTo} min="1" required /> + + </label> + <br /> + <noscript> + <button type="submit" class="btn variant-filled" + >After adding a file, click to submit! (Not yet implemented)</button + > + </noscript> + {#if disableInput} + <h3 class="h3">Truncating the file, this may take time!</h3> + <br /> + <ProgressBar /> + {/if} + </form> + </div> +</div> |