stream: let the listener download the current track (/download)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
nemunaire 2026-07-02 23:58:22 +08:00
commit 1f6937f22c
2 changed files with 32 additions and 0 deletions

View file

@ -78,6 +78,7 @@
<audio id="player" controls autoplay preload="none"></audio>
<div class="actions">
<button id="skipBtn" type="button">⏭ Suivant</button>
<a id="dlBtn" href="/download" download>⬇ Télécharger</a>
</div>
<div class="share">
<input id="streamUrl" type="text" readonly>

View file

@ -143,3 +143,34 @@ harbor.http.register(
resp.json({skipped=true})
end
)
# Télécharger le fichier du morceau en cours. Le chemin vient de la métadonnée
# `filename` de la source diffusée : c'est bien le fichier à l'antenne, et il est
# forcément encore sur le disque tant qu'il joue (pas encore évincé par le LRU).
def content_type_of(name) =
low = string.case(lower=true, name)
if string.contains(suffix=".flac", low) then "audio/flac"
elsif string.contains(suffix=".ogg", low) then "audio/ogg"
elsif string.contains(suffix=".opus", low) then "audio/opus"
elsif string.contains(suffix=".m4a", low) or string.contains(suffix=".aac", low) then "audio/mp4"
elsif string.contains(suffix=".wav", low) then "audio/wav"
else "audio/mpeg"
end
end
harbor.http.register(
port=8000, method="GET", "/download",
fun(_, resp) -> begin
m = now_playing()
fname = m["filename"]
if fname == "" or not file.exists(fname) then
resp.status_code(404)
resp.data("no track currently available")
else
base = path.basename(fname)
resp.content_type(content_type_of(base))
resp.header("Content-Disposition", "attachment; filename=\"#{base}\"")
resp.data(file.contents(fname))
end
end
)