58 lines
1.6 KiB
TypeScript
58 lines
1.6 KiB
TypeScript
import { NextResponse } from 'next/server'
|
|
|
|
interface MBRecording {
|
|
id: string
|
|
title: string
|
|
score: number
|
|
length?: number
|
|
'artist-credit'?: { name: string }[]
|
|
releases?: { title: string; date?: string }[]
|
|
}
|
|
|
|
export async function GET(request: Request) {
|
|
const { searchParams } = new URL(request.url)
|
|
const q = searchParams.get('q')
|
|
|
|
if (!q || q.length < 2) {
|
|
return NextResponse.json({ results: [] })
|
|
}
|
|
|
|
try {
|
|
const controller = new AbortController()
|
|
const timeout = setTimeout(() => controller.abort(), 5000)
|
|
|
|
const res = await fetch(
|
|
`https://musicbrainz.org/ws/2/recording?query=${encodeURIComponent(q)}&fmt=json&limit=20`,
|
|
{
|
|
headers: {
|
|
'User-Agent': 'SoulSync/1.0 (jeffemmett@gmail.com)',
|
|
Accept: 'application/json',
|
|
},
|
|
signal: controller.signal,
|
|
cache: 'no-store',
|
|
}
|
|
)
|
|
clearTimeout(timeout)
|
|
|
|
if (!res.ok) {
|
|
throw new Error(`MusicBrainz returned ${res.status}`)
|
|
}
|
|
|
|
const data = await res.json()
|
|
const results = (data.recordings || []).map((r: MBRecording) => ({
|
|
mbid: r.id,
|
|
title: r.title,
|
|
artist: r['artist-credit']?.[0]?.name || 'Unknown',
|
|
album: r.releases?.[0]?.title || '',
|
|
year: r.releases?.[0]?.date?.slice(0, 4) || '',
|
|
duration: r.length ? Math.round(r.length / 1000) : 0,
|
|
score: r.score,
|
|
}))
|
|
|
|
return NextResponse.json({ results })
|
|
} catch (error) {
|
|
console.error('MusicBrainz search error:', error)
|
|
return NextResponse.json({ error: 'MusicBrainz search failed' }, { status: 502 })
|
|
}
|
|
}
|