Nutzer-Wunsch 20.08.2026: "diese seite vom streamplan soll viel geiler und spezieller sein, ueberrasch mich." Neues Herzstueck: ein 24-Stunden-Ziffernblatt (reines SVG, keine Bild-Assets), das den festen 20-Uhr-Termin als dauerhaft leuchtenden Fixpunkt zeigt (goldener Puls) und einen "Jetzt"-Zeiger in Echtzeit mit der tatsaechlichen Uhrzeit der besuchenden Person mitbewegt (Babyblau, DogFather-Markenfarbe). Nutzt denselben /live-status-Endpunkt wie die Startseite: - Offline: echter Sekunden-Countdown zum naechsten lokalen 20-Uhr-Termin. - Live: komplettes Radar schaltet auf Rot/Puls um, zeigt den Stream-Titel und einen "Jetzt anschauen"-Knopf direkt zu TikTok. Sanft rotierender Lichtschein fuer Atmosphaere, komplett augenschonend (gedeckte Farben, respektiert prefers-reduced-motion vollstaendig). Bugfix unterwegs gefunden (Playwright-Screenshot, dritte Wiederholung desselben Musters heute): der "Jetzt anschauen"-Knopf blieb trotz [hidden]-Attribut sichtbar, weil .btn selbst "display" setzt und damit gleiche Spezifitaet wie die eingebaute [hidden]-Regel hat -- explizite Regel ergaenzt. Co-Authored-By: Claude Opus 5 <[email protected]>
132 lines
5.6 KiB
JavaScript
132 lines
5.6 KiB
JavaScript
/* =====================================================================
|
|
streamplan.js — "Live-Radar" NUR für streamplan.html (20.08.2026,
|
|
Nutzer-Wunsch: "soll viel geiler und spezieller sein, überrasch mich").
|
|
|
|
Ein 24-Stunden-Ziffernblatt (reines SVG, keine Bild-Assets nötig): der
|
|
feste 20-Uhr-Termin leuchtet dauerhaft als Fixpunkt, ein "Jetzt"-Zeiger
|
|
bewegt sich mit der echten Uhrzeit der besuchenden Person mit. Nutzt
|
|
denselben /live-status-Endpunkt wie die Startseite (main.js lädt
|
|
window.dogiUebersetzen/dogiSprache VOR dieser Datei, siehe <script>-
|
|
Reihenfolge in streamplan.html) — läuft DogFather laut TikTok gerade
|
|
wirklich, schaltet das ganze Radar auf Rot/Puls um und zeigt einen
|
|
"Jetzt anschauen"-Knopf, sonst zählt ein echter Sekunden-Countdown zum
|
|
nächsten lokalen 20-Uhr-Termin runter. ===================================================================== */
|
|
(function () {
|
|
const API_BASE_URL = "https://postfach.dogfather-universe.com";
|
|
const FIX_STUNDE = 20; // täglicher Fix-Termin, in der Ortszeit der besuchenden Person
|
|
|
|
const radar = document.getElementById("stream-radar");
|
|
if (!radar) return; // Datei ist nur auf streamplan.html eingebunden
|
|
|
|
const CX = 150, CY = 150, R_OUT = 130, R_TICK_IN = 116, R_TICK_MAJOR_IN = 106, R_HAND = 100;
|
|
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
|
|
function polar(r, stundenAnteil) {
|
|
const winkel = (stundenAnteil / 24) * 360 - 90; // 0 Uhr oben, im Uhrzeigersinn
|
|
const rad = (winkel * Math.PI) / 180;
|
|
return { x: CX + r * Math.cos(rad), y: CY + r * Math.sin(rad) };
|
|
}
|
|
|
|
// ---------- 24 Stundenstriche (alle 6 Std. etwas länger/heller) ----------
|
|
const ticksHost = document.getElementById("radar-ticks");
|
|
for (let h = 0; h < 24; h++) {
|
|
const major = h % 6 === 0;
|
|
const p1 = polar(R_OUT, h);
|
|
const p2 = polar(major ? R_TICK_MAJOR_IN : R_TICK_IN, h);
|
|
const line = document.createElementNS(SVG_NS, "line");
|
|
line.setAttribute("x1", p1.x); line.setAttribute("y1", p1.y);
|
|
line.setAttribute("x2", p2.x); line.setAttribute("y2", p2.y);
|
|
line.setAttribute("class", major ? "radar-tick radar-tick-major" : "radar-tick");
|
|
ticksHost.appendChild(line);
|
|
}
|
|
|
|
// ---------- Fixmarkierung beim täglichen 20-Uhr-Termin ----------
|
|
const fixHost = document.getElementById("radar-fixmarker");
|
|
const fixPos = polar(R_OUT + 11, FIX_STUNDE);
|
|
const fixDot = document.createElementNS(SVG_NS, "circle");
|
|
fixDot.setAttribute("cx", fixPos.x); fixDot.setAttribute("cy", fixPos.y);
|
|
fixDot.setAttribute("r", 6.5);
|
|
fixDot.setAttribute("class", "radar-fixmarker-dot");
|
|
fixHost.appendChild(fixDot);
|
|
|
|
// ---------- "Jetzt"-Zeiger: bewegt sich mit der echten Uhrzeit mit ----------
|
|
const nowHand = document.getElementById("radar-now-hand");
|
|
const nowDot = document.getElementById("radar-now-dot");
|
|
function zeigerAktualisieren() {
|
|
const jetzt = new Date();
|
|
const stundenAnteil = jetzt.getHours() + jetzt.getMinutes() / 60 + jetzt.getSeconds() / 3600;
|
|
const spitze = polar(R_HAND, stundenAnteil);
|
|
nowHand.setAttribute("x2", spitze.x); nowHand.setAttribute("y2", spitze.y);
|
|
nowDot.setAttribute("cx", spitze.x); nowDot.setAttribute("cy", spitze.y);
|
|
}
|
|
zeigerAktualisieren();
|
|
setInterval(zeigerAktualisieren, 15000); // alle 15s reicht für eine sichtbare, ruhige Bewegung
|
|
|
|
// ---------- Countdown zum nächsten lokalen 20-Uhr-Termin ----------
|
|
function naechsterFixTermin() {
|
|
const jetzt = new Date();
|
|
const ziel = new Date(jetzt);
|
|
ziel.setHours(FIX_STUNDE, 0, 0, 0);
|
|
if (ziel <= jetzt) ziel.setDate(ziel.getDate() + 1);
|
|
return ziel;
|
|
}
|
|
function zweistellig(n) { return String(n).padStart(2, "0"); }
|
|
|
|
const countdownEl = document.getElementById("radar-countdown");
|
|
const statusText = document.getElementById("radar-status-text");
|
|
const statusSub = document.getElementById("radar-status-sub");
|
|
const watchBtn = document.getElementById("radar-watch-btn");
|
|
|
|
let istLive = false;
|
|
let letzterTitel = null;
|
|
|
|
function countdownTick() {
|
|
if (istLive) return; // im Live-Zustand zeigt der Countdown-Platz die Uhrzeit/den Titel, siehe unten
|
|
const diffMs = naechsterFixTermin() - new Date();
|
|
const gesamtSek = Math.max(0, Math.floor(diffMs / 1000));
|
|
const std = Math.floor(gesamtSek / 3600);
|
|
const min = Math.floor((gesamtSek % 3600) / 60);
|
|
const sek = gesamtSek % 60;
|
|
countdownEl.textContent = `${zweistellig(std)}:${zweistellig(min)}:${zweistellig(sek)}`;
|
|
}
|
|
setInterval(countdownTick, 1000);
|
|
|
|
function texteNeuSetzen() {
|
|
const t = window.dogiUebersetzen || ((k) => k);
|
|
if (istLive) {
|
|
statusText.textContent = t("sp_radar_live");
|
|
countdownEl.textContent = letzterTitel || t("sp_radar_live_generic");
|
|
statusSub.textContent = "";
|
|
watchBtn.hidden = false;
|
|
} else {
|
|
statusText.textContent = t("sp_radar_offline");
|
|
statusSub.textContent = t("sp_radar_countdown_label");
|
|
watchBtn.hidden = true;
|
|
countdownTick();
|
|
}
|
|
}
|
|
|
|
function liveStatusAnwenden(data) {
|
|
istLive = !!(data && data.live);
|
|
letzterTitel = data && data.title ? data.title : null;
|
|
radar.classList.toggle("ist-live", istLive);
|
|
texteNeuSetzen();
|
|
}
|
|
|
|
function liveStatusLaden() {
|
|
return fetch(`${API_BASE_URL}/live-status`, { cache: "no-store" })
|
|
.then((res) => res.json())
|
|
.then(liveStatusAnwenden)
|
|
.catch(() => {
|
|
istLive = false;
|
|
radar.classList.remove("ist-live");
|
|
texteNeuSetzen();
|
|
});
|
|
}
|
|
|
|
liveStatusLaden();
|
|
setInterval(liveStatusLaden, 30000);
|
|
document.addEventListener("visibilitychange", () => { if (!document.hidden) liveStatusLaden(); });
|
|
document.addEventListener("dogi-sprache-geaendert", texteNeuSetzen);
|
|
})();
|