Initiales Release: Busch-Radio Spotify Bridge v1.0.0
Stellt Spotify-Musik via Spotify Connect als HTTP-MP3-Stream bereit, den das Busch-Jäger Unterputz-Internetradio direkt abspielen kann. Komponenten: - ha-addon/: Home Assistant Add-on (librespot + ffmpeg + Icecast2) - custom_components/: Optionale HA Integration mit Media-Player-Entity - README.md: Vollständige Installations- und Konfigurationsanleitung - example-config.yaml: Kommentierte Beispielkonfiguration Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
209
ha-addon/run.sh
Normal file
209
ha-addon/run.sh
Normal file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# ==============================================================================
|
||||
# Busch-Radio Spotify Bridge – Startup-Script
|
||||
#
|
||||
# Startet:
|
||||
# 1. Icecast2 – HTTP-Stream-Server
|
||||
# 2. librespot – Virtueller Spotify Connect-Empfänger (gibt PCM auf stdout aus)
|
||||
# 3. ffmpeg – Kodiert PCM → MP3 und schickt es als Icecast-Quelle
|
||||
#
|
||||
# Bei Absturz wird die komplette Pipeline nach 5 Sekunden neu gestartet.
|
||||
# ==============================================================================
|
||||
|
||||
set -u
|
||||
|
||||
# ── Konfiguration lesen ───────────────────────────────────────────────────────
|
||||
DEVICE_NAME=$(bashio::config 'device_name')
|
||||
BITRATE=$(bashio::config 'bitrate')
|
||||
STREAM_PORT=$(bashio::config 'stream_port')
|
||||
STREAM_MOUNT=$(bashio::config 'stream_mount')
|
||||
ICECAST_PASSWORD=$(bashio::config 'icecast_password')
|
||||
|
||||
bashio::log.info "╔══════════════════════════════════════════════╗"
|
||||
bashio::log.info "║ Busch-Radio Spotify Bridge v1.0.0 ║"
|
||||
bashio::log.info "╚══════════════════════════════════════════════╝"
|
||||
bashio::log.info "Gerätename : ${DEVICE_NAME}"
|
||||
bashio::log.info "Bitrate : ${BITRATE} kbps"
|
||||
bashio::log.info "Stream-Port : ${STREAM_PORT}"
|
||||
bashio::log.info "Stream-Pfad : ${STREAM_MOUNT}"
|
||||
|
||||
# ── Verzeichnisse anlegen ─────────────────────────────────────────────────────
|
||||
mkdir -p /var/log/icecast /run/icecast /tmp/busch-radio
|
||||
|
||||
# ── Icecast-Webroot ermitteln ─────────────────────────────────────────────────
|
||||
# Alpine und Debian legen Icecast in unterschiedliche Pfade
|
||||
ICECAST_WEBROOT=""
|
||||
for candidate in /usr/share/icecast /usr/share/icecast2; do
|
||||
if [ -d "$candidate" ]; then
|
||||
ICECAST_WEBROOT="$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$ICECAST_WEBROOT" ]; then
|
||||
bashio::log.warning "Icecast-Webroot nicht gefunden, verwende /usr/share/icecast"
|
||||
ICECAST_WEBROOT="/usr/share/icecast"
|
||||
mkdir -p "${ICECAST_WEBROOT}/web" "${ICECAST_WEBROOT}/admin"
|
||||
fi
|
||||
|
||||
bashio::log.debug "Icecast-Webroot: ${ICECAST_WEBROOT}"
|
||||
|
||||
# ── Icecast-Konfiguration generieren ─────────────────────────────────────────
|
||||
bashio::log.info "Icecast-Konfiguration wird erstellt..."
|
||||
|
||||
cat > /tmp/busch-radio/icecast.xml <<ICECAST_EOF
|
||||
<icecast>
|
||||
<location>Home Assistant</location>
|
||||
<admin>admin@localhost</admin>
|
||||
|
||||
<limits>
|
||||
<clients>10</clients>
|
||||
<sources>2</sources>
|
||||
<queue-size>524288</queue-size>
|
||||
<client-timeout>30</client-timeout>
|
||||
<header-timeout>15</header-timeout>
|
||||
<source-timeout>10</source-timeout>
|
||||
<burst-on-connect>0</burst-on-connect>
|
||||
<burst-size>65536</burst-size>
|
||||
</limits>
|
||||
|
||||
<authentication>
|
||||
<source-password>${ICECAST_PASSWORD}</source-password>
|
||||
<relay-password>${ICECAST_PASSWORD}</relay-password>
|
||||
<admin-user>admin</admin-user>
|
||||
<admin-password>${ICECAST_PASSWORD}</admin-password>
|
||||
</authentication>
|
||||
|
||||
<hostname>0.0.0.0</hostname>
|
||||
|
||||
<listen-socket>
|
||||
<port>${STREAM_PORT}</port>
|
||||
</listen-socket>
|
||||
|
||||
<mount>
|
||||
<mount-name>${STREAM_MOUNT}</mount-name>
|
||||
<public>0</public>
|
||||
<stream-name>Busch-Radio Spotify Bridge</stream-name>
|
||||
<stream-description>Spotify via Home Assistant</stream-description>
|
||||
<bitrate>${BITRATE}</bitrate>
|
||||
<type>audio/mpeg</type>
|
||||
</mount>
|
||||
|
||||
<fileserve>1</fileserve>
|
||||
|
||||
<paths>
|
||||
<basedir>${ICECAST_WEBROOT}</basedir>
|
||||
<logdir>/var/log/icecast</logdir>
|
||||
<webroot>${ICECAST_WEBROOT}/web</webroot>
|
||||
<adminroot>${ICECAST_WEBROOT}/admin</adminroot>
|
||||
<pidfile>/run/icecast/icecast.pid</pidfile>
|
||||
</paths>
|
||||
|
||||
<logging>
|
||||
<!-- "-" loggt auf stderr → wird von HA erfasst -->
|
||||
<accesslog>-</accesslog>
|
||||
<errorlog>-</errorlog>
|
||||
<loglevel>2</loglevel>
|
||||
<logsize>10000</logsize>
|
||||
</logging>
|
||||
|
||||
<security>
|
||||
<chroot>0</chroot>
|
||||
</security>
|
||||
</icecast>
|
||||
ICECAST_EOF
|
||||
|
||||
# ── Icecast starten ───────────────────────────────────────────────────────────
|
||||
bashio::log.info "Icecast wird gestartet (Port: ${STREAM_PORT})..."
|
||||
icecast -c /tmp/busch-radio/icecast.xml &
|
||||
ICECAST_PID=$!
|
||||
|
||||
# Kurz warten bis Icecast hochgefahren ist
|
||||
sleep 3
|
||||
|
||||
if ! kill -0 "${ICECAST_PID}" 2>/dev/null; then
|
||||
bashio::log.fatal "Icecast konnte nicht gestartet werden! Prüfe die Konfiguration."
|
||||
exit 1
|
||||
fi
|
||||
bashio::log.info "Icecast läuft (PID: ${ICECAST_PID})"
|
||||
|
||||
# ── Librespot-Argumente zusammenstellen ───────────────────────────────────────
|
||||
LIBRESPOT_ARGS=(
|
||||
"--name" "${DEVICE_NAME}"
|
||||
"--bitrate" "${BITRATE}"
|
||||
"--backend" "pipe"
|
||||
"--disable-audio-cache"
|
||||
"--initial-volume" "100"
|
||||
)
|
||||
|
||||
# Optionale Spotify-Zugangsdaten
|
||||
SP_USER=$(bashio::config 'username')
|
||||
SP_PASS=$(bashio::config 'password')
|
||||
|
||||
if [ -n "${SP_USER}" ]; then
|
||||
LIBRESPOT_ARGS+=("--username" "${SP_USER}")
|
||||
bashio::log.info "Spotify-Konto: ${SP_USER}"
|
||||
else
|
||||
bashio::log.info "Kein Spotify-Konto konfiguriert (Zeroconf/mDNS-Erkennung aktiv)"
|
||||
fi
|
||||
|
||||
if [ -n "${SP_PASS}" ]; then
|
||||
LIBRESPOT_ARGS+=("--password" "${SP_PASS}")
|
||||
fi
|
||||
|
||||
# ── Icecast-Source-URL ────────────────────────────────────────────────────────
|
||||
ICECAST_SOURCE_URL="icecast://source:${ICECAST_PASSWORD}@localhost:${STREAM_PORT}${STREAM_MOUNT}"
|
||||
|
||||
# ── Stream-URL ausgeben ───────────────────────────────────────────────────────
|
||||
bashio::log.info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
bashio::log.info "Stream-URL für das Busch-Jäger Radio:"
|
||||
bashio::log.info " http://<homeassistant-ip>:${STREAM_PORT}${STREAM_MOUNT}"
|
||||
bashio::log.info ""
|
||||
bashio::log.info "Icecast-Statusseite:"
|
||||
bashio::log.info " http://<homeassistant-ip>:${STREAM_PORT}"
|
||||
bashio::log.info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
bashio::log.info "Wähle '${DEVICE_NAME}' in der Spotify-App als Abspielgerät."
|
||||
bashio::log.info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
# ── Aufräumen bei SIGTERM ─────────────────────────────────────────────────────
|
||||
cleanup() {
|
||||
bashio::log.info "Add-on wird beendet..."
|
||||
kill "${ICECAST_PID}" 2>/dev/null || true
|
||||
exit 0
|
||||
}
|
||||
trap cleanup SIGTERM SIGINT
|
||||
|
||||
# ── Haupt-Schleife: Pipeline starten und bei Absturz neu starten ──────────────
|
||||
#
|
||||
# Signalfluss:
|
||||
# librespot (Spotify Connect) → stdout (raw PCM 44100Hz/S16LE/Stereo)
|
||||
# ↓
|
||||
# ffmpeg (PCM → MP3 Encoding) → Icecast (HTTP-Stream)
|
||||
# ↓
|
||||
# Busch-Jäger Radio (HTTP-Client)
|
||||
#
|
||||
# Wenn entweder librespot oder ffmpeg abstürzt, wird die komplette Pipeline
|
||||
# nach RESTART_DELAY Sekunden neu gestartet.
|
||||
RESTART_DELAY=5
|
||||
ATTEMPT=0
|
||||
|
||||
while true; do
|
||||
ATTEMPT=$((ATTEMPT + 1))
|
||||
bashio::log.info "Pipeline-Start (Versuch ${ATTEMPT})..."
|
||||
|
||||
librespot "${LIBRESPOT_ARGS[@]}" \
|
||||
| ffmpeg \
|
||||
-hide_banner \
|
||||
-loglevel warning \
|
||||
-f s16le -ar 44100 -ac 2 \
|
||||
-i pipe:0 \
|
||||
-codec:a libmp3lame \
|
||||
-b:a "${BITRATE}k" \
|
||||
-q:a 2 \
|
||||
-f mp3 \
|
||||
"${ICECAST_SOURCE_URL}" \
|
||||
|| true
|
||||
|
||||
bashio::log.warning "Pipeline beendet. Neustart in ${RESTART_DELAY}s..."
|
||||
sleep "${RESTART_DELAY}"
|
||||
done
|
||||
Reference in New Issue
Block a user