Files
playwish/install/install-player.sh
T
99admandClaude Opus 5.5 b83da952ee Durchsicht: Robustheit bei Neuinstallationen
- auth.py: .env auch in schreibgeschütztem Ordner aktualisieren (Server-Login)
- Controller: ohne Spotify-Login warten statt abstürzen; Playlist darf fehlen;
  nicht abspielbare Wünsche überspringen statt hängen zu bleiben
- install-server.sh: alle SSH-Ports freigeben (kein Aussperren), curl und
  python3-systemd (fail2ban) installieren
- install-player.sh: Bluetooth per rfkill entsperren und Dienst starten

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 19:55:00 +01:00

199 lines
9.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Audiofy – Installation der Rolle "Player": Spotify-Connect-Gerät (raspotify) und Controller.
#
# install/install-player.sh Neuinstallation (fragt alles Nötige ab)
# install/install-player.sh --update nur Code, Python-Umgebung und Dienst aktualisieren
#
# Läuft auf Raspberry Pi, Mini-PC oder VM mit Debian 12+ (arm64, armhf oder amd64).
# Ausgabe wahlweise über einen Bluetooth-Lautsprecher (BlueALSA) oder einen ALSA-Ausgang
# (Klinke, HDMI, USB-DAC). Der Player baut nur ausgehende Verbindungen auf.
set -euo pipefail
source "$(dirname "$0")/lib.sh"
UPDATE=0
BLUETOOTH=0
for arg in "$@"; do
case "$arg" in
--update) UPDATE=1 ;;
-h|--help) sed -n '2,10p' "$0"; exit 0 ;;
*) abbruch "Unbekannte Option: $arg" ;;
esac
done
KONFIG="$AUDIOFY_DIR/config"
ENV_DATEI="$KONFIG/.env"
RASPOTIFY_CONF=/etc/raspotify/conf
export AUDIOFY_DIR AUDIOFY_USER
schritt "Audiofy-Player: $([ $UPDATE = 1 ] && echo Update || echo Neuinstallation)"
pruefe_system
ARCH="$(dpkg --print-architecture)"
case "$ARCH" in arm64|armhf|amd64) ;; *) abbruch "raspotify gibt es nicht für $ARCH (nur arm64, armhf, amd64)." ;; esac
if [ $UPDATE = 1 ] && ! $SUDO test -f "$ENV_DATEI"; then
abbruch "Keine bestehende Installation in $AUDIOFY_DIR gefunden – ohne --update ausführen."
fi
# ------------------------------------------------------------------ Abfragen
if [ $UPDATE = 0 ]; then
schritt "Angaben"
frage GERAETENAME "Name des Spotify-Connect-Geräts" "Audiofy"
echo " Audio-Ausgabe: 1) Bluetooth-Lautsprecher 2) Kabel/HDMI/USB (ALSA)"
frage AUSGABE "Auswahl" "1"
if [ "$AUSGABE" = 2 ]; then
BLUETOOTH=0
if command -v aplay >/dev/null; then
info "Verfügbare ALSA-Ausgänge:"
aplay -L 2>/dev/null | grep -E '^(default|sysdefault|plughw|hdmi)' | sed 's/^/ /' | head -20 || true
fi
frage ALSA_GERAET "ALSA-Gerät" "default"
else
BLUETOOTH=1
ALSA_GERAET="bluealsa:DEV=00:00:00:00:00:00,PROFILE=a2dp" # = zuletzt verbundener Lautsprecher
fi
frage SERVER_URL "Adresse des Audiofy-Servers (leer = ohne Wünsche, nur Playlist)" ""
SERVER_URL="${SERVER_URL%/}"
PLAYER_TOKEN=""
[ -n "$SERVER_URL" ] && frage_geheim PLAYER_TOKEN "PLAYER_API_TOKEN vom Server (verdeckt)"
info "Spotify-App (developer.spotify.com): Redirect-URI http://127.0.0.1:8888/callback eintragen."
frage SPOTIFY_CLIENT_ID "Spotify Client ID"
frage_geheim SPOTIFY_CLIENT_SECRET "Spotify Client Secret (verdeckt)"
frage PLAYLIST "Grund-Playlist (Link oder ID; mit Server wird sie dort eingestellt)"
PLAYLIST_ID="$(sed -E 's#.*playlist[/:]([A-Za-z0-9]{22}).*#\1#' <<<"$PLAYLIST")"
[[ "$PLAYLIST_ID" =~ ^[A-Za-z0-9]{22}$ ]] || { warnung "Keine gültige Playlist – bitte später eintragen."; PLAYLIST_ID=""; }
fi
# ------------------------------------------------------------------ Pakete
schritt "Pakete"
$SUDO apt-get update -qq
PAKETE=(python3-venv curl ca-certificates alsa-utils)
if [ $UPDATE = 0 ] && [ "$BLUETOOTH" = 1 ]; then
PAKETE+=(bluez bluez-alsa-utils libasound2-plugin-bluez)
fi
pakete "${PAKETE[@]}"
if ! dpkg -s raspotify >/dev/null 2>&1; then
schritt "raspotify (Spotify Connect)"
$SUDO curl -sSfL https://dtcooper.github.io/raspotify/key.asc -o /usr/share/keyrings/raspotify_key.asc
$SUDO chmod 644 /usr/share/keyrings/raspotify_key.asc
echo "deb [signed-by=/usr/share/keyrings/raspotify_key.asc] https://dtcooper.github.io/raspotify raspotify main" \
| $SUDO tee /etc/apt/sources.list.d/raspotify.list >/dev/null
$SUDO apt-get update -qq
pakete raspotify
fi
# ------------------------------------------------------------------ raspotify einstellen (nur Neuinstallation)
if [ $UPDATE = 0 ]; then
schritt "raspotify einstellen"
$SUDO test -f "$RASPOTIFY_CONF.orig" || $SUDO cp "$RASPOTIFY_CONF" "$RASPOTIFY_CONF.orig"
setze_raspotify() { # KEY WERT – vorhandene (auch auskommentierte) Zeile ersetzen, sonst anhängen
if $SUDO grep -qE "^#?\s*$1=" "$RASPOTIFY_CONF"; then
$SUDO sed -i -E "0,/^#?\s*$1=.*/s||$1=\"$2\"|" "$RASPOTIFY_CONF"
else
echo "$1=\"$2\"" | $SUDO tee -a "$RASPOTIFY_CONF" >/dev/null
fi
}
setze_raspotify LIBRESPOT_NAME "$GERAETENAME"
setze_raspotify LIBRESPOT_DEVICE_TYPE "speaker"
setze_raspotify LIBRESPOT_BACKEND "alsa"
setze_raspotify LIBRESPOT_DEVICE "$ALSA_GERAET"
setze_raspotify LIBRESPOT_BITRATE "320"
# Anmeldedaten speichern (sonst nach jedem Neustart unsichtbar) und normal protokollieren
$SUDO sed -i -E 's/^(LIBRESPOT_DISABLE_CREDENTIAL_CACHE=|LIBRESPOT_QUIET=)/#\1/' "$RASPOTIFY_CONF"
info "Name „$GERAETENAME“, Ausgabe $ALSA_GERAET"
fi
$SUDO install -d /etc/systemd/system/raspotify.service.d
vorlage raspotify-10-audiofy.conf /etc/systemd/system/raspotify.service.d/10-audiofy.conf
$SUDO systemctl daemon-reload
$SUDO systemctl enable raspotify >/dev/null 2>&1
[ $UPDATE = 0 ] && $SUDO systemctl restart raspotify
# ------------------------------------------------------------------ Bluetooth (nur Neuinstallation)
BT_MAC=""
if [ $UPDATE = 0 ] && [ "$BLUETOOTH" = 1 ]; then
schritt "Bluetooth-Lautsprecher"
# Auf frischen Systemen ist Bluetooth oft per rfkill gesperrt (z. B. ohne gesetztes WLAN-Land)
command -v rfkill >/dev/null && { $SUDO rfkill unblock bluetooth || true; }
$SUDO systemctl enable --now bluetooth >/dev/null 2>&1 || warnung "Bluetooth-Dienst ließ sich nicht starten."
# Der Player soll nicht selbst als Bluetooth-Empfänger für fremde Handys dienen
$SUDO systemctl disable --now bluealsa-aplay >/dev/null 2>&1 || true
info "Lautsprecher jetzt in den Kopplungsmodus versetzen (meist Bluetooth-Taste halten, bis die LED blinkt)."
if ja_nein "Jetzt suchen und koppeln?" j; then
BT_MAC="$(cd "$REPO/player" && python3 - <<'PY'
import sys, lautsprecher as l
print(" Suche 15 s …", file=sys.stderr)
geraete = l.suchen()
if not geraete:
print(" Kein Audiogerät gefunden.", file=sys.stderr); sys.exit(0)
for i, g in enumerate(geraete, 1):
print(f" {i}) {g['name'] or 'Unbekannt'} ({g['mac']})", file=sys.stderr)
print(" Nummer: ", end="", file=sys.stderr, flush=True)
wahl = open("/dev/tty").readline().strip()
if not wahl.isdigit() or not 1 <= int(wahl) <= len(geraete):
sys.exit(0)
mac = geraete[int(wahl) - 1]["mac"]
ok, meldung = l.koppeln(mac)
print(f" {meldung}", file=sys.stderr)
if ok:
print(mac)
PY
)" || true
[ -n "$BT_MAC" ] || warnung "Kein Lautsprecher gekoppelt – später im Admin-Bereich unter Einstellungen → Lautsprecher."
fi
fi
# ------------------------------------------------------------------ Benutzer, Ordner, Code
schritt "Dienst-Benutzer, Ordner und Code"
dienst_benutzer
$SUDO install -d -o root -g "$AUDIOFY_USER" -m 750 "$AUDIOFY_DIR"
$SUDO install -d -o "$AUDIOFY_USER" -g "$AUDIOFY_USER" -m 700 "$KONFIG"
code_kopieren "$REPO/player" "$AUDIOFY_DIR/app"
venv_einrichten "$AUDIOFY_DIR/app/requirements.txt"
info "Code in $AUDIOFY_DIR/app, Konfiguration in $KONFIG"
# ------------------------------------------------------------------ Konfiguration
schritt "Konfiguration ($ENV_DATEI)"
if [ $UPDATE = 0 ]; then
$SUDO test -f "$ENV_DATEI" || $SUDO install -o "$AUDIOFY_USER" -g "$AUDIOFY_USER" -m 600 /dev/null "$ENV_DATEI"
env_setzen "$ENV_DATEI" SPOTIFY_CLIENT_ID "$SPOTIFY_CLIENT_ID"
env_setzen "$ENV_DATEI" SPOTIFY_CLIENT_SECRET "$SPOTIFY_CLIENT_SECRET"
env_setzen "$ENV_DATEI" SPOTIFY_REDIRECT_URI "http://127.0.0.1:8888/callback"
env_setzen "$ENV_DATEI" DEVICE_NAME "$GERAETENAME"
env_setzen "$ENV_DATEI" WISH_EVERY_N "3"
[ -n "$PLAYLIST_ID" ] && env_setzen "$ENV_DATEI" SPOTIFY_PLAYLIST_ID "$PLAYLIST_ID"
[ -n "$BT_MAC" ] && env_setzen "$ENV_DATEI" BT_SPEAKER_MAC "$BT_MAC"
if [ -n "$SERVER_URL" ]; then
env_setzen "$ENV_DATEI" SERVER_URL "$SERVER_URL"
env_setzen "$ENV_DATEI" PLAYER_API_TOKEN "$PLAYER_TOKEN"
fi
unset SPOTIFY_CLIENT_SECRET PLAYER_TOKEN
schritt "Spotify-Login für die Wiedergabe-Steuerung"
info "Öffne gleich die angezeigte Adresse im Browser, melde dich an und füge danach die"
info "Adresse aus der Adresszeile (http://127.0.0.1:8888/callback?...) hier ein."
"${ALS_DIENST[@]}" "$AUDIOFY_DIR/.venv/bin/python" "$AUDIOFY_DIR/app/auth.py" --profil player --env "$ENV_DATEI" \
|| warnung "Login fehlgeschlagen – später nachholen (siehe README)."
else
# alte Schlüsselnamen übernehmen
env_umbenennen "$ENV_DATEI" VPS_URL SERVER_URL
env_umbenennen "$ENV_DATEI" PI_API_TOKEN PLAYER_API_TOKEN
fi
# ------------------------------------------------------------------ Dienst
schritt "Dienst audiofy-controller"
vorlage audiofy-controller.service /etc/systemd/system/audiofy-controller.service
$SUDO systemctl daemon-reload
$SUDO systemctl enable audiofy-controller >/dev/null 2>&1
$SUDO systemctl restart audiofy-controller
sleep 5
systemctl is-active --quiet audiofy-controller || abbruch "audiofy-controller läuft nicht – siehe: journalctl -u audiofy-controller"
info "audiofy-controller läuft"
# ------------------------------------------------------------------ Zusammenfassung
schritt "Fertig"
info "Logs: journalctl -u audiofy-controller -f · journalctl -u raspotify -f"
if [ $UPDATE = 0 ]; then
info ""
info "Wichtig: Wähle das Gerät „$GERAETENAME“ EINMAL in der Spotify-App aus (im selben Netz)."
info "Danach sind die Anmeldedaten gespeichert, und der Player startet nach jedem Neustart selbst."
fi