65 lines
1.6 KiB
TypeScript
65 lines
1.6 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 RGPlace {
|
|
id: string
|
|
title: string
|
|
country: string
|
|
geo: [number, number] // [lng, lat]
|
|
size: number
|
|
}
|
|
|
|
interface RGPlacesResponse {
|
|
data: { list: RGPlace[] }
|
|
}
|
|
|
|
export interface SlimPlace {
|
|
id: string
|
|
title: string
|
|
country: string
|
|
lat: number
|
|
lng: number
|
|
size: number
|
|
}
|
|
|
|
let cache: { data: SlimPlace[]; fetchedAt: number } | null = null
|
|
const CACHE_TTL = 24 * 60 * 60 * 1000 // 24 hours
|
|
|
|
export async function GET() {
|
|
try {
|
|
if (cache && Date.now() - cache.fetchedAt < CACHE_TTL) {
|
|
return NextResponse.json(cache.data)
|
|
}
|
|
|
|
const res = await fetch(`${RADIO_GARDEN_API}/ara/content/places`, {
|
|
headers: HEADERS,
|
|
signal: AbortSignal.timeout(10000),
|
|
})
|
|
if (!res.ok) throw new Error(`Radio Garden returned ${res.status}`)
|
|
|
|
const json: RGPlacesResponse = await res.json()
|
|
|
|
const places: SlimPlace[] = json.data.list.map((p) => ({
|
|
id: p.id,
|
|
title: p.title,
|
|
country: p.country,
|
|
lat: p.geo[1],
|
|
lng: p.geo[0],
|
|
size: p.size,
|
|
}))
|
|
|
|
cache = { data: places, fetchedAt: Date.now() }
|
|
return NextResponse.json(places)
|
|
} catch (error) {
|
|
console.error('Failed to fetch radio places:', error)
|
|
if (cache) return NextResponse.json(cache.data)
|
|
return NextResponse.json({ error: 'Failed to load radio stations' }, { status: 502 })
|
|
}
|
|
}
|