#!/bin/bash # ============================================================================================== # ========================= Upgrade Webhook Setup ============================================= # ============================================================================================== # # PURPOSE # ───────────────────────────────────────────────────────────────────────────── # Registers the Varaverk upgrade webhook in Sonarr, Radarr, and Lidarr via # their notification APIs. Idempotent — skips any arr that already has it. # # Run once after first install, or any time you add a new arr or host. # The listener (start_webhook_listener.sh) must be running before arrs will # actually deliver events, but this script can register the connection first. # # ============================================================================================== # OPERATIONAL MODEL # ============================================================================================== # # 1. Generate WEBHOOK_SECRET in master.conf if empty # 2. Register webhook in each local arr (Sonarr / Radarr / Lidarr) # 3. SSH to remote host and run itself there (unless --local-only) # # ============================================================================================== # DESIGN PRINCIPLES # ============================================================================================== # # Idempotent Registration # Skips any arr that already has the webhook registered. Safe to re-run after # adding a new arr or after a conf change without creating duplicate entries. # # Self-Propagating # SSHes to the remote and runs itself with --local-only — one execution # configures both servers without a separate remote step. # # ============================================================================================== # OPERATIONAL SAFEGUARDS # ============================================================================================== # # Idempotent — skips arrs that already have the webhook registered # Secret auto-gen — WEBHOOK_SECRET generated if empty; never left blank # --local-only — used internally for SSH; prevents infinite recursion # --dry-run mode — shows what would be registered without making API calls # # ============================================================================================== # RUNTIME MODES # ============================================================================================== # # webhook_setup.sh # Configure local arrs, then SSH to remote and configure remote arrs. # # webhook_setup.sh --local-only # Local arrs only (used internally when called via SSH on the remote). # # webhook_setup.sh --dry-run # Show what would be registered without making any changes. # # ============================================================================================== set -uo pipefail LOCAL_ONLY=false DRY_RUN=false for arg in "$@"; do case "$arg" in --local-only) LOCAL_ONLY=true ;; --dry-run) DRY_RUN=true ;; esac done SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ECOSYSTEM_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" MASTER_CONF="$ECOSYSTEM_ROOT/Configurations/master.conf" source "$ECOSYSTEM_ROOT/load_config.sh" detect_hosts WEBHOOK_NAME="Varaverk Upgrade" # ── Resolve or generate the secret ────────────────────────────────────────── # OVERRIDE_SECRET env var is set when called recursively via SSH from the # primary host, so both ends use the same secret. if [[ -n "${OVERRIDE_SECRET:-}" ]]; then if [[ -z "${WEBHOOK_SECRET:-}" ]]; then sed -i "s/WEBHOOK_SECRET=\"\"/WEBHOOK_SECRET=\"$OVERRIDE_SECRET\"/" "$MASTER_CONF" fi WEBHOOK_SECRET="$OVERRIDE_SECRET" fi if [[ -z "${WEBHOOK_SECRET:-}" ]]; then if [[ "$DRY_RUN" == true ]]; then WEBHOOK_SECRET="" else GENERATED=$(openssl rand -hex 32) sed -i "s/WEBHOOK_SECRET=\"\"/WEBHOOK_SECRET=\"$GENERATED\"/" "$MASTER_CONF" WEBHOOK_SECRET="$GENERATED" echo "Generated WEBHOOK_SECRET — saved to master.conf" fi fi LOCAL_IP=$(hostname -I | awk '{print $1}') WEBHOOK_URL="http://${LOCAL_IP}:${WEBHOOK_PORT}/webhook?key=${WEBHOOK_SECRET}" # ── Helper: register webhook in one arr ───────────────────────────────────── _register() { local label="$1" base_url="$2" api_key="$3" api_ver="$4" local import_field="$5" # onDownload (Sonarr/Radarr) or onReleaseImport (Lidarr) if [[ "$DRY_RUN" == true ]]; then echo " [$label] Would register → $WEBHOOK_URL" return 0 fi # Check if already registered by name local existing existing=$(curl -sf --max-time 5 \ -H "X-Api-Key: $api_key" \ "$base_url/api/$api_ver/notification" 2>/dev/null) || { echo " [$label] Cannot reach arr — skipping" return 1 } if echo "$existing" | grep -q "\"name\":[[:space:]]*\"${WEBHOOK_NAME}\""; then echo " [$label] Already registered — skipping" return 0 fi local payload payload=$(printf '{ "name": "%s", "implementation": "Webhook", "configContract": "WebhookSettings", "onGrab": false, "%s": true, "onUpgrade": true, "onRename": false, "onHealthIssue": false, "includeHealthWarnings": false, "onApplicationUpdate": false, "tags": [], "fields": [ {"name": "url", "value": "%s"}, {"name": "method", "value": 1}, {"name": "username", "value": ""}, {"name": "password", "value": ""} ] }' "$WEBHOOK_NAME" "$import_field" "$WEBHOOK_URL") local http_code http_code=$(curl -sf --max-time 5 -o /dev/null -w '%{http_code}' \ -X POST \ -H "X-Api-Key: $api_key" \ -H 'Content-Type: application/json' \ -d "$payload" \ "$base_url/api/$api_ver/notification" 2>/dev/null) if [[ "$http_code" == "201" || "$http_code" == "200" ]]; then echo " [$label] Registered ✅ → $WEBHOOK_URL" else echo " [$label] Failed (HTTP ${http_code:-timeout})" return 1 fi } # ── Local arrs ─────────────────────────────────────────────────────────────── echo "" echo "━━━ Upgrade Webhook Setup — $MY_ID ($LOCAL_SERVER_NAME) ━━━" echo " LAN IP : $LOCAL_IP" echo " Port : $WEBHOOK_PORT" echo " URL : $WEBHOOK_URL" echo "" [[ -n "${SONARR_URL:-}" && -n "${SONARR_API_KEY:-}" ]] && \ _register "Sonarr" "$SONARR_URL" "$SONARR_API_KEY" "v3" "onDownload" [[ -n "${RADARR_URL:-}" && -n "${RADARR_API_KEY:-}" ]] && \ _register "Radarr" "$RADARR_URL" "$RADARR_API_KEY" "v3" "onDownload" [[ -n "${LIDARR_URL:-}" && -n "${LIDARR_API_KEY:-}" ]] && \ _register "Lidarr" "$LIDARR_URL" "$LIDARR_API_KEY" "v1" "onReleaseImport" # ── Remote host ─────────────────────────────────────────────────────────────── if [[ "$LOCAL_ONLY" == false && -n "${REMOTE_ID:-}" ]]; then echo "" echo "━━━ Configuring remote: $REMOTE_SERVER_NAME ━━━" remote_ip=$(resolve_tailscale_ip "$REMOTE_SERVER_NAME") || { echo " Cannot resolve Tailscale IP for $REMOTE_SERVER_NAME — skipping" echo " Run manually on that host: Tools/webhook_setup.sh --local-only" echo "" exit 0 } remote_flags="--local-only" [[ "$DRY_RUN" == true ]] && remote_flags="$remote_flags --dry-run" ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o StrictHostKeyChecking=no \ root@"$remote_ip" \ "OVERRIDE_SECRET='$WEBHOOK_SECRET' bash /boot/config/plugins/varaverk/Tools/webhook_setup.sh $remote_flags" \ || echo " Remote setup failed — check SSH and that Varaverk is installed on $REMOTE_SERVER_NAME" fi echo "" echo "Done."