/* ===================================================================== live.js — IST ER GERADE LIVE? Eine Auskunft, eine Auslegung. ===================================================================== Filipe am 22.09.2026: „in dieser kachel soll wenn ich live bin um 20h bis 22h ein live button der richtig geil ist mit einem live roten punkt symbol am besten, das soll aufblinken für zwei stunden. man soll nicht drauf drücken können aber so dass es auffällt." WARUM DAS EINE EIGENE DATEI IST Drei Stellen sollen ab jetzt dasselbe wissen: die Kachel „Draußen" auf der Startseite, die Kanalkarten auf der Draußen-Seite und die Pulskarte darunter. Drei Abfragen wären drei Auslegungen — und spätestens beim nächsten Umbau widersprechen sie sich. Dann steht auf der Kachel LIVE und auf der Seite daneben „wartet". DER DRITTE AUSGANG IST HIER DER WICHTIGE Die öffentliche Seite (`assets/js/streamplan.js`) fängt jeden Fehler ab und setzt `istLive = false`. Aus „wir konnten nicht fragen" wird dort „er sendet nicht" — und wer das liest, macht zu und verpasst den Stream. Der Dienst SAGT sogar, ob er nachsehen konnte (`autoHealthy`); gelesen wird es dort nicht. Hier gibt es drei Antworten: live / wartet / weiss-nicht. Bei „weiss-nicht" blinkt nichts — aber es behauptet auch niemand, dass nichts läuft. BLINKEN, NICHT FLACKERN Das Haus hat die Regel „keine aggressiven Flacker-Effekte, prefers-reduced-motion respektieren" (12.08.2026). Ein LIVE-Punkt, der zehnmal pro Sekunde an und aus geht, ist genau das — und auf einem Handy in der Hosentasche kein bisschen auffälliger als einer, der ruhig atmet. Deshalb ein Puls von 1,4 Sekunden: unübersehbar, ohne in den Augen wehzutun. Wer Bewegungsarmut eingestellt hat, bekommt einen ruhigen roten Punkt — er sieht dasselbe, es bewegt sich nur nicht. ===================================================================== */ (function () { 'use strict'; var POSTFACH = 'https://postfach.dogfather-universe.com'; var TAKT = 30000; var lage = { zustand: 'laedt', titel: '' }; var zuhoerer = []; var uhr = 0; var laeuft = false; /** Eine Auslegung, an einer Stelle. * * `live` — es läuft, belegt. * `wartet` — der Dienst hat nachgesehen, es läuft nichts. * `weissnicht` — wir konnten nicht nachsehen. NICHT dasselbe wie * „wartet", und deshalb ein eigener Zustand. */ function auswerten(d) { if (!d || d.ok !== true) return { zustand: 'weissnicht', titel: '' }; if (d.live) return { zustand: 'live', titel: d.title || '' }; /* Hat jemand den Status von Hand gesetzt, gilt der -- die Gesundheit des automatischen Prüfers spielt dann keine Rolle. */ if (d.source === 'automatisch' && d.autoHealthy === false) { return { zustand: 'weissnicht', titel: '' }; } return { zustand: 'wartet', titel: '' }; } function melden() { for (var i = 0; i < zuhoerer.length; i++) { try { zuhoerer[i](lage); } catch (f) { /* ein Zuhörer darf den Rest nicht aufhalten */ } } } async function holen() { if (laeuft) return lage; laeuft = true; try { var antwort = await fetch(POSTFACH + '/live-status', { cache: 'no-store' }); if (!antwort.ok) throw new Error('HTTP ' + antwort.status); lage = auswerten(await antwort.json()); } catch (f) { lage = { zustand: 'weissnicht', titel: '' }; } finally { laeuft = false; } melden(); return lage; } function anschalten() { if (uhr) return; uhr = setInterval(holen, TAKT); } function ausschalten() { if (!uhr) return; clearInterval(uhr); uhr = 0; } /** Meldet sich sofort mit dem aktuellen Stand und danach bei jeder * Änderung. Gibt eine Funktion zum Abmelden zurück. */ function beobachten(rueckruf) { zuhoerer.push(rueckruf); try { rueckruf(lage); } catch (f) { /* Zugabe */ } anschalten(); holen(); return function () { var i = zuhoerer.indexOf(rueckruf); if (i >= 0) zuhoerer.splice(i, 1); if (!zuhoerer.length) ausschalten(); }; } /* IM HINTERGRUND WIRD NICHT GEFRAGT. Ein Tab, der seit gestern offen ist, braucht keine 2880 Abfragen -- und beim Zurückkommen ist die erste Frage ohnehin die wichtigste. */ document.addEventListener('visibilitychange', function () { if (document.hidden) { ausschalten(); return; } if (zuhoerer.length) { anschalten(); holen(); } }); /** Baut das LIVE-Abzeichen: roter Punkt plus Wort. * * `aria-hidden` und `pointer-events: none` (im CSS): Filipe * ausdrücklich — „man soll nicht drauf drücken können aber so dass * es auffällt". Ein Abzeichen, das aussieht wie ein Knopf und * nichts tut, ist eine Sackgasse; eins, das gar nicht erst nach * Knopf aussieht, ist eine Auskunft. * * Für Vorleseprogramme steht der Text trotzdem da -- unsichtbar * wäre er die halbe Auskunft. */ function abzeichen(text) { var a = document.createElement('span'); a.className = 'live-marke'; a.setAttribute('role', 'status'); var p = document.createElement('span'); p.className = 'live-marke__punkt'; p.setAttribute('aria-hidden', 'true'); a.appendChild(p); var w = document.createElement('span'); w.className = 'live-marke__wort'; w.textContent = text || 'LIVE'; a.appendChild(w); return a; } window.LiveStatus = { beobachten: beobachten, holen: holen, abzeichen: abzeichen, /* Nur zum Messen -- eine Prüfung soll die Auslegung prüfen können, ohne den echten Dienst zu brauchen. */ auswerten: auswerten, get lage() { return lage; }, }; }());