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 <noreply@anthropic.com>
This commit is contained in:
@@ -21,13 +21,12 @@ const bucket = process.env.S3_BUCKET!;
|
|||||||
export async function createUploadUrl(
|
export async function createUploadUrl(
|
||||||
key: string,
|
key: string,
|
||||||
contentType: string,
|
contentType: string,
|
||||||
maxSize: number,
|
_maxSize?: number,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const command = new PutObjectCommand({
|
const command = new PutObjectCommand({
|
||||||
Bucket: bucket,
|
Bucket: bucket,
|
||||||
Key: key,
|
Key: key,
|
||||||
ContentType: contentType,
|
ContentType: contentType,
|
||||||
ContentLength: maxSize,
|
|
||||||
});
|
});
|
||||||
return getSignedUrl(s3, command, { expiresIn: 900 }); // 15 min
|
return getSignedUrl(s3, command, { expiresIn: 900 }); // 15 min
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,35 +62,39 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function uploadOne(file: File, idx: number) {
|
async function uploadOne(file: File, idx: number) {
|
||||||
|
let step = 'URL';
|
||||||
try {
|
try {
|
||||||
|
const mimeType = file.type || 'audio/wav';
|
||||||
const { uploadUrl, fileKey } = await api.post<{ uploadUrl: string; fileKey: string }>(
|
const { uploadUrl, fileKey } = await api.post<{ uploadUrl: string; fileKey: string }>(
|
||||||
`/stems/track/${trackId}/upload-url`,
|
`/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 };
|
files[idx] = { ...files[idx], progress: p };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
step = 'DB';
|
||||||
await api.post(`/stems/track/${trackId}`, {
|
await api.post(`/stems/track/${trackId}`, {
|
||||||
fileKey,
|
fileKey,
|
||||||
name: stemNameFromFile(file.name),
|
name: stemNameFromFile(file.name),
|
||||||
originalFileName: file.name,
|
originalFileName: file.name,
|
||||||
mimeType: file.type || 'audio/wav',
|
mimeType,
|
||||||
fileSize: file.size,
|
fileSize: file.size,
|
||||||
});
|
});
|
||||||
|
|
||||||
files[idx] = { ...files[idx], progress: 100 };
|
files[idx] = { ...files[idx], progress: 100 };
|
||||||
} catch (err) {
|
} 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<void> {
|
function uploadWithProgress(url: string, file: File, mimeType: string, onProgress: (p: number) => void): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open('PUT', url);
|
xhr.open('PUT', url);
|
||||||
xhr.setRequestHeader('Content-Type', file.type || 'audio/wav');
|
xhr.setRequestHeader('Content-Type', mimeType);
|
||||||
xhr.upload.onprogress = (e) => {
|
xhr.upload.onprogress = (e) => {
|
||||||
if (e.lengthComputable) onProgress(Math.round((e.loaded / e.total) * 100));
|
if (e.lengthComputable) onProgress(Math.round((e.loaded / e.total) * 100));
|
||||||
};
|
};
|
||||||
@@ -117,7 +121,7 @@
|
|||||||
<input
|
<input
|
||||||
id="stem-input-{trackId}"
|
id="stem-input-{trackId}"
|
||||||
type="file"
|
type="file"
|
||||||
accept=".wav,.mp3,.flac,.aiff,.aif"
|
accept="audio/*"
|
||||||
multiple
|
multiple
|
||||||
onchange={handleFileSelect}
|
onchange={handleFileSelect}
|
||||||
hidden
|
hidden
|
||||||
@@ -125,7 +129,7 @@
|
|||||||
<div class="dropzone-content">
|
<div class="dropzone-content">
|
||||||
<span class="icon"><Icon name="upload" size={24} /></span>
|
<span class="icon"><Icon name="upload" size={24} /></span>
|
||||||
<p>STEMs hier ablegen oder klicken</p>
|
<p>STEMs hier ablegen oder klicken</p>
|
||||||
<span class="hint">Mehrere Dateien gleichzeitig möglich · WAV, FLAC, AIFF · max 500 MB</span>
|
<span class="hint">Mehrere Dateien gleichzeitig möglich · WAV, MP3, FLAC, AIFF · max 500 MB</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user