159 lines
8.5 KiB
Bash
159 lines
8.5 KiB
Bash
#!/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'
|