diff --git a/install_for_jruby b/install_for_jruby index dddab0e..e7d82ec 100755 --- a/install_for_jruby +++ b/install_for_jruby @@ -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_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) NEW_CRONTAB="${CURRENT_CRONTAB}" diff --git a/schedule.txt b/schedule.txt index 3ed5d7e..eda1872 100644 --- a/schedule.txt +++ b/schedule.txt @@ -6,3 +6,19 @@ # Examples: # 0 8 * * 2 show hardcore_history # 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 diff --git a/station.liq b/station.liq index 6da9854..2aa7420 100644 --- a/station.liq +++ b/station.liq @@ -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 -# --------------------------------------------------------------- -# 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. -# --------------------------------------------------------------- +settings.log.file.set(false) -set("log.stdout", true) -set("log.level", 3) +# --- Load config --- +# 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) --- -let config_path = "config.json" +storage_base = storage +music_dir = "#{storage}/music" +queue_dir = "#{storage}/queues" -# --- Step 2: read and parse the whole file with explicit types -- -let json.parse (cfg : { - storage: string, - icecast: { - host: string, - port: int, - mount: string, - username: string, - password: string - } -}) = file.contents(config_path) +icecast_host = host +icecast_port = port +icecast_mount = mount +icecast_user = source_username +icecast_pass = source_password -# --- 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 +print("Config loaded: storage=#{storage_base}, icecast=#{icecast_host}:#{icecast_port}#{icecast_mount}") -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) -- -music_playlist = - mksafe(playlist("#{storage}/music")) +# --- Show queue source (reads current_queue.txt each tick) --- +# In 2.2.x the callback must return a request (type ()->request), not null. +# 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 ------ -sched_queue = request.queue(id="scheduler") +show_source = request.dynamic(prefetch=1, read_queue) -# --- Jingles / announcements (uncomment when dirs have content) --- -# jingles_src = -# mksafe(playlist("#{storage}/jingles")) -# -# announcements_src = -# mksafe(playlist("#{storage}/announcements")) +# --- Mux: show takes priority, fall back to background music --- +main_out = mksafe(fallback([show_source, background_music])) -# --- Assemble the stream --------------------------------------- -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 to Icecast --- output.icecast( - %mp3(bitrate=128, samplerate=44100, stereo=true), - host=ic_host, - port=ic_port, - user=ic_username, - password=ic_password, - mount=ic_mount, - name="Radio Station", - description="Automated internet radio", - genre="Various", + %mp3(bitrate=128), + host=icecast_host, + port=icecast_port, + user=icecast_user, + password=icecast_pass, + mount=icecast_mount, + name="Road Unit Radio", + description="Community radio automation", + genre="various", + url="", public=true, - radio + main_out ) diff --git a/station.rb b/station.rb index 3d00d3d..1ec22c6 100755 --- a/station.rb +++ b/station.rb @@ -1,2 +1,3 @@ +#!/usr/bin/env jruby Dir.chdir(File.expand_path(__dir__)) exec("liquidsoap", File.expand_path("station.liq"))