#!/usr/bin/env liquidsoap # --------------------------------------------------------------- # 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. # --------------------------------------------------------------- configure.bindir() set("log.stdout", true) set("log.level", 3) # --- Load Icecast credentials + storage path from config.json --- let cfg : { storage: string, icecast: { host: string, port: int, mount: string, username: string, password: string }, gpodder: { enable: bool, host: string, username: string, password: string } } = json.parse(file.contents("#{bindir()}/config.json")) 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) --- music_playlist = request.cue( playlist( recurse=true, pattern="\\.(mp3|m4a)$", "#{storage}/music" ) ) # --- 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" def has_audio(dir) = try let l = list.filter(fun(f) -> regexp("\\.(mp3|m4a)$").test(f), ls.dir(dir)) list.length(l) > 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 announcements_src = if has_audio(announce_dir) then mksafe(request.cue(playlist(recurse=true, pattern="\\.(mp3|m4a)$", announce_dir))) else null() end # --- 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]) end final_content = match announcements_src with | null() => content | src => fallback(track_sensitive=false, [src, content]) end radio = normalize(final_content) # --- 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", public=true, radio )