Compare commits

...
2 Commits
Author SHA1 Message Date
nobswebdev 9696c85a8e Cache zeroperl.wasm in the ExifTool worker after first fetch.
Avoid repeat multi-megabyte downloads when Tor/Firefox do not HTTP-cache worker WASM responses.
2026-10-31 00:17:12 +01:00
nobswebdev c95af9576f Improve upload metadata status copy and stack status lines on all widths. 2026-10-31 00:10:18 +01:00
3 changed files with 27 additions and 8 deletions
@@ -26,7 +26,7 @@
{{ prettyBytes(row.file.size, { maximumFractionDigits: 1 }) }} {{ prettyBytes(row.file.size, { maximumFractionDigits: 1 }) }}
</span> </span>
</div> </div>
<div class="flex min-w-0 flex-col gap-0.5 text-xs sm:flex-row sm:flex-wrap sm:gap-x-3"> <div class="flex min-w-0 flex-col gap-0.5 text-xs">
<span class="min-w-0 truncate" :class="metadataStatusClass(row.metadata)"> <span class="min-w-0 truncate" :class="metadataStatusClass(row.metadata)">
{{ row.metadata.message }} {{ row.metadata.message }}
</span> </span>
+1 -1
View File
@@ -5,7 +5,7 @@ import type { MetadataPreviewEntry } from '@/types/metadata/MetadataPreview';
import { makeKeyFromFile } from '@/utils/file/makeKeyFromFile'; import { makeKeyFromFile } from '@/utils/file/makeKeyFromFile';
const METADATA_IDLE_MESSAGE = 'Waiting to load metadata...'; const METADATA_IDLE_MESSAGE = 'Waiting to load metadata...';
const EXIFTOOL_INITIALIZING_MESSAGE = 'Initializing ExifTool...'; const EXIFTOOL_INITIALIZING_MESSAGE = 'Initializing ExifTool. It may take a minute on slow networks...';
const METADATA_PROCESSING_MESSAGE = 'Stripping metadata...'; const METADATA_PROCESSING_MESSAGE = 'Stripping metadata...';
const METADATA_READY_MESSAGE = 'Metadata stripped'; const METADATA_READY_MESSAGE = 'Metadata stripped';
const METADATA_LOAD_ERROR_MESSAGE = 'Could not load image metadata'; const METADATA_LOAD_ERROR_MESSAGE = 'Could not load image metadata';
+25 -6
View File
@@ -6,8 +6,31 @@ import type { ExiftoolWorkerJob } from '@/types/workers/exiftoolWorkerJob';
import { resolveErrorMessage } from '@/utils/resolveErrorMessage'; import { resolveErrorMessage } from '@/utils/resolveErrorMessage';
import { toArrayBuffer } from '@/utils/toArrayBuffer'; import { toArrayBuffer } from '@/utils/toArrayBuffer';
let cachedZeroperlWasm: ArrayBuffer | null = null;
/**
* Load `zeroperl.wasm` once per worker lifetime. Tor/Firefox often skip HTTP cache for
* worker fetches and may not store responses above the memory-cache entry size limit.
*/
const fetchZeroperlWasm = async (): Promise<Response> => {
if (!cachedZeroperlWasm) {
const response = await fetch(zeroperlWasmUrl);
if (!response.ok) {
throw new Error(`Failed to load zeroperl.wasm: HTTP ${response.status}`);
}
cachedZeroperlWasm = await response.arrayBuffer();
}
return new Response(cachedZeroperlWasm, {
status: 200,
headers: { 'Content-Type': 'application/wasm' }
});
};
/** Custom fetch function for `@uswriting/exiftool` to load `zeroperl.wasm` from the worker. */ /** Custom fetch function for `@uswriting/exiftool` to load `zeroperl.wasm` from the worker. */
const exiftoolParseOptions = { fetch: () => fetch(zeroperlWasmUrl) }; const exiftoolParseOptions = { fetch: fetchZeroperlWasm };
const jobQueue: ExiftoolWorkerJob[] = []; const jobQueue: ExiftoolWorkerJob[] = [];
let drainPromise: Promise<void> | null = null; let drainPromise: Promise<void> | null = null;
@@ -137,11 +160,7 @@ const processJob = async (job: ExiftoolWorkerJob): Promise<void> => {
try { try {
await initializeWorker(); await initializeWorker();
const result = await writeMetadata( const result = await writeMetadata(job.file, {}, { args: ['-all='], ...exiftoolParseOptions });
job.file,
{},
{ args: ['-all='], ...exiftoolParseOptions }
);
if (!result.success) { if (!result.success) {
const message = result.error ?? 'Could not strip image metadata'; const message = result.error ?? 'Could not strip image metadata';