mirror of
https://github.com/migatu/conjurer.git
synced 2026-07-14 13:34:40 +00:00
ebc73c16d4
Dockerises the radio_conjurer.liq environment on Debian bookworm: - Dockerfile.radio builds Liquidsoap through opam with build args for OPAM_VERSION (static binary), OCAML_VERSION (default 4.14.2; 2.1.x needs OCaml 4.x - prod ran 4.13.0, pass it for parity) and LIQUIDSOAP_VERSION (default 2.1.4, matching the script) - LIQ_OPAM_PACKAGES installs exactly the features the script uses: mad+lame (mp3), cry (icecast), taglib (tags/replaygain), pulseaudio (mic/out), samplerate, inotify (watch-reload), ffmpeg - ffmpeg.pref verdict: the Pi pin forced Debian's FFmpeg 5.x family (libavcodec59...) over RPi OS repo builds because the ocaml-ffmpeg bindings are compiled against those sonames; bookworm ships them natively so the container needs no pin (documented, not copied) - pulse-access/audio group memberships baked in (were manual on the Pi); PULSE_MODE=internal runs a system-wide pulse with a null sink so the unmodified script works on a headless VM (mic = silence), host mode mounts the real socket, none for edited scripts - mounts mirror the script's hardcoded paths (/home/pi/Conjurer, /home/pi/MediaFolder/mp3) so radio_conjurer.liq runs unmodified; entrypoint seeds script+params on first run (never overwrites), creates missing playlists, seeds placeholder icecast credentials (loud warning) and generates a silent emergency mp3 when the single() file is missing - compose.radio.yaml: extra_hosts maps the script's host="radio" to ICECAST_HOST_IP; exposes 54321 (bot's RADIO_HARBOR /skip) and 9999 - docs: radio section with build args, pulse modes and the ffmpeg.pref / groups verdicts Part 2 of this PR (splitting bot<->radio comms out of the musician into a radio+betoniarka container) follows on this branch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
67 lines
2.8 KiB
Bash
Executable File
67 lines
2.8 KiB
Bash
Executable File
#!/bin/sh
|
|
# Prepare the radio volumes so radio_conjurer.liq boots on a fresh VM, then
|
|
# start (or point at) PulseAudio and exec liquidsoap. Existing files are never
|
|
# overwritten - live-edited script/params/playlists always win.
|
|
set -e
|
|
|
|
DATA="${RADIO_DATA_DIR:-/home/pi/Conjurer}"
|
|
MUSIC="${RADIO_MUSIC_DIR:-/home/pi/MediaFolder/mp3}"
|
|
mkdir -p "$DATA" "$MUSIC"
|
|
|
|
# Seed the script + persistent interactive params from the image on first run.
|
|
[ -e "$DATA/radio_conjurer.liq" ] || cp /app/radio_conjurer.liq "$DATA/"
|
|
if [ ! -e "$DATA/script.params" ]; then
|
|
if [ -e /app/script.params ]; then cp /app/script.params "$DATA/"; else : > "$DATA/script.params"; fi
|
|
fi
|
|
|
|
# Playlists + logs the script watches/writes; empty files keep it happy until
|
|
# the musician/betoniarka populate them.
|
|
for f in all_playlist.playlist priority_queue.playlist hit.playlist \
|
|
request.playlist jingles.playlist persistence.log; do
|
|
[ -e "$DATA/$f" ] || : > "$DATA/$f"
|
|
done
|
|
|
|
# Icecast credentials are a secret - never baked into the image. Seed a
|
|
# placeholder so the script can parse the JSON, but shout about it.
|
|
if [ ! -e "$DATA/icecast_credentials.json" ]; then
|
|
printf '{\n"password" : "CHANGE_ME"\n}\n' > "$DATA/icecast_credentials.json"
|
|
echo "WARNING: seeded placeholder icecast_credentials.json - the icecast" >&2
|
|
echo " output will be rejected until you set the real password!" >&2
|
|
fi
|
|
|
|
# single() aborts the whole script when its file is missing; guarantee the
|
|
# emergency fallback exists (5s of silence beats a dead radio).
|
|
EMERGENCY="$MUSIC/Youtube/Dr. Peacock - Trip to Ireland [GvrvQTUbUcA].mp3"
|
|
if [ ! -e "$EMERGENCY" ]; then
|
|
mkdir -p "$MUSIC/Youtube"
|
|
if ffmpeg -loglevel error -f lavfi -i anullsrc=r=44100:cl=stereo -t 5 \
|
|
-codec:a libmp3lame -q:a 9 "$EMERGENCY"; then
|
|
echo "WARNING: emergency track was missing - generated silent placeholder" >&2
|
|
else
|
|
echo "WARNING: could not create emergency track; single() may abort" >&2
|
|
fi
|
|
fi
|
|
|
|
# PulseAudio wiring:
|
|
# internal (default) - system-wide pulse inside the container with a null
|
|
# sink (see /etc/pulse/system.pa); no sound hardware
|
|
# needed, mic path reads silence.
|
|
# host - use a socket mounted from the host; set PULSE_SERVER
|
|
# (e.g. unix:/tmp/pulseaudio.socket) in the env file.
|
|
# none - you edited the script to drop pulse in/out.
|
|
case "${PULSE_MODE:-internal}" in
|
|
internal)
|
|
pulseaudio --system --daemonize=yes --disallow-exit --exit-idle-time=-1 \
|
|
|| echo "WARNING: internal pulseaudio failed to start" >&2
|
|
export PULSE_SERVER="${PULSE_SERVER:-unix:/var/run/pulse/native}"
|
|
;;
|
|
host)
|
|
[ -n "$PULSE_SERVER" ] || echo "WARNING: PULSE_MODE=host but PULSE_SERVER is unset" >&2
|
|
;;
|
|
none)
|
|
;;
|
|
esac
|
|
|
|
cd "$DATA"
|
|
exec "$@"
|