chore: remove local installer scripts from repo
This commit is contained in:
960
install-dev.sh
960
install-dev.sh
@@ -1,960 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# =============================================================================
|
|
||||||
# Ripster – Installationsskript
|
|
||||||
# Unterstützt: Debian 11/12, Ubuntu 22.04/24.04
|
|
||||||
# Benötigt: sudo / root
|
|
||||||
#
|
|
||||||
# Verwendung:
|
|
||||||
# chmod +x install.sh
|
|
||||||
# sudo ./install.sh [Optionen]
|
|
||||||
#
|
|
||||||
# Optionen:
|
|
||||||
# --dir <pfad> Installationsverzeichnis (Standard: /opt/ripster)
|
|
||||||
# --user <benutzer> Systembenutzer für den Dienst (Standard: ripster)
|
|
||||||
# --port <port> Backend-Port (Standard: 3001)
|
|
||||||
# --host <hostname> Hostname/IP für die Weboberfläche (Standard: Maschinen-IP)
|
|
||||||
# --no-makemkv MakeMKV-Installation überspringen
|
|
||||||
# --no-handbrake HandBrake-Installation überspringen
|
|
||||||
# --build-handbrake HandBrake aus Quellcode mit NVDEC-Unterstützung bauen
|
|
||||||
# --handbrake-version HandBrake-Version für Source-Build (Standard: 1.9.0)
|
|
||||||
# --handbrake-update-policy <keep|prompt|build>
|
|
||||||
# Bei NVDEC-Self-Build: bei neuer Git-Release behalten,
|
|
||||||
# nachfragen oder direkt neu bauen (Standard: keep)
|
|
||||||
# --no-nginx Nginx-Einrichtung überspringen (Frontend läuft dann auf Port 5173)
|
|
||||||
# --reinstall Vorhandene Installation ersetzen (Daten bleiben erhalten)
|
|
||||||
# -h, --help Diese Hilfe anzeigen
|
|
||||||
# =============================================================================
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# --- Farben -------------------------------------------------------------------
|
|
||||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
|
||||||
BLUE='\033[0;34m'; BOLD='\033[1m'; RESET='\033[0m'
|
|
||||||
|
|
||||||
info() { echo -e "${BLUE}[INFO]${RESET} $*"; }
|
|
||||||
ok() { echo -e "${GREEN}[OK]${RESET} $*"; }
|
|
||||||
warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; }
|
|
||||||
error() { echo -e "${RED}[FEHLER]${RESET} $*" >&2; }
|
|
||||||
header() { echo -e "\n${BOLD}${BLUE}══════════════════════════════════════════${RESET}"; \
|
|
||||||
echo -e "${BOLD} $*${RESET}"; \
|
|
||||||
echo -e "${BOLD}${BLUE}══════════════════════════════════════════${RESET}"; }
|
|
||||||
fatal() { error "$*"; exit 1; }
|
|
||||||
|
|
||||||
# --- Standard-Optionen --------------------------------------------------------
|
|
||||||
INSTALL_DIR="/opt/ripster"
|
|
||||||
SERVICE_USER="ripster"
|
|
||||||
BACKEND_PORT="3001"
|
|
||||||
FRONTEND_HOST="" # wird automatisch ermittelt, wenn leer
|
|
||||||
SKIP_MAKEMKV=false
|
|
||||||
SKIP_HANDBRAKE=false
|
|
||||||
BUILD_HANDBRAKE_NVDEC=false
|
|
||||||
HANDBRAKE_MODE_SELECTED=false
|
|
||||||
HANDBRAKE_VERSION="1.9.0"
|
|
||||||
HANDBRAKE_UPDATE_POLICY="keep"
|
|
||||||
HANDBRAKE_UPDATE_POLICY_SELECTED=false
|
|
||||||
SKIP_NGINX=false
|
|
||||||
REINSTALL=false
|
|
||||||
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
HANDBRAKE_SELFBUILD_MARKER="/usr/local/share/ripster/handbrake-selfbuild.env"
|
|
||||||
|
|
||||||
# --- Argumente parsen ---------------------------------------------------------
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--dir) INSTALL_DIR="$2"; shift 2 ;;
|
|
||||||
--user) SERVICE_USER="$2"; shift 2 ;;
|
|
||||||
--port) BACKEND_PORT="$2"; shift 2 ;;
|
|
||||||
--host) FRONTEND_HOST="$2"; shift 2 ;;
|
|
||||||
--no-makemkv) SKIP_MAKEMKV=true; shift ;;
|
|
||||||
--no-handbrake) SKIP_HANDBRAKE=true; shift ;;
|
|
||||||
--build-handbrake) BUILD_HANDBRAKE_NVDEC=true; HANDBRAKE_MODE_SELECTED=true; shift ;;
|
|
||||||
--handbrake-version) HANDBRAKE_VERSION="$2"; shift 2 ;;
|
|
||||||
--handbrake-update-policy)
|
|
||||||
case "$2" in
|
|
||||||
keep|prompt|build) HANDBRAKE_UPDATE_POLICY="$2"; HANDBRAKE_UPDATE_POLICY_SELECTED=true ;;
|
|
||||||
*) fatal "Ungültige --handbrake-update-policy: $2 (erlaubt: keep|prompt|build)" ;;
|
|
||||||
esac
|
|
||||||
shift 2 ;;
|
|
||||||
--no-nginx) SKIP_NGINX=true; shift ;;
|
|
||||||
--reinstall) REINSTALL=true; shift ;;
|
|
||||||
-h|--help)
|
|
||||||
sed -n '/^# Verwendung/,/^# ====/p' "$0" | head -n -1 | sed 's/^# \?//'
|
|
||||||
exit 0 ;;
|
|
||||||
*) fatal "Unbekannte Option: $1" ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# --- Voraussetzungen prüfen ---------------------------------------------------
|
|
||||||
header "Ripster Installationsskript"
|
|
||||||
|
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
fatal "Dieses Skript muss als root ausgeführt werden (sudo ./install.sh)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# OS-Erkennung
|
|
||||||
if [[ ! -f /etc/os-release ]]; then
|
|
||||||
fatal "Betriebssystem nicht erkennbar. Nur Debian/Ubuntu wird unterstützt."
|
|
||||||
fi
|
|
||||||
. /etc/os-release
|
|
||||||
case "$ID" in
|
|
||||||
debian|ubuntu|linuxmint|pop) ok "Betriebssystem: $PRETTY_NAME" ;;
|
|
||||||
*) fatal "Nicht unterstütztes OS: $ID. Nur Debian/Ubuntu unterstützt." ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Host-IP ermitteln
|
|
||||||
if [[ -z "$FRONTEND_HOST" ]]; then
|
|
||||||
FRONTEND_HOST=$(hostname -I | awk '{print $1}')
|
|
||||||
info "Erkannte IP: $FRONTEND_HOST"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Quelldirectory prüfen
|
|
||||||
[[ -f "$SOURCE_DIR/backend/package.json" ]] || \
|
|
||||||
fatal "Ripster-Quellen nicht gefunden in: $SOURCE_DIR"
|
|
||||||
|
|
||||||
info "Quellverzeichnis: $SOURCE_DIR"
|
|
||||||
info "Installationsverzeichnis: $INSTALL_DIR"
|
|
||||||
info "Systembenutzer: $SERVICE_USER"
|
|
||||||
info "Backend-Port: $BACKEND_PORT"
|
|
||||||
info "Frontend-Host: $FRONTEND_HOST"
|
|
||||||
|
|
||||||
# --- Hilfsfunktionen ----------------------------------------------------------
|
|
||||||
|
|
||||||
command_exists() { command -v "$1" &>/dev/null; }
|
|
||||||
|
|
||||||
install_node() {
|
|
||||||
header "Node.js installieren"
|
|
||||||
local required_major=20
|
|
||||||
|
|
||||||
if command_exists node; then
|
|
||||||
local current_major
|
|
||||||
current_major=$(node -e "process.stdout.write(String(process.version.split('.')[0].replace('v','')))")
|
|
||||||
if [[ "$current_major" -ge "$required_major" ]]; then
|
|
||||||
ok "Node.js $(node --version) bereits installiert"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
warn "Node.js $(node --version) zu alt – Node.js 20 wird installiert"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Installiere Node.js 20.x über NodeSource..."
|
|
||||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
|
||||||
apt-get install -y nodejs
|
|
||||||
ok "Node.js $(node --version) installiert"
|
|
||||||
}
|
|
||||||
|
|
||||||
install_makemkv() {
|
|
||||||
header "MakeMKV installieren"
|
|
||||||
|
|
||||||
if command_exists makemkvcon; then
|
|
||||||
local mk_version_line
|
|
||||||
mk_version_line="$(makemkvcon --version 2>&1 | head -1 || true)"
|
|
||||||
if [[ -z "$mk_version_line" || "$mk_version_line" == *"unrecognized option"* ]]; then
|
|
||||||
mk_version_line="$(makemkvcon 2>&1 | head -1 || true)"
|
|
||||||
fi
|
|
||||||
ok "makemkvcon bereits installiert (${mk_version_line:-Version unbekannt})"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Installiere Build-Abhängigkeiten für MakeMKV..."
|
|
||||||
apt-get install -y \
|
|
||||||
build-essential pkg-config libc6-dev libssl-dev \
|
|
||||||
libexpat1-dev libavcodec-dev libgl1-mesa-dev \
|
|
||||||
qtbase5-dev zlib1g-dev wget
|
|
||||||
|
|
||||||
local makemkv_fallback="1.18.3"
|
|
||||||
info "Ermittle aktuelle MakeMKV-Version (forum.makemkv.com)..."
|
|
||||||
local makemkv_version
|
|
||||||
makemkv_version=$(curl -s --max-time 15 \
|
|
||||||
"https://forum.makemkv.com/forum/viewtopic.php?f=3&t=224" \
|
|
||||||
| grep -oP 'MakeMKV \K[0-9]+\.[0-9]+\.[0-9]+(?= for Linux)' | head -1 || true)
|
|
||||||
|
|
||||||
if [[ -z "$makemkv_version" ]]; then
|
|
||||||
warn "MakeMKV-Version konnte nicht ermittelt werden – verwende Fallback $makemkv_fallback"
|
|
||||||
makemkv_version="$makemkv_fallback"
|
|
||||||
else
|
|
||||||
info "Gefundene Version: $makemkv_version"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Baue MakeMKV $makemkv_version..."
|
|
||||||
local tmp_dir
|
|
||||||
tmp_dir=$(mktemp -d)
|
|
||||||
cd "$tmp_dir"
|
|
||||||
|
|
||||||
local base_url="https://www.makemkv.com/download"
|
|
||||||
wget -q "${base_url}/makemkv-bin-${makemkv_version}.tar.gz"
|
|
||||||
wget -q "${base_url}/makemkv-oss-${makemkv_version}.tar.gz"
|
|
||||||
|
|
||||||
tar xf "makemkv-oss-${makemkv_version}.tar.gz"
|
|
||||||
cd "makemkv-oss-${makemkv_version}"
|
|
||||||
./configure
|
|
||||||
make -j"$(nproc)"
|
|
||||||
make install
|
|
||||||
|
|
||||||
cd "$tmp_dir"
|
|
||||||
tar xf "makemkv-bin-${makemkv_version}.tar.gz"
|
|
||||||
cd "makemkv-bin-${makemkv_version}"
|
|
||||||
mkdir -p tmp && echo "accepted" > tmp/eula_accepted
|
|
||||||
make -j"$(nproc)"
|
|
||||||
make install
|
|
||||||
|
|
||||||
cd /
|
|
||||||
rm -rf "$tmp_dir"
|
|
||||||
ok "MakeMKV $makemkv_version installiert"
|
|
||||||
warn "Hinweis: MakeMKV benötigt eine Lizenz oder den Beta-Key."
|
|
||||||
warn "Beta-Key: https://www.makemkv.com/forum/viewtopic.php?t=1053"
|
|
||||||
}
|
|
||||||
|
|
||||||
handbrake_has_nvdec() {
|
|
||||||
command_exists HandBrakeCLI || return 1
|
|
||||||
HandBrakeCLI --help 2>&1 | grep -qi "nvdec"
|
|
||||||
}
|
|
||||||
|
|
||||||
handbrake_installed_version() {
|
|
||||||
command_exists HandBrakeCLI || return 1
|
|
||||||
HandBrakeCLI --version 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+){1,3}' | head -1
|
|
||||||
}
|
|
||||||
|
|
||||||
handbrake_latest_git_version() {
|
|
||||||
local latest=""
|
|
||||||
latest=$(curl -fsSL --max-time 10 "https://api.github.com/repos/HandBrake/HandBrake/releases/latest" 2>/dev/null \
|
|
||||||
| grep -oE '"tag_name"[[:space:]]*:[[:space:]]*"[^"]+"' \
|
|
||||||
| head -1 \
|
|
||||||
| sed -E 's/.*"([^"]+)".*/\1/' \
|
|
||||||
| sed 's/^v//')
|
|
||||||
[[ -n "$latest" ]] || return 1
|
|
||||||
[[ "$latest" =~ ^[0-9]+(\.[0-9]+){1,3}$ ]] || return 1
|
|
||||||
printf '%s\n' "$latest"
|
|
||||||
}
|
|
||||||
|
|
||||||
handbrake_is_self_built() {
|
|
||||||
local hb_path="${1:-$(command -v HandBrakeCLI 2>/dev/null || true)}"
|
|
||||||
local resolved_path=""
|
|
||||||
[[ -n "$hb_path" ]] || return 1
|
|
||||||
[[ "$hb_path" == "/usr/local/bin/HandBrakeCLI" ]] || return 1
|
|
||||||
[[ -f "$HANDBRAKE_SELFBUILD_MARKER" ]] && return 0
|
|
||||||
resolved_path=$(readlink -f "$hb_path" 2>/dev/null || true)
|
|
||||||
dpkg -S "$hb_path" >/dev/null 2>&1 && return 1
|
|
||||||
[[ -n "$resolved_path" ]] && dpkg -S "$resolved_path" >/dev/null 2>&1 && return 1
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_non_selfbuilt_handbrake() {
|
|
||||||
info "Entferne nicht-selbst-gebaute HandBrake-Installationen..."
|
|
||||||
apt-get remove -y handbrake-cli handbrake 2>/dev/null || true
|
|
||||||
snap remove handbrake-cli 2>/dev/null || true
|
|
||||||
|
|
||||||
rm -f /usr/bin/HandBrakeCLI \
|
|
||||||
/snap/bin/handbrake-cli \
|
|
||||||
/snap/bin/HandBrakeCLI
|
|
||||||
|
|
||||||
if [[ -e /usr/local/bin/HandBrakeCLI ]] && ! handbrake_is_self_built "/usr/local/bin/HandBrakeCLI"; then
|
|
||||||
warn "Entferne fremdes /usr/local/bin/HandBrakeCLI"
|
|
||||||
rm -f /usr/local/bin/HandBrakeCLI
|
|
||||||
fi
|
|
||||||
|
|
||||||
hash -r 2>/dev/null || true
|
|
||||||
ok "Bereinigung abgeschlossen"
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_selfbuilt_handbrake() {
|
|
||||||
if [[ -e /usr/local/bin/HandBrakeCLI ]] && handbrake_is_self_built "/usr/local/bin/HandBrakeCLI"; then
|
|
||||||
warn "Entferne selbst gebautes /usr/local/bin/HandBrakeCLI"
|
|
||||||
rm -f /usr/local/bin/HandBrakeCLI
|
|
||||||
fi
|
|
||||||
rm -f "$HANDBRAKE_SELFBUILD_MARKER"
|
|
||||||
hash -r 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
build_handbrake_nvdec() {
|
|
||||||
header "HandBrake ${HANDBRAKE_VERSION} mit NVDEC aus Quellcode bauen"
|
|
||||||
|
|
||||||
local cache_dir="/var/cache/ripster/handbrake"
|
|
||||||
local src_url="https://github.com/HandBrake/HandBrake/releases/download/${HANDBRAKE_VERSION}/HandBrake-${HANDBRAKE_VERSION}-source.tar.bz2"
|
|
||||||
local tarball="${cache_dir}/HandBrake-${HANDBRAKE_VERSION}-source.tar.bz2"
|
|
||||||
local src_dir="${cache_dir}/HandBrake-${HANDBRAKE_VERSION}"
|
|
||||||
|
|
||||||
if [[ -t 0 && -d "$cache_dir" ]]; then
|
|
||||||
local clear_cache_answer=""
|
|
||||||
warn "Build-Cache gefunden: $cache_dir"
|
|
||||||
warn "Wenn du ihn löschst, startet der Source-Build wieder komplett von vorne."
|
|
||||||
read -r -p "Build-Cache jetzt löschen (sudo rm -rf $cache_dir)? [y/N] " clear_cache_answer
|
|
||||||
case "${clear_cache_answer,,}" in
|
|
||||||
y|yes|j|ja)
|
|
||||||
rm -rf "$cache_dir"
|
|
||||||
info "Build-Cache gelöscht."
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
mkdir -p "$cache_dir"
|
|
||||||
|
|
||||||
# Build-Abhängigkeiten
|
|
||||||
info "Installiere Build-Abhängigkeiten..."
|
|
||||||
apt-get install -y \
|
|
||||||
autoconf automake build-essential clang cmake git \
|
|
||||||
libass-dev libbz2-dev libdvdnav-dev libdvdread-dev \
|
|
||||||
libfontconfig-dev libfreetype-dev libfribidi-dev libharfbuzz-dev \
|
|
||||||
libjansson-dev liblzma-dev libmp3lame-dev libnuma-dev libogg-dev \
|
|
||||||
libopus-dev libsamplerate0-dev libspeex-dev libtheora-dev libtool libtool-bin libva-dev \
|
|
||||||
libturbojpeg0-dev libvorbis-dev libvpx-dev libx264-dev libxml2-dev \
|
|
||||||
m4 meson nasm ninja-build patch pkg-config python3 tar yasm zlib1g-dev \
|
|
||||||
>/dev/null
|
|
||||||
|
|
||||||
# CUDA Toolkit für NVDEC-Header
|
|
||||||
info "Installiere CUDA Toolkit (für NVDEC-Header)..."
|
|
||||||
if ! dpkg -l 2>/dev/null | grep -q '^ii.*nvidia-cuda-toolkit'; then
|
|
||||||
apt-get install -y nvidia-cuda-toolkit >/dev/null 2>&1 || {
|
|
||||||
warn "nvidia-cuda-toolkit nicht verfügbar – versuche Fallback-Header..."
|
|
||||||
local cuda_keyring="/tmp/cuda-keyring.deb"
|
|
||||||
local ubuntu_ver="${VERSION_ID//./}"
|
|
||||||
curl -fsSL "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu${ubuntu_ver}/x86_64/cuda-keyring_1.1-1_all.deb" \
|
|
||||||
-o "$cuda_keyring" 2>/dev/null && \
|
|
||||||
dpkg -i "$cuda_keyring" 2>/dev/null && \
|
|
||||||
apt-get update -qq && \
|
|
||||||
apt-get install -y cuda-cudart-dev-12-8 >/dev/null 2>&1 || \
|
|
||||||
warn "CUDA-Header konnten nicht installiert werden – NVDEC wird möglicherweise nicht verfügbar sein."
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
ok "Build-Abhängigkeiten installiert"
|
|
||||||
|
|
||||||
if [[ ! -d "$src_dir" ]]; then
|
|
||||||
if [[ ! -f "$tarball" ]]; then
|
|
||||||
info "Lade HandBrake ${HANDBRAKE_VERSION} herunter..."
|
|
||||||
curl -fsSL "$src_url" -o "$tarball" 2>/dev/null || \
|
|
||||||
wget -q "$src_url" -O "$tarball" || \
|
|
||||||
fatal "HandBrake-Quellcode konnte nicht heruntergeladen werden (${src_url})"
|
|
||||||
else
|
|
||||||
info "Nutze vorhandenes HandBrake-Source-Archiv: $tarball"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Entpacke Quellcode..."
|
|
||||||
tar xjf "$tarball" -C "$cache_dir"
|
|
||||||
[[ -d "$src_dir" ]] || src_dir=$(find "$cache_dir" -maxdepth 1 -type d -name "HandBrake*" | head -1)
|
|
||||||
[[ -d "$src_dir" ]] || fatal "HandBrake-Quellverzeichnis nicht gefunden in $cache_dir"
|
|
||||||
else
|
|
||||||
info "Nutze vorhandenen HandBrake-Source-Baum: $src_dir"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$src_dir"
|
|
||||||
|
|
||||||
local configure_log="${src_dir}/build/configure-ripster.log"
|
|
||||||
local configure_stamp="${src_dir}/build/.ripster-config"
|
|
||||||
local configure_args="--enable-nvdec --disable-gtk --prefix=/usr/local"
|
|
||||||
local need_configure="false"
|
|
||||||
local configure_cmd=(
|
|
||||||
./configure
|
|
||||||
--launch-jobs="$(nproc)"
|
|
||||||
--enable-nvdec
|
|
||||||
--disable-gtk
|
|
||||||
--prefix=/usr/local
|
|
||||||
)
|
|
||||||
|
|
||||||
if [[ ! -f "$src_dir/build/GNUmakefile" ]]; then
|
|
||||||
need_configure="true"
|
|
||||||
elif [[ ! -f "$configure_stamp" ]]; then
|
|
||||||
need_configure="true"
|
|
||||||
elif ! grep -qx "args=${configure_args}" "$configure_stamp"; then
|
|
||||||
need_configure="true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$need_configure" == "true" ]]; then
|
|
||||||
if [[ -d "$src_dir/build" ]]; then
|
|
||||||
configure_cmd=(./configure --force "${configure_cmd[@]:1}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -f "$src_dir/build/GNUmakefile" ]]; then
|
|
||||||
info "Vorhandener Build gefunden – aktualisiere Konfiguration (CLI-only)."
|
|
||||||
else
|
|
||||||
info "Konfiguriere HandBrake mit NVDEC (CLI-only)..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! "${configure_cmd[@]}" >"$configure_log" 2>&1; then
|
|
||||||
tail -n 50 "$configure_log" >&2 || true
|
|
||||||
fatal "HandBrake-Konfiguration fehlgeschlagen. Vollständiges Log: $configure_log"
|
|
||||||
fi
|
|
||||||
tail -n 10 "$configure_log"
|
|
||||||
|
|
||||||
mkdir -p "${src_dir}/build"
|
|
||||||
cat > "$configure_stamp" <<EOF
|
|
||||||
args=${configure_args}
|
|
||||||
version=${HANDBRAKE_VERSION}
|
|
||||||
configured_at_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
||||||
EOF
|
|
||||||
else
|
|
||||||
info "Vorhandene CLI-only-Konfiguration erkannt – überspringe configure."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -x "$src_dir/build/HandBrakeCLI" ]]; then
|
|
||||||
info "Vorhandenes HandBrakeCLI-Build-Artefakt gefunden – versuche direkte Installation."
|
|
||||||
if ! make --directory=build install; then
|
|
||||||
warn "Direkte Installation fehlgeschlagen – setze Build fort."
|
|
||||||
make --directory=build -j"$(nproc)"
|
|
||||||
make --directory=build install
|
|
||||||
fi
|
|
||||||
hash -r 2>/dev/null || true
|
|
||||||
if ! command_exists HandBrakeCLI; then
|
|
||||||
warn "HandBrakeCLI nach direkter Installation nicht gefunden – setze Build fort."
|
|
||||||
make --directory=build -j"$(nproc)"
|
|
||||||
make --directory=build install
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
info "Baue HandBrake ($(nproc) Threads – bitte warten)..."
|
|
||||||
make --directory=build -j"$(nproc)"
|
|
||||||
info "Installiere HandBrake nach /usr/local/bin..."
|
|
||||||
make --directory=build install
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd /
|
|
||||||
hash -r 2>/dev/null || true
|
|
||||||
|
|
||||||
if command_exists HandBrakeCLI; then
|
|
||||||
local ver
|
|
||||||
ver=$(HandBrakeCLI --version 2>&1 | head -1)
|
|
||||||
handbrake_has_nvdec || fatal "HandBrakeCLI ist installiert, aber ohne NVDEC-Unterstützung."
|
|
||||||
|
|
||||||
mkdir -p "$(dirname "$HANDBRAKE_SELFBUILD_MARKER")"
|
|
||||||
cat > "$HANDBRAKE_SELFBUILD_MARKER" <<EOF
|
|
||||||
version=${HANDBRAKE_VERSION}
|
|
||||||
source_dir=${src_dir}
|
|
||||||
binary_path=$(command -v HandBrakeCLI)
|
|
||||||
installed_at_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
||||||
EOF
|
|
||||||
|
|
||||||
ok "HandBrakeCLI mit NVDEC installiert: ${ver}"
|
|
||||||
if ldconfig -p 2>/dev/null | grep -q libnvcuvid; then
|
|
||||||
ok "libnvcuvid gefunden – NVDEC ist zur Laufzeit verfügbar."
|
|
||||||
else
|
|
||||||
warn "libnvcuvid NICHT gefunden. NVDEC benötigt den installierten NVIDIA-Treiber."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
fatal "HandBrakeCLI nach dem Build nicht gefunden – Build fehlgeschlagen."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
has_nvidia_gpu() {
|
|
||||||
[[ -e /dev/nvidia0 ]] && return 0
|
|
||||||
command_exists nvidia-smi && nvidia-smi &>/dev/null && return 0
|
|
||||||
command_exists lspci && lspci 2>/dev/null | grep -qi "nvidia" && return 0
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
install_handbrake() {
|
|
||||||
header "HandBrake CLI installieren"
|
|
||||||
|
|
||||||
local hb_path
|
|
||||||
local current_mode="none"
|
|
||||||
hb_path=$(command -v HandBrakeCLI 2>/dev/null || true)
|
|
||||||
if [[ -n "$hb_path" ]]; then
|
|
||||||
if handbrake_has_nvdec; then
|
|
||||||
current_mode="nvdec"
|
|
||||||
else
|
|
||||||
current_mode="standard"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$BUILD_HANDBRAKE_NVDEC" == true ]]; then
|
|
||||||
info "Installmodus: Source-Build mit NVDEC-Support"
|
|
||||||
if has_nvidia_gpu; then
|
|
||||||
info "NVIDIA-GPU erkannt – NVDEC-Build wird verwendet."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if handbrake_has_nvdec; then
|
|
||||||
if handbrake_is_self_built "$hb_path"; then
|
|
||||||
local installed_ver latest_ver answer
|
|
||||||
installed_ver=$(handbrake_installed_version || true)
|
|
||||||
latest_ver=$(handbrake_latest_git_version || true)
|
|
||||||
|
|
||||||
if [[ -n "$installed_ver" && -n "$latest_ver" ]] && dpkg --compare-versions "$latest_ver" gt "$installed_ver"; then
|
|
||||||
case "$HANDBRAKE_UPDATE_POLICY" in
|
|
||||||
keep)
|
|
||||||
warn "Neuere HandBrake-Version verfügbar (${latest_ver}, installiert: ${installed_ver}) – behalte aktuelle Installation."
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
prompt)
|
|
||||||
if [[ -t 0 ]]; then
|
|
||||||
read -r -p "Neue HandBrake-Version ${latest_ver} verfügbar (installiert ${installed_ver}). Neu bauen? [y/N] " answer
|
|
||||||
case "${answer,,}" in
|
|
||||||
y|yes|j|ja)
|
|
||||||
info "Aktualisiere auf HandBrake ${latest_ver}."
|
|
||||||
HANDBRAKE_VERSION="$latest_ver"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
info "Behalte bestehende Installation (${installed_ver})."
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
warn "Neuere HandBrake-Version verfügbar (${latest_ver}), aber kein TTY für Rückfrage – behalte aktuelle Installation."
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
build)
|
|
||||||
info "Neuere HandBrake-Version verfügbar (${latest_ver}, installiert: ${installed_ver}) – aktualisiere."
|
|
||||||
HANDBRAKE_VERSION="$latest_ver"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
ok "Selbst gebautes HandBrakeCLI mit NVDEC bereits installiert: $(HandBrakeCLI --version 2>&1 | head -1)"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
warn "HandBrakeCLI mit NVDEC gefunden (${hb_path}), aber nicht als Selbst-Build erkannt."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "$hb_path" ]] && ! handbrake_has_nvdec; then
|
|
||||||
warn "HandBrakeCLI ohne NVDEC gefunden (${hb_path}) – wird ersetzt durch Selbst-Build."
|
|
||||||
elif [[ -z "$hb_path" ]]; then
|
|
||||||
info "Kein HandBrakeCLI gefunden – baue aus Quellcode."
|
|
||||||
fi
|
|
||||||
|
|
||||||
remove_non_selfbuilt_handbrake
|
|
||||||
build_handbrake_nvdec
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Installmodus: Standard (APT, ohne NVDEC-Zwang)"
|
|
||||||
if [[ "$current_mode" == "standard" ]] && ! handbrake_is_self_built "$hb_path"; then
|
|
||||||
ok "HandBrakeCLI bereits installiert: $(HandBrakeCLI --version 2>&1 | head -1)"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$current_mode" == "nvdec" ]]; then
|
|
||||||
warn "Umschalten von NVDEC-Build auf Standard-Installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
remove_selfbuilt_handbrake
|
|
||||||
remove_non_selfbuilt_handbrake
|
|
||||||
|
|
||||||
info "Installiere HandBrakeCLI aus den Standard-Repositories..."
|
|
||||||
apt_update
|
|
||||||
apt-get install -y handbrake-cli >/dev/null
|
|
||||||
hash -r 2>/dev/null || true
|
|
||||||
|
|
||||||
if command_exists HandBrakeCLI; then
|
|
||||||
ok "HandBrakeCLI installiert: $(HandBrakeCLI --version 2>&1 | head -1)"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command_exists handbrake-cli; then
|
|
||||||
ln -sf "$(command -v handbrake-cli)" /usr/local/bin/HandBrakeCLI
|
|
||||||
hash -r 2>/dev/null || true
|
|
||||||
ok "HandBrakeCLI Alias angelegt auf: $(command -v handbrake-cli)"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
fatal "HandBrake wurde installiert, aber kein CLI-Befehl wurde gefunden."
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- apt-Hilfsfunktionen ------------------------------------------------------
|
|
||||||
|
|
||||||
apt_update() {
|
|
||||||
local output
|
|
||||||
if output=$(apt-get update 2>&1); then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if echo "$output" | grep -q "no longer has a Release file\|does not have a Release file"; then
|
|
||||||
warn "apt-Sources fehlerhaft. Versuche Reparatur..."
|
|
||||||
|
|
||||||
if apt-get update --allow-releaseinfo-change -qq 2>/dev/null; then
|
|
||||||
ok "apt-Update mit --allow-releaseinfo-change erfolgreich"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "${VERSION_CODENAME:-}" ]]; then
|
|
||||||
warn "Schreibe minimale sources.list für $VERSION_CODENAME..."
|
|
||||||
local main_list=/etc/apt/sources.list
|
|
||||||
cp "$main_list" "${main_list}.bak-$(date +%Y%m%d%H%M%S)" 2>/dev/null || true
|
|
||||||
|
|
||||||
case "$ID" in
|
|
||||||
ubuntu)
|
|
||||||
cat > "$main_list" <<EOF
|
|
||||||
deb http://archive.ubuntu.com/ubuntu ${VERSION_CODENAME} main restricted universe multiverse
|
|
||||||
deb http://archive.ubuntu.com/ubuntu ${VERSION_CODENAME}-updates main restricted universe multiverse
|
|
||||||
deb http://archive.ubuntu.com/ubuntu ${VERSION_CODENAME}-security main restricted universe multiverse
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
debian)
|
|
||||||
cat > "$main_list" <<EOF
|
|
||||||
deb http://deb.debian.org/debian ${VERSION_CODENAME} main contrib non-free
|
|
||||||
deb http://deb.debian.org/debian ${VERSION_CODENAME}-updates main contrib non-free
|
|
||||||
deb http://security.debian.org/debian-security ${VERSION_CODENAME}-security main contrib non-free
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if apt-get update -qq 2>/dev/null; then
|
|
||||||
ok "apt-Update nach Sources-Reparatur erfolgreich"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
warn "Deaktiviere fehlerhafte Eintraege in /etc/apt/sources.list.d/ ..."
|
|
||||||
local broken_files
|
|
||||||
broken_files=$(apt-get update 2>&1 | grep -oP "(?<=The repository ').*?(?=' )" | \
|
|
||||||
xargs -I{} grep -rl "{}" /etc/apt/sources.list.d/ 2>/dev/null || true)
|
|
||||||
if [[ -n "$broken_files" ]]; then
|
|
||||||
echo "$broken_files" | while read -r f; do
|
|
||||||
warn "Deaktiviere: $f"
|
|
||||||
mv "$f" "${f}.disabled" 2>/dev/null || true
|
|
||||||
done
|
|
||||||
if apt-get update -qq 2>/dev/null; then
|
|
||||||
ok "apt-Update nach Deaktivierung fehlerhafter Sources erfolgreich"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
error "apt-Update fehlgeschlagen. Bitte Sources manuell pruefen:"
|
|
||||||
echo "$output"
|
|
||||||
fatal "Installation abgebrochen. Repariere /etc/apt/sources.list und starte erneut."
|
|
||||||
else
|
|
||||||
error "apt-Update fehlgeschlagen:"
|
|
||||||
echo "$output"
|
|
||||||
fatal "Installation abgebrochen."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Systemabhängigkeiten -----------------------------------------------------
|
|
||||||
header "Systemabhängigkeiten installieren"
|
|
||||||
|
|
||||||
info "Paketlisten aktualisieren..."
|
|
||||||
apt_update
|
|
||||||
|
|
||||||
info "Installiere Basispakete..."
|
|
||||||
apt-get install -y \
|
|
||||||
curl wget git \
|
|
||||||
mediainfo \
|
|
||||||
util-linux udev \
|
|
||||||
ca-certificates gnupg \
|
|
||||||
lsb-release
|
|
||||||
|
|
||||||
ok "Basispakete installiert"
|
|
||||||
|
|
||||||
# Node.js
|
|
||||||
install_node
|
|
||||||
|
|
||||||
# MakeMKV
|
|
||||||
if [[ "$SKIP_MAKEMKV" == false ]]; then
|
|
||||||
install_makemkv
|
|
||||||
else
|
|
||||||
warn "MakeMKV-Installation übersprungen (--no-makemkv)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# HandBrake
|
|
||||||
if [[ "$SKIP_HANDBRAKE" == false ]]; then
|
|
||||||
install_handbrake
|
|
||||||
else
|
|
||||||
warn "HandBrake-Installation übersprungen (--no-handbrake)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Nginx
|
|
||||||
if [[ "$SKIP_NGINX" == false ]]; then
|
|
||||||
if ! command_exists nginx; then
|
|
||||||
info "Installiere nginx..."
|
|
||||||
apt-get install -y nginx
|
|
||||||
fi
|
|
||||||
ok "nginx installiert"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Systembenutzer anlegen ---------------------------------------------------
|
|
||||||
header "Systembenutzer anlegen"
|
|
||||||
|
|
||||||
if id "$SERVICE_USER" &>/dev/null; then
|
|
||||||
ok "Benutzer '$SERVICE_USER' existiert bereits"
|
|
||||||
else
|
|
||||||
info "Lege Systembenutzer '$SERVICE_USER' an..."
|
|
||||||
useradd --system --no-create-home --shell /usr/sbin/nologin "$SERVICE_USER"
|
|
||||||
ok "Benutzer '$SERVICE_USER' angelegt"
|
|
||||||
fi
|
|
||||||
|
|
||||||
SERVICE_HOME="$(getent passwd "$SERVICE_USER" | cut -d: -f6)"
|
|
||||||
if [[ -z "$SERVICE_HOME" || "$SERVICE_HOME" == "/" || "$SERVICE_HOME" == "/nonexistent" ]]; then
|
|
||||||
SERVICE_HOME="/home/$SERVICE_USER"
|
|
||||||
fi
|
|
||||||
mkdir -p "$SERVICE_HOME"
|
|
||||||
chown "$SERVICE_USER:$SERVICE_USER" "$SERVICE_HOME" 2>/dev/null || true
|
|
||||||
chmod 755 "$SERVICE_HOME" 2>/dev/null || true
|
|
||||||
info "Service-Home für '$SERVICE_USER': $SERVICE_HOME"
|
|
||||||
|
|
||||||
# Optisches Laufwerk: Benutzer zur cdrom/optical-Gruppe hinzufügen
|
|
||||||
for grp in cdrom optical disk; do
|
|
||||||
if getent group "$grp" &>/dev/null; then
|
|
||||||
usermod -aG "$grp" "$SERVICE_USER" 2>/dev/null || true
|
|
||||||
info "Benutzer '$SERVICE_USER' zur Gruppe '$grp' hinzugefügt"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# --- Dateien kopieren ---------------------------------------------------------
|
|
||||||
header "Ripster-Dateien installieren"
|
|
||||||
|
|
||||||
if [[ -d "$INSTALL_DIR" && "$REINSTALL" == false ]]; then
|
|
||||||
fatal "Verzeichnis $INSTALL_DIR existiert bereits.\nVerwende --reinstall um zu überschreiben (Daten bleiben erhalten)."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Bei Reinstall: Daten sichern
|
|
||||||
if [[ -d "$INSTALL_DIR/backend/data" ]]; then
|
|
||||||
info "Sichere vorhandene Datenbank..."
|
|
||||||
cp -a "$INSTALL_DIR/backend/data" "/tmp/ripster-data-backup-$(date +%Y%m%d%H%M%S)"
|
|
||||||
ok "Datenbank gesichert"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Kopiere Quellen nach $INSTALL_DIR..."
|
|
||||||
mkdir -p "$INSTALL_DIR"
|
|
||||||
|
|
||||||
rsync -a --delete \
|
|
||||||
--exclude='.git' \
|
|
||||||
--exclude='node_modules' \
|
|
||||||
--exclude='backend/node_modules' \
|
|
||||||
--exclude='frontend/node_modules' \
|
|
||||||
--exclude='backend/data' \
|
|
||||||
--exclude='backend/logs' \
|
|
||||||
--exclude='frontend/dist' \
|
|
||||||
--exclude='*.sh' \
|
|
||||||
--exclude='deploy-ripster.sh' \
|
|
||||||
--exclude='debug/' \
|
|
||||||
--exclude='site/' \
|
|
||||||
--exclude='docs/' \
|
|
||||||
"$SOURCE_DIR/" "$INSTALL_DIR/"
|
|
||||||
|
|
||||||
# Datenbank-/Log-Verzeichnisse anlegen
|
|
||||||
mkdir -p "$INSTALL_DIR/backend/data"
|
|
||||||
mkdir -p "$INSTALL_DIR/backend/logs"
|
|
||||||
|
|
||||||
# Bei Reinstall: Daten wiederherstellen
|
|
||||||
if [[ -d "$INSTALL_DIR/../ripster-data-backup" ]]; then
|
|
||||||
cp -a /tmp/ripster-data-backup-*/ "$INSTALL_DIR/backend/data/" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
ok "Dateien kopiert"
|
|
||||||
|
|
||||||
# --- npm-Abhängigkeiten installieren -----------------------------------------
|
|
||||||
header "npm-Abhängigkeiten installieren"
|
|
||||||
|
|
||||||
info "Installiere Root-Abhängigkeiten..."
|
|
||||||
npm install --prefix "$INSTALL_DIR" --omit=dev --silent
|
|
||||||
|
|
||||||
info "Installiere Backend-Abhängigkeiten..."
|
|
||||||
npm install --prefix "$INSTALL_DIR/backend" --omit=dev --silent
|
|
||||||
|
|
||||||
info "Installiere Frontend-Abhängigkeiten..."
|
|
||||||
npm install --prefix "$INSTALL_DIR/frontend" --silent
|
|
||||||
|
|
||||||
ok "npm-Abhängigkeiten installiert"
|
|
||||||
|
|
||||||
# --- Frontend bauen -----------------------------------------------------------
|
|
||||||
header "Frontend bauen"
|
|
||||||
|
|
||||||
info "Baue Frontend für $FRONTEND_HOST..."
|
|
||||||
|
|
||||||
# Relative URLs verwenden – funktioniert mit jedem Hostnamen/Domain, da nginx
|
|
||||||
# /api/ und /ws auf dem selben Host proxied. Absolute IP-URLs würden Chromes
|
|
||||||
# Private Network Access (PNA) Policy verletzen, wenn das Frontend über einen
|
|
||||||
# Domainnamen aufgerufen wird.
|
|
||||||
rm -f "$INSTALL_DIR/frontend/.env.production.local"
|
|
||||||
|
|
||||||
npm run build --prefix "$INSTALL_DIR/frontend" --silent
|
|
||||||
ok "Frontend gebaut: $INSTALL_DIR/frontend/dist"
|
|
||||||
|
|
||||||
# --- Backend-Konfiguration ---------------------------------------------------
|
|
||||||
header "Backend konfigurieren"
|
|
||||||
|
|
||||||
ENV_FILE="$INSTALL_DIR/backend/.env"
|
|
||||||
|
|
||||||
if [[ -f "$ENV_FILE" && "$REINSTALL" == false ]]; then
|
|
||||||
warn "Backend .env existiert bereits – wird nicht überschrieben"
|
|
||||||
else
|
|
||||||
info "Erstelle Backend .env..."
|
|
||||||
cat > "$ENV_FILE" <<EOF
|
|
||||||
# Ripster Backend – Konfiguration
|
|
||||||
# Generiert von install.sh am $(date)
|
|
||||||
|
|
||||||
PORT=${BACKEND_PORT}
|
|
||||||
DB_PATH=./data/ripster.db
|
|
||||||
LOG_DIR=./logs
|
|
||||||
LOG_LEVEL=info
|
|
||||||
|
|
||||||
# CORS: Erlaube Anfragen vom Frontend (nginx)
|
|
||||||
CORS_ORIGIN=http://${FRONTEND_HOST}
|
|
||||||
EOF
|
|
||||||
ok "Backend .env erstellt"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Berechtigungen setzen ---------------------------------------------------
|
|
||||||
chown -R "$SERVICE_USER:$SERVICE_USER" "$INSTALL_DIR"
|
|
||||||
chmod -R 755 "$INSTALL_DIR"
|
|
||||||
chmod 600 "$ENV_FILE"
|
|
||||||
|
|
||||||
# MakeMKV erwartet pro Benutzer ein eigenes Konfigurationsverzeichnis.
|
|
||||||
MAKEMKV_SERVICE_DIR="${SERVICE_HOME}/.MakeMKV"
|
|
||||||
if [[ ! -d "$MAKEMKV_SERVICE_DIR" ]]; then
|
|
||||||
mkdir -p "$MAKEMKV_SERVICE_DIR"
|
|
||||||
ok "MakeMKV-Verzeichnis erstellt: $MAKEMKV_SERVICE_DIR"
|
|
||||||
else
|
|
||||||
info "MakeMKV-Verzeichnis vorhanden: $MAKEMKV_SERVICE_DIR"
|
|
||||||
fi
|
|
||||||
chown "$SERVICE_USER:$SERVICE_USER" "$MAKEMKV_SERVICE_DIR" 2>/dev/null || true
|
|
||||||
chmod 700 "$MAKEMKV_SERVICE_DIR" 2>/dev/null || true
|
|
||||||
|
|
||||||
# --- Systemd-Dienst: Backend -------------------------------------------------
|
|
||||||
header "Systemd-Dienst (Backend) erstellen"
|
|
||||||
|
|
||||||
cat > /etc/systemd/system/ripster-backend.service <<EOF
|
|
||||||
[Unit]
|
|
||||||
Description=Ripster Backend API
|
|
||||||
Documentation=https://github.com/your-repo/ripster
|
|
||||||
After=network.target
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=${SERVICE_USER}
|
|
||||||
Group=${SERVICE_USER}
|
|
||||||
WorkingDirectory=${INSTALL_DIR}/backend
|
|
||||||
ExecStart=$(command -v node) src/index.js
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=5
|
|
||||||
StartLimitIntervalSec=60
|
|
||||||
StartLimitBurst=3
|
|
||||||
|
|
||||||
# Umgebung
|
|
||||||
Environment=NODE_ENV=production
|
|
||||||
Environment=HOME=${SERVICE_HOME}
|
|
||||||
Environment=LANG=C.UTF-8
|
|
||||||
Environment=LC_ALL=C.UTF-8
|
|
||||||
Environment=LANGUAGE=C.UTF-8
|
|
||||||
EnvironmentFile=${INSTALL_DIR}/backend/.env
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
StandardOutput=journal
|
|
||||||
StandardError=journal
|
|
||||||
SyslogIdentifier=ripster-backend
|
|
||||||
|
|
||||||
# Sicherheit
|
|
||||||
# Für Skriptausführung via GUI (inkl. optionalem sudo in User-Skripten)
|
|
||||||
# darf no_new_privileges nicht aktiv sein.
|
|
||||||
NoNewPrivileges=false
|
|
||||||
ProtectSystem=full
|
|
||||||
ProtectHome=read-only
|
|
||||||
ReadWritePaths=${INSTALL_DIR}/backend/data ${INSTALL_DIR}/backend/logs /tmp ${SERVICE_HOME} ${MAKEMKV_SERVICE_DIR}
|
|
||||||
PrivateTmp=true
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
ok "ripster-backend.service erstellt"
|
|
||||||
|
|
||||||
# --- nginx konfigurieren -----------------------------------------------------
|
|
||||||
if [[ "$SKIP_NGINX" == false ]]; then
|
|
||||||
header "nginx konfigurieren"
|
|
||||||
|
|
||||||
cat > /etc/nginx/sites-available/ripster <<EOF
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name ${FRONTEND_HOST} _;
|
|
||||||
|
|
||||||
# Frontend (statische Dateien)
|
|
||||||
root ${INSTALL_DIR}/frontend/dist;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
# SPA: alle unbekannten Pfade → index.html
|
|
||||||
location / {
|
|
||||||
try_files \$uri \$uri/ /index.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
# API → Backend
|
|
||||||
location /api/ {
|
|
||||||
proxy_pass http://127.0.0.1:${BACKEND_PORT};
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Host \$host;
|
|
||||||
proxy_set_header X-Real-IP \$remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
||||||
proxy_read_timeout 300s;
|
|
||||||
proxy_connect_timeout 10s;
|
|
||||||
}
|
|
||||||
|
|
||||||
# WebSocket → Backend
|
|
||||||
location /ws {
|
|
||||||
proxy_pass http://127.0.0.1:${BACKEND_PORT}/ws;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade \$http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Host \$host;
|
|
||||||
proxy_read_timeout 3600s;
|
|
||||||
proxy_send_timeout 3600s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Alte Default-Seite deaktivieren, Ripster aktivieren
|
|
||||||
rm -f /etc/nginx/sites-enabled/default
|
|
||||||
ln -sf /etc/nginx/sites-available/ripster /etc/nginx/sites-enabled/ripster
|
|
||||||
|
|
||||||
nginx -t && ok "nginx-Konfiguration gültig" || fatal "nginx-Konfiguration fehlerhaft!"
|
|
||||||
|
|
||||||
ok "nginx konfiguriert"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Dienste aktivieren und starten ------------------------------------------
|
|
||||||
header "Dienste starten"
|
|
||||||
|
|
||||||
systemctl daemon-reload
|
|
||||||
|
|
||||||
systemctl enable ripster-backend
|
|
||||||
systemctl restart ripster-backend
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
if systemctl is-active --quiet ripster-backend; then
|
|
||||||
ok "ripster-backend läuft"
|
|
||||||
else
|
|
||||||
error "ripster-backend konnte nicht gestartet werden!"
|
|
||||||
journalctl -u ripster-backend -n 30 --no-pager
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$SKIP_NGINX" == false ]]; then
|
|
||||||
systemctl enable nginx
|
|
||||||
systemctl restart nginx
|
|
||||||
if systemctl is-active --quiet nginx; then
|
|
||||||
ok "nginx läuft"
|
|
||||||
else
|
|
||||||
error "nginx konnte nicht gestartet werden!"
|
|
||||||
journalctl -u nginx -n 20 --no-pager
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Zusammenfassung ----------------------------------------------------------
|
|
||||||
header "Installation abgeschlossen!"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e " ${GREEN}${BOLD}Ripster ist installiert und läuft.${RESET}"
|
|
||||||
echo ""
|
|
||||||
if [[ "$SKIP_NGINX" == false ]]; then
|
|
||||||
echo -e " ${BOLD}Weboberfläche:${RESET} http://${FRONTEND_HOST}"
|
|
||||||
else
|
|
||||||
echo -e " ${BOLD}Backend API:${RESET} http://${FRONTEND_HOST}:${BACKEND_PORT}/api"
|
|
||||||
warn "nginx deaktiviert – Frontend nicht automatisch erreichbar."
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
echo -e " ${BOLD}Dienste verwalten:${RESET}"
|
|
||||||
echo -e " sudo systemctl status ripster-backend"
|
|
||||||
echo -e " sudo systemctl restart ripster-backend"
|
|
||||||
echo -e " sudo systemctl stop ripster-backend"
|
|
||||||
echo -e " sudo journalctl -u ripster-backend -f"
|
|
||||||
echo ""
|
|
||||||
echo -e " ${BOLD}Konfiguration:${RESET} $INSTALL_DIR/backend/.env"
|
|
||||||
echo -e " ${BOLD}Datenbank:${RESET} $INSTALL_DIR/backend/data/ripster.db"
|
|
||||||
echo -e " ${BOLD}Logs:${RESET} $INSTALL_DIR/backend/logs/"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Warnungen zu fehlenden Tools
|
|
||||||
missing_tools=()
|
|
||||||
command_exists makemkvcon || missing_tools+=("makemkvcon")
|
|
||||||
command_exists HandBrakeCLI || missing_tools+=("HandBrakeCLI")
|
|
||||||
command_exists mediainfo || missing_tools+=("mediainfo")
|
|
||||||
|
|
||||||
if [[ ${#missing_tools[@]} -gt 0 ]]; then
|
|
||||||
echo -e " ${YELLOW}${BOLD}Hinweis:${RESET} Folgende Tools fehlen noch:"
|
|
||||||
for t in "${missing_tools[@]}"; do
|
|
||||||
echo -e " ${YELLOW}✗${RESET} $t"
|
|
||||||
done
|
|
||||||
echo -e " Diese können in den Ripster-Einstellungen konfiguriert werden."
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
761
install.sh
761
install.sh
@@ -1,761 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# =============================================================================
|
|
||||||
# Ripster – Installationsskript (Git)
|
|
||||||
# Unterstützt: Debian 11/12, Ubuntu 22.04/24.04
|
|
||||||
# Benötigt: sudo / root, Internetzugang
|
|
||||||
#
|
|
||||||
# Verwendung:
|
|
||||||
# curl -fsSL https://raw.githubusercontent.com/Mboehmlaender/ripster/main/install.sh | sudo bash
|
|
||||||
# oder:
|
|
||||||
# wget -qO- https://raw.githubusercontent.com/Mboehmlaender/ripster/main/install.sh | sudo bash
|
|
||||||
#
|
|
||||||
# Mit Optionen (nur via Datei möglich):
|
|
||||||
# sudo bash install.sh [Optionen]
|
|
||||||
#
|
|
||||||
# Optionen:
|
|
||||||
# --branch <branch> Git-Branch (Standard: main)
|
|
||||||
# --dir <pfad> Installationsverzeichnis (Standard: /opt/ripster)
|
|
||||||
# --user <benutzer> Systembenutzer für den Dienst (Standard: ripster)
|
|
||||||
# --port <port> Backend-Port (Standard: 3001)
|
|
||||||
# --host <hostname> Hostname/IP für die Weboberfläche (Standard: Maschinen-IP)
|
|
||||||
# --no-makemkv MakeMKV-Installation überspringen
|
|
||||||
# --no-handbrake HandBrake-Installation überspringen
|
|
||||||
# --no-nginx Nginx-Einrichtung überspringen
|
|
||||||
# --reinstall Vorhandene Installation aktualisieren (Daten bleiben erhalten)
|
|
||||||
# -h, --help Diese Hilfe anzeigen
|
|
||||||
# =============================================================================
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
REPO_URL="https://github.com/Mboehmlaender/ripster.git"
|
|
||||||
REPO_RAW_BASE="https://raw.githubusercontent.com/Mboehmlaender/ripster"
|
|
||||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd -P)"
|
|
||||||
BUNDLED_HANDBRAKE_CLI="${SCRIPT_DIR}/bin/HandBrakeCLI"
|
|
||||||
|
|
||||||
# --- Farben -------------------------------------------------------------------
|
|
||||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
|
||||||
BLUE='\033[0;34m'; BOLD='\033[1m'; RESET='\033[0m'
|
|
||||||
|
|
||||||
info() { echo -e "${BLUE}[INFO]${RESET} $*"; }
|
|
||||||
ok() { echo -e "${GREEN}[OK]${RESET} $*"; }
|
|
||||||
warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; }
|
|
||||||
error() { echo -e "${RED}[FEHLER]${RESET} $*" >&2; }
|
|
||||||
header() { echo -e "\n${BOLD}${BLUE}══════════════════════════════════════════${RESET}"; \
|
|
||||||
echo -e "${BOLD} $*${RESET}"; \
|
|
||||||
echo -e "${BOLD}${BLUE}══════════════════════════════════════════${RESET}"; }
|
|
||||||
fatal() { error "$*"; exit 1; }
|
|
||||||
|
|
||||||
# --- Standard-Optionen --------------------------------------------------------
|
|
||||||
GIT_BRANCH="dev"
|
|
||||||
INSTALL_DIR="/opt/ripster"
|
|
||||||
SERVICE_USER="ripster"
|
|
||||||
BACKEND_PORT="3001"
|
|
||||||
FRONTEND_HOST=""
|
|
||||||
SKIP_MAKEMKV=false
|
|
||||||
SKIP_HANDBRAKE=false
|
|
||||||
HANDBRAKE_INSTALL_MODE=""
|
|
||||||
SKIP_NGINX=false
|
|
||||||
REINSTALL=false
|
|
||||||
|
|
||||||
# --- Argumente parsen ---------------------------------------------------------
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--branch) GIT_BRANCH="$2"; shift 2 ;;
|
|
||||||
--dir) INSTALL_DIR="$2"; shift 2 ;;
|
|
||||||
--user) SERVICE_USER="$2"; shift 2 ;;
|
|
||||||
--port) BACKEND_PORT="$2"; shift 2 ;;
|
|
||||||
--host) FRONTEND_HOST="$2"; shift 2 ;;
|
|
||||||
--no-makemkv) SKIP_MAKEMKV=true; shift ;;
|
|
||||||
--no-handbrake) SKIP_HANDBRAKE=true; shift ;;
|
|
||||||
--no-nginx) SKIP_NGINX=true; shift ;;
|
|
||||||
--reinstall) REINSTALL=true; shift ;;
|
|
||||||
-h|--help)
|
|
||||||
sed -n '/^# Verwendung/,/^# ====/p' "$0" | head -n -1 | sed 's/^# \?//'
|
|
||||||
exit 0 ;;
|
|
||||||
*) fatal "Unbekannte Option: $1" ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# --- Voraussetzungen prüfen ---------------------------------------------------
|
|
||||||
header "Ripster Installationsskript (Git)"
|
|
||||||
|
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
fatal "Dieses Skript muss als root ausgeführt werden (sudo bash install.sh)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f /etc/os-release ]]; then
|
|
||||||
fatal "Betriebssystem nicht erkennbar. Nur Debian/Ubuntu wird unterstützt."
|
|
||||||
fi
|
|
||||||
. /etc/os-release
|
|
||||||
case "$ID" in
|
|
||||||
debian|ubuntu|linuxmint|pop) ok "Betriebssystem: $PRETTY_NAME" ;;
|
|
||||||
*) fatal "Nicht unterstütztes OS: $ID. Nur Debian/Ubuntu unterstützt." ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [[ -z "$FRONTEND_HOST" ]]; then
|
|
||||||
FRONTEND_HOST=$(hostname -I | awk '{print $1}')
|
|
||||||
info "Erkannte IP: $FRONTEND_HOST"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Repository: $REPO_URL"
|
|
||||||
info "Branch: $GIT_BRANCH"
|
|
||||||
info "Installationsverzeichnis: $INSTALL_DIR"
|
|
||||||
info "Systembenutzer: $SERVICE_USER"
|
|
||||||
info "Backend-Port: $BACKEND_PORT"
|
|
||||||
info "Frontend-Host: $FRONTEND_HOST"
|
|
||||||
|
|
||||||
# --- Hilfsfunktionen ----------------------------------------------------------
|
|
||||||
|
|
||||||
command_exists() { command -v "$1" &>/dev/null; }
|
|
||||||
|
|
||||||
download_file() {
|
|
||||||
local url="$1"
|
|
||||||
local target="$2"
|
|
||||||
|
|
||||||
if command_exists curl; then
|
|
||||||
curl -fsSL "$url" -o "$target"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command_exists wget; then
|
|
||||||
wget -q "$url" -O "$target"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
install_node() {
|
|
||||||
header "Node.js installieren"
|
|
||||||
local required_major=20
|
|
||||||
|
|
||||||
if command_exists node; then
|
|
||||||
local current_major
|
|
||||||
current_major=$(node -e "process.stdout.write(String(process.version.split('.')[0].replace('v','')))")
|
|
||||||
if [[ "$current_major" -ge "$required_major" ]]; then
|
|
||||||
ok "Node.js $(node --version) bereits installiert"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
warn "Node.js $(node --version) zu alt – Node.js 20 wird installiert"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Installiere Node.js 20.x über NodeSource..."
|
|
||||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
|
||||||
apt-get install -y nodejs
|
|
||||||
ok "Node.js $(node --version) installiert"
|
|
||||||
}
|
|
||||||
|
|
||||||
install_makemkv() {
|
|
||||||
header "MakeMKV installieren"
|
|
||||||
|
|
||||||
if command_exists makemkvcon; then
|
|
||||||
ok "makemkvcon bereits installiert ($(makemkvcon --version 2>&1 | head -1))"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Installiere Build-Abhängigkeiten für MakeMKV..."
|
|
||||||
apt-get install -y \
|
|
||||||
build-essential pkg-config libc6-dev libssl-dev \
|
|
||||||
libexpat1-dev libavcodec-dev libgl1-mesa-dev \
|
|
||||||
qtbase5-dev zlib1g-dev wget
|
|
||||||
|
|
||||||
# Aktuelle Version aus dem offiziellen Linux-Forum-Thread ermitteln.
|
|
||||||
# Der Titel lautet immer: "MakeMKV X.Y.Z for Linux is available"
|
|
||||||
local makemkv_fallback="1.18.3"
|
|
||||||
info "Ermittle aktuelle MakeMKV-Version (forum.makemkv.com)..."
|
|
||||||
local makemkv_version
|
|
||||||
makemkv_version=$(curl -s --max-time 15 \
|
|
||||||
"https://forum.makemkv.com/forum/viewtopic.php?f=3&t=224" \
|
|
||||||
| grep -oP 'MakeMKV \K[0-9]+\.[0-9]+\.[0-9]+(?= for Linux)' | head -1 || true)
|
|
||||||
|
|
||||||
if [[ -z "$makemkv_version" ]]; then
|
|
||||||
warn "MakeMKV-Version konnte nicht ermittelt werden – verwende Fallback $makemkv_fallback"
|
|
||||||
makemkv_version="$makemkv_fallback"
|
|
||||||
else
|
|
||||||
info "Aktuelle Version: $makemkv_version"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Baue MakeMKV $makemkv_version..."
|
|
||||||
local tmp_dir
|
|
||||||
tmp_dir=$(mktemp -d)
|
|
||||||
cd "$tmp_dir"
|
|
||||||
|
|
||||||
local base_url="https://www.makemkv.com/download"
|
|
||||||
wget -q "${base_url}/makemkv-bin-${makemkv_version}.tar.gz"
|
|
||||||
wget -q "${base_url}/makemkv-oss-${makemkv_version}.tar.gz"
|
|
||||||
|
|
||||||
tar xf "makemkv-oss-${makemkv_version}.tar.gz"
|
|
||||||
cd "makemkv-oss-${makemkv_version}"
|
|
||||||
./configure
|
|
||||||
make -j"$(nproc)"
|
|
||||||
make install
|
|
||||||
|
|
||||||
cd "$tmp_dir"
|
|
||||||
tar xf "makemkv-bin-${makemkv_version}.tar.gz"
|
|
||||||
cd "makemkv-bin-${makemkv_version}"
|
|
||||||
mkdir -p tmp && echo "accepted" > tmp/eula_accepted
|
|
||||||
make -j"$(nproc)"
|
|
||||||
make install
|
|
||||||
|
|
||||||
cd /
|
|
||||||
rm -rf "$tmp_dir"
|
|
||||||
ok "MakeMKV $makemkv_version installiert"
|
|
||||||
warn "Hinweis: MakeMKV benötigt eine Lizenz oder den Beta-Key."
|
|
||||||
warn "Beta-Key: https://www.makemkv.com/forum/viewtopic.php?t=1053"
|
|
||||||
}
|
|
||||||
|
|
||||||
select_handbrake_mode() {
|
|
||||||
[[ "$SKIP_HANDBRAKE" == true ]] && return
|
|
||||||
|
|
||||||
local mode_answer=""
|
|
||||||
echo ""
|
|
||||||
echo "Install HandBrake:"
|
|
||||||
echo ""
|
|
||||||
echo "1. Standard version (apt install handbrake-cli)"
|
|
||||||
echo "2. GPU version with NVDEC (use bundled binary)"
|
|
||||||
|
|
||||||
if [[ -t 0 ]]; then
|
|
||||||
read -r -p "Select option [1/2]: " mode_answer
|
|
||||||
elif [[ -r /dev/tty ]]; then
|
|
||||||
read -r -p "Select option [1/2]: " mode_answer </dev/tty
|
|
||||||
else
|
|
||||||
HANDBRAKE_INSTALL_MODE="standard"
|
|
||||||
warn "Kein interaktives Terminal erkannt – verwende Standardversion (apt)."
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$mode_answer" in
|
|
||||||
2) HANDBRAKE_INSTALL_MODE="gpu" ;;
|
|
||||||
1|"") HANDBRAKE_INSTALL_MODE="standard" ;;
|
|
||||||
*) warn "Ungültige Auswahl '$mode_answer' – verwende Standardversion."; HANDBRAKE_INSTALL_MODE="standard" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
install_handbrake_standard() {
|
|
||||||
info "Installiere HandBrakeCLI aus den Standard-Repositories..."
|
|
||||||
info "Aktualisiere Paketlisten..."
|
|
||||||
apt_update
|
|
||||||
apt-get install -y handbrake-cli
|
|
||||||
hash -r 2>/dev/null || true
|
|
||||||
|
|
||||||
if command_exists HandBrakeCLI; then
|
|
||||||
ok "HandBrakeCLI installiert: $(HandBrakeCLI --version 2>&1 | head -1)"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command_exists handbrake-cli; then
|
|
||||||
ok "handbrake-cli installiert: $(handbrake-cli --version 2>&1 | head -1)"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
fatal "HandBrake wurde installiert, aber kein CLI-Befehl wurde gefunden."
|
|
||||||
}
|
|
||||||
|
|
||||||
install_handbrake_gpu_bundled() {
|
|
||||||
info "Installiere gebündeltes HandBrakeCLI mit NVDEC..."
|
|
||||||
local bundled_source="$BUNDLED_HANDBRAKE_CLI"
|
|
||||||
local downloaded_tmp=""
|
|
||||||
|
|
||||||
if [[ ! -f "$bundled_source" ]]; then
|
|
||||||
local remote_url="${REPO_RAW_BASE}/${GIT_BRANCH}/bin/HandBrakeCLI"
|
|
||||||
downloaded_tmp=$(mktemp)
|
|
||||||
info "Lokale Binary fehlt – lade aus Branch '$GIT_BRANCH' nach..."
|
|
||||||
if download_file "$remote_url" "$downloaded_tmp"; then
|
|
||||||
chmod 0755 "$downloaded_tmp"
|
|
||||||
bundled_source="$downloaded_tmp"
|
|
||||||
ok "Bundled HandBrakeCLI temporär heruntergeladen"
|
|
||||||
else
|
|
||||||
rm -f "$downloaded_tmp" 2>/dev/null || true
|
|
||||||
fatal "Bundled Binary fehlt lokal ($BUNDLED_HANDBRAKE_CLI) und Download schlug fehl: $remote_url"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
install -m 0755 "$bundled_source" /usr/local/bin/HandBrakeCLI
|
|
||||||
hash -r 2>/dev/null || true
|
|
||||||
if [[ -n "$downloaded_tmp" ]]; then
|
|
||||||
rm -f "$downloaded_tmp" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
ok "Bundled HandBrakeCLI installiert nach /usr/local/bin/HandBrakeCLI"
|
|
||||||
if command_exists HandBrakeCLI; then
|
|
||||||
ok "HandBrakeCLI Version: $(HandBrakeCLI --version 2>&1 | head -1)"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install_handbrake() {
|
|
||||||
header "HandBrake CLI installieren"
|
|
||||||
|
|
||||||
if [[ -z "$HANDBRAKE_INSTALL_MODE" ]]; then
|
|
||||||
HANDBRAKE_INSTALL_MODE="standard"
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$HANDBRAKE_INSTALL_MODE" in
|
|
||||||
standard) install_handbrake_standard ;;
|
|
||||||
gpu) install_handbrake_gpu_bundled ;;
|
|
||||||
*) fatal "Unbekannter HandBrake-Modus: $HANDBRAKE_INSTALL_MODE" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- apt-Hilfsfunktionen ------------------------------------------------------
|
|
||||||
|
|
||||||
# Führt apt-get update aus. Bei Release-Fehlern wird versucht, die Sources zu
|
|
||||||
# reparieren (Proxmox-Container, veraltete Spiegelserver, etc.).
|
|
||||||
apt_update() {
|
|
||||||
local output
|
|
||||||
if output=$(apt-get update 2>&1); then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Release-Datei fehlt → versuche Repair
|
|
||||||
if echo "$output" | grep -q "no longer has a Release file\|does not have a Release file"; then
|
|
||||||
warn "apt-Sources fehlerhaft. Versuche Reparatur..."
|
|
||||||
|
|
||||||
# Strategie 1: --allow-releaseinfo-change
|
|
||||||
if apt-get update --allow-releaseinfo-change -qq 2>/dev/null; then
|
|
||||||
ok "apt-Update mit --allow-releaseinfo-change erfolgreich"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Strategie 2: Kaputte Einträge aus sources.list.d entfernen und Fallback
|
|
||||||
# auf offizielle Spiegel schreiben
|
|
||||||
if [[ -n "${VERSION_CODENAME:-}" ]]; then
|
|
||||||
warn "Schreibe minimale sources.list für $VERSION_CODENAME..."
|
|
||||||
local main_list=/etc/apt/sources.list
|
|
||||||
|
|
||||||
# Backup
|
|
||||||
cp "$main_list" "${main_list}.bak-$(date +%Y%m%d%H%M%S)" 2>/dev/null || true
|
|
||||||
|
|
||||||
case "$ID" in
|
|
||||||
ubuntu)
|
|
||||||
cat > "$main_list" <<EOF
|
|
||||||
deb http://archive.ubuntu.com/ubuntu ${VERSION_CODENAME} main restricted universe multiverse
|
|
||||||
deb http://archive.ubuntu.com/ubuntu ${VERSION_CODENAME}-updates main restricted universe multiverse
|
|
||||||
deb http://archive.ubuntu.com/ubuntu ${VERSION_CODENAME}-security main restricted universe multiverse
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
debian)
|
|
||||||
cat > "$main_list" <<EOF
|
|
||||||
deb http://deb.debian.org/debian ${VERSION_CODENAME} main contrib non-free
|
|
||||||
deb http://deb.debian.org/debian ${VERSION_CODENAME}-updates main contrib non-free
|
|
||||||
deb http://security.debian.org/debian-security ${VERSION_CODENAME}-security main contrib non-free
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if apt-get update -qq 2>/dev/null; then
|
|
||||||
ok "apt-Update nach Sources-Reparatur erfolgreich"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Strategie 3: Kaputte .list-Dateien in sources.list.d deaktivieren
|
|
||||||
warn "Deaktiviere fehlerhafte Eintraege in /etc/apt/sources.list.d/ ..."
|
|
||||||
local broken_files
|
|
||||||
broken_files=$(apt-get update 2>&1 | grep -oP "(?<=The repository ').*?(?=' )" | \
|
|
||||||
xargs -I{} grep -rl "{}" /etc/apt/sources.list.d/ 2>/dev/null || true)
|
|
||||||
if [[ -n "$broken_files" ]]; then
|
|
||||||
echo "$broken_files" | while read -r f; do
|
|
||||||
warn "Deaktiviere: $f"
|
|
||||||
mv "$f" "${f}.disabled" 2>/dev/null || true
|
|
||||||
done
|
|
||||||
if apt-get update -qq 2>/dev/null; then
|
|
||||||
ok "apt-Update nach Deaktivierung fehlerhafter Sources erfolgreich"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
error "apt-Update fehlgeschlagen. Bitte Sources manuell pruefen:"
|
|
||||||
echo "$output"
|
|
||||||
fatal "Installation abgebrochen. Repariere /etc/apt/sources.list und starte erneut."
|
|
||||||
else
|
|
||||||
error "apt-Update fehlgeschlagen:"
|
|
||||||
echo "$output"
|
|
||||||
fatal "Installation abgebrochen."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- HandBrake-Installmodus auswählen ----------------------------------------
|
|
||||||
select_handbrake_mode
|
|
||||||
|
|
||||||
# --- Systemabhängigkeiten -----------------------------------------------------
|
|
||||||
header "Systemabhängigkeiten installieren"
|
|
||||||
|
|
||||||
info "Paketlisten aktualisieren..."
|
|
||||||
apt_update
|
|
||||||
|
|
||||||
info "Installiere Basispakete..."
|
|
||||||
apt-get install -y \
|
|
||||||
curl wget git jq \
|
|
||||||
mediainfo \
|
|
||||||
util-linux udev \
|
|
||||||
ca-certificates gnupg \
|
|
||||||
lsb-release
|
|
||||||
|
|
||||||
ok "Basispakete installiert"
|
|
||||||
|
|
||||||
info "Installiere CD-Ripping-Tools..."
|
|
||||||
apt-get install -y \
|
|
||||||
cdparanoia \
|
|
||||||
flac \
|
|
||||||
lame \
|
|
||||||
opus-tools \
|
|
||||||
vorbis-tools
|
|
||||||
|
|
||||||
ok "CD-Ripping-Tools installiert (cdparanoia, flac, lame, opus-tools, vorbis-tools)"
|
|
||||||
|
|
||||||
install_node
|
|
||||||
|
|
||||||
if [[ "$SKIP_MAKEMKV" == false ]]; then
|
|
||||||
install_makemkv
|
|
||||||
else
|
|
||||||
warn "MakeMKV-Installation übersprungen (--no-makemkv)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$SKIP_HANDBRAKE" == false ]]; then
|
|
||||||
install_handbrake
|
|
||||||
else
|
|
||||||
warn "HandBrake-Installation übersprungen (--no-handbrake)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$SKIP_NGINX" == false ]]; then
|
|
||||||
if ! command_exists nginx; then
|
|
||||||
info "Installiere nginx..."
|
|
||||||
apt-get install -y nginx
|
|
||||||
fi
|
|
||||||
ok "nginx installiert"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Systembenutzer anlegen ---------------------------------------------------
|
|
||||||
header "Systembenutzer anlegen"
|
|
||||||
|
|
||||||
if id "$SERVICE_USER" &>/dev/null; then
|
|
||||||
ok "Benutzer '$SERVICE_USER' existiert bereits"
|
|
||||||
else
|
|
||||||
info "Lege Systembenutzer '$SERVICE_USER' an..."
|
|
||||||
useradd --system --no-create-home --shell /usr/sbin/nologin "$SERVICE_USER"
|
|
||||||
ok "Benutzer '$SERVICE_USER' angelegt"
|
|
||||||
fi
|
|
||||||
|
|
||||||
SERVICE_HOME="$(getent passwd "$SERVICE_USER" | cut -d: -f6)"
|
|
||||||
if [[ -z "$SERVICE_HOME" || "$SERVICE_HOME" == "/" || "$SERVICE_HOME" == "/nonexistent" ]]; then
|
|
||||||
SERVICE_HOME="/home/$SERVICE_USER"
|
|
||||||
fi
|
|
||||||
mkdir -p "$SERVICE_HOME"
|
|
||||||
chown "$SERVICE_USER:$SERVICE_USER" "$SERVICE_HOME" 2>/dev/null || true
|
|
||||||
chmod 755 "$SERVICE_HOME" 2>/dev/null || true
|
|
||||||
info "Service-Home für '$SERVICE_USER': $SERVICE_HOME"
|
|
||||||
|
|
||||||
for grp in cdrom optical disk video render; do
|
|
||||||
if getent group "$grp" &>/dev/null; then
|
|
||||||
usermod -aG "$grp" "$SERVICE_USER" 2>/dev/null || true
|
|
||||||
info "Benutzer '$SERVICE_USER' zur Gruppe '$grp' hinzugefügt"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# --- Repository klonen / aktualisieren ----------------------------------------
|
|
||||||
header "Repository holen (Git)"
|
|
||||||
|
|
||||||
# Prüfen ob der gewünschte Branch auf dem Remote existiert
|
|
||||||
info "Prüfe Branch '$GIT_BRANCH' auf Remote..."
|
|
||||||
if ! git ls-remote --exit-code --heads "$REPO_URL" "$GIT_BRANCH" &>/dev/null; then
|
|
||||||
fatal "Branch '$GIT_BRANCH' existiert nicht im Repository $REPO_URL.\nVerfügbare Branches: $(git ls-remote --heads "$REPO_URL" | awk '{print $2}' | sed 's|refs/heads/||' | tr '\n' ' ')"
|
|
||||||
fi
|
|
||||||
ok "Branch '$GIT_BRANCH' gefunden"
|
|
||||||
|
|
||||||
if [[ -d "$INSTALL_DIR/.git" ]]; then
|
|
||||||
if [[ "$REINSTALL" == true ]]; then
|
|
||||||
info "Aktualisiere bestehendes Repository..."
|
|
||||||
# Daten sichern
|
|
||||||
if [[ -d "$INSTALL_DIR/backend/data" ]]; then
|
|
||||||
DATA_BACKUP="/tmp/ripster-data-backup-$(date +%Y%m%d%H%M%S)"
|
|
||||||
cp -a "$INSTALL_DIR/backend/data" "$DATA_BACKUP"
|
|
||||||
info "Datenbank gesichert nach: $DATA_BACKUP"
|
|
||||||
fi
|
|
||||||
# safe.directory nötig wenn das Verzeichnis einem anderen User gehört
|
|
||||||
# (z.B. ripster-Serviceuser nach erstem Install)
|
|
||||||
git config --global --add safe.directory "$INSTALL_DIR" 2>/dev/null || true
|
|
||||||
git -C "$INSTALL_DIR" remote set-branches origin '*'
|
|
||||||
git -C "$INSTALL_DIR" fetch --quiet origin
|
|
||||||
git -C "$INSTALL_DIR" reset --hard HEAD
|
|
||||||
git -C "$INSTALL_DIR" checkout --quiet -B "$GIT_BRANCH" "origin/$GIT_BRANCH"
|
|
||||||
git -C "$INSTALL_DIR" reset --hard "origin/$GIT_BRANCH"
|
|
||||||
ok "Repository aktualisiert auf Branch '$GIT_BRANCH'"
|
|
||||||
else
|
|
||||||
fatal "$INSTALL_DIR enthält bereits ein Git-Repository.\nVerwende --reinstall um zu aktualisieren."
|
|
||||||
fi
|
|
||||||
elif [[ -d "$INSTALL_DIR" && "$REINSTALL" == false ]]; then
|
|
||||||
fatal "Verzeichnis $INSTALL_DIR existiert bereits (kein Git-Repo).\nBitte manuell entfernen oder --reinstall verwenden."
|
|
||||||
else
|
|
||||||
info "Klone $REPO_URL (Branch: $GIT_BRANCH)..."
|
|
||||||
git clone --quiet --branch "$GIT_BRANCH" --depth 1 "$REPO_URL" "$INSTALL_DIR"
|
|
||||||
ok "Repository geklont nach $INSTALL_DIR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Daten- und Log-Verzeichnisse sicherstellen
|
|
||||||
mkdir -p "$INSTALL_DIR/backend/data"
|
|
||||||
mkdir -p "$INSTALL_DIR/backend/logs"
|
|
||||||
mkdir -p "$INSTALL_DIR/backend/data/output/raw"
|
|
||||||
mkdir -p "$INSTALL_DIR/backend/data/output/movies"
|
|
||||||
mkdir -p "$INSTALL_DIR/backend/data/output/cd"
|
|
||||||
mkdir -p "$INSTALL_DIR/backend/data/logs"
|
|
||||||
|
|
||||||
# Gesicherte Daten zurückspielen
|
|
||||||
if [[ -n "${DATA_BACKUP:-}" && -d "$DATA_BACKUP" ]]; then
|
|
||||||
cp -a "$DATA_BACKUP/." "$INSTALL_DIR/backend/data/"
|
|
||||||
ok "Datenbank wiederhergestellt"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- npm-Abhängigkeiten installieren -----------------------------------------
|
|
||||||
header "npm-Abhängigkeiten installieren"
|
|
||||||
|
|
||||||
info "Root-Abhängigkeiten..."
|
|
||||||
npm install --prefix "$INSTALL_DIR" --omit=dev --silent
|
|
||||||
|
|
||||||
info "Backend-Abhängigkeiten..."
|
|
||||||
npm install --prefix "$INSTALL_DIR/backend" --omit=dev --silent
|
|
||||||
|
|
||||||
info "Frontend-Abhängigkeiten..."
|
|
||||||
npm install --prefix "$INSTALL_DIR/frontend" --silent
|
|
||||||
|
|
||||||
ok "npm-Abhängigkeiten installiert"
|
|
||||||
|
|
||||||
# --- Frontend bauen -----------------------------------------------------------
|
|
||||||
header "Frontend bauen"
|
|
||||||
|
|
||||||
info "Baue Frontend für $FRONTEND_HOST..."
|
|
||||||
|
|
||||||
# Relative URLs verwenden – funktioniert mit jedem Hostnamen/Domain, da nginx
|
|
||||||
# /api/ und /ws auf dem selben Host proxied. Absolute IP-URLs würden Chromes
|
|
||||||
# Private Network Access (PNA) Policy verletzen, wenn das Frontend über einen
|
|
||||||
# Domainnamen aufgerufen wird.
|
|
||||||
rm -f "$INSTALL_DIR/frontend/.env.production.local"
|
|
||||||
|
|
||||||
npm run build --prefix "$INSTALL_DIR/frontend" --silent
|
|
||||||
ok "Frontend gebaut: $INSTALL_DIR/frontend/dist"
|
|
||||||
|
|
||||||
# --- Backend-Konfiguration ---------------------------------------------------
|
|
||||||
header "Backend konfigurieren"
|
|
||||||
|
|
||||||
ENV_FILE="$INSTALL_DIR/backend/.env"
|
|
||||||
|
|
||||||
if [[ -f "$ENV_FILE" && "$REINSTALL" == true ]]; then
|
|
||||||
warn "Bestehende .env bleibt erhalten (--reinstall)"
|
|
||||||
else
|
|
||||||
info "Erstelle Backend .env..."
|
|
||||||
cat > "$ENV_FILE" <<EOF
|
|
||||||
# Ripster Backend – Konfiguration
|
|
||||||
# Generiert von install.sh am $(date)
|
|
||||||
|
|
||||||
PORT=${BACKEND_PORT}
|
|
||||||
DB_PATH=./data/ripster.db
|
|
||||||
LOG_DIR=./logs
|
|
||||||
LOG_LEVEL=info
|
|
||||||
|
|
||||||
# CORS: Erlaube Anfragen vom Frontend (nginx)
|
|
||||||
CORS_ORIGIN=http://${FRONTEND_HOST}
|
|
||||||
|
|
||||||
# Standard-Ausgabepfade (Fallback wenn in den Einstellungen kein Pfad gesetzt)
|
|
||||||
DEFAULT_RAW_DIR=${INSTALL_DIR}/backend/data/output/raw
|
|
||||||
DEFAULT_MOVIE_DIR=${INSTALL_DIR}/backend/data/output/movies
|
|
||||||
DEFAULT_CD_DIR=${INSTALL_DIR}/backend/data/output/cd
|
|
||||||
EOF
|
|
||||||
ok "Backend .env erstellt"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Berechtigungen setzen ---------------------------------------------------
|
|
||||||
chown -R "$SERVICE_USER:$SERVICE_USER" "$INSTALL_DIR"
|
|
||||||
chmod -R 755 "$INSTALL_DIR"
|
|
||||||
chmod 600 "$ENV_FILE"
|
|
||||||
|
|
||||||
# Ausgabe- und Log-Verzeichnisse dem installierenden User zuweisen
|
|
||||||
# (SUDO_USER = der echte User hinter sudo; leer wenn direkt als root ausgeführt)
|
|
||||||
ACTUAL_USER="${SUDO_USER:-}"
|
|
||||||
if [[ -n "$ACTUAL_USER" && "$ACTUAL_USER" != "root" ]]; then
|
|
||||||
chown -R "$ACTUAL_USER:$SERVICE_USER" \
|
|
||||||
"$INSTALL_DIR/backend/data/output" \
|
|
||||||
"$INSTALL_DIR/backend/data/logs"
|
|
||||||
chmod -R 775 \
|
|
||||||
"$INSTALL_DIR/backend/data/output" \
|
|
||||||
"$INSTALL_DIR/backend/data/logs"
|
|
||||||
ok "Verzeichnisse $ACTUAL_USER:$SERVICE_USER (775) zugewiesen"
|
|
||||||
else
|
|
||||||
ok "Verzeichnisse bereits $SERVICE_USER gehörig (kein SUDO_USER erkannt)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# MakeMKV erwartet pro Benutzer ein eigenes Konfigurationsverzeichnis.
|
|
||||||
# Laufzeit-relevant ist das Verzeichnis des Service-Users.
|
|
||||||
MAKEMKV_SERVICE_DIR="${SERVICE_HOME}/.MakeMKV"
|
|
||||||
if [[ ! -d "$MAKEMKV_SERVICE_DIR" ]]; then
|
|
||||||
mkdir -p "$MAKEMKV_SERVICE_DIR"
|
|
||||||
ok "MakeMKV-Verzeichnis erstellt: $MAKEMKV_SERVICE_DIR"
|
|
||||||
else
|
|
||||||
info "MakeMKV-Verzeichnis vorhanden: $MAKEMKV_SERVICE_DIR"
|
|
||||||
fi
|
|
||||||
chown "$SERVICE_USER:$SERVICE_USER" "$MAKEMKV_SERVICE_DIR" 2>/dev/null || true
|
|
||||||
chmod 700 "$MAKEMKV_SERVICE_DIR" 2>/dev/null || true
|
|
||||||
|
|
||||||
# --- Systemd-Dienst: Backend -------------------------------------------------
|
|
||||||
header "Systemd-Dienst (Backend) erstellen"
|
|
||||||
|
|
||||||
cat > /etc/systemd/system/ripster-backend.service <<EOF
|
|
||||||
[Unit]
|
|
||||||
Description=Ripster Backend API
|
|
||||||
After=network.target
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=${SERVICE_USER}
|
|
||||||
Group=${SERVICE_USER}
|
|
||||||
WorkingDirectory=${INSTALL_DIR}/backend
|
|
||||||
ExecStart=$(command -v node) src/index.js
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=5
|
|
||||||
StartLimitIntervalSec=60
|
|
||||||
StartLimitBurst=3
|
|
||||||
|
|
||||||
Environment=NODE_ENV=production
|
|
||||||
Environment=HOME=${SERVICE_HOME}
|
|
||||||
Environment=LANG=C.UTF-8
|
|
||||||
Environment=LC_ALL=C.UTF-8
|
|
||||||
Environment=LANGUAGE=C.UTF-8
|
|
||||||
EnvironmentFile=${INSTALL_DIR}/backend/.env
|
|
||||||
|
|
||||||
StandardOutput=journal
|
|
||||||
StandardError=journal
|
|
||||||
SyslogIdentifier=ripster-backend
|
|
||||||
|
|
||||||
# Kein statisches DeviceAllow: Device-Pfade unterscheiden sich je nach Host/Container.
|
|
||||||
# Damit Ripster auf unterschiedlichen Systemen funktioniert, kein Device-Cgroup-Filter.
|
|
||||||
DevicePolicy=auto
|
|
||||||
SupplementaryGroups=video render cdrom disk
|
|
||||||
|
|
||||||
# Für Skriptausführung via GUI (inkl. optionalem sudo in User-Skripten)
|
|
||||||
# darf no_new_privileges nicht aktiv sein.
|
|
||||||
NoNewPrivileges=false
|
|
||||||
ProtectSystem=full
|
|
||||||
ProtectHome=read-only
|
|
||||||
ReadWritePaths=${INSTALL_DIR}/backend/data ${INSTALL_DIR}/backend/logs /tmp ${SERVICE_HOME} ${MAKEMKV_SERVICE_DIR}
|
|
||||||
PrivateTmp=true
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
ok "ripster-backend.service erstellt"
|
|
||||||
|
|
||||||
# --- nginx konfigurieren -----------------------------------------------------
|
|
||||||
if [[ "$SKIP_NGINX" == false ]]; then
|
|
||||||
header "nginx konfigurieren"
|
|
||||||
|
|
||||||
cat > /etc/nginx/sites-available/ripster <<EOF
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name ${FRONTEND_HOST} _;
|
|
||||||
|
|
||||||
root ${INSTALL_DIR}/frontend/dist;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
try_files \$uri \$uri/ /index.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /api/ {
|
|
||||||
proxy_pass http://127.0.0.1:${BACKEND_PORT};
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Host \$host;
|
|
||||||
proxy_set_header X-Real-IP \$remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
||||||
proxy_read_timeout 300s;
|
|
||||||
proxy_connect_timeout 10s;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /ws {
|
|
||||||
proxy_pass http://127.0.0.1:${BACKEND_PORT}/ws;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade \$http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Host \$host;
|
|
||||||
proxy_read_timeout 3600s;
|
|
||||||
proxy_send_timeout 3600s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
rm -f /etc/nginx/sites-enabled/default
|
|
||||||
ln -sf /etc/nginx/sites-available/ripster /etc/nginx/sites-enabled/ripster
|
|
||||||
|
|
||||||
nginx -t && ok "nginx-Konfiguration gültig" || fatal "nginx-Konfiguration fehlerhaft!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Dienste starten ----------------------------------------------------------
|
|
||||||
header "Dienste starten"
|
|
||||||
|
|
||||||
systemctl daemon-reload
|
|
||||||
|
|
||||||
systemctl enable ripster-backend
|
|
||||||
systemctl restart ripster-backend
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
if systemctl is-active --quiet ripster-backend; then
|
|
||||||
ok "ripster-backend läuft"
|
|
||||||
else
|
|
||||||
error "ripster-backend konnte nicht gestartet werden!"
|
|
||||||
journalctl -u ripster-backend -n 30 --no-pager
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$SKIP_NGINX" == false ]]; then
|
|
||||||
systemctl enable nginx
|
|
||||||
systemctl restart nginx
|
|
||||||
if systemctl is-active --quiet nginx; then
|
|
||||||
ok "nginx läuft"
|
|
||||||
else
|
|
||||||
error "nginx konnte nicht gestartet werden!"
|
|
||||||
journalctl -u nginx -n 20 --no-pager
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Zusammenfassung ----------------------------------------------------------
|
|
||||||
header "Installation abgeschlossen!"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e " ${GREEN}${BOLD}Ripster ist installiert und läuft.${RESET}"
|
|
||||||
echo ""
|
|
||||||
if [[ "$SKIP_NGINX" == false ]]; then
|
|
||||||
echo -e " ${BOLD}Weboberfläche:${RESET} http://${FRONTEND_HOST}"
|
|
||||||
else
|
|
||||||
echo -e " ${BOLD}Backend API:${RESET} http://${FRONTEND_HOST}:${BACKEND_PORT}/api"
|
|
||||||
warn "nginx deaktiviert – Frontend nicht automatisch erreichbar."
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
echo -e " ${BOLD}Dienste verwalten:${RESET}"
|
|
||||||
echo -e " sudo systemctl status ripster-backend"
|
|
||||||
echo -e " sudo systemctl restart ripster-backend"
|
|
||||||
echo -e " sudo systemctl stop ripster-backend"
|
|
||||||
echo -e " sudo journalctl -u ripster-backend -f"
|
|
||||||
echo ""
|
|
||||||
echo -e " ${BOLD}Konfiguration:${RESET} $INSTALL_DIR/backend/.env"
|
|
||||||
echo -e " ${BOLD}Datenbank:${RESET} $INSTALL_DIR/backend/data/ripster.db"
|
|
||||||
echo -e " ${BOLD}Logs:${RESET} $INSTALL_DIR/backend/logs/"
|
|
||||||
echo -e " ${BOLD}Aktualisieren:${RESET} sudo bash $INSTALL_DIR/install.sh --reinstall"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
missing_tools=()
|
|
||||||
command_exists makemkvcon || missing_tools+=("makemkvcon")
|
|
||||||
command_exists HandBrakeCLI || missing_tools+=("HandBrakeCLI")
|
|
||||||
command_exists mediainfo || missing_tools+=("mediainfo")
|
|
||||||
command_exists cdparanoia || missing_tools+=("cdparanoia")
|
|
||||||
command_exists flac || missing_tools+=("flac")
|
|
||||||
command_exists lame || missing_tools+=("lame")
|
|
||||||
command_exists opusenc || missing_tools+=("opusenc")
|
|
||||||
command_exists oggenc || missing_tools+=("oggenc")
|
|
||||||
|
|
||||||
if [[ ${#missing_tools[@]} -gt 0 ]]; then
|
|
||||||
echo -e " ${YELLOW}${BOLD}Hinweis:${RESET} Folgende Tools fehlen noch:"
|
|
||||||
for t in "${missing_tools[@]}"; do
|
|
||||||
echo -e " ${YELLOW}✗${RESET} $t"
|
|
||||||
done
|
|
||||||
echo -e " Diese können in den Ripster-Einstellungen konfiguriert werden."
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
154
setup.sh
154
setup.sh
@@ -1,154 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
REPO_OWNER="Mboehmlaender"
|
|
||||||
REPO_NAME="ripster"
|
|
||||||
REPO_RAW_BASE="https://raw.githubusercontent.com/${REPO_OWNER}/${REPO_NAME}"
|
|
||||||
BRANCHES_API_URL="https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/branches?per_page=100"
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<'EOF'
|
|
||||||
Verwendung:
|
|
||||||
bash setup.sh [Optionen]
|
|
||||||
|
|
||||||
Optionen (wie install.sh):
|
|
||||||
--branch <branch> Branch direkt setzen (ohne Auswahlmenue)
|
|
||||||
--dir <pfad> Installationsverzeichnis
|
|
||||||
--user <benutzer> Systembenutzer fuer den Dienst
|
|
||||||
--port <port> Backend-Port
|
|
||||||
--host <hostname> Hostname/IP fuer die Weboberflaeche
|
|
||||||
--no-makemkv MakeMKV-Installation ueberspringen
|
|
||||||
--no-handbrake HandBrake-Installation ueberspringen
|
|
||||||
--no-nginx Nginx-Einrichtung ueberspringen
|
|
||||||
--reinstall Vorhandene Installation aktualisieren
|
|
||||||
-h, --help Hilfe anzeigen
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
SELECTED_BRANCH=""
|
|
||||||
FORWARDED_ARGS=()
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--branch)
|
|
||||||
[[ $# -ge 2 ]] || { echo "Fehlender Wert fuer --branch" >&2; exit 1; }
|
|
||||||
SELECTED_BRANCH="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--dir|--user|--port|--host)
|
|
||||||
[[ $# -ge 2 ]] || { echo "Fehlender Wert fuer $1" >&2; exit 1; }
|
|
||||||
FORWARDED_ARGS+=("$1" "$2")
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--no-makemkv|--no-handbrake|--no-nginx|--reinstall)
|
|
||||||
FORWARDED_ARGS+=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h|--help)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unbekannter Parameter: $1" >&2
|
|
||||||
usage >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
fetch_url() {
|
|
||||||
local url="$1"
|
|
||||||
|
|
||||||
if command -v curl >/dev/null 2>&1; then
|
|
||||||
curl -fsSL "$url"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v wget >/dev/null 2>&1; then
|
|
||||||
wget -qO- "$url"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Weder curl noch wget gefunden. Bitte eines davon installieren." >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
download_file() {
|
|
||||||
local url="$1"
|
|
||||||
local target="$2"
|
|
||||||
fetch_url "$url" > "$target"
|
|
||||||
}
|
|
||||||
|
|
||||||
select_branch() {
|
|
||||||
local branches_json
|
|
||||||
local -a branches
|
|
||||||
local selection
|
|
||||||
|
|
||||||
branches_json="$(fetch_url "$BRANCHES_API_URL")"
|
|
||||||
mapfile -t branches < <(
|
|
||||||
printf '%s\n' "$branches_json" \
|
|
||||||
| grep -oE '"name"[[:space:]]*:[[:space:]]*"[^"]+"' \
|
|
||||||
| sed -E 's/"name"[[:space:]]*:[[:space:]]*"([^"]+)"/\1/'
|
|
||||||
)
|
|
||||||
|
|
||||||
if [[ ${#branches[@]} -eq 0 ]]; then
|
|
||||||
echo "Keine Branches gefunden oder API-Antwort ungültig." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "$SELECTED_BRANCH" ]]; then
|
|
||||||
local found=false
|
|
||||||
for branch in "${branches[@]}"; do
|
|
||||||
if [[ "$branch" == "$SELECTED_BRANCH" ]]; then
|
|
||||||
found=true
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [[ "$found" == false ]]; then
|
|
||||||
echo "Branch '$SELECTED_BRANCH' nicht gefunden." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -t 0 ]]; then
|
|
||||||
echo "Kein interaktives Terminal für die Branch-Auswahl verfügbar." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Verfügbare Branches:"
|
|
||||||
for i in "${!branches[@]}"; do
|
|
||||||
printf " %2d) %s\n" "$((i + 1))" "${branches[$i]}"
|
|
||||||
done
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
read -r -p "Bitte Branch auswählen [1-${#branches[@]}]: " selection
|
|
||||||
if [[ "$selection" =~ ^[0-9]+$ ]] && (( selection >= 1 && selection <= ${#branches[@]} )); then
|
|
||||||
SELECTED_BRANCH="${branches[$((selection - 1))]}"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
echo "Ungültige Auswahl."
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
TMP_DIR="$(mktemp -d)"
|
|
||||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
||||||
|
|
||||||
select_branch
|
|
||||||
|
|
||||||
INSTALL_SCRIPT="${TMP_DIR}/install.sh"
|
|
||||||
INSTALL_URL="${REPO_RAW_BASE}/${SELECTED_BRANCH}/install.sh"
|
|
||||||
|
|
||||||
echo "Lade install.sh aus Branch '${SELECTED_BRANCH}'..."
|
|
||||||
download_file "$INSTALL_URL" "$INSTALL_SCRIPT"
|
|
||||||
chmod +x "$INSTALL_SCRIPT"
|
|
||||||
|
|
||||||
if [[ $EUID -eq 0 ]]; then
|
|
||||||
bash "$INSTALL_SCRIPT" --branch "$SELECTED_BRANCH" "${FORWARDED_ARGS[@]}"
|
|
||||||
else
|
|
||||||
if ! command -v sudo >/dev/null 2>&1; then
|
|
||||||
echo "sudo nicht gefunden. Bitte als root ausführen." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
sudo bash "$INSTALL_SCRIPT" --branch "$SELECTED_BRANCH" "${FORWARDED_ARGS[@]}"
|
|
||||||
fi
|
|
||||||
Reference in New Issue
Block a user