#!/usr/bin/env bash # ============================================================ # PiCopy – Installer # https://git.leuschner.dev/Tobias/PiCopy # # Usage: # sudo bash install.sh # or one-line: # curl -sSL https://git.leuschner.dev/Tobias/PiCopy/raw/branch/main/install.sh | sudo bash # ============================================================ set -euo pipefail INSTALL_DIR="/opt/picopy" SERVICE_NAME="picopy" PORT=8080 REPO_RAW="https://git.leuschner.dev/Tobias/PiCopy/raw/branch/main" # ── Farben ─────────────────────────────────────────────────────────────────── R='\033[0;31m'; G='\033[0;32m'; Y='\033[1;33m'; B='\033[0;34m'; N='\033[0m' info() { echo -e "${B}[PiCopy]${N} $1"; } ok() { echo -e "${G}[ OK ]${N} $1"; } warn() { echo -e "${Y}[ WARN ]${N} $1"; } fail() { echo -e "${R}[ FAIL ]${N} $1"; exit 1; } # ── Voraussetzungen ─────────────────────────────────────────────────────────── [ "$EUID" -eq 0 ] || fail "Bitte als root ausführen: sudo bash install.sh" command -v apt-get &>/dev/null || fail "apt-get nicht gefunden (nur Debian/Raspberry Pi OS unterstützt)" echo "" echo -e "${B}╔══════════════════════════════════════════╗${N}" echo -e "${B}║ PiCopy – Installation ║${N}" echo -e "${B}╚══════════════════════════════════════════╝${N}" echo "" # ── System-Pakete ───────────────────────────────────────────────────────────── info "Systemabhängigkeiten werden installiert..." apt-get update -q apt-get install -y -q python3 python3-venv python3-pip util-linux rclone \ exfatprogs dosfstools ntfs-3g ok "Systemabhängigkeiten installiert" # ── Verzeichnisse anlegen ───────────────────────────────────────────────────── info "Installationsverzeichnis: $INSTALL_DIR" mkdir -p "$INSTALL_DIR/logs" mkdir -p "$INSTALL_DIR/picopy" mkdir -p "$INSTALL_DIR/routes" mkdir -p "$INSTALL_DIR/templates" # ── Hilfsfunktion: Datei kopieren oder herunterladen ────────────────────────── install_file() { local src="$1" # relativer Pfad im Repo / im lokalen Verzeichnis local dst="$2" # absoluter Zielpfad if [ -f "./$src" ]; then info "Lokale Datei wird verwendet: $src" cp "./$src" "$dst" else info "Datei wird heruntergeladen: $src" curl -sSfL "$REPO_RAW/$src" -o "$dst" \ || warn "Download fehlgeschlagen: $src (nicht kritisch wenn optional)" fi } # ── Hauptdateien ────────────────────────────────────────────────────────────── install_file "app.py" "$INSTALL_DIR/app.py" ok "app.py installiert" install_file "version.txt" "$INSTALL_DIR/version.txt" ok "version.txt installiert" install_file "PiCopy_Logo.png" "$INSTALL_DIR/PiCopy_Logo.png" ok "Logo installiert" # ── picopy/ Paket ───────────────────────────────────────────────────────────── install_file "picopy/__init__.py" "$INSTALL_DIR/picopy/__init__.py" install_file "picopy/config.py" "$INSTALL_DIR/picopy/config.py" install_file "picopy/state.py" "$INSTALL_DIR/picopy/state.py" install_file "picopy/usb.py" "$INSTALL_DIR/picopy/usb.py" install_file "picopy/copy_engine.py" "$INSTALL_DIR/picopy/copy_engine.py" install_file "picopy/wifi.py" "$INSTALL_DIR/picopy/wifi.py" install_file "picopy/wireguard.py" "$INSTALL_DIR/picopy/wireguard.py" install_file "picopy/samba.py" "$INSTALL_DIR/picopy/samba.py" install_file "picopy/upload.py" "$INSTALL_DIR/picopy/upload.py" install_file "picopy/system.py" "$INSTALL_DIR/picopy/system.py" ok "picopy/-Paket installiert" # ── routes/ Paket ───────────────────────────────────────────────────────────── install_file "routes/__init__.py" "$INSTALL_DIR/routes/__init__.py" install_file "routes/copy_routes.py" "$INSTALL_DIR/routes/copy_routes.py" install_file "routes/wifi_routes.py" "$INSTALL_DIR/routes/wifi_routes.py" install_file "routes/wireguard_routes.py" "$INSTALL_DIR/routes/wireguard_routes.py" install_file "routes/upload_routes.py" "$INSTALL_DIR/routes/upload_routes.py" install_file "routes/system_routes.py" "$INSTALL_DIR/routes/system_routes.py" install_file "routes/browse_routes.py" "$INSTALL_DIR/routes/browse_routes.py" ok "routes/-Paket installiert" # ── templates/ ──────────────────────────────────────────────────────────────── install_file "templates/index.html" "$INSTALL_DIR/templates/index.html" ok "Template installiert" # ── Python-Umgebung ─────────────────────────────────────────────────────────── info "Python venv wird erstellt..." python3 -m venv "$INSTALL_DIR/venv" "$INSTALL_DIR/venv/bin/pip" install --quiet --upgrade pip "$INSTALL_DIR/venv/bin/pip" install --quiet flask pyudev ok "Python-Umgebung erstellt" # ── Systemd-Service ─────────────────────────────────────────────────────────── info "Systemd-Service wird eingerichtet..." if [ -f "./picopy.service" ]; then cp picopy.service /etc/systemd/system/picopy.service else cat > /etc/systemd/system/picopy.service << 'EOF' [Unit] Description=PiCopy – Automatischer USB-Kopierdienst After=network.target [Service] Type=simple User=root WorkingDirectory=/opt/picopy ExecStart=/opt/picopy/venv/bin/python /opt/picopy/app.py Restart=always RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target EOF fi systemctl daemon-reload systemctl enable "$SERVICE_NAME" systemctl restart "$SERVICE_NAME" # ── Ergebnis ───────────────────────────────────────────────────────────────── sleep 3 if systemctl is-active --quiet "$SERVICE_NAME"; then IP=$(hostname -I | awk '{print $1}') echo "" echo -e "${G}╔══════════════════════════════════════════╗${N}" echo -e "${G}║ PiCopy ist bereit! ║${N}" echo -e "${G}╚══════════════════════════════════════════╝${N}" echo "" echo -e " Web-Interface: ${B}http://$IP:$PORT${N}" echo "" echo " Nützliche Befehle:" echo " sudo systemctl status $SERVICE_NAME # Status" echo " journalctl -u $SERVICE_NAME -f # Live-Logs" echo " sudo systemctl restart $SERVICE_NAME # Neustart" echo "" else fail "PiCopy konnte nicht gestartet werden."$'\n'"Logs: journalctl -u $SERVICE_NAME -n 50" fi