stream: add a whole-station restart of the current track
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Wire the Media Session previous-track control to a new POST /restart-track route that requeues the current song from the start for every listener, and keep next-track as skip. Exposing both handlers also makes Android (Chrome) show the skip button, which it hides when only nexttrack is set. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
622210197f
commit
96a1ba89e6
2 changed files with 45 additions and 5 deletions
|
|
@ -245,9 +245,17 @@
|
|||
safe(() => media.setActionHandler("play", () => player.play().catch(() => {})));
|
||||
safe(() => media.setActionHandler("pause", () => player.pause()));
|
||||
safe(() => media.setActionHandler("stop", () => player.pause()));
|
||||
// Pas de reprise possible sur un direct : « précédent » comme « suivant »
|
||||
// passent au morceau suivant côté serveur.
|
||||
// « Suivant » saute le morceau courant. « Précédent » le rejoue depuis le
|
||||
// début, pour toute l'antenne (flux partagé, pas de position par
|
||||
// auditeur). Brancher les deux est aussi nécessaire sous Android (Chrome),
|
||||
// qui traite précédent/suivant comme une paire et masque le bouton suivant
|
||||
// si seul « nexttrack » est défini.
|
||||
safe(() => media.setActionHandler("nexttrack", () => { skipBtn.click(); }));
|
||||
safe(() => media.setActionHandler("previoustrack", () => {
|
||||
fetch("/restart-track", { method: "POST" })
|
||||
.then(() => setTimeout(() => { poll(); pollHistory(); }, 900))
|
||||
.catch(() => {});
|
||||
}));
|
||||
// Le direct n'est pas déplaçable : on neutralise les actions de seek pour
|
||||
// éviter que le système n'affiche des boutons d'avance/recul inopérants.
|
||||
safe(() => media.setActionHandler("seekbackward", null));
|
||||
|
|
|
|||
|
|
@ -72,9 +72,17 @@ backup = playlist(
|
|||
check_next=audio_only, fallback_file
|
||||
)
|
||||
|
||||
# fallback préfère la source principale et bascule sur le cache si elle n'a
|
||||
# rien de prêt. track_sensitive=true : on ne coupe pas un morceau en cours.
|
||||
music = fallback(track_sensitive=true, [main, backup])
|
||||
# File de rejeu ponctuel : normalement vide (donc non prête, transparente). Le
|
||||
# endpoint /restart-track y pousse le morceau courant pour le rejouer depuis le
|
||||
# début à l'antenne. Placée en tête du fallback, elle préempte la source
|
||||
# principale dès qu'un morceau y est poussé.
|
||||
requeue = request.queue(id="requeue")
|
||||
|
||||
# fallback préfère la file de rejeu, puis la source principale, et bascule sur le
|
||||
# cache si rien n'est prêt. track_sensitive=true : on ne coupe pas un morceau en
|
||||
# cours (le rejeu ne prend donc effet qu'à la prochaine frontière, provoquée
|
||||
# explicitement par source.skip dans /restart-track).
|
||||
music = fallback(track_sensitive=true, [requeue, main, backup])
|
||||
|
||||
# --- Jingles : intercalés toutes les 2 chansons -----------------------------
|
||||
# Le dossier /jingles (monté depuis ./jingles) est parcouru et lu au hasard.
|
||||
|
|
@ -270,6 +278,30 @@ harbor.http.register(
|
|||
end
|
||||
)
|
||||
|
||||
# Rejouer le morceau courant depuis le début, pour TOUTE l'antenne (le flux est
|
||||
# partagé : il n'existe pas de position par auditeur). On repousse le fichier
|
||||
# courant — pris dans le cache, donc forcément local et présent — en tête via la
|
||||
# file de rejeu, puis on saute le morceau en cours pour l'y enchaîner aussitôt.
|
||||
# On remet le compteur de chansons à zéro pour qu'un jingle ne vole pas la place
|
||||
# du rejeu à cette frontière. Un morceau introuvable (jingle en cours, cache
|
||||
# évincé) renvoie 409.
|
||||
harbor.http.register(
|
||||
port=8000, method="POST", "/restart-track",
|
||||
fun(_, resp) -> begin
|
||||
base = path.basename(list.assoc(default="", "filename", now_playing()))
|
||||
full = "/cache/#{base}"
|
||||
if base != "" and file.exists(full) then
|
||||
song_count := 0
|
||||
requeue.push.uri(full)
|
||||
source.skip(radio)
|
||||
resp.json({restarted=true})
|
||||
else
|
||||
resp.status_code(409)
|
||||
resp.json({restarted=false})
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
# Télécharger un morceau. Sans paramètre : le titre en cours. Avec `?file=<nom>` :
|
||||
# n'importe quel fichier encore présent dans le cache (les titres passés listés
|
||||
# par /history exposent ce jeton). Le cache étant borné par le LRU, un morceau
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue