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

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}` });
}