From e55a825e134736143f9f563486fd60aeede6c44d Mon Sep 17 00:00:00 2001 From: Nose Date: Fri, 19 Jun 2026 14:27:27 -0700 Subject: [PATCH] update App.tsx for embedding --- src/App.tsx | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 074a64e..4e39c62 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -286,6 +286,20 @@ function triggerBrowserDownload(href: string, fileName: string) { link.remove() } +async function withAsyncTimeout(promise: Promise, timeoutMs: number, message: string): Promise { + let timeoutHandle: ReturnType | null = null + + const timeoutPromise = new Promise((_, reject) => { + timeoutHandle = setTimeout(() => reject(new Error(message)), timeoutMs) + }) + + try { + return await Promise.race([promise, timeoutPromise]) + } finally { + if (timeoutHandle) clearTimeout(timeoutHandle) + } +} + async function embedDownloadMetadata(blob: Blob, track: Track, details?: HydrusFileDetails | null, contentType?: string | null) { const metadata = buildHydrusDownloadMetadata(track, details) if (isMp3Download(track, details, contentType)) { @@ -312,7 +326,11 @@ async function embedDownloadMetadata(blob: Blob, track: Track, details?: HydrusF if (!metadata.title && !metadata.artist && !metadata.album && !metadata.trackNumber) return { blob, note: undefined as string | undefined } try { - const taggedBlob = await embedContainerAudioMetadata(blob, getTrackExtension(track, details), metadata) + const taggedBlob = await withAsyncTimeout( + embedContainerAudioMetadata(blob, getTrackExtension(track, details), metadata), + 15000, + 'Metadata embedding timed out' + ) return { blob: taggedBlob, @@ -760,10 +778,19 @@ function App() { }) } - updateDownload(id, { - note: 'Embedding metadata...', - }) - const taggedDownload = await embedDownloadMetadata(blob, track, details, response.headers.get('content-type')) + const shouldEmbedMetadataClientSide = !isAppleMobileOrTablet + const taggedDownload = shouldEmbedMetadataClientSide + ? await (async () => { + updateDownload(id, { + note: 'Embedding metadata...', + }) + return embedDownloadMetadata(blob, track, details, response.headers.get('content-type')) + })() + : { + blob, + note: 'iOS download: using server-provided metadata (client embedding skipped)', + } + blob = taggedDownload.blob const downloadName = buildTrackDownloadName(track, details, response.headers.get('content-disposition')) const objectUrl = window.URL.createObjectURL(blob) @@ -809,7 +836,7 @@ function App() { delete downloadAbortControllersRef.current[id] } })() - }, [downloads, updateDownload]) + }, [downloads, isAppleMobileOrTablet, updateDownload]) const cancelDownload = useCallback((id: string) => { const controller = downloadAbortControllersRef.current[id]