bugfix-3
All checks were successful
release-tag / release-image (push) Successful in 1m55s

This commit is contained in:
2025-09-21 19:27:18 +02:00
parent 70a328ef4d
commit 6882453b6a
2 changed files with 66 additions and 29 deletions

View File

@@ -75,6 +75,7 @@ func main() {
"font-src 'self'", "font-src 'self'",
"script-src 'self'", "script-src 'self'",
"connect-src 'self'", "connect-src 'self'",
"media-src 'self'", // <- wichtig
}, "; "), }, "; "),
) )
w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-Content-Type-Options", "nosniff")

View File

@@ -5,40 +5,76 @@
const viewersEl = document.getElementById('viewers'); const viewersEl = document.getElementById('viewers');
const srcEl = document.getElementById('hlssrc'); const srcEl = document.getElementById('hlssrc');
function updateLive(live){ const manifest = '/hls/' + encodeURIComponent(name) + '/index.m3u8';
liveEl.className = 'pill ' + (live ? 'live' : 'off');
liveEl.textContent = live ? 'LIVE' : 'Offline'; function setLive(l){
liveEl.className = 'pill ' + (l ? 'live' : 'off');
liveEl.textContent = l ? 'LIVE' : 'Offline';
} }
async function refresh(){ async function head(url){
let data; try {
try{ const r = await fetch(url, { method: 'HEAD', cache:'no-store' });
const r = await fetch('/api/streams', { cache: 'no-store' }); return r.ok;
if (!r.ok) throw new Error('api '+r.status); } catch (_) { return false; }
data = await r.json(); }
}catch(e){
console.warn('streams api error:', e); async function tryInitPlayer(){
setLive(false); // 1) Manifest erreichbar?
viewersEl.textContent = 'Zuschauer: -'; const ok = await head(manifest);
return; srcEl.textContent = manifest;
} setLive(ok);
const r = await fetch('/api/streams'); if (!ok) return false;
const d = await r.json();
const it = d.items.find(x=>x.name===name); // 2) Player initialisieren
const live = !!(it && it.live); try {
updateLive(live); if (window.Hls && Hls.isSupported()) {
viewersEl.textContent = 'Zuschauer: ' + (it ? it.viewers : 0); if (!window._hls) {
if(live){ window._hls = new Hls({ maxLiveSyncPlaybackRate: 1.0 });
const src = '/hls/'+encodeURIComponent(name); window._hls.on(Hls.Events.ERROR, (_, data)=>console.warn('hls.js error', data));
srcEl.textContent = src; window._hls.attachMedia(v);
if (window.Hls && Hls.isSupported()){ }
if(!window._hls){ window._hls = new Hls(); window._hls.attachMedia(v); } window._hls.loadSource(manifest);
window._hls.loadSource(src);
} else if (v.canPlayType('application/vnd.apple.mpegurl')) { } else if (v.canPlayType('application/vnd.apple.mpegurl')) {
v.src = src; v.src = manifest; // Safari / iOS
} else {
console.warn('HLS nicht unterstützt');
return false;
} }
return true;
} catch (e) {
console.warn('Player init fail', e);
return false;
} }
} }
refresh(); setInterval(refresh, 2500); async function refreshMeta(){
// UI-Infos (viewer count etc.) optional, darf nie Player blockieren
try {
const r = await fetch('/api/streams', { cache:'no-store' });
if (!r.ok) return;
const d = await r.json();
const it = d.items.find(x=>x.name===name);
if (it) {
setLive(!!it.live);
viewersEl.textContent = 'Zuschauer: ' + it.viewers;
}
} catch (_) {}
}
// Video-Fehler sichtbar loggen
v.addEventListener('error', (e)=>console.warn('video error', e));
v.addEventListener('loadedmetadata', ()=>console.log('metadata loaded'));
v.addEventListener('playing', ()=>console.log('playing'));
// Boot-Sequenz mit Retries
(async function boot(){
for (let i=0; i<10; i++) {
const ok = await tryInitPlayer();
if (ok) break;
await new Promise(r=>setTimeout(r, 1500)); // kurz warten, bis HLS bereit ist
}
refreshMeta();
setInterval(refreshMeta, 2500);
})();
})(); })();