secubox-openwrt/package/secubox/secubox-app-lyrion-bridge/files/usr/lib/lyrion-bridge/ffmpeg-bridge.sh
CyberMind-FR 6db547f7f8 feat: Add WebRadio, TURN server, and Lyrion streaming integration
New packages:
- luci-app-webradio: Web radio management with Lyrion bridge tab
- luci-app-turn: TURN/STUN server UI for WebRTC (Jitsi integration)
- secubox-app-lyrion-bridge: Lyrion → Squeezelite → FFmpeg → Icecast pipeline
- secubox-app-squeezelite: Squeezelite audio player with FIFO output
- secubox-app-turn: TURN server with ACME SSL and Jitsi setup
- secubox-app-webradio: Icecast/ezstream web radio server

Features:
- HTTPS streaming via HAProxy (stream.gk2.secubox.in)
- Lyrion Music Server bridge for streaming playlists to Icecast
- TURN server with time-limited credential generation
- CrowdSec integration for WebRadio security
- Schedule-based radio programming with jingles

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-21 17:46:54 +01:00

125 lines
3.8 KiB
Bash

#!/bin/sh
# Lyrion to Icecast Bridge - FFmpeg Audio Pipeline
# Reads PCM from Squeezelite FIFO and streams to Icecast
LOG_FILE="/var/log/lyrion-bridge.log"
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG_FILE"
logger -t lyrion-bridge "$1"
}
uci_get() { uci -q get "lyrion-bridge.$1" 2>/dev/null || echo "$2"; }
# Load configuration
INPUT_FIFO=$(uci_get audio.input_fifo "/tmp/squeezelite.pcm")
SAMPLE_RATE=$(uci_get audio.sample_rate "44100")
CHANNELS=$(uci_get audio.channels "2")
FORMAT=$(uci_get audio.format "s16le")
ICECAST_HOST=$(uci_get icecast.host "127.0.0.1")
ICECAST_PORT=$(uci_get icecast.port "8000")
ICECAST_MOUNT=$(uci_get icecast.mount "/lyrion")
ICECAST_PASS=$(uci_get icecast.password "hackme")
BITRATE=$(uci_get icecast.bitrate "192")
STREAM_NAME=$(uci_get icecast.name "Lyrion Stream")
STREAM_DESC=$(uci_get icecast.description "Streaming from Lyrion Music Server")
STREAM_GENRE=$(uci_get icecast.genre "Various")
METADATA_SYNC=$(uci_get metadata.sync_enabled "1")
METADATA_INTERVAL=$(uci_get metadata.sync_interval "5")
log "Starting Lyrion to Icecast bridge..."
log "Input: $INPUT_FIFO (PCM $FORMAT, ${SAMPLE_RATE}Hz, ${CHANNELS}ch)"
log "Output: icecast://${ICECAST_HOST}:${ICECAST_PORT}${ICECAST_MOUNT} (MP3 ${BITRATE}kbps)"
# Ensure FIFO exists
if [ ! -p "$INPUT_FIFO" ]; then
log "Creating FIFO: $INPUT_FIFO"
mkfifo "$INPUT_FIFO"
fi
# Wait for Squeezelite to start writing to FIFO
log "Waiting for audio input..."
while [ ! -s "$INPUT_FIFO" ] && [ -p "$INPUT_FIFO" ]; do
sleep 1
done
# Build Icecast URL
ICECAST_URL="icecast://source:${ICECAST_PASS}@${ICECAST_HOST}:${ICECAST_PORT}${ICECAST_MOUNT}"
# Metadata update function (background process)
update_metadata() {
local lyrion_host=$(uci_get main.lyrion_server "127.0.0.1")
local lyrion_port=$(uci_get main.lyrion_port "9000")
while true; do
# Query Lyrion for current track info
local status=$(curl -s "http://${lyrion_host}:${lyrion_port}/jsonrpc.js" \
-d '{"id":1,"method":"slim.request","params":["",["status","-",1,"tags:adl"]]}' 2>/dev/null)
if [ -n "$status" ]; then
local title=$(echo "$status" | jsonfilter -e '@.result.playlist_loop[0].title' 2>/dev/null)
local artist=$(echo "$status" | jsonfilter -e '@.result.playlist_loop[0].artist' 2>/dev/null)
local album=$(echo "$status" | jsonfilter -e '@.result.playlist_loop[0].album' 2>/dev/null)
if [ -n "$title" ]; then
local metadata="${artist:+$artist - }${title}"
# Update Icecast metadata via admin API
curl -s "http://admin:$(uci -q get webradio.main.admin_password)@${ICECAST_HOST}:${ICECAST_PORT}/admin/metadata?mount=${ICECAST_MOUNT}&mode=updinfo&song=$(echo "$metadata" | sed 's/ /%20/g')" >/dev/null 2>&1
fi
fi
sleep "$METADATA_INTERVAL"
done
}
# Start metadata sync in background
if [ "$METADATA_SYNC" = "1" ]; then
update_metadata &
METADATA_PID=$!
log "Metadata sync started (PID: $METADATA_PID)"
fi
# Cleanup on exit
cleanup() {
log "Stopping bridge..."
[ -n "$METADATA_PID" ] && kill $METADATA_PID 2>/dev/null
[ -n "$FFMPEG_PID" ] && kill $FFMPEG_PID 2>/dev/null
exit 0
}
trap cleanup INT TERM
# Main streaming loop
while true; do
log "Starting FFmpeg stream..."
ffmpeg -re \
-f $FORMAT -ar $SAMPLE_RATE -ac $CHANNELS \
-i "$INPUT_FIFO" \
-acodec libmp3lame -ab ${BITRATE}k -ar $SAMPLE_RATE -ac $CHANNELS \
-f mp3 \
-content_type audio/mpeg \
"$ICECAST_URL" \
2>> "$LOG_FILE" &
FFMPEG_PID=$!
log "FFmpeg started (PID: $FFMPEG_PID)"
# Wait for FFmpeg to exit
wait $FFMPEG_PID
EXIT_CODE=$?
log "FFmpeg exited with code $EXIT_CODE"
# If exited normally (0 or 255), it means stream ended - wait and retry
if [ $EXIT_CODE -eq 0 ] || [ $EXIT_CODE -eq 255 ]; then
log "Stream ended, waiting for new audio..."
sleep 2
else
# Error - wait longer before retry
log "Stream error, retrying in 5 seconds..."
sleep 5
fi
done