added lite version

This commit is contained in:
Marco Mooren
2026-05-27 15:04:14 +02:00
parent 3def9e0aac
commit 2e833b0bae
7 changed files with 47 additions and 13 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Radio Master</title>
<script type="module" crossorigin src="/assets/master-x_buNpFo.js"></script>
<link rel="modulepreload" crossorigin href="/assets/modulepreload-polyfill-B5Qt9EMX.js">
<link rel="modulepreload" crossorigin href="/assets/debug-B-FoNBZ5.js">

View File

@@ -90,15 +90,20 @@ router.post('/:id/play/end', requireUser, (req, res) => {
});
router.post('/:id/resolve', requireUser, async (req, res) => {
const id = Number(req.params.id);
const streams = getStreamsForStation(id);
if (!streams.length) return res.status(404).json({ error: 'no streams' });
const preferred = req.body?.streamId
? streams.find((s) => s.id === Number(req.body.streamId))
: streams[0];
if (!preferred) return res.status(404).json({ error: 'stream not found' });
const resolved = await resolveStream({ url: preferred.url, format: preferred.format });
res.json({ stream: preferred, resolved });
try {
const id = Number(req.params.id);
const streams = getStreamsForStation(id);
if (!streams.length) return res.status(404).json({ error: 'no streams' });
const preferred = req.body?.streamId
? streams.find((s) => s.id === Number(req.body.streamId))
: streams[0];
if (!preferred) return res.status(404).json({ error: 'stream not found' });
const resolved = await resolveStream({ url: preferred.url, format: preferred.format });
res.json({ stream: preferred, resolved });
} catch (err) {
if (err?.name === 'AbortError' || res.headersSent) return;
res.status(500).json({ error: 'resolve failed' });
}
});
// Same-origin streaming proxy. Adds the CORS headers Icecast/SHOUTcast servers
@@ -116,8 +121,14 @@ router.get('/:id/proxy', requireUser, async (req, res) => {
const resolved = await resolveStream({ url: preferred.url, format: preferred.format });
if (resolved.format === 'hls') return res.status(415).json({ error: 'hls not proxied' });
// Use an AbortController only for the fetch-connection phase. Once the
// upstream connection is established the listener is removed and streaming
// teardown switches to reader.cancel(). Keeping the controller active after
// fetch() resolves causes undici to emit an unhandled AbortError on the
// response-body stream when the client disconnects.
const controller = new AbortController();
req.on('close', () => { try { controller.abort(); } catch { } });
const abortFetch = () => { try { controller.abort(); } catch { } };
req.once('close', abortFetch);
let upstream;
try {
@@ -127,10 +138,14 @@ router.get('/:id/proxy', requireUser, async (req, res) => {
headers: { 'User-Agent': 'oradio-kiosk/1.0', 'Icy-MetaData': '0' }
});
} catch (err) {
if (err.name === 'AbortError') { res.end(); return; }
req.off('close', abortFetch);
if (err?.name === 'AbortError') { res.end(); return; }
if (!res.headersSent) res.status(502).json({ error: `upstream: ${err.message || err}` });
return;
}
// Fetch resolved — detach the abort listener so controller.abort() is
// never called on an already-resolved fetch.
req.off('close', abortFetch);
if (!upstream.ok || !upstream.body) {
return res.status(502).json({ error: `upstream HTTP ${upstream.status}` });
}