diff --git a/app/admin/page.tsx b/app/admin/page.tsx index c5c2157..685e6bc 100644 --- a/app/admin/page.tsx +++ b/app/admin/page.tsx @@ -84,7 +84,25 @@ export default function AdminPage() { }); if (res.ok) { - setMessage('Song uploaded successfully!'); + const data = await res.json(); + const validation = data.validation; + + let statusMessage = 'āœ… Song uploaded successfully!\n\n'; + statusMessage += `šŸ“Š Audio Info:\n`; + statusMessage += `• Format: ${validation.codec || 'unknown'}\n`; + statusMessage += `• Bitrate: ${Math.round(validation.bitrate / 1000)} kbps\n`; + statusMessage += `• Sample Rate: ${validation.sampleRate} Hz\n`; + statusMessage += `• Duration: ${Math.round(validation.duration)} seconds\n`; + statusMessage += `• Cover Art: ${validation.hasCover ? 'āœ… Yes' : 'āŒ No'}\n`; + + if (validation.warnings.length > 0) { + statusMessage += `\nāš ļø Warnings:\n`; + validation.warnings.forEach((warning: string) => { + statusMessage += `• ${warning}\n`; + }); + } + + setMessage(statusMessage); setFile(null); fetchSongs(); } else { @@ -247,7 +265,20 @@ export default function AdminPage() { - {message &&

{message}

} + {message && ( +
+ {message} +
+ )} diff --git a/app/api/songs/route.ts b/app/api/songs/route.ts index 0a9dad9..3aae87e 100644 --- a/app/api/songs/route.ts +++ b/app/api/songs/route.ts @@ -41,17 +41,62 @@ export async function POST(request: Request) { const buffer = Buffer.from(await file.arrayBuffer()); - // Extract metadata from file + // Validate and extract metadata from file + let metadata; + let validationInfo = { + isValid: true, + hasCover: false, + format: '', + bitrate: 0, + sampleRate: 0, + duration: 0, + codec: '', + warnings: [] as string[], + }; + try { - const metadata = await parseBuffer(buffer, file.type); + metadata = await parseBuffer(buffer, file.type); + + // Extract basic metadata if (metadata.common.title) { title = metadata.common.title; } if (metadata.common.artist) { artist = metadata.common.artist; } + + // Validation info + validationInfo.hasCover = !!metadata.common.picture?.[0]; + validationInfo.format = metadata.format.container || 'unknown'; + validationInfo.bitrate = metadata.format.bitrate || 0; + validationInfo.sampleRate = metadata.format.sampleRate || 0; + validationInfo.duration = metadata.format.duration || 0; + validationInfo.codec = metadata.format.codec || 'unknown'; + + // Validate format + if (metadata.format.container !== 'MPEG') { + validationInfo.warnings.push('File may not be a standard MP3 (MPEG container expected)'); + } + + // Check bitrate + if (validationInfo.bitrate && validationInfo.bitrate < 96000) { + validationInfo.warnings.push(`Low bitrate detected: ${Math.round(validationInfo.bitrate / 1000)} kbps`); + } + + // Check sample rate + if (validationInfo.sampleRate && ![44100, 48000].includes(validationInfo.sampleRate)) { + validationInfo.warnings.push(`Non-standard sample rate: ${validationInfo.sampleRate} Hz (recommended: 44100 or 48000 Hz)`); + } + + // Check duration + if (!validationInfo.duration || validationInfo.duration < 30) { + validationInfo.warnings.push('Audio file is very short (less than 30 seconds)'); + } + } catch (e) { console.error('Failed to parse metadata:', e); + validationInfo.isValid = false; + validationInfo.warnings.push('Failed to parse audio metadata - file may be corrupted'); } // Fallback if still missing @@ -66,8 +111,7 @@ export async function POST(request: Request) { // Handle cover image let coverImage = null; try { - const metadata = await parseBuffer(buffer, file.type); - const picture = metadata.common.picture?.[0]; + const picture = metadata?.common.picture?.[0]; if (picture) { const extension = picture.format.split('/')[1] || 'jpg'; @@ -90,7 +134,10 @@ export async function POST(request: Request) { }, }); - return NextResponse.json(song); + return NextResponse.json({ + song, + validation: validationInfo, + }); } catch (error) { console.error('Error uploading song:', error); return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });