mirror of
https://github.com/mistergibson/radio.git
synced 2026-09-08 22:09:51 -07:00
testing
This commit is contained in:
parent
57aa2aa1c9
commit
11e1292a75
3 changed files with 55 additions and 52 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
# Secrets and local configuration
|
# Secrets and local configuration
|
||||||
config.json
|
config.json
|
||||||
|
dirs.txt
|
||||||
# Runtime data (should live under the storage path, not here)
|
# Runtime data (should live under the storage path, not here)
|
||||||
.venv/
|
.venv/
|
||||||
state/
|
state/
|
||||||
|
|
|
||||||
12
check_dirs.sh
Executable file
12
check_dirs.sh
Executable file
|
|
@ -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
|
||||||
93
station.liq
93
station.liq
|
|
@ -2,18 +2,20 @@
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# station.liq - Liquidsoap configuration for radio automation
|
# station.liq - Liquidsoap configuration for radio automation
|
||||||
# Auto-detects its own location so all paths are relative.
|
# Written for Liquidsoap 2.2.x. Run from /srv/radio so that the
|
||||||
# Music/jingles/announcements live under the storage path from
|
# relative config.json path resolves correctly; media lives under
|
||||||
# config.json; code stays in the install dir.
|
# the storage path read from that file. Directory playlists scan
|
||||||
|
# recursively for audio files automatically.
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
configure.bindir()
|
|
||||||
|
|
||||||
set("log.stdout", true)
|
set("log.stdout", true)
|
||||||
set("log.level", 3)
|
set("log.level", 3)
|
||||||
|
|
||||||
# --- Load Icecast credentials + storage path from config.json ---
|
# --- Step 1: path to config.json (relative to working directory) ---
|
||||||
let cfg : {
|
let config_path = "config.json"
|
||||||
|
|
||||||
|
# --- Step 2: read and parse the whole file with explicit types --
|
||||||
|
let json.parse (cfg : {
|
||||||
storage: string,
|
storage: string,
|
||||||
icecast: {
|
icecast: {
|
||||||
host: string,
|
host: string,
|
||||||
|
|
@ -21,82 +23,71 @@ let cfg : {
|
||||||
mount: string,
|
mount: string,
|
||||||
username: string,
|
username: string,
|
||||||
password: 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_host = cfg.icecast.host
|
||||||
let ic_port = cfg.icecast.port
|
let ic_port = cfg.icecast.port
|
||||||
let ic_mount = cfg.icecast.mount
|
let ic_mount = cfg.icecast.mount
|
||||||
let ic_username = cfg.icecast.username
|
let ic_username = cfg.icecast.username
|
||||||
let ic_password = cfg.icecast.password
|
let ic_password = cfg.icecast.password
|
||||||
let storage = cfg.storage
|
|
||||||
|
|
||||||
set("log.file.path", "#{storage}/logs/liquidsoap.log")
|
set("log.file.path", "#{storage}/logs/liquidsoap.log")
|
||||||
|
|
||||||
# --- Background music library (recursive scan for mp3/m4a) ---
|
# --- Background music library (directory scanned recursively) --
|
||||||
music_playlist =
|
music_playlist =
|
||||||
request.cue(
|
playlist("#{storage}/music")
|
||||||
playlist(
|
|
||||||
recurse=true,
|
|
||||||
pattern="\\.(mp3|m4a)$",
|
|
||||||
"#{storage}/music"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Scheduled content: request queue fed by schedule.txt ---
|
# --- Scheduled content: request queue fed by schedule.txt ------
|
||||||
sched_queue = request.queue(id="scheduler")
|
sched_queue = request.queue(id="scheduler")
|
||||||
|
|
||||||
# --- Jingles / announcements (optional) ---
|
# --- Helper: check if a directory contains any audio files -----
|
||||||
jingle_dir = "#{storage}/jingles"
|
|
||||||
announce_dir = "#{storage}/announcements"
|
|
||||||
|
|
||||||
def has_audio(dir) =
|
def has_audio(dir) =
|
||||||
try
|
try
|
||||||
let l = list.filter(fun(f) -> regexp("\\.(mp3|m4a)$").test(f), ls.dir(dir))
|
let entries = file.ls(dir)
|
||||||
list.length(l) > 0
|
let audio_count = list.length(
|
||||||
|
list.filter(fun(f) -> regexp("\\.(mp3|m4a)$").test(f), entries)
|
||||||
|
)
|
||||||
|
audio_count > 0
|
||||||
catch _ do
|
catch _ do
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
jingles_src =
|
# --- Jingles / announcements (only active if they have content) ---
|
||||||
if has_audio(jingle_dir) then
|
jingles_active = has_audio("#{storage}/jingles")
|
||||||
mksafe(request.cue(playlist(recurse=true, pattern="\\.(mp3|m4a)$", jingle_dir)))
|
announcements_active = has_audio("#{storage}/announcements")
|
||||||
else
|
|
||||||
null()
|
|
||||||
end
|
|
||||||
|
|
||||||
announcements_src =
|
log("#[info] Jingles directory has audio: #{string(jingles_active)}")
|
||||||
if has_audio(announce_dir) then
|
log("#[info] Announcements directory has audio: #{string(announcements_active)}")
|
||||||
mksafe(request.cue(playlist(recurse=true, pattern="\\.(mp3|m4a)$", announce_dir)))
|
|
||||||
else
|
|
||||||
null()
|
|
||||||
end
|
|
||||||
|
|
||||||
# --- Assemble the stream ---
|
# --- Assemble the stream ---------------------------------------
|
||||||
primary = fallback(track_sensitive=false, [sched_queue, music_playlist])
|
primary = fallback(track_sensitive=false, [sched_queue, music_playlist])
|
||||||
|
|
||||||
content =
|
content =
|
||||||
match jingles_src with
|
if jingles_active then
|
||||||
| null() => primary
|
random(weights=[1, 8], [
|
||||||
| src => random(weights=[1, 8], [src, primary])
|
mksafe(playlist("#{storage}/jingles")),
|
||||||
|
primary
|
||||||
|
])
|
||||||
|
else
|
||||||
|
primary
|
||||||
end
|
end
|
||||||
|
|
||||||
final_content =
|
final_content =
|
||||||
match announcements_src with
|
if announcements_active then
|
||||||
| null() => content
|
fallback(track_sensitive=false, [
|
||||||
| src => fallback(track_sensitive=false, [src, content])
|
mksafe(playlist("#{storage}/announcements")),
|
||||||
|
content
|
||||||
|
])
|
||||||
|
else
|
||||||
|
content
|
||||||
end
|
end
|
||||||
|
|
||||||
radio = normalize(final_content)
|
radio = normalize(final_content)
|
||||||
|
|
||||||
# --- Output to Icecast ---
|
# --- Output to Icecast -----------------------------------------
|
||||||
output.icecast(
|
output.icecast(
|
||||||
%mp3(bitrate=128, samplerate=44100, stereo=true),
|
%mp3(bitrate=128, samplerate=44100, stereo=true),
|
||||||
host=ic_host,
|
host=ic_host,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue