feat: arr-native distributed media sync + config architecture fixes

Arr sync (new):
- Media/arr_sync.sh — full mesh bidirectional sync across all HOST* nodes
  - Lidarr (MusicBrainz), Sonarr (TVDB), Radarr (TMDB) all handled in one script
  - Remote API keys read live from config.xml via SSH — never stored in conf files
  - Shared blocklist (DATA_DIR/arr_sync_blocklist.tsv) merged from all nodes at runtime
  - Graceful skip if arr not configured locally or not reachable on a remote node
  - --blocklist-add / --blocklist-remove / --blocklist-list management flags
- daily_sync_maintenance.sh — arr sync runs as explicit phase before rsync
- partnership_onboard.sh — Step 3 bootstraps merged library on both sides at onboard
- master.conf — ARR_SYNC_* config block, DOCKER_APPDATA_BASE

Rsync / cleanup:
- DEFAULT_RSYNC_OPTS — removed --delete; arr_cleanup.sh owns orphan enforcement
- lidarr_cleanup.sh — removed HOST1-only guard; runs on any node with Lidarr configured

Config architecture:
- HOST1/HOST2 hostnames moved from master_host*.conf → master.conf (not credentials)
- Sparse checkout now works correctly: each server only needs its own host conf
- detect_hosts() still resolves MY_ID + REMOTE_ID via master.conf hostname values

Bug fix:
- common.sh line 493 — watchdog toggle eval had broken quoting; all SYS_WATCHDOG_CHECK_*
  globals were silently set to empty instead of their configured values

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gmer4Lfe
2026-05-09 09:53:40 -04:00
co-authored by Claude Sonnet 4.6
parent 009820e981
commit b65f572367
21 changed files with 1548 additions and 272 deletions
+10 -12
View File
@@ -62,8 +62,6 @@ if [[ "$EUID" -ne 0 ]]; then
error "Must be run as root"
exit 1
fi
success "Running as root"
acquire_lock
# detect_hosts() sets MY_ID — needed for sparse checkout configuration
@@ -84,7 +82,7 @@ else
log "Gitea not running locally — checking remote server"
GITEA_IP=$(tailscale ip -4 "${REMOTE_SERVER_NAME,,}" 2>/dev/null)
if [[ -n "$GITEA_IP" ]]; then
info "$ICON_NET Gitea on $REMOTE_SERVER_NAME — connecting via Tailscale $GITEA_IP"
echo " Gitea on $REMOTE_SERVER_NAME — connecting via Tailscale $GITEA_IP"
elif [[ -n "${GITEA_DOMAIN:-}" ]]; then
warn "Tailscale resolution failed — falling back to $GITEA_DOMAIN"
GITEA_IP="$GITEA_DOMAIN"
@@ -172,7 +170,7 @@ configure_sparse_checkout() {
done
if [[ "$excluded" -gt 0 ]]; then
info "$ICON_LOCK Sparse checkout: excluding $excluded peer conf file(s) — credentials protected"
echo " Sparse checkout: excluding $excluded peer conf file(s) — credentials protected"
else
log "Sparse checkout: no peer conf files to exclude (single server or first run)"
fi
@@ -201,7 +199,7 @@ else
if [[ -d ".git" ]]; then
# ── Existing repository ──────────────────────────────────────────────
info "$ICON_SYNC Existing repository detected — updating"
echo " Existing repository — updating"
# Configure sparse checkout BEFORE pull
# Uses conf files already present from last pull to determine exclusions
@@ -213,9 +211,9 @@ else
log "git clean -fd"
git clean -fd
info "Pulling latest changes..."
echo " Pulling latest changes..."
if GIT_SSH_COMMAND="ssh -i $GITEA_SSH_KEY -p $SSH_PORT" git pull; then
success "Git pull successful"
echo " Git pull successful"
SYNC_SUCCESS=true
else
error "Git pull failed"
@@ -225,20 +223,20 @@ else
else
# ── Fresh clone ──────────────────────────────────────────────────────
info "$ICON_SYNC No repository found — cloning"
echo " No repository found — cloning"
# Clone first — need the repo to exist before configuring sparse checkout
if GIT_SSH_COMMAND="ssh -i $GITEA_SSH_KEY -p $SSH_PORT" git clone "$REPO_SSH" .; then
success "Clone successful"
echo " Clone successful"
# Configure sparse checkout after clone
# Now all master_host*.conf files are present — can detect exclusions
configure_sparse_checkout "$TARGET_DIR"
# Apply sparse checkout — removes excluded files from working tree
info "Applying sparse checkout..."
echo " Applying sparse checkout..."
git read-tree -mu HEAD
success "Sparse checkout applied — peer credentials removed from working tree"
echo " Sparse checkout applied — peer credentials removed from working tree"
SYNC_SUCCESS=true
else
@@ -253,7 +251,7 @@ else
echo "━━━ $ICON_GEAR Permissions ━━━"
log "Setting executable permissions on all .sh files..."
find "$TARGET_DIR" -type f -name "*.sh" -exec chmod +x {} \;
log "Permissions applied"
echo " Permissions set on .sh files"
fi
END=$(date +%s)