aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/package.json1
-rw-r--r--app/src/lib/svelte/Navigation.svelte2
-rw-r--r--app/src/lib/ts/crc32.worker.ts10
-rw-r--r--app/src/lib/ts/download.ts33
-rw-r--r--app/src/lib/ts/truncate.worker.ts10
-rw-r--r--app/src/lib/types/truncate-worker.ts8
-rw-r--r--app/src/routes/crc32/+page.svelte55
-rw-r--r--app/src/routes/truncate/+page.svelte75
-rw-r--r--app/tsconfig.json2
-rw-r--r--pnpm-lock.yaml7
10 files changed, 136 insertions, 67 deletions
diff --git a/app/package.json b/app/package.json
index dce4f60..2905c41 100644
--- a/app/package.json
+++ b/app/package.json
@@ -14,6 +14,7 @@
"@tailwindcss/typography": "0.5.10",
"@types/html-minifier-terser": "^7.0.0",
"@types/node": "20.6.0",
+ "@types/wicg-file-system-access": "^2020.9.8",
"@typescript-eslint/eslint-plugin": "^6.7.3",
"@typescript-eslint/parser": "^6.7.3",
"@vite-pwa/sveltekit": "^0.2.7",
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>
diff --git a/app/tsconfig.json b/app/tsconfig.json
index a25e61a..8cac8a3 100644
--- a/app/tsconfig.json
+++ b/app/tsconfig.json
@@ -9,7 +9,7 @@
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
- "types": ["vite-plugin-pwa/client"]
+ "types": ["vite-plugin-pwa/client", "@types/wicg-file-system-access"]
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index adbe91b..43251d9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -48,6 +48,9 @@ importers:
'@types/node':
specifier: 20.6.0
version: 20.6.0
+ '@types/wicg-file-system-access':
+ specifier: ^2020.9.8
+ version: 2020.9.8
'@typescript-eslint/eslint-plugin':
specifier: ^6.7.3
version: 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2)
@@ -1886,6 +1889,10 @@ packages:
resolution: {integrity: sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==}
dev: true
+ /@types/wicg-file-system-access@2020.9.8:
+ resolution: {integrity: sha512-ggMz8nOygG7d/stpH40WVaNvBwuyYLnrg5Mbyf6bmsj/8+gb6Ei4ZZ9/4PNpcPNTT8th9Q8sM8wYmWGjMWLX/A==}
+ dev: true
+
/@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2):
resolution: {integrity: sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==}
engines: {node: ^16.0.0 || >=18.0.0}