93 lines
2.3 KiB
TypeScript
93 lines
2.3 KiB
TypeScript
import { NextResponse } from 'next/server'
|
|
|
|
const RADIO_GARDEN_API = 'https://radio.garden/api'
|
|
const HEADERS = {
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
'Accept': 'application/json',
|
|
'Referer': 'https://radio.garden/',
|
|
}
|
|
|
|
interface RGSearchHit {
|
|
_source: {
|
|
code: string
|
|
type: 'channel' | 'place' | 'country'
|
|
page: {
|
|
url: string
|
|
title: string
|
|
place?: { id: string; title: string }
|
|
country?: { id: string; title: string }
|
|
subtitle?: string
|
|
}
|
|
}
|
|
_score: number
|
|
}
|
|
|
|
interface RGSearchResponse {
|
|
hits: { hits: RGSearchHit[] }
|
|
}
|
|
|
|
function extractId(url: string): string {
|
|
const parts = url.split('/')
|
|
return parts[parts.length - 1]
|
|
}
|
|
|
|
export interface SearchStation {
|
|
id: string
|
|
title: string
|
|
placeId: string
|
|
placeTitle: string
|
|
country: string
|
|
}
|
|
|
|
export interface SearchPlace {
|
|
id: string
|
|
title: string
|
|
country: 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({ stations: [], places: [] })
|
|
}
|
|
|
|
try {
|
|
const res = await fetch(`${RADIO_GARDEN_API}/search?q=${encodeURIComponent(q)}`, {
|
|
headers: HEADERS,
|
|
signal: AbortSignal.timeout(10000),
|
|
})
|
|
if (!res.ok) throw new Error(`Radio Garden search returned ${res.status}`)
|
|
|
|
const json: RGSearchResponse = await res.json()
|
|
|
|
const stations: SearchStation[] = []
|
|
const places: SearchPlace[] = []
|
|
|
|
for (const hit of json.hits.hits) {
|
|
const src = hit._source
|
|
if (src.type === 'channel') {
|
|
stations.push({
|
|
id: extractId(src.page.url),
|
|
title: src.page.title,
|
|
placeId: src.page.place?.id || '',
|
|
placeTitle: src.page.place?.title || '',
|
|
country: src.page.country?.title || src.code,
|
|
})
|
|
} else if (src.type === 'place') {
|
|
places.push({
|
|
id: extractId(src.page.url),
|
|
title: src.page.title,
|
|
country: src.page.country?.title || src.code,
|
|
})
|
|
}
|
|
}
|
|
|
|
return NextResponse.json({ stations, places })
|
|
} catch (error) {
|
|
console.error('Radio search error:', error)
|
|
return NextResponse.json({ error: 'Search failed' }, { status: 502 })
|
|
}
|
|
}
|