|
|
@@ -1,18 +1,17 @@
|
|
|
#!/bin/sh
|
|
|
-# ---------------------------------------------------------------------------
|
|
|
-# WeBrake installer — run INSIDE an existing Alpine Linux LXC container.
|
|
|
-#
|
|
|
+# ==========================================================================
|
|
|
+# WeBrake installer — run this INSIDE an existing Alpine Linux LXC.
|
|
|
# wget -qO- https://gogs.av2x.dev/av2x/WeBrake/raw/master/install.sh | ash
|
|
|
#
|
|
|
-# This script never touches the Proxmox host. It:
|
|
|
-# 1. Installs Python, HandBrakeCLI and VA-API drivers via apk
|
|
|
-# 2. Pulls app.py / index.html / update.sh from the repo
|
|
|
-# 3. Generates a local token.json (never fetched from, or pushed to, the repo)
|
|
|
-# 4. Registers and starts an OpenRC service
|
|
|
-# ---------------------------------------------------------------------------
|
|
|
+# 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_RAW="${WEBRAKE_REPO:-https://gogs.av2x.dev/av2x/WeBrake/raw/master}"
|
|
|
+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}"
|
|
|
@@ -20,77 +19,106 @@ 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; }
|
|
|
|
|
|
-# --- sanity: Alpine, root, inside a container -------------------------------
|
|
|
+# fetch <dest> <validator-grep> <path> [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."
|
|
|
-[ -f /etc/alpine-release ] || die "This installer only supports Alpine Linux (run it inside the LXC, not on the Proxmox host)."
|
|
|
-if [ -r /proc/1/environ ] && grep -qa 'container=' /proc/1/environ 2>/dev/null; then :; fi
|
|
|
+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 packages via apk..."
|
|
|
-# HandBrake lives in the community repository — make sure it is enabled.
|
|
|
-if ! grep -Eq '^[^#].*community' /etc/apk/repositories; then
|
|
|
- ALPINE_VER=$(cut -d. -f1,2 /etc/alpine-release)
|
|
|
- echo "https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VER}/community" >> /etc/apk/repositories
|
|
|
- say "Enabled the Alpine community repository."
|
|
|
-fi
|
|
|
-apk update
|
|
|
-apk add --no-cache python3 py3-flask wget ca-certificates
|
|
|
+say "Installing on Alpine $(cat /etc/alpine-release)"
|
|
|
|
|
|
-if ! apk add --no-cache handbrake >/dev/null 2>&1; then
|
|
|
- say "handbrake not in this release's community repo — trying edge/community..."
|
|
|
- apk add --no-cache handbrake \
|
|
|
- --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community \
|
|
|
- --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main \
|
|
|
- || die "Could not install HandBrakeCLI via apk. Install it manually, then re-run."
|
|
|
-fi
|
|
|
+# ---- 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
|
|
|
|
|
|
-# VA-API / QSV userspace drivers (harmless if no GPU is passed through)
|
|
|
-apk add --no-cache libva libva-utils mesa-va-gallium intel-media-driver 2>/dev/null || \
|
|
|
- say "GPU driver packages unavailable on this release — software encoding will still work."
|
|
|
+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)"
|
|
|
|
|
|
-command -v HandBrakeCLI >/dev/null || die "HandBrakeCLI is not on PATH after install."
|
|
|
-say "HandBrake: $(HandBrakeCLI --version 2>&1 | head -n1)"
|
|
|
+# 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)."
|
|
|
|
|
|
-# --- fetch application files from the repo ----------------------------------
|
|
|
-say "Pulling application files from ${REPO_RAW} ..."
|
|
|
-mkdir -p "$APP_DIR" "$DATA_DIR"
|
|
|
-for f in app.py index.html update.sh; do
|
|
|
- wget -q -O "$APP_DIR/$f.new" "$REPO_RAW/$f" || die "Failed to fetch $f from the repo."
|
|
|
- mv "$APP_DIR/$f.new" "$APP_DIR/$f"
|
|
|
-done
|
|
|
+# ---- 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" "^<!DOCTYPE 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"
|
|
|
|
|
|
-# --- generate token.json locally (NEVER pulled from or pushed to the repo) --
|
|
|
-if [ ! -f "$APP_DIR/token.json" ]; then
|
|
|
- say "Generating local token.json ..."
|
|
|
- python3 - "$APP_DIR/token.json" <<'PY'
|
|
|
+# ---- 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({
|
|
|
- "api_token": secrets.token_urlsafe(32),
|
|
|
- "secret_key": secrets.token_urlsafe(32),
|
|
|
- "note": "Generated locally by WeBrake. Do not commit this file."
|
|
|
- }, f, indent=2)
|
|
|
+ json.dump(tok, f, indent=2)
|
|
|
os.chmod(path, 0o600)
|
|
|
-PY
|
|
|
-else
|
|
|
- say "Existing token.json found — keeping it."
|
|
|
+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 "Registering OpenRC service..."
|
|
|
+# ---- OpenRC service ---------------------------------------------------------
|
|
|
+say "Installing OpenRC service…"
|
|
|
cat > /etc/init.d/webrake <<EOF
|
|
|
#!/sbin/openrc-run
|
|
|
-name="WeBrake"
|
|
|
-description="WeBrake HandBrake web UI"
|
|
|
+name="webrake"
|
|
|
+description="WeBrake — HandBrake web UI"
|
|
|
command="/usr/bin/python3"
|
|
|
command_args="$APP_DIR/app.py"
|
|
|
-command_background="yes"
|
|
|
-directory="$APP_DIR"
|
|
|
+command_background=true
|
|
|
pidfile="/run/webrake.pid"
|
|
|
output_log="/var/log/webrake.log"
|
|
|
error_log="/var/log/webrake.log"
|
|
|
export WEBRAKE_PORT="$PORT"
|
|
|
+export WEBRAKE_DATA="$DATA_DIR"
|
|
|
|
|
|
depend() {
|
|
|
need net
|
|
|
@@ -100,18 +128,6 @@ chmod +x /etc/init.d/webrake
|
|
|
rc-update add webrake default >/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)
|
|
|
-TOKEN=$(python3 -c "import json;print(json.load(open('$APP_DIR/token.json'))['api_token'])")
|
|
|
-
|
|
|
-say "----------------------------------------------------------------"
|
|
|
-say "WeBrake is up."
|
|
|
-say " URL: http://${IP:-<container-ip>}:${PORT}"
|
|
|
-say " API token: ${TOKEN}"
|
|
|
-say " Token file: $APP_DIR/token.json (local only — never in the repo)"
|
|
|
-say " Update: $APP_DIR/update.sh"
|
|
|
-if [ ! -e /dev/dri ] && [ ! -e /dev/nvidia0 ]; then
|
|
|
-say " GPU: no /dev/dri or /dev/nvidia* visible. To enable hardware"
|
|
|
-say " encoding, add a device passthrough to this container's"
|
|
|
-say " config on the Proxmox host (see README), then restart it."
|
|
|
-fi
|
|
|
-say "----------------------------------------------------------------"
|
|
|
+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:-<container-ip>}:${PORT}"
|
|
|
+say "Update any time with: $APP_DIR/update.sh"
|