let timersData = [];
let detailOpenFor = null;
function formatDiff(target) {
const targetDate = target instanceof Date ? target : new Date(target);
const now = new Date();
const diff = targetDate - now;
if (diff <= 0) return "Abgelaufen";
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((diff / (1000 * 60)) % 60);
const seconds = Math.floor((diff / 1000) % 60);
return `${days}d ${hours}h ${minutes}m ${seconds}s`;
}
fetch("/api/countdowns")
.then(res => res.json())
.then(data => {
timersData = data.timers || [];
const mainTargetDate = new Date(data.main.target);
const mainLabel = data.main.label || "";
const mainLabelEl = document.getElementById("main-label");
const mainCountdownEl = document.getElementById("main-countdown");
function updateMainTimer() {
const now = new Date();
const diff = mainTargetDate - now;
if (diff <= 0) {
mainLabelEl.textContent = mainLabel;
mainCountdownEl.textContent = "Abgelaufen";
return;
}
mainLabelEl.textContent = mainLabel;
mainCountdownEl.textContent = formatDiff(mainTargetDate);
}
function updateSmallTimers() {
timersData.forEach(t => {
const el = document.getElementById(t.id);
if (!el) return;
const now = new Date();
const nextEntry = t.targets
.map(e => ({ ...e, date: new Date(e.time) }))
.find(e => e.date > now);
if (nextEntry) {
el.textContent = `${nextEntry.label}\n${formatDiff(nextEntry.date)}`;
} else {
el.textContent = `${t.label}\nAbgelaufen`;
}
});
}
function updateDetailsPanel() {
if (!detailOpenFor) return;
const timer = timersData.find(t => t.id === detailOpenFor);
if (!timer) return;
timer.targets.forEach((target, idx) => {
const el = document.getElementById(`detail-${timer.id}-${idx}`);
if (!el) return;
el.textContent = formatDiff(target.time);
});
}
function renderDetails(timer) {
const detailEl = document.getElementById("timer-details");
if (!detailEl) return;
detailOpenFor = timer.id;
const entries = timer.targets.map((target, idx) => {
const entryId = `detail-${timer.id}-${idx}`;
return `
`;
}).join("");
detailEl.innerHTML = `
${timer.label}
${timer.targets.length} Termine
${entries}
`;
detailEl.classList.remove("hidden");
const closeBtn = document.getElementById("timer-details-close");
if (closeBtn) {
closeBtn.addEventListener("click", () => {
detailOpenFor = null;
detailEl.classList.add("hidden");
});
}
updateDetailsPanel();
}
setInterval(() => {
updateMainTimer();
updateSmallTimers();
updateDetailsPanel();
}, 1000);
updateMainTimer();
updateSmallTimers();
document.querySelectorAll(".small-circle").forEach(circle => {
circle.addEventListener("click", () => {
const timerId = circle.getAttribute("data-timer");
const timer = timersData.find(t => t.id === timerId);
if (timer) renderDetails(timer);
});
});
});
document.getElementById("fullscreen-btn").addEventListener("click", () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else {
document.exitFullscreen();
}
});
const cantinaAudio = document.getElementById("cantina-audio");
const circleContainer = document.querySelector(".circle-container");
function playCantina() {
if (!cantinaAudio) return;
cantinaAudio.currentTime = 0;
cantinaAudio.play().catch(err => console.warn("Cantina playback blocked:", err));
}
if (circleContainer) {
circleContainer.addEventListener("click", playCantina);
}
function scheduleNextFullHour() {
const now = new Date();
const next = new Date(now);
next.setMinutes(0, 0, 0);
if (next <= now) {
next.setHours(next.getHours() + 1);
}
const delay = next - now;
setTimeout(() => {
playCantina();
scheduleNextFullHour();
}, delay);
}
scheduleNextFullHour();
const overlay = document.getElementById("twitter-overlay");
function showOverlay() {
overlay.style.display = "flex";
const gongVideo = document.getElementById("gong-video-fullscreen");
if (gongVideo) {
gongVideo.currentTime = 0;
gongVideo.play().catch(err => console.warn("Autoplay-Fehler:", err));
}
setTimeout(() => {
overlay.style.display = "none";
}, 60000);
}
(() => {
const now = new Date();
const target = new Date();
target.setHours(23, 40, 0, 0);
if (now > target && now - target < 60000) {
showOverlay();
} else if (now <= target) {
const delay = target - now;
setTimeout(showOverlay, delay);
}
})();