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

This commit is contained in:
2025-09-21 19:56:14 +02:00
parent 9faa53e149
commit 3fd8408605

View File

@@ -5,6 +5,8 @@
const viewersEl = document.getElementById('viewers');
const srcEl = document.getElementById('hlssrc');
let playerLive = false; // <- neue Quelle der Wahrheit
function setLive(on){
liveEl.className = 'pill ' + (on ? 'live' : 'off');
liveEl.textContent = on ? 'LIVE' : 'Offline';
@@ -14,71 +16,84 @@
const enc = encodeURIComponent(name);
const candidates = [
`/hls/${enc}/index.m3u8`,
`/hls/${enc}/main_stream.m3u8`, // Fallback, wenn es keinen Master gibt
`/hls/${enc}/main_stream.m3u8`,
];
for (const url of candidates) {
try {
const r = await fetch(url, { cache: 'no-store' });
if (r.ok) return url; // WICHTIG: GET statt HEAD
} catch (_) {}
try { const r = await fetch(url, { cache: 'no-store' }); if (r.ok) return url; } catch {}
}
return null;
}
async function initPlayer() {
const url = await chooseManifest();
if (!url) { setLive(false); return false; }
if (!url) { playerLive = false; setLive(false); return false; }
srcEl.textContent = url;
setLive(true);
try { v.muted = true; v.playsInline = true; } catch(_) {}
try { v.muted = true; v.playsInline = true; } catch {}
if (window.Hls && Hls.isSupported()) {
if (!window._hls) {
window._hls = new Hls({ liveDurationInfinity: true });
window._hls.on(Hls.Events.MANIFEST_PARSED, (_e, data) => {
console.log('HLS manifest parsed. levels=', data.levels?.length);
window._hls.on(Hls.Events.MANIFEST_PARSED, () => {
// Manifest geladen → sehr gutes Live-Signal
playerLive = true;
setLive(true);
});
window._hls.on(Hls.Events.ERROR, (_e, data) => {
console.warn('hls.js error', data);
// fatale Fehler → als offline markieren
if (data?.fatal) { playerLive = false; setLive(false); }
});
window._hls.attachMedia(v);
}
window._hls.loadSource(url);
} else if (v.canPlayType('application/vnd.apple.mpegurl')) {
v.src = url; // Safari / iOS
v.src = url; // Safari/iOS
} else {
console.warn('HLS nicht unterstützt');
playerLive = false; setLive(false);
return false;
}
try { await v.play(); } catch(e){ console.log('autoplay blockiert (ok):', e?.name||e); }
try { await v.play(); } catch(e){ /* Autoplay blockiert ist ok */ }
return true;
}
// Zusätzliche Player-Signale
v.addEventListener('loadedmetadata', () => { playerLive = true; setLive(true); });
v.addEventListener('playing', () => { playerLive = true; setLive(true); });
v.addEventListener('error', () => { playerLive = false; setLive(false); });
async function refreshMeta(){
// API nur als Zusatz überschreibt NIE ein „echtes“ playerLive=true
try {
const r = await fetch('/api/streams', { cache: 'no-store' });
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 (_) {}
}
if (!it) return;
v.addEventListener('error', e => console.warn('video error', e));
v.addEventListener('loadedmetadata', () => console.log('loadedmetadata'));
v.addEventListener('playing', () => console.log('playing'));
const apiLive = !!it.live;
const combinedLive = playerLive || apiLive;
setLive(combinedLive);
let viewers = it.viewers ?? 0;
if (combinedLive && viewers === 0) {
// Wir sehen selbst Video → mindestens 1 Betrachter
viewers = '≥1';
}
viewersEl.textContent = 'Zuschauer: ' + viewers;
} catch (_) {
// Bei API-Fehler nichts überschreiben
}
}
(async function boot(){
for (let i=0; i<10; i++){
const ok = await initPlayer();
if (ok) break;
await new Promise(r => setTimeout(r, 1500));
await new Promise(r => setTimeout(r, 1200));
}
refreshMeta();
setInterval(refreshMeta, 2500);