commit ef4716d360ce5dec8761ef15f672ab17078f674e Author: KenwoodFox Date: Tue Jun 16 23:47:37 2026 -0400 Add all bp diff --git a/css/grafana.css b/css/grafana.css new file mode 100644 index 0000000..59a9ee8 --- /dev/null +++ b/css/grafana.css @@ -0,0 +1,32 @@ +/* + * Grafana embed wrappers for rx.kitsunehosting.net + * + * Cross-origin iframes cannot be styled from this page — Grafana renders on + * grafana.kitsunehosting.net. Use URL params on the iframe src instead: + * theme=dark|light panel colors + * kiosk=tv hide Grafana chrome (nav, menus) + * refresh=30s auto-refresh interval + * + * Custom Grafana themes require server-side config on the Grafana instance. + */ + +.grafana-embed { + margin-bottom: 12px; + background: #000000; + border: 2px inset #808080; + padding: 2px; + overflow: hidden; +} + +.grafana-embed iframe { + display: block; + width: 100%; + height: 200px; + border: 0; + background: #000000; +} + +/* Match the retro terminal vibe when Grafana is in dark mode */ +.grafana-embed--dark { + box-shadow: inset 0 0 12px rgba(0, 255, 0, 0.08); +} diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..5c4e6bb --- /dev/null +++ b/css/style.css @@ -0,0 +1,208 @@ +* { + box-sizing: border-box; +} + +body { + margin: 0; + padding: 16px; + background: #c0c0c0; + color: #000000; + font-family: "Times New Roman", Times, serif; + font-size: 16px; +} + +a { + color: #0000ee; +} + +a:visited { + color: #551a8b; +} + +a:hover { + color: #ff0000; +} + +.banner { + text-align: center; + background: #000080; + color: #ffff00; + padding: 12px; + border: 4px outset #808080; + font-size: 28px; + font-weight: bold; + letter-spacing: 2px; + text-shadow: 2px 2px #000000; +} + +.nav { + text-align: center; + margin: 12px 0; + padding: 8px; + background: #d4d0c8; + border: 2px inset #808080; +} + +.nav a { + margin: 0 16px; + font-weight: bold; + text-decoration: underline; +} + +.nav a.active { + color: #000000; + text-decoration: none; + background: #ffffff; + padding: 2px 6px; + border: 1px inset #808080; +} + +hr { + border: none; + height: 2px; + background: #808080; + margin: 16px 0; +} + +.panel { + background: #d4d0c8; + border: 2px inset #808080; + padding: 12px; +} + +.panel-title { + text-align: center; + font-weight: bold; + font-size: 18px; + margin: 0 0 12px 0; + text-decoration: underline; +} + +.live-feed { + text-align: center; + margin: 0 auto; + max-width: 960px; +} + +.live-feed img { + display: block; + margin: 0 auto; + width: 100%; + height: auto; + aspect-ratio: 16 / 9; + object-fit: contain; + border: 3px inset #808080; + background: #000000; +} + +.live-label { + margin-top: 8px; + font-family: "Courier New", Courier, monospace; + font-size: 14px; + color: #008000; +} + +.live-timestamp { + margin: 4px 0 0; + font-family: "Courier New", Courier, monospace; + font-size: 12px; + color: #404040; +} + +.blink { + animation: blink 1s step-end infinite; +} + +@keyframes blink { + 50% { + opacity: 0; + } +} + +.content-table { + width: 100%; + border-collapse: collapse; + table-layout: fixed; +} + +.content-table td { + vertical-align: top; + padding: 0 6px; +} + +.graphs-panel { + min-height: 280px; +} + +.graph-placeholder { + height: 200px; + background: #000000; + border: 2px inset #808080; + display: flex; + align-items: center; + justify-content: center; + color: #00ff00; + font-family: "Courier New", Courier, monospace; + font-size: 14px; + margin-bottom: 12px; +} + +.stats-panel { + min-height: 280px; +} + +.stat-block { + text-align: center; + margin-bottom: 16px; + padding: 12px; + background: #ffffff; + border: 2px outset #808080; +} + +.stat-value { + font-size: 48px; + font-weight: bold; + font-family: "Courier New", Courier, monospace; + color: #000080; + line-height: 1; +} + +.stat-value--ok { + color: #008000; +} + +.stat-value--bad { + color: #cc0000; +} + +#stat-status { + font-size: 32px; +} + +.stat-label { + font-size: 14px; + margin-top: 4px; + text-transform: uppercase; +} + +.placeholder-page { + text-align: center; + padding: 48px 16px; +} + +.placeholder-page h2 { + font-size: 24px; +} + +.under-construction { + font-size: 48px; + margin: 24px 0; +} + +.footer { + text-align: center; + margin-top: 24px; + font-size: 12px; + font-family: "Courier New", Courier, monospace; + color: #404040; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..e270810 --- /dev/null +++ b/index.html @@ -0,0 +1,91 @@ + + + + + + RX.KITSUNEHOSTING.NET - Live + + + + + + + + + +
+ +
+

Live

+ Live feed +

LIVE

+

+
+ +
+ + + + + + + + + + + + + diff --git a/js/live.js b/js/live.js new file mode 100644 index 0000000..0e0757c --- /dev/null +++ b/js/live.js @@ -0,0 +1,161 @@ +(function () { + var LIVE_IMAGE = "live/live.png"; + var LIVE_DATA = "live/live.json"; + var REFRESH_MS = 60 * 1000; + var TICK_MS = 1000; + + var img = document.getElementById("live-feed"); + var timestampEl = document.getElementById("live-timestamp"); + var statUptime = document.getElementById("stat-uptime"); + var statListeners = document.getElementById("stat-listeners"); + var statStatus = document.getElementById("stat-status"); + var lastCapturedAt = null; + + if (!img) { + return; + } + + function formatTimeAgo(unixSeconds) { + var diff = Math.floor(Date.now() / 1000) - unixSeconds; + if (diff < 0) { + diff = 0; + } + + if (diff < 60) { + return diff === 1 ? "1 second ago" : diff + " seconds ago"; + } + + var minutes = Math.floor(diff / 60); + if (minutes < 60) { + return minutes === 1 ? "1 minute ago" : minutes + " minutes ago"; + } + + var hours = Math.floor(diff / 3600); + if (hours < 24) { + return hours === 1 ? "1 hour ago" : hours + " hours ago"; + } + + var days = Math.floor(diff / 86400); + return days === 1 ? "1 day ago" : days + " days ago"; + } + + function formatDuration(seconds) { + var diff = Math.max(0, Math.floor(seconds)); + var days = Math.floor(diff / 86400); + var hours = Math.floor((diff % 86400) / 3600); + var minutes = Math.floor((diff % 3600) / 60); + + if (days > 0) { + return days + "d " + hours + "h"; + } + if (hours > 0) { + return hours + "h " + minutes + "m"; + } + if (minutes > 0) { + return minutes + "m"; + } + return diff + "s"; + } + + function formatUptime(value) { + if (value === null || value === undefined || value === "") { + return "---"; + } + if (typeof value === "number") { + return formatDuration(value); + } + return String(value); + } + + function formatListeners(value) { + if (value === null || value === undefined || value === "") { + return "---"; + } + return String(value); + } + + function formatStatus(value) { + if (value === null || value === undefined || value === "") { + return "---"; + } + return String(value); + } + + function updateTimeAgo() { + if (!timestampEl) { + return; + } + + if (!lastCapturedAt) { + timestampEl.textContent = ""; + return; + } + + timestampEl.textContent = "Captured " + formatTimeAgo(lastCapturedAt); + } + + function updateStats(data) { + if (statUptime) { + statUptime.textContent = formatUptime(data.uptime); + } + if (statListeners) { + var listeners = data.listeners; + if (listeners === undefined) { + listeners = data.live_listeners; + } + statListeners.textContent = formatListeners(listeners); + } + if (statStatus) { + statStatus.textContent = formatStatus(data.status); + statStatus.classList.remove("stat-value--ok", "stat-value--bad"); + var status = String(data.status || "").toLowerCase(); + if (status === "online" || status === "ok" || status === "up") { + statStatus.classList.add("stat-value--ok"); + } else if (status === "offline" || status === "down" || status === "error") { + statStatus.classList.add("stat-value--bad"); + } + } + } + + function clearStats() { + updateStats({}); + } + + function fetchLiveData() { + fetch(LIVE_DATA + "?t=" + Date.now()) + .then(function (response) { + if (!response.ok) { + throw new Error("live data unavailable"); + } + return response.json(); + }) + .then(function (data) { + if (data && data.timestamp) { + lastCapturedAt = data.timestamp; + updateTimeAgo(); + } else { + lastCapturedAt = null; + updateTimeAgo(); + } + updateStats(data || {}); + }) + .catch(function () { + lastCapturedAt = null; + updateTimeAgo(); + clearStats(); + }); + } + + function refreshLiveImage() { + img.src = LIVE_IMAGE + "?t=" + Date.now(); + fetchLiveData(); + } + + img.addEventListener("error", function () { + img.alt = "Live feed unavailable"; + }); + + refreshLiveImage(); + setInterval(refreshLiveImage, REFRESH_MS); + setInterval(updateTimeAgo, TICK_MS); +})(); diff --git a/live/live.json b/live/live.json new file mode 100644 index 0000000..39ea15d --- /dev/null +++ b/live/live.json @@ -0,0 +1,6 @@ +{ + "timestamp": 1781667629, + "uptime": 86412, + "listeners": 0, + "status": "online" +} diff --git a/live/live.png b/live/live.png new file mode 100644 index 0000000..29cdb59 Binary files /dev/null and b/live/live.png differ diff --git a/radio.html b/radio.html new file mode 100644 index 0000000..710814e --- /dev/null +++ b/radio.html @@ -0,0 +1,32 @@ + + + + + + RX.KITSUNEHOSTING.NET - Radio + + + + + + + + +
+ +
+
+

Radio

+

Coming soon.

+
+ + + + + diff --git a/tools.html b/tools.html new file mode 100644 index 0000000..069cee4 --- /dev/null +++ b/tools.html @@ -0,0 +1,32 @@ + + + + + + RX.KITSUNEHOSTING.NET - Tools + + + + + + + + +
+ +
+
+

Tools

+

Coming soon.

+
+ + + + +