Serve a small web page at http://<host>:8000/ (stream/index.html) from the Liquidsoap harbor, alongside the /radio.mp3 stream. It shows the track currently on air and refreshes it from a /nowplaying JSON endpoint, fed by the broadcast source's live metadata — accurate even though the ingest daemon runs a track ahead (prefetch). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
66 lines
2.6 KiB
HTML
66 lines
2.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>radieo</title>
|
|
<style>
|
|
:root { color-scheme: dark; }
|
|
* { box-sizing: border-box; }
|
|
body {
|
|
margin: 0; min-height: 100vh; display: flex; align-items: center;
|
|
justify-content: center; font-family: system-ui, sans-serif;
|
|
background: radial-gradient(circle at 30% 20%, #2a2140, #0d0b14 70%);
|
|
color: #f2f0f7;
|
|
}
|
|
.card {
|
|
width: min(90vw, 420px); padding: 2.5rem 2rem;
|
|
background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08);
|
|
border-radius: 18px; box-shadow: 0 20px 60px rgba(0,0,0,.45);
|
|
backdrop-filter: blur(8px); text-align: center;
|
|
}
|
|
.logo { font-size: .8rem; letter-spacing: .35em; text-transform: uppercase;
|
|
color: #9b8cff; margin-bottom: 1.75rem; }
|
|
.np-label { font-size: .7rem; letter-spacing: .2em; text-transform: uppercase;
|
|
color: #7d768f; margin-bottom: .5rem; }
|
|
.title { font-size: 1.55rem; font-weight: 650; line-height: 1.25;
|
|
word-wrap: break-word; }
|
|
.artist { margin-top: .35rem; font-size: 1.05rem; color: #b8b2c8; }
|
|
audio { width: 100%; margin-top: 2rem; }
|
|
.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%;
|
|
background: #4ade80; margin-right: .4rem; vertical-align: middle;
|
|
box-shadow: 0 0 0 0 rgba(74,222,128,.6); animation: pulse 2s infinite; }
|
|
@keyframes pulse {
|
|
0% { box-shadow: 0 0 0 0 rgba(74,222,128,.5); }
|
|
70% { box-shadow: 0 0 0 10px rgba(74,222,128,0); }
|
|
100% { box-shadow: 0 0 0 0 rgba(74,222,128,0); }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main class="card">
|
|
<div class="logo">◈ radieo</div>
|
|
<div class="np-label"><span class="dot"></span>en cours</div>
|
|
<div class="title" id="title">—</div>
|
|
<div class="artist" id="artist"></div>
|
|
<audio id="player" controls autoplay preload="none" src="/radio.mp3"></audio>
|
|
</main>
|
|
<script>
|
|
const titleEl = document.getElementById("title");
|
|
const artistEl = document.getElementById("artist");
|
|
async function poll() {
|
|
try {
|
|
const r = await fetch("/nowplaying", { cache: "no-store" });
|
|
const m = await r.json();
|
|
const t = (m.title || "").trim();
|
|
const a = (m.artist || "").trim();
|
|
titleEl.textContent = t || "—";
|
|
artistEl.textContent = a;
|
|
document.title = t ? (a ? `${t} — ${a} · radieo` : `${t} · radieo`) : "radieo";
|
|
} catch (e) { /* keep last known values */ }
|
|
}
|
|
poll();
|
|
setInterval(poll, 5000);
|
|
</script>
|
|
</body>
|
|
</html>
|