#!/bin/sh # ========================================================================== # WeBrake installer — run this INSIDE an existing Alpine Linux LXC. # wget -qO- https://gogs.av2x.dev/av2x/WeBrake/raw/master/install.sh | ash # # It will refuse to run on a Proxmox host. Nothing is ever installed from # the host side; GPU passthru is host *configuration* only (see README). # Files are pulled from the repo. token.json is generated locally and is # never fetched from, nor pushed to, the repository. # ========================================================================== set -eu REPO_BASE="${WEBRAKE_REPO_BASE:-https://gogs.av2x.dev/av2x/WeBrake/raw}" BRANCHES="${WEBRAKE_BRANCH:-master main}" APP_DIR="/opt/webrake" DATA_DIR="/var/lib/webrake" PORT="${WEBRAKE_PORT:-8090}" say() { printf '\033[1;33m[WeBrake]\033[0m %s\n' "$*"; } die() { printf '\033[1;31m[WeBrake]\033[0m %s\n' "$*" >&2; exit 1; } # fetch [alt-path…] — tries every branch/path # combo and validates the payload so a Gogs error/login page is never installed. fetch() { dest="$1"; check="$2"; shift 2 for br in $BRANCHES; do for p in "$@"; do url="$REPO_BASE/$br/$p" if wget -q -O "$dest.tmp" "$url" && [ -s "$dest.tmp" ] \ && head -c 4096 "$dest.tmp" | grep -q "$check"; then mv "$dest.tmp" "$dest" say " fetched $p (branch: $br)" return 0 fi done done rm -f "$dest.tmp" return 1 } # ---- guard rails --------------------------------------------------------- [ "$(id -u)" = "0" ] || die "Run as root inside the Alpine container." command -v pveversion >/dev/null 2>&1 && \ die "This looks like a Proxmox HOST. Run the installer inside the Alpine LXC instead." [ -f /etc/alpine-release ] || \ die "This installer targets Alpine Linux. /etc/alpine-release not found." say "Installing on Alpine $(cat /etc/alpine-release)" # ---- packages ------------------------------------------------------------ say "Installing packages (python3, flask, handbrake, VA-API drivers)…" apk update >/dev/null apk add --no-cache python3 py3-flask wget ca-certificates >/dev/null if ! command -v HandBrakeCLI >/dev/null 2>&1; then if ! apk add --no-cache handbrake >/dev/null 2>&1; then say "handbrake not in enabled repos — trying community/testing…" REL="$(cut -d. -f1,2 /etc/alpine-release)" apk add --no-cache handbrake \ --repository="https://dl-cdn.alpinelinux.org/alpine/v${REL}/community" \ >/dev/null 2>&1 || \ apk add --no-cache handbrake \ --repository="https://dl-cdn.alpinelinux.org/alpine/edge/community" \ --repository="https://dl-cdn.alpinelinux.org/alpine/edge/main" \ >/dev/null 2>&1 || \ die "Could not install the 'handbrake' package. Enable the community repository in /etc/apk/repositories and re-run." fi fi say "HandBrakeCLI: $(HandBrakeCLI --version 2>/dev/null | head -n1 || echo installed)" # GPU userspace drivers (harmless if no GPU is passed through) apk add --no-cache libva libva-utils mesa-va-gallium intel-media-driver libdrm >/dev/null 2>&1 || \ say "VA-API driver packages unavailable on this release — skipping (software encode still works)." # ---- app files from repo --------------------------------------------------- say "Pulling application files from ${REPO_BASE} (branches tried: ${BRANCHES})…" mkdir -p "$APP_DIR/static" "$DATA_DIR/uploads" "$DATA_DIR/output" "$DATA_DIR/jobs" fetch "$APP_DIR/app.py" "^#!/usr/bin/env python3" "app.py" \ || die "Failed to fetch a valid app.py — check the repo URL, branch name, and that the repo is public." fetch "$APP_DIR/static/index.html" "^" "static/index.html" "index.html" \ || die "Failed to fetch a valid index.html — expected at static/index.html (or repo root) on branch master or main." fetch "$APP_DIR/update.sh" "^#!/bin/sh" "update.sh" \ || die "Failed to fetch a valid update.sh from the repo." chmod +x "$APP_DIR/update.sh" # ---- token.json (generated locally, NEVER from the repo) ------------------- if [ -f "$APP_DIR/token.json" ]; then say "token.json already exists — keeping existing secrets." else say "Generating token.json (local secrets — not stored in the repo)…" python3 - "$APP_DIR/token.json" <<'PYEOF' import json, secrets, sys, os path = sys.argv[1] tok = { "api_token": secrets.token_urlsafe(32), "secret_key": secrets.token_urlsafe(32), "require_auth": False, "bots": {} } with open(path, "w") as f: json.dump(tok, f, indent=2) os.chmod(path, 0o600) print(" api_token:", tok["api_token"]) PYEOF say "Set \"require_auth\": true in $APP_DIR/token.json to require this token for all API/bot access." fi # ---- OpenRC service --------------------------------------------------------- say "Installing OpenRC service…" cat > /etc/init.d/webrake </dev/null 2>&1 || true rc-service webrake restart >/dev/null 2>&1 || rc-service webrake start IP="$(ip -4 addr show scope global 2>/dev/null | awk '/inet /{print $2}' | cut -d/ -f1 | head -n1)" say "Done. WeBrake is running at: http://${IP:-}:${PORT}" say "Update any time with: $APP_DIR/update.sh"