# radieo — reverse-proxy vers le daemon d'ingestion. # # Inclus par radio.liq. Le player n'a pas d'accès direct au réseau interne # (l'ingest n'est joignable que depuis les autres conteneurs) : on relaie donc # ces quelques endpoints à travers le harbor du flux (port 8000). Ces routes # sont autonomes — elles ne dépendent que de `http`/`url`, jamais du pipeline — # et renvoient une valeur neutre plutôt qu'une erreur si l'ingest est # injoignable, pour ne pas casser le player. # File d'attente des prochains morceaux, relayée depuis le daemon d'ingestion. ingest_queue_url = "http://ingest:8080/queue" harbor.http.register( port=8000, method="GET", "/queue", fun(_, resp) -> begin resp.content_type("application/json; charset=utf-8") body = http.get(ingest_queue_url, timeout=5.0) if body.status_code == 200 then resp.data(string.trim(body) ^ "\n") else resp.data("[]") end end ) # État du préchargement {ready, prefetch}. Si le daemon est injoignable on # renvoie un objet neutre plutôt qu'une erreur, pour ne pas casser le player. ingest_status_url = "http://ingest:8080/status" harbor.http.register( port=8000, method="GET", "/ingest/status", fun(_, resp) -> begin resp.content_type("application/json; charset=utf-8") body = http.get(ingest_status_url, timeout=5.0) if body.status_code == 200 then resp.data(string.trim(body) ^ "\n") else resp.data("{}") end end ) # Mettre une URL yt-dlp en file d'attente (piste seule, ou playlist/album # entier). On relaie la demande vers l'ingest, qui résout l'URL et la place en # file prioritaire (le prochain /next la servira). On renvoie tel quel son code # et son corps JSON ({queued: N} ou une erreur). Timeout large : résoudre une # grosse playlist peut prendre du temps. NB : la variable locale s'appelle # `link`, pas `url`, pour ne pas masquer le module `url` (url.encode). ingest_enqueue_url = "http://ingest:8080/enqueue" harbor.http.register( port=8000, method="POST", "/enqueue", fun(req, resp) -> begin link = list.assoc(default="", "url", req.query) if link == "" then resp.status_code(400) resp.data("missing url") else body = http.post( data="", timeout=60.0, "#{ingest_enqueue_url}?url=#{url.encode(link)}" ) resp.status_code(body.status_code) resp.content_type("application/json; charset=utf-8") resp.data(string.trim(body) ^ "\n") end end ) # Retirer un morceau de la file d'attente. Symétrique de /enqueue : on relaie la # demande (l'`id` opaque fourni par /queue) vers l'ingest, qui retire l'entrée # correspondante. On renvoie tel quel son code et son corps JSON ({removed: true} # ou une erreur). ingest_dequeue_url = "http://ingest:8080/dequeue" harbor.http.register( port=8000, method="POST", "/dequeue", fun(req, resp) -> begin id = list.assoc(default="", "id", req.query) if id == "" then resp.status_code(400) resp.data("missing id") else body = http.post( data="", timeout=10.0, "#{ingest_dequeue_url}?id=#{url.encode(id)}" ) resp.status_code(body.status_code) resp.content_type("application/json; charset=utf-8") resp.data(string.trim(body) ^ "\n") end end ) # Partage Subsonic à la demande. Un morceau de la bibliothèque Subsonic n'a pas # d'URL publique : son lien « source » pointe ici avec l'id du morceau. On # demande alors à l'ingest (qui détient les identifiants Subsonic) de créer un # partage public via createShare, puis on redirige l'auditeur vers l'URL # renvoyée. Le partage n'est donc créé que si quelqu'un clique réellement sur le # lien — jamais à chaque morceau joué. 404 si l'id manque, 502 si l'ingest ne # peut pas partager (partage désactivé côté serveur, injoignable…). ingest_share_url = "http://ingest:8080/share" harbor.http.register( port=8000, method="GET", "/share", fun(req, resp) -> begin song = list.assoc(default="", "song", req.query) if song == "" then resp.status_code(404) resp.data("missing song id") else body = http.post(data="", timeout=10.0, "#{ingest_share_url}?id=#{url.encode(song)}") share = json.parse(default={url=""}, string.trim(body)) if body.status_code == 200 and share.url != "" then resp.status_code(302) resp.header("Location", share.url) resp.data("") else resp.status_code(502) resp.data("share unavailable") end end end )