stream: show a history of aired tracks (/history)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a468d78153
commit
7fc372f18d
2 changed files with 62 additions and 4 deletions
|
|
@ -51,6 +51,14 @@
|
|||
}
|
||||
.actions button:hover, .actions a:hover { background: rgba(155,140,255,.3); }
|
||||
.actions button:disabled { opacity: .5; cursor: default; }
|
||||
.history { margin-top: 1.75rem; text-align: left; }
|
||||
.history h2 { font-size: .7rem; letter-spacing: .2em; text-transform: uppercase;
|
||||
color: #7d768f; margin: 0 0 .4rem; font-weight: 600; }
|
||||
.history ul { list-style: none; margin: 0; padding: 0; }
|
||||
.history li { padding: .45rem 0; border-top: 1px solid rgba(255,255,255,.06); }
|
||||
.history .h-title { color: #e8e4f2; font-size: .92rem; }
|
||||
.history .h-artist { color: #8b849c; font-size: .8rem; margin-top: .1rem; }
|
||||
.history .empty { color: #6b6480; font-size: .85rem; padding: .45rem 0; }
|
||||
.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; }
|
||||
|
|
@ -75,6 +83,10 @@
|
|||
<input id="streamUrl" type="text" readonly>
|
||||
<button id="copyBtn" type="button">Copier</button>
|
||||
</div>
|
||||
<section class="history">
|
||||
<h2>Historique</h2>
|
||||
<ul id="historyList"></ul>
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
const titleEl = document.getElementById("title");
|
||||
|
|
@ -109,6 +121,30 @@
|
|||
document.title = t ? (a ? `${t} — ${a} · radieo` : `${t} · radieo`) : "radieo";
|
||||
} catch (e) { /* keep last known values */ }
|
||||
}
|
||||
|
||||
// Historique des titres passés. Le premier élément renvoyé est le morceau
|
||||
// en cours (déjà affiché plus haut), on ne montre donc que les précédents.
|
||||
const historyList = document.getElementById("historyList");
|
||||
const escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => (
|
||||
{ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]
|
||||
));
|
||||
async function pollHistory() {
|
||||
try {
|
||||
const r = await fetch("/history", { cache: "no-store" });
|
||||
const items = await r.json();
|
||||
const past = Array.isArray(items) ? items.slice(1) : [];
|
||||
if (past.length === 0) {
|
||||
historyList.innerHTML = '<li class="empty">—</li>';
|
||||
return;
|
||||
}
|
||||
historyList.innerHTML = past.map((m) => {
|
||||
const t = escapeHtml((m.title || "").trim() || "—");
|
||||
const a = (m.artist || "").trim();
|
||||
const artist = a ? `<div class="h-artist">${escapeHtml(a)}</div>` : "";
|
||||
return `<li><div class="h-title">${t}</div>${artist}</li>`;
|
||||
}).join("");
|
||||
} catch (e) { /* keep last known values */ }
|
||||
}
|
||||
// Lien nu du flux, à ouvrir dans un lecteur externe (VLC…).
|
||||
const shareUrl = location.origin + "/radio.mp3";
|
||||
const urlEl = document.getElementById("streamUrl");
|
||||
|
|
@ -132,11 +168,12 @@
|
|||
skipBtn.disabled = true;
|
||||
try { await fetch("/skip", { method: "POST" }); } catch (e) { /* ignore */ }
|
||||
// Laisser le temps à la bascule, puis rafraîchir l'affichage.
|
||||
setTimeout(() => { skipBtn.disabled = false; poll(); }, 900);
|
||||
setTimeout(() => { skipBtn.disabled = false; poll(); pollHistory(); }, 900);
|
||||
});
|
||||
|
||||
poll();
|
||||
setInterval(poll, 5000);
|
||||
pollHistory();
|
||||
setInterval(() => { poll(); pollHistory(); }, 5000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue