From e63dc30a7f07be11d2b68fcf27b297b6728ed0a5 Mon Sep 17 00:00:00 2001 From: Robin Choice Date: Mon, 13 Apr 2026 18:30:50 +0200 Subject: [PATCH] fix: remove ContentLength from presigned URL, fix macOS multi-select - ContentLength in PutObjectCommand causes XHR upload failures (browser does not send matching Content-Length header in presigned PUT requests) - Change accept to audio/* so macOS Finder allows multi-file selection - Add step prefix to errors ([URL]/[S3]/[DB]) for easier debugging Co-Authored-By: Claude Sonnet 4.6 --- apps/api/src/storage/s3.ts | 3 +-- .../audio/StemUploadDropzone.svelte | 20 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/api/src/storage/s3.ts b/apps/api/src/storage/s3.ts index e12067c..4e005c6 100644 --- a/apps/api/src/storage/s3.ts +++ b/apps/api/src/storage/s3.ts @@ -21,13 +21,12 @@ const bucket = process.env.S3_BUCKET!; export async function createUploadUrl( key: string, contentType: string, - maxSize: number, + _maxSize?: number, ): Promise { const command = new PutObjectCommand({ Bucket: bucket, Key: key, ContentType: contentType, - ContentLength: maxSize, }); return getSignedUrl(s3, command, { expiresIn: 900 }); // 15 min } diff --git a/apps/web/src/lib/components/audio/StemUploadDropzone.svelte b/apps/web/src/lib/components/audio/StemUploadDropzone.svelte index 73b7955..5175a86 100644 --- a/apps/web/src/lib/components/audio/StemUploadDropzone.svelte +++ b/apps/web/src/lib/components/audio/StemUploadDropzone.svelte @@ -62,35 +62,39 @@ } async function uploadOne(file: File, idx: number) { + let step = 'URL'; try { + const mimeType = file.type || 'audio/wav'; const { uploadUrl, fileKey } = await api.post<{ uploadUrl: string; fileKey: string }>( `/stems/track/${trackId}/upload-url`, - { fileName: file.name, mimeType: file.type || 'audio/wav', fileSize: file.size }, + { fileName: file.name, mimeType, fileSize: file.size }, ); - await uploadWithProgress(uploadUrl, file, (p) => { + step = 'S3'; + await uploadWithProgress(uploadUrl, file, mimeType, (p) => { files[idx] = { ...files[idx], progress: p }; }); + step = 'DB'; await api.post(`/stems/track/${trackId}`, { fileKey, name: stemNameFromFile(file.name), originalFileName: file.name, - mimeType: file.type || 'audio/wav', + mimeType, fileSize: file.size, }); files[idx] = { ...files[idx], progress: 100 }; } catch (err) { - files[idx] = { ...files[idx], error: err instanceof Error ? err.message : 'Fehler' }; + files[idx] = { ...files[idx], error: `[${step}] ${err instanceof Error ? err.message : 'Fehler'}` }; } } - function uploadWithProgress(url: string, file: File, onProgress: (p: number) => void): Promise { + function uploadWithProgress(url: string, file: File, mimeType: string, onProgress: (p: number) => void): Promise { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('PUT', url); - xhr.setRequestHeader('Content-Type', file.type || 'audio/wav'); + xhr.setRequestHeader('Content-Type', mimeType); xhr.upload.onprogress = (e) => { if (e.lengthComputable) onProgress(Math.round((e.loaded / e.total) * 100)); }; @@ -117,7 +121,7 @@

STEMs hier ablegen oder klicken

- Mehrere Dateien gleichzeitig möglich · WAV, FLAC, AIFF · max 500 MB + Mehrere Dateien gleichzeitig möglich · WAV, MP3, FLAC, AIFF · max 500 MB