stream: web player with now-playing

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>
This commit is contained in:
nemunaire 2026-07-02 22:46:37 +08:00
commit f4eaf8e7d1
3 changed files with 92 additions and 0 deletions

View file

@ -4,6 +4,7 @@
# La source principale est pilotée par le daemon d'ingestion via GET /next.
# Le dossier /cache sert de secours quand le daemon n'a rien à proposer
# (daemon indisponible, file momentanément vide…). Si tout est vide : silence.
# Le harbor sert aussi une petite page web (/) et le titre courant (/nowplaying).
# --- Journalisation : tout sur la sortie standard (pratique en conteneur) ---
settings.log.stdout := true
@ -59,6 +60,11 @@ radio = crossfade(duration=3.0, fade_in=3.0, fade_out=3.0, radio)
# mksafe garantit un flux continu : silence plutôt que plantage si tout est vide.
radio = mksafe(radio)
# --- Métadonnées « en cours de lecture » -----------------------------------
# On mémorise les dernières métadonnées vues sur le flux réellement diffusé.
now_playing = ref([])
radio.on_metadata(synchronous=false, fun(m) -> now_playing := m)
# --- Sortie : flux MP3 sur http://<hote>:8000/radio.mp3 ---
output.harbor(
%mp3(bitrate=192),
@ -66,3 +72,22 @@ output.harbor(
mount="radio.mp3",
radio
)
# --- Page web et API de lecture (mêmes port/harbor que le flux) ---
home_html = file.contents("/etc/liquidsoap/index.html")
harbor.http.register(
port=8000, method="GET", "/",
fun(_, resp) -> begin
resp.content_type("text/html; charset=utf-8")
resp.html(home_html)
end
)
harbor.http.register(
port=8000, method="GET", "/nowplaying",
fun(_, resp) -> begin
m = now_playing()
resp.json({title=m["title"], artist=m["artist"]})
end
)