Add player functionality with HLS support and API integration

- Implemented a new Player class in player.js to handle audio playback, including HLS support using hls.js.
- Created a shared API module in api.js for making HTTP requests with proper error handling.
- Added DOM utility functions in dom.js for creating and clearing elements.
- Introduced WebSocket connection handling in ws.js for real-time updates.
- Developed a comprehensive CSS stylesheet for styling the application, including a high-contrast theme.
This commit is contained in:
Marco Mooren
2026-05-10 14:43:00 +02:00
commit e0a60f7b64
51 changed files with 9022 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
// 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
}]
};
}