bugfixes
This commit is contained in:
@@ -147,12 +147,16 @@ func main() {
|
|||||||
func apiStreams(w http.ResponseWriter, r *http.Request) {
|
func apiStreams(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
|
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := &mtx.Client{BaseURL: mtxAPI, User: os.Getenv("MTX_API_USER"), Pass: os.Getenv("MTX_API_PASS")}
|
c := &mtx.Client{BaseURL: mtxAPI, User: os.Getenv("MTX_API_USER"), Pass: os.Getenv("MTX_API_PASS")}
|
||||||
pl, err := c.Paths(ctx)
|
pl, err := c.Paths(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadGateway)
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusBadGateway)
|
||||||
|
_ = json.NewEncoder(w).Encode(map[string]any{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed := map[string]bool{}
|
allowed := map[string]bool{}
|
||||||
if streamsCSV != "" {
|
if streamsCSV != "" {
|
||||||
for _, s := range strings.Split(streamsCSV, ",") {
|
for _, s := range strings.Split(streamsCSV, ",") {
|
||||||
@@ -174,7 +178,7 @@ func apiStreams(w http.ResponseWriter, r *http.Request) {
|
|||||||
out.Items = append(out.Items, item{Name: p.Name, Live: p.Live(), Viewers: p.Viewers()})
|
out.Items = append(out.Items, item{Name: p.Name, Live: p.Live(), Viewers: p.Viewers()})
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(out)
|
_ = json.NewEncoder(w).Encode(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pageIndex(w http.ResponseWriter, r *http.Request) {
|
func pageIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -1,25 +1,35 @@
|
|||||||
async function load(){
|
async function load(){
|
||||||
const r = await fetch('/api/streams');
|
let data;
|
||||||
const data = await r.json();
|
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();
|
const q = (document.getElementById('filter').value||'').toLowerCase();
|
||||||
const list = document.getElementById('list');
|
const list = document.getElementById('list');
|
||||||
list.innerHTML = '';
|
list.innerHTML = '';
|
||||||
data.items
|
data.items.filter(it => !q || it.name.toLowerCase().includes(q)).forEach(it => {
|
||||||
.filter(it => !q || it.name.toLowerCase().includes(q))
|
const a = document.createElement('a');
|
||||||
.forEach(it => {
|
a.href = '/' + encodeURIComponent(it.name);
|
||||||
const a = document.createElement('a');
|
a.className = 'card';
|
||||||
a.href = '/' + encodeURIComponent(it.name);
|
a.innerHTML = `
|
||||||
a.className = 'card';
|
<div class="row space-between">
|
||||||
a.innerHTML = `
|
<div>
|
||||||
<div class="row space-between">
|
<div class="title-strong">${it.name}</div>
|
||||||
<div>
|
<div class="muted">Zuschauer: ${it.viewers}</div>
|
||||||
<div class="title-strong">${it.name}</div>
|
</div>
|
||||||
<div class="muted">Zuschauer: ${it.viewers}</div>
|
<div class="pill ${it.live ? 'live':'off'}">${it.live ? 'LIVE' : 'Offline'}</div>
|
||||||
</div>
|
</div>`;
|
||||||
<div class="pill ${it.live ? 'live':'off'}">${it.live ? 'LIVE' : 'Offline'}</div>
|
list.appendChild(a);
|
||||||
</div>`;
|
});
|
||||||
list.appendChild(a);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
document.getElementById('filter').addEventListener('input', load);
|
document.getElementById('filter').addEventListener('input', load);
|
||||||
load(); setInterval(load, 3000);
|
document.getElementById('reload').addEventListener('click', load);
|
||||||
|
load();
|
||||||
|
setInterval(load, 3000);
|
||||||
|
|||||||
@@ -11,6 +11,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function refresh(){
|
async function refresh(){
|
||||||
|
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);
|
||||||
|
setLive(false);
|
||||||
|
viewersEl.textContent = 'Zuschauer: –';
|
||||||
|
return;
|
||||||
|
}
|
||||||
const r = await fetch('/api/streams');
|
const r = await fetch('/api/streams');
|
||||||
const d = await r.json();
|
const d = await r.json();
|
||||||
const it = d.items.find(x=>x.name===name);
|
const it = d.items.find(x=>x.name===name);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<h1 class="title-no-margin">🎬 Streams</h1>
|
<h1 class="title-no-margin">🎬 Streams</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<input id="filter" placeholder="Filter (z. B. stream1)">
|
<input id="filter" placeholder="Filter (z. B. stream1)">
|
||||||
<a href="/refresh" class="pill">Neu laden</a>
|
<button id="reload" class="pill" type="button">Neu laden</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="muted">RTMP Ingest: <code>rtmp://HOST/<name></code> · HLS: <code>http(s)://HOST/hls/<name></code></p>
|
<p class="muted">RTMP Ingest: <code>rtmp://HOST/<name></code> · HLS: <code>http(s)://HOST/hls/<name></code></p>
|
||||||
|
|||||||
Reference in New Issue
Block a user