From 11e1292a751f1adbaa95d56d2af8fa579c3fc2f8 Mon Sep 17 00:00:00 2001 From: "G. Gibson" Date: Tue, 1 Sep 2026 09:57:29 -0700 Subject: [PATCH] testing --- .gitignore | 2 +- check_dirs.sh | 12 +++++++ station.liq | 93 +++++++++++++++++++++++---------------------------- 3 files changed, 55 insertions(+), 52 deletions(-) create mode 100755 check_dirs.sh diff --git a/.gitignore b/.gitignore index 6d2fce2..1a94786 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Secrets and local configuration config.json - +dirs.txt # Runtime data (should live under the storage path, not here) .venv/ state/ diff --git a/check_dirs.sh b/check_dirs.sh new file mode 100755 index 0000000..d75ebd8 --- /dev/null +++ b/check_dirs.sh @@ -0,0 +1,12 @@ +#!/bin/bash +STORAGE="/mnt/storage/radio" +JINGLES="no" +ANNOUNCEMENTS="no" +if find "$STORAGE/jingles" -type f \( -name "*.mp3" -o -name "*.m4a" \) 2>/dev/null | grep -q .; then + JINGLES="yes" +fi +if find "$STORAGE/announcements" -type f \( -name "*.mp3" -o -name "*.m4a" \) 2>/dev/null | grep -q .; then + ANNOUNCEMENTS="yes" +fi +echo "jingles=$JINGLES" > /srv/radio/dirs.txt +echo "announcements=$ANNOUNCEMENTS" >> /srv/radio/dirs.txt diff --git a/station.liq b/station.liq index fd1510c..4123264 100644 --- a/station.liq +++ b/station.liq @@ -2,18 +2,20 @@ # --------------------------------------------------------------- # station.liq - Liquidsoap configuration for radio automation -# Auto-detects its own location so all paths are relative. -# Music/jingles/announcements live under the storage path from -# config.json; code stays in the install dir. +# Written for Liquidsoap 2.2.x. Run from /srv/radio so that the +# relative config.json path resolves correctly; media lives under +# the storage path read from that file. Directory playlists scan +# recursively for audio files automatically. # --------------------------------------------------------------- -configure.bindir() - set("log.stdout", true) set("log.level", 3) -# --- Load Icecast credentials + storage path from config.json --- -let cfg : { +# --- Step 1: path to config.json (relative to working directory) --- +let config_path = "config.json" + +# --- Step 2: read and parse the whole file with explicit types -- +let json.parse (cfg : { storage: string, icecast: { host: string, @@ -21,82 +23,71 @@ let cfg : { mount: string, username: string, password: string - }, - gpodder: { - enable: bool, - host: string, - username: string, - password: string } -} = json.parse(file.contents("#{bindir()}/config.json")) +}) = file.contents(config_path) +# --- Step 3: pull out the values we need ------------------------ +let storage = cfg.storage let ic_host = cfg.icecast.host let ic_port = cfg.icecast.port let ic_mount = cfg.icecast.mount let ic_username = cfg.icecast.username let ic_password = cfg.icecast.password -let storage = cfg.storage set("log.file.path", "#{storage}/logs/liquidsoap.log") -# --- Background music library (recursive scan for mp3/m4a) --- +# --- Background music library (directory scanned recursively) -- music_playlist = - request.cue( - playlist( - recurse=true, - pattern="\\.(mp3|m4a)$", - "#{storage}/music" - ) - ) + playlist("#{storage}/music") -# --- Scheduled content: request queue fed by schedule.txt --- +# --- Scheduled content: request queue fed by schedule.txt ------ sched_queue = request.queue(id="scheduler") -# --- Jingles / announcements (optional) --- -jingle_dir = "#{storage}/jingles" -announce_dir = "#{storage}/announcements" - +# --- Helper: check if a directory contains any audio files ----- def has_audio(dir) = try - let l = list.filter(fun(f) -> regexp("\\.(mp3|m4a)$").test(f), ls.dir(dir)) - list.length(l) > 0 + let entries = file.ls(dir) + let audio_count = list.length( + list.filter(fun(f) -> regexp("\\.(mp3|m4a)$").test(f), entries) + ) + audio_count > 0 catch _ do false end -end -jingles_src = - if has_audio(jingle_dir) then - mksafe(request.cue(playlist(recurse=true, pattern="\\.(mp3|m4a)$", jingle_dir))) - else - null() - end +# --- Jingles / announcements (only active if they have content) --- +jingles_active = has_audio("#{storage}/jingles") +announcements_active = has_audio("#{storage}/announcements") -announcements_src = - if has_audio(announce_dir) then - mksafe(request.cue(playlist(recurse=true, pattern="\\.(mp3|m4a)$", announce_dir))) - else - null() - end +log("#[info] Jingles directory has audio: #{string(jingles_active)}") +log("#[info] Announcements directory has audio: #{string(announcements_active)}") -# --- Assemble the stream --- +# --- Assemble the stream --------------------------------------- primary = fallback(track_sensitive=false, [sched_queue, music_playlist]) content = - match jingles_src with - | null() => primary - | src => random(weights=[1, 8], [src, primary]) + if jingles_active then + random(weights=[1, 8], [ + mksafe(playlist("#{storage}/jingles")), + primary + ]) + else + primary end final_content = - match announcements_src with - | null() => content - | src => fallback(track_sensitive=false, [src, content]) + if announcements_active then + fallback(track_sensitive=false, [ + mksafe(playlist("#{storage}/announcements")), + content + ]) + else + content end radio = normalize(final_content) -# --- Output to Icecast --- +# --- Output to Icecast ----------------------------------------- output.icecast( %mp3(bitrate=128, samplerate=44100, stereo=true), host=ic_host,