Compare commits

..

5 commits

Author SHA1 Message Date
85cd5d1b74 stream: show a random Navidrome-style background image
All checks were successful
continuous-integration/drone/push Build is passing
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:42:51 +08:00
dcdfda2fdb stream: listen on IPv6 as well as IPv4
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:42:51 +08:00
534ade0ba5 stream: add a synthwave favicon
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:42:51 +08:00
032a9b86b8 ingest: resolve bandcamp label sources down to individual tracks
A yt-dlp source pointing at a label/artist page flat-extracts to a mix of
/track/ and /album/ URLs. The provider used each verbatim as a locator, so an
/album/ URL was handed to the fetcher as if it were a track: yt-dlp then
(mis)downloaded the whole album into one file and tagged it from the
playlist-level info, which carries the album title and no artist — surfacing as
"Unknown artist" on the stream.

Drill picked container entries down to a single track before emitting a
locator, bounded by a small depth so nested containers (label -> album ->
track) resolve while a real track (which flat-extracts to just itself) is the
base case. Locators are now always downloadable tracks, so the existing
tag/fetch path and anti-repeat keying work as intended.

Also make guess_metadata trust the explicit artist tag over the "Artist -
Title" title split: some label uploads double the artist into the title
("Artist - Artist - Title"), which the blind last-" - " split mis-parsed. When
that artist prefixes the title we peel it off (repeatedly), falling back to the
split only when there is no artist tag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:42:51 +08:00
a65cc61ccd stream: play a scheduled jingle right after key times of day
Adds special jingle folders (midi, gouter, bisous) that take priority
over the default jingle rotation once per day, briefly after 11h00,
15h00, 16h30 and 21h00.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:42:51 +08:00

View file

@ -81,11 +81,15 @@ music = fallback(track_sensitive=true, [main, backup])
# reload_mode="watch" : un jingle ajouté/retiré est pris en compte à chaud.
# Dossier vide → source jamais prête → le switch retombe simplement sur la
# musique, sans jingle et sans plantage.
# file.ls (utilisé en interne par playlist pour lister un dossier) n'est pas
# récursif par défaut : les sous-dossiers spéciaux ci-dessous n'entrent donc
# pas dans la rotation par défaut.
# ATTENTION : playlist explore récursivement les sous-dossiers. Pour la rotation
# par défaut on ne veut QUE les fichiers directement dans /jingles ; les
# sous-dossiers spéciaux (midi, gouter, moment) sont gérés à part. On
# filtre donc sur le dossier parent en plus du test audio habituel.
def jingle_top_level(r) =
audio_only(r) and path.dirname(request.uri(r)) == "/jingles"
end
jingles = playlist(
mode="randomize", reload_mode="watch", check_next=audio_only, "/jingles"
mode="randomize", reload_mode="watch", check_next=jingle_top_level, "/jingles"
)
# Jingles spéciaux, joués une seule fois juste après une heure donnée (au
@ -134,9 +138,9 @@ end
special_jingle_slots = [
make_special_slot(11, 0, jingles_midi),
make_special_slot(15, 0, jingles_bisous),
make_special_slot(15, 0, jingles_moment),
make_special_slot(16, 30, jingles_gouter),
make_special_slot(21, 0, jingles_bisous),
make_special_slot(21, 0, jingles_moment),
]
# On compte les morceaux de musique réellement diffusés : on_track ne se