VoicePult/setup.sh
2026-10-03 11:07:47 +02:00

159 lines
8.5 KiB
Bash
Raw Permalink 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
# Install VoicePult for the logged-in Linux desktop user.
set -Eeuo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
NO_START=0
NO_OPEN=0
AUTOSTART=1
SKIP_PACKAGES=0
DRY_RUN=0
LAN_ARGS=()
usage() {
cat <<'HELP'
VoicePult – automatische Einrichtung für Linux
Aufruf: ./setup.sh [Optionen]
Ohne sudo in der angemeldeten Desktop-Sitzung ausführen. Nur fehlende
Systempakete werden über sudo installiert. Unterstützt apt, dnf und pacman.
--lan Tablet-/Handyzugriff mit Zugangscode aktivieren
--no-start Dateien einrichten, aber keine Dienste starten
--no-open Nach der Einrichtung keinen Browser öffnen
--no-autostart Nicht automatisch bei der Anmeldung starten
--skip-packages Paketinstallation überspringen (Voraussetzungen prüfen)
--dry-run Einrichtung anzeigen, ohne Änderungen vorzunehmen
-h, --help Diese Hilfe anzeigen
Die Installation erfolgt benutzerspezifisch in den XDG-Daten-,
Konfigurations- und Statusverzeichnissen. Vorhandene Einstellungen bleiben
bei erneuter Ausführung erhalten. Die heruntergeladene Projektkopie kann
anschließend verschoben werden.
HELP
}
for arg in "$@"; do
case "$arg" in
--lan) LAN_ARGS=(--lan) ;;
--no-start) NO_START=1; NO_OPEN=1 ;;
--no-open) NO_OPEN=1 ;;
--no-autostart) AUTOSTART=0 ;;
--skip-packages) SKIP_PACKAGES=1 ;;
--dry-run) DRY_RUN=1 ;;
-h|--help) usage; exit 0 ;;
*) printf 'Unbekannte Option: %s\n' "$arg" >&2; usage >&2; exit 2 ;;
esac
done
say() { printf '\n[VoicePult] %s\n' "$*"; }
fail() { printf '\n[VoicePult] Fehler: %s\n' "$*" >&2; exit 1; }
trap 'printf "\n[VoicePult] Einrichtung fehlgeschlagen (Zeile %s). Nach Behebung erneut ./setup.sh ausführen.\n" "$LINENO" >&2' ERR
[[ "$(uname -s)" == Linux ]] || fail 'Diese Version unterstützt Linux, nicht Windows oder macOS.'
[[ "$EUID" -ne 0 ]] || fail 'Bitte ./setup.sh als normalen Desktop-Benutzer ausführen, nicht mit sudo. Paketinstallationen fragen sudo selbst an.'
for file in lan_access.py audio_meter.py server.py start.sh web/index.html web/app.js web/style.css web/icon.svg scripts/install.py scripts/launcher.py; do
[[ -f "$SCRIPT_DIR/$file" ]] || fail "Projektdatei fehlt: $file. Bitte den vollständigen VoicePult-Ordner kopieren."
done
# Validate XDG destinations before using them as installation paths.
for destination in "${XDG_DATA_HOME:-$HOME/.local/share}" "${XDG_CONFIG_HOME:-$HOME/.config}" "${XDG_STATE_HOME:-$HOME/.local/state}"; do
[[ "$destination" == /* && "$destination" != / && "$destination" != *$'\n'* && "$destination" != *$'\r'* && "$destination" != *$'\t'* ]] || fail 'XDG-Verzeichnisse müssen absolute Pfade ohne Steuerzeichen sein.'
done
manager=''
if command -v apt-get >/dev/null; then manager=apt
elif command -v dnf >/dev/null; then manager=dnf
elif command -v pacman >/dev/null; then manager=pacman
fi
packages=()
if ! command -v python3 >/dev/null || ! python3 -c 'import sys; sys.exit(sys.version_info < (3, 10))' 2>/dev/null; then
if [[ "$manager" == pacman ]]; then packages+=(python); else packages+=(python3); fi
fi
if ! command -v pactl >/dev/null || ! command -v parec >/dev/null; then
if [[ "$manager" == pacman ]]; then packages+=(libpulse); else packages+=(pulseaudio-utils); fi
fi
command -v xdg-open >/dev/null || packages+=(xdg-utils)
browser_found=0
for browser_cmd in firefox firefox-esr chromium chromium-browser google-chrome brave-browser microsoft-edge epiphany; do
if command -v "$browser_cmd" >/dev/null; then browser_found=1; break; fi
done
if [[ "$browser_found" == 0 ]] && command -v xdg-settings >/dev/null; then
# Also recognize browsers installed through Flatpak or desktop launchers.
if [[ -n "$(xdg-settings get default-web-browser 2>/dev/null || true)" ]]; then browser_found=1; fi
fi
if [[ "$browser_found" == 0 ]]; then
os_id="$(awk -F= '$1=="ID" {gsub(/"/,"",$2); print $2}' /etc/os-release 2>/dev/null || true)"
if [[ "$manager" == apt && "$os_id" != ubuntu && "$os_id" != linuxmint && "$os_id" != pop && "$os_id" != neon ]]; then
packages+=(firefox-esr)
else
packages+=(firefox)
fi
fi
# Do not replace an existing PulseAudio or PipeWire installation.
audio_ready=0
new_audio=0
if command -v pactl >/dev/null && timeout 5 pactl info >/dev/null 2>&1; then audio_ready=1; fi
if [[ "$audio_ready" == 0 ]] && ! command -v pipewire-pulse >/dev/null && ! command -v pulseaudio >/dev/null; then
new_audio=1
case "$manager" in
apt) packages+=(pipewire pipewire-pulse wireplumber) ;;
dnf) packages+=(pipewire pipewire-pulseaudio wireplumber) ;;
pacman) packages+=(pipewire pipewire-audio pipewire-pulse wireplumber) ;;
*) [[ "$SKIP_PACKAGES" == 1 ]] || fail 'Kein unterstützter Paketmanager. Python ≥ 3.10, pactl, xdg-open und PipeWire-Pulse installieren und --skip-packages verwenden.' ;;
esac
fi
say "Installation für $USER"
printf ' Programm: %s/voicepult/app\n' "${XDG_DATA_HOME:-$HOME/.local/share}"
printf ' Einstellungen: %s/voicepult/config.json\n' "${XDG_CONFIG_HOME:-$HOME/.config}"
printf ' Protokoll: %s/voicepult/server.log\n' "${XDG_STATE_HOME:-$HOME/.local/state}"
printf ' Autostart: %s\n' "$([[ "$AUTOSTART" == 1 ]] && printf ja || printf nein)"
if ((${#packages[@]})); then printf ' Fehlende Pakete (%s): %s\n' "${manager:-manuell}" "${packages[*]}"; fi
if [[ "$DRY_RUN" == 1 ]]; then
say 'Vorschau beendet. Keine Dateien, Pakete oder Dienste geändert.'
exit 0
fi
if ((${#packages[@]})) && [[ "$SKIP_PACKAGES" == 0 ]]; then
[[ -n "$manager" ]] || fail 'Kein unterstützter Paketmanager; Voraussetzungen manuell installieren und --skip-packages verwenden.'
command -v sudo >/dev/null || fail 'sudo fehlt. Bitte die oben genannten Pakete administrativ installieren und Setup erneut ausführen.'
say 'Installiere fehlende Systempakete. sudo fragt gegebenenfalls dein Passwort ab.'
sudo -v
case "$manager" in
apt) sudo apt-get update; sudo apt-get install -y --no-remove "${packages[@]}" ;;
dnf) sudo dnf install -y "${packages[@]}" ;;
pacman) sudo pacman -S --needed --noconfirm "${packages[@]}" ;;
esac
fi
command -v python3 >/dev/null || fail 'Python 3 fehlt.'
python3 -c 'import sys; sys.exit(sys.version_info < (3, 10))' || fail 'Python ≥ 3.10 erforderlich. Bitte das Betriebssystem bzw. Python aktualisieren.'
command -v pactl >/dev/null || fail 'pactl fehlt. Bitte pulseaudio-utils (Arch: libpulse) installieren.'
command -v xdg-open >/dev/null || fail 'xdg-open fehlt. Bitte xdg-utils installieren.'
if [[ "$browser_found" == 0 && "$SKIP_PACKAGES" == 1 ]]; then
say 'Kein Browser erkannt. Bitte einen Browser installieren oder die lokale URL in einem vorhandenen Browser öffnen.'
fi
# Only start the already-installed audio stack if it is currently unreachable.
if [[ "$NO_START" == 0 && "$audio_ready" == 0 ]]; then
say 'Prüfe den Audioserver der Desktop-Sitzung.'
if command -v systemctl >/dev/null && systemctl --user show-environment >/dev/null 2>&1; then
if command -v pipewire-pulse >/dev/null; then
if [[ "$new_audio" == 1 ]]; then
systemctl --user enable --now pipewire.socket pipewire-pulse.socket wireplumber.service || fail 'Der neue PipeWire-Dienst konnte nicht aktiviert werden.'
else
systemctl --user start pipewire.socket pipewire-pulse.socket wireplumber.service || fail 'PipeWire konnte nicht gestartet werden. Bitte in einer angemeldeten Desktop-Sitzung erneut versuchen.'
fi
elif command -v pulseaudio >/dev/null; then
systemctl --user start pulseaudio.socket || fail 'PulseAudio konnte nicht gestartet werden.'
fi
elif command -v pulseaudio >/dev/null; then
pulseaudio --start || fail 'PulseAudio konnte nicht gestartet werden.'
fi
for attempt in {1..10}; do
if timeout 5 pactl info >/dev/null 2>&1; then audio_ready=1; break; fi
sleep 1
done
[[ "$audio_ready" == 1 ]] || fail 'Kein Audioserver erreichbar. Bitte in deiner grafischen Desktop-Sitzung ausführen; pactl info muss funktionieren. Bei Systemen ohne systemd PipeWire über die Sitzungsverwaltung starten.'
fi
say 'Installiere Programm, Menüeintrag und Benutzer-Autostart.'
python3 "$SCRIPT_DIR/scripts/install.py" --source "$SCRIPT_DIR" --autostart "$AUTOSTART" --start "$((1-NO_START))" --open "$((1-NO_OPEN))" "${LAN_ARGS[@]}"
say 'Einrichtung abgeschlossen. VoicePult findest du im Anwendungsmenü.'
printf ' Oberfläche: http://127.0.0.1:8765\n'