- Introduced a new HTML documentation page for the oradio API, including a JavaScript file to handle dynamic content and API requests. - Added a CSS file for styling the documentation page. - Implemented an underground station importer script that fetches data from Radio-Browser and writes it to a JSON file. - Created a stats module to compute and manage vote and play statistics for radio stations. - Added a polyfill for modulepreload to ensure compatibility with older browsers.
66 lines
2.2 KiB
JavaScript
66 lines
2.2 KiB
JavaScript
// Thin wrapper around the Radio-Browser community API.
|
|
// Docs: https://api.radio-browser.info/
|
|
|
|
const SERVERS = [
|
|
'https://de1.api.radio-browser.info',
|
|
'https://nl1.api.radio-browser.info',
|
|
'https://at1.api.radio-browser.info'
|
|
];
|
|
|
|
let activeServer = SERVERS[0];
|
|
|
|
async function rb(path, params) {
|
|
const url = new URL(path, activeServer);
|
|
if (params) for (const [k, v] of Object.entries(params)) {
|
|
if (v != null) url.searchParams.set(k, String(v));
|
|
}
|
|
const res = await fetch(url, { headers: { 'User-Agent': 'OnlineRadioExplorer/0.1' } });
|
|
if (!res.ok) throw new Error(`Radio-Browser ${res.status}`);
|
|
return res.json();
|
|
}
|
|
|
|
export async function search({ name, country, tag, limit = 30 }) {
|
|
const list = await rb('/json/stations/search', {
|
|
name, country, tag, limit, hidebroken: true, order: 'votes', reverse: true
|
|
});
|
|
return list.map(toCanonical);
|
|
}
|
|
|
|
export async function byUuid(uuid) {
|
|
const list = await rb('/json/stations/byuuid', { uuids: uuid });
|
|
return list[0] ? toCanonical(list[0]) : null;
|
|
}
|
|
|
|
function detectFormat(codec, url) {
|
|
const c = (codec || '').toLowerCase();
|
|
if (c.includes('mp3')) return 'mp3';
|
|
if (c.includes('aac')) return 'aac';
|
|
if (c.includes('ogg') || c.includes('vorbis') || c.includes('opus')) return 'ogg';
|
|
if (url?.endsWith('.m3u8')) return 'hls';
|
|
if (url?.endsWith('.m3u')) return 'm3u';
|
|
if (url?.endsWith('.pls')) return 'pls';
|
|
return 'unknown';
|
|
}
|
|
|
|
function toCanonical(s) {
|
|
return {
|
|
uuid: s.stationuuid || undefined,
|
|
name: s.name,
|
|
slug: `rb-${s.stationuuid}`,
|
|
homepage: s.homepage || null,
|
|
country: s.countrycode || s.country || null,
|
|
genres: (s.tags || '').split(',').map((t) => t.trim()).filter(Boolean),
|
|
description: null,
|
|
image_url: s.favicon || null,
|
|
source: 'radiobrowser',
|
|
source_ref: s.stationuuid,
|
|
streams: [{
|
|
url: s.url_resolved || s.url,
|
|
format: detectFormat(s.codec, s.url_resolved || s.url),
|
|
bitrate: s.bitrate || null,
|
|
label: s.codec ? `${s.codec} ${s.bitrate || ''}`.trim() : null,
|
|
priority: 0
|
|
}]
|
|
};
|
|
}
|