# Audiofy – gemeinsame Hilfsfunktionen für die Install-Skripte (wird per "source" geladen) # shellcheck shell=bash AUDIOFY_DIR="${AUDIOFY_DIR:-/opt/audiofy}" AUDIOFY_USER="${AUDIOFY_USER:-audiofy}" REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" VORLAGEN="$REPO/install/vorlagen" if [ "$(id -u)" -eq 0 ]; then SUDO="" ALS_DIENST=(runuser -u "$AUDIOFY_USER" --) else SUDO="sudo" ALS_DIENST=(sudo -u "$AUDIOFY_USER") fi # --- Ausgabe ------------------------------------------------------------------ schritt() { printf '\n\033[1m==> %s\033[0m\n' "$*"; } info() { printf ' %s\n' "$*"; } warnung() { printf '\033[33m ! %s\033[0m\n' "$*"; } abbruch() { printf '\033[31m ✗ %s\033[0m\n' "$*" >&2; exit 1; } # --- Abfragen ----------------------------------------------------------------- # frage VAR "Text" [Standard] frage() { local antwort read -r -p " $2${3:+ [$3]}: " antwort printf -v "$1" '%s' "${antwort:-${3:-}}" } # frage_geheim VAR "Text" – Eingabe wird nicht angezeigt frage_geheim() { local antwort read -r -s -p " $2: " antwort echo printf -v "$1" '%s' "$antwort" } # ja_nein "Frage" [j|n] – Rückgabewert 0 = ja ja_nein() { local standard="${2:-j}" antwort read -r -p " $1 [$([ "$standard" = j ] && echo J/n || echo j/N)]: " antwort antwort="${antwort:-$standard}" [[ "$antwort" =~ ^[jJyY] ]] } # --- System ------------------------------------------------------------------- pruefe_system() { [ -f /etc/debian_version ] || abbruch "Nur für Debian und Debian-basierte Systeme (z. B. Raspberry Pi OS)." command -v systemctl >/dev/null || abbruch "systemd wird benötigt." command -v apt-get >/dev/null || abbruch "apt wird benötigt." if [ -n "$SUDO" ]; then command -v sudo >/dev/null || abbruch "Bitte als root ausführen oder sudo installieren." info "Für die Einrichtung sind root-Rechte nötig – sudo fragt ggf. nach deinem Passwort." sudo true || abbruch "sudo nicht möglich." fi python3 -c 'import sys; sys.exit(sys.version_info < (3, 11))' 2>/dev/null \ || abbruch "Python 3.11 oder neuer wird benötigt (Debian 12 oder neuer)." } pakete() { info "Installiere: $*" $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y -qq "$@" >/dev/null } dienst_benutzer() { if ! id "$AUDIOFY_USER" >/dev/null 2>&1; then $SUDO useradd --system --home-dir "$AUDIOFY_DIR" --no-create-home --shell /usr/sbin/nologin "$AUDIOFY_USER" info "Dienst-Benutzer '$AUDIOFY_USER' angelegt (ohne Login, ohne sudo)" fi } # code_kopieren QUELLE ZIEL – ersetzt den Inhalt von ZIEL (gehört root, Dienst darf nur lesen) code_kopieren() { local quelle="$1" ziel="$2" $SUDO install -d -o root -g "$AUDIOFY_USER" -m 750 "$ziel" $SUDO find "$ziel" -mindepth 1 -delete tar -C "$quelle" --exclude='__pycache__' --exclude='.venv' --exclude='.pytest_cache' --exclude='tests' -cf - . \ | $SUDO tar -C "$ziel" --no-same-owner -xf - $SUDO chown -R root:"$AUDIOFY_USER" "$ziel" $SUDO find "$ziel" -type d -exec chmod 750 {} + $SUDO find "$ziel" -type f -exec chmod 640 {} + } # venv_einrichten REQUIREMENTS venv_einrichten() { local venv="$AUDIOFY_DIR/.venv" [ -x "$venv/bin/python" ] || $SUDO python3 -m venv "$venv" $SUDO "$venv/bin/pip" install -q --upgrade pip $SUDO "$venv/bin/pip" install -q -r "$1" $SUDO chown -R root:"$AUDIOFY_USER" "$venv" $SUDO chmod -R g+rX,o-rwx "$venv" } # vorlage DATEI ZIEL – ersetzt {{NAME}} durch den Wert der Shell-Variablen NAME vorlage() { local inhalt inhalt="$(python3 - "$VORLAGEN/$1" <<'PY' import os, re, sys text = open(sys.argv[1]).read() def ersetzen(m): wert = os.environ.get(m.group(1)) if wert is None: sys.exit(f"Vorlage {sys.argv[1]}: {m.group(1)} ist nicht gesetzt") return wert print(re.sub(r"\{\{([A-Z_]+)\}\}", ersetzen, text), end="") PY )" || abbruch "Vorlage $1 konnte nicht ausgefüllt werden" printf '%s\n' "$inhalt" | $SUDO tee "$2" >/dev/null } # --- .env (gehört dem Dienst-Benutzer, Rechte 600) ------------------------------ # env_setzen DATEI KEY WERT – der Wert läuft über stdin (nicht in der Prozessliste sichtbar) env_setzen() { printf '%s' "$3" | "${ALS_DIENST[@]}" python3 -c ' import os, sys pfad, key = sys.argv[1], sys.argv[2] wert = sys.stdin.read() zeilen = open(pfad).read().splitlines() if os.path.exists(pfad) else [] zeilen = [z for z in zeilen if not z.strip().startswith(key + "=")] + [f"{key}={wert}"] fd = os.open(pfad, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) with os.fdopen(fd, "w") as f: f.write("\n".join(zeilen) + "\n") ' "$1" "$2" } # env_wert DATEI KEY – gibt den Wert aus (leer, wenn nicht vorhanden) env_wert() { "${ALS_DIENST[@]}" sh -c 'grep -m1 "^$2=" "$1" 2>/dev/null | cut -d= -f2-' _ "$1" "$2" || true } # env_umbenennen DATEI ALT NEU – übernimmt alte Schlüsselnamen (für Updates) env_umbenennen() { local wert if [ -z "$(env_wert "$1" "$3")" ]; then wert="$(env_wert "$1" "$2")" if [ -n "$wert" ]; then env_setzen "$1" "$3" "$wert" info "$2 → $3 übernommen" fi fi }