bugfixes --> station.liq : workarounds for LiquidSoap 2.2.4-dev

This commit is contained in:
G. Gibson 2026-10-02 17:39:17 -07:00
commit 6c31b74d2f
4 changed files with 78 additions and 83 deletions

View file

@ -192,7 +192,7 @@ chmod 664 "$STORAGE_ROOT/state/"*.db 2>/dev/null || true
# --- Cron entries (liquidsoap user's crontab already exists from package) ----- # --- Cron entries (liquidsoap user's crontab already exists from package) -----
CRON_FETCH="0 * * * * cd ${INSTALL_DIR} && ${INSTALL_DIR}/run_radio.sh fetch_podcasts.rb --fetch-all >> ${STORAGE_ROOT}/logs/fetch_cron.log 2>&1" CRON_FETCH="0 * * * * cd ${INSTALL_DIR} && ${INSTALL_DIR}/run_radio.sh fetch_podcasts.rb --fetch-all >> ${STORAGE_ROOT}/logs/fetch_cron.log 2>&1"
CRON_UPDATE="30 * * * * cd ${INSTALL_DIR} && ${INSTALL_DIR}/run_radio.sh update_playlist.rb >> ${STORAGE_ROOT}/logs/update_cron.log 2>&1" CRON_UPDATE="30 * * * * cd ${INSTALL_DIR} && ${INSTALL_DIR}/run_radio.sh update_playlists.rb >> ${STORAGE_ROOT}/logs/update_cron.log 2>&1"
CURRENT_CRONTAB=$(crontab -u liquidsoap -l 2>/dev/null || true) CURRENT_CRONTAB=$(crontab -u liquidsoap -l 2>/dev/null || true)
NEW_CRONTAB="${CURRENT_CRONTAB}" NEW_CRONTAB="${CURRENT_CRONTAB}"

View file

@ -6,3 +6,19 @@
# Examples: # Examples:
# 0 8 * * 2 show hardcore_history # 0 8 * * 2 show hardcore_history
# 0 6 * * 1 stream http://example.org:8000/live.mp3 3600 # 0 6 * * 1 stream http://example.org:8000/live.mp3 3600
# ################################################################### Daily
# KOPB --> BBC News & Local (Midnight to 7am)
0 0 * * 1-7 stream http://stream1.opb.org/radio.mp3 25200
# History of Rome (Noon to 1pm)
0 12 * * 1-7 show the_history_of_rome
# ################################################################### Weekdays
# UpFront KPFA
0 7 * * 1-5 stream https://streams.kpfa.org:8443/kpfa 3600
# Bradcast
0 8 * * 1-5 show the_bradcast_w_brad_friedman
# Hardknock Radio KPFA
0 16 * * 1-5 stream https://streams.kpfa.org:8443/kpfa 3600
# Flashpoints KPFA
0 17 * * 1-5 stream https://streams.kpfa.org:8443/kpfa 3600
# Evening News KPFA
0 18 * * 1-5 stream https://streams.kpfa.org:8443/kpfa 3600

View file

@ -1,85 +1,63 @@
#!/usr/bin/env liquidsoap # station.liq - Cascadia Digital Collective Radio Automation
# Liquidsoap 2.2.4-1+dev compatible
# Run from /srv/radio so relative paths resolve correctly
# --------------------------------------------------------------- settings.log.file.set(false)
# station.liq - Liquidsoap configuration for radio automation
# 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.
#
# JINGLE/ANNOUNCEMENT NOTE:
# random() stalls when one branch is permanently down (empty dir).
# Until jingles/announcements directories contain audio files,
# they are excluded from the graph. Uncomment the relevant lines
# below once you've added content to those folders.
# ---------------------------------------------------------------
set("log.stdout", true) # --- Load config ---
set("log.level", 3) # Explicit type annotation required: without it, fields used only in #{...}
# interpolations default to null (see liquidsoap json docs).
let json.parse ({ storage, icecast = { host, port, mount, source_username, source_password } }
: { storage: string,
icecast: { host: string, port: int, mount: string,
source_username: string, source_password: string } })
= file.contents("config.json")
# --- Step 1: path to config.json (relative to working directory) --- storage_base = storage
let config_path = "config.json" music_dir = "#{storage}/music"
queue_dir = "#{storage}/queues"
# --- Step 2: read and parse the whole file with explicit types -- icecast_host = host
let json.parse (cfg : { icecast_port = port
storage: string, icecast_mount = mount
icecast: { icecast_user = source_username
host: string, icecast_pass = source_password
port: int,
mount: string,
username: string,
password: string
}
}) = file.contents(config_path)
# --- Step 3: pull out the values we need ------------------------ print("Config loaded: storage=#{storage_base}, icecast=#{icecast_host}:#{icecast_port}#{icecast_mount}")
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
set("log.file.path", "#{storage}/logs/liquidsoap.log") # --- Background music playlist (loops forever by default) ---
background_music = playlist(music_dir)
# --- Background music library (directory scanned recursively) -- # --- Show queue source (reads current_queue.txt each tick) ---
music_playlist = # In 2.2.x the callback must return a request (type ()->request), not null.
mksafe(playlist("#{storage}/music")) # When the queue is empty we play a short synthesized tone so the source
# stays up without needing an external file.
def read_queue()
qf = "#{queue_dir}/current_queue.txt"
if file.exists(qf) and file.contents(qf) != "" then
request.create(file.contents(qf))
else
request.create("synth:shape=sine,frequency=440.,duration=1.")
end
end
# --- Scheduled content: request queue fed by schedule.txt ------ show_source = request.dynamic(prefetch=1, read_queue)
sched_queue = request.queue(id="scheduler")
# --- Jingles / announcements (uncomment when dirs have content) --- # --- Mux: show takes priority, fall back to background music ---
# jingles_src = main_out = mksafe(fallback([show_source, background_music]))
# mksafe(playlist("#{storage}/jingles"))
#
# announcements_src =
# mksafe(playlist("#{storage}/announcements"))
# --- Assemble the stream --------------------------------------- # --- Output to Icecast ---
primary = fallback(track_sensitive=false, [sched_queue, music_playlist])
# When jingles are active, uncomment this and comment out the line below:
# content = random(weights=[1, 8], [jingles_src, primary])
content = primary
# When announcements are active, uncomment this and comment out the line below:
# final_content = fallback(track_sensitive=false, [announcements_src, content])
final_content = content
radio = normalize(final_content)
# --- Output to Icecast -----------------------------------------
output.icecast( output.icecast(
%mp3(bitrate=128, samplerate=44100, stereo=true), %mp3(bitrate=128),
host=ic_host, host=icecast_host,
port=ic_port, port=icecast_port,
user=ic_username, user=icecast_user,
password=ic_password, password=icecast_pass,
mount=ic_mount, mount=icecast_mount,
name="Radio Station", name="Road Unit Radio",
description="Automated internet radio", description="Community radio automation",
genre="Various", genre="various",
url="",
public=true, public=true,
radio main_out
) )

View file

@ -1,2 +1,3 @@
#!/usr/bin/env jruby
Dir.chdir(File.expand_path(__dir__)) Dir.chdir(File.expand_path(__dir__))
exec("liquidsoap", File.expand_path("station.liq")) exec("liquidsoap", File.expand_path("station.liq"))