Feat: Drag & Drop MP3/WAV Upload mit Progress-Tracking

Backend:
- multer reaktiviert (war auskommentiert) mit diskStorage + Collision-Handling
- /api/upload (POST, admin-protected): bis zu 20 Dateien gleichzeitig
- MP3/WAV-Filter (50MB Limit), sofortige Hintergrund-Normalisierung nach Upload

Frontend:
- Globale window dragenter/dragleave/drop Listener mit Counter gegen false-positives
- Drag-Overlay: Vollbild-Blur + animierter Drop-Zone (pulsierender Accent-Border, bouncing Icon)
- Upload-Queue: floating Card bottom-right mit Per-Datei Progressbar + Status-Icons
  (sync-Animation beim Hochladen, check_circle grün, error rot)
- Auto-Refresh der Soundliste + Analytics nach Upload
- Auto-Dismiss der Queue nach 3.5s

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bot 2026-03-01 22:15:07 +01:00
parent a61663166f
commit 52c86240af
4 changed files with 426 additions and 3 deletions

View file

@ -206,7 +206,34 @@ export async function playUrl(url: string, guildId: string, channelId: string, v
}
}
// uploadFile removed (build reverted)
/** Lädt eine einzelne MP3/WAV-Datei hoch. Gibt den gespeicherten Dateinamen zurück. */
export function uploadFile(
file: File,
onProgress: (pct: number) => void,
): Promise<string> {
return new Promise((resolve, reject) => {
const form = new FormData();
form.append('files', file);
const xhr = new XMLHttpRequest();
xhr.open('POST', `${API_BASE}/upload`);
xhr.upload.onprogress = e => {
if (e.lengthComputable) onProgress(Math.round((e.loaded / e.total) * 100));
};
xhr.onload = () => {
if (xhr.status === 200) {
try {
const data = JSON.parse(xhr.responseText);
resolve(data.files?.[0]?.name ?? file.name);
} catch { resolve(file.name); }
} else {
try { reject(new Error(JSON.parse(xhr.responseText).error)); }
catch { reject(new Error(`HTTP ${xhr.status}`)); }
}
};
xhr.onerror = () => reject(new Error('Netzwerkfehler'));
xhr.send(form);
});
}