This commit is contained in:
@@ -1,35 +1,42 @@
|
||||
async function load(){
|
||||
let data;
|
||||
try {
|
||||
const r = await fetch('/api/streams', { cache: 'no-store' });
|
||||
if (!r.ok) throw new Error('api '+r.status);
|
||||
data = await r.json();
|
||||
} catch (e) {
|
||||
console.warn('streams api error:', e);
|
||||
// UI freundlich degradieren
|
||||
document.getElementById('list').innerHTML =
|
||||
'<div class="card"><div class="muted">Keine Daten (API-Fehler)</div></div>';
|
||||
return;
|
||||
}
|
||||
const q = (document.getElementById('filter').value||'').toLowerCase();
|
||||
(function(){
|
||||
const list = document.getElementById('list');
|
||||
list.innerHTML = '';
|
||||
data.items.filter(it => !q || it.name.toLowerCase().includes(q)).forEach(it => {
|
||||
const a = document.createElement('a');
|
||||
a.href = '/' + encodeURIComponent(it.name);
|
||||
a.className = 'card';
|
||||
a.innerHTML = `
|
||||
<div class="row space-between">
|
||||
<div>
|
||||
<div class="title-strong">${it.name}</div>
|
||||
<div class="muted">Zuschauer: ${it.viewers}</div>
|
||||
</div>
|
||||
<div class="pill ${it.live ? 'live':'off'}">${it.live ? 'LIVE' : 'Offline'}</div>
|
||||
</div>`;
|
||||
list.appendChild(a);
|
||||
const filter = document.getElementById('filter');
|
||||
|
||||
function render(data){
|
||||
const q = (filter.value||'').toLowerCase();
|
||||
list.innerHTML = '';
|
||||
data.items
|
||||
.filter(it => !q || it.name.toLowerCase().includes(q))
|
||||
.forEach(it => {
|
||||
const a = document.createElement('a');
|
||||
a.href = '/' + encodeURIComponent(it.name);
|
||||
a.className = 'card';
|
||||
a.innerHTML = `
|
||||
<div class="row space-between">
|
||||
<div>
|
||||
<div class="title-strong">${it.name}</div>
|
||||
<div class="muted">Zuschauer: ${it.viewers ?? 0}</div>
|
||||
</div>
|
||||
<div class="pill ${it.live ? 'live':'off'}">${it.live ? 'LIVE' : 'Offline'}</div>
|
||||
</div>`;
|
||||
list.appendChild(a);
|
||||
});
|
||||
}
|
||||
|
||||
filter.addEventListener('input', ()=>{/* re-render mit letztem snapshot */}
|
||||
);
|
||||
|
||||
let last = {items:[]};
|
||||
const es = new EventSource('/api/streams/events', { withCredentials: false });
|
||||
es.addEventListener('update', (ev)=>{
|
||||
try {
|
||||
last = JSON.parse(ev.data);
|
||||
render(last);
|
||||
} catch(e) { console.warn('sse parse', e); }
|
||||
});
|
||||
}
|
||||
document.getElementById('filter').addEventListener('input', load);
|
||||
document.getElementById('reload').addEventListener('click', load);
|
||||
load();
|
||||
setInterval(load, 3000);
|
||||
es.onerror = (e)=>console.warn('sse error', e);
|
||||
|
||||
// Optionaler Reload-Button:
|
||||
const btn = document.getElementById('reload');
|
||||
if (btn) btn.addEventListener('click', ()=>render(last));
|
||||
})();
|
||||
|
||||
@@ -96,6 +96,23 @@
|
||||
await new Promise(r => setTimeout(r, 1200));
|
||||
}
|
||||
refreshMeta();
|
||||
setInterval(refreshMeta, 2500);
|
||||
//setInterval(refreshMeta, 2500);
|
||||
})();
|
||||
|
||||
|
||||
const es = new EventSource('/api/streams/events');
|
||||
es.addEventListener('update', (ev)=>{
|
||||
try {
|
||||
const data = JSON.parse(ev.data);
|
||||
const it = data.items.find(x=>x.name===name);
|
||||
if (!it) return;
|
||||
const apiLive = !!it.live;
|
||||
const combinedLive = playerLive || apiLive;
|
||||
setLive(combinedLive);
|
||||
|
||||
let viewers = it.viewers ?? 0;
|
||||
if (combinedLive && viewers === 0) viewers = '≥1';
|
||||
viewersEl.textContent = 'Zuschauer: ' + viewers;
|
||||
} catch(e){ /* ignore */ }
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user