mirror of
https://github.com/mistergibson/radio.git
synced 2026-09-08 22:09:51 -07:00
116 lines
4 KiB
Text
116 lines
4 KiB
Text
# station.liq - Main liquidsoap configuration
|
|
# All paths are resolved relative to this file's location.
|
|
# Move the whole directory tree and nothing else needs changing.
|
|
|
|
# -------------------------------------------------------
|
|
# Resolve root directory from script location
|
|
# -------------------------------------------------------
|
|
let ROOT = configure.bindir()
|
|
|
|
let MUSIC_DIR = ROOT ^ "/music"
|
|
let PODCASTS_DIR = ROOT ^ "/podcasts"
|
|
let PLAYLISTS_DIR = ROOT ^ "/playlists"
|
|
let SCHEDULE_FILE = ROOT ^ "/schedule.txt"
|
|
let CONFIG_FILE = ROOT ^ "/config.json"
|
|
|
|
# -------------------------------------------------------
|
|
# Load Icecast credentials from config.json
|
|
# -------------------------------------------------------
|
|
let cfg = json.from_file(CONFIG_FILE)
|
|
let ic_host = json.(cfg.icecast.host)
|
|
let ic_port = int_of_string(json.(cfg.icecast.port))
|
|
let ic_mount = json.(cfg.icecast.mount)
|
|
let ic_user = json.(cfg.icecast.username)
|
|
let ic_pass = json.(cfg.icecast.password)
|
|
|
|
# -------------------------------------------------------
|
|
# Background music source
|
|
# -------------------------------------------------------
|
|
let music =
|
|
playlist.recursive(
|
|
mode="random",
|
|
duration=3600,
|
|
path=MUSIC_DIR,
|
|
extensions=["mp3", "m4a", "ogg", "flac"]
|
|
)
|
|
|
|
# -------------------------------------------------------
|
|
# Scheduled content via request queue
|
|
# -------------------------------------------------------
|
|
def q = ref []
|
|
|
|
def push_request(req) =
|
|
q := req :: (!q)
|
|
|
|
# Build a show source from its .pls file (written by update_playlists.py)
|
|
def show_source(slug) =
|
|
let pls_path = PLAYLISTS_DIR ^ "/" ^ slug ^ ".pls"
|
|
if file.test(pls_path) then
|
|
log("# Playing scheduled show: #{slug}")
|
|
Some(request.create(pls_path))
|
|
else
|
|
log("! No playlist found for show: #{slug}, skipping")
|
|
None
|
|
end
|
|
|
|
# Parse schedule.txt and register cron-triggered tasks
|
|
def load_schedule() =
|
|
try
|
|
if not(file.test(SCHEDULE_FILE)) then
|
|
log("WARNING: schedule.txt not found at #{SCHEDULE_FILE}")
|
|
else
|
|
let lines = file.lines(SCHEDULE_FILE)
|
|
List.iter(fun line ->
|
|
let t = String.strip(line)
|
|
if t != "" && not(String.starts_with(t, "#")) then
|
|
let p = String.split(t, sep=" ")
|
|
|> List.filter(fun x -> String.strip(x) != "")
|
|
if List.length(p) >= 7 then
|
|
let cron_expr = String.concat(sep=" ", List.take(p, 5))
|
|
let stype = List.nth(p, 5)
|
|
let target = List.nth(p, 6)
|
|
match stype with
|
|
| "show" ->
|
|
cron.add(id=target, cron_expr, fun () ->
|
|
match show_source(target) with
|
|
| Some(r) -> push_request r
|
|
| None -> ()
|
|
)
|
|
| "stream" ->
|
|
let runlen_str =
|
|
if List.length(p) > 7 then List.nth(p, 7) else "3600"
|
|
let runlen = int_of_string(runlen_str)
|
|
cron.add(id=target, cron_expr, fun () ->
|
|
log("Triggering stream: #{target} (#{runlen}s)")
|
|
# For external streams, create a request with duration cap
|
|
let s = single.file(fallback=false, target)
|
|
push_request(request.create(target))
|
|
)
|
|
| _ ->
|
|
log("Unknown schedule type '#{stype}' for target '#{target}', ignoring")
|
|
end
|
|
else
|
|
log("Malformed schedule line (need at least 7 fields): #{t}")
|
|
end
|
|
end
|
|
) lines
|
|
log("Schedule loaded from #{SCHEDULE_FILE}")
|
|
with e ->
|
|
log("ERROR loading schedule: #{e}")
|
|
|
|
# Load schedule once at startup
|
|
thread.run(at=now(), fun () -> load_schedule())
|
|
|
|
# -------------------------------------------------------
|
|
# Output: scheduled content over background music fallback
|
|
# -------------------------------------------------------
|
|
output.icecast(
|
|
%mp3(bitrate=128),
|
|
host=ic_host,
|
|
port=ic_port,
|
|
user=ic_user,
|
|
password=ic_pass,
|
|
mount=ic_mount,
|
|
fallback=music,
|
|
request.queue(q)
|
|
)
|