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
+6 -7
View File
@@ -66,8 +66,6 @@ if [[ "$EUID" -ne 0 ]]; then
error "Must be run as root"
exit 1
fi
success "Running as root"
acquire_lock
if ! command -v docker &>/dev/null; then
@@ -75,7 +73,6 @@ if ! command -v docker &>/dev/null; then
notify "Docker daily restart failed — Docker not found on $(hostname)" "Docker Daily Restart" "warning"
exit 1
fi
success "Docker found"
# detect_hosts() sets MY_ID and aliases HOST*_DAILY_RESTART_CONTAINERS → DAILY_RESTART_CONTAINERS
detect_hosts
@@ -86,6 +83,8 @@ if [[ ${#DAILY_RESTART_CONTAINERS[@]} -eq 0 ]]; then
exit 0
fi
echo " $MY_ID ($LOCAL_SERVER_NAME) — ${#DAILY_RESTART_CONTAINERS[@]} containers configured"
# ==============================================================================================
# ━━━ Status ━━━
# ==============================================================================================
@@ -114,10 +113,10 @@ retry_docker() {
local attempt=1
while [[ "$attempt" -le "$RETRY_COUNT" ]]; do
info "$ICON_RETRY Attempt $attempt of $RETRY_COUNT: $*"
log "$ICON_RETRY Attempt $attempt of $RETRY_COUNT: $*"
if "$@"; then
success "Succeeded on attempt $attempt"
log "Succeeded on attempt $attempt"
return 0
else
warn "Attempt $attempt failed"
@@ -225,7 +224,7 @@ check_dependency_delay() {
local deps="${WATCHDOG_DEPENDENCIES[$container]:-}"
if [[ -n "$deps" ]] && [[ "$deps" == *"$last"* ]]; then
info "Waiting ${CONTAINER_DELAY}s — $container depends on $last..."
echo " Waiting ${CONTAINER_DELAY}s — $container depends on $last..."
sleep "$CONTAINER_DELAY"
fi
}
@@ -240,7 +239,7 @@ retry_docker() {
info "$ICON_RETRY Attempt $attempt of $RETRY_COUNT: $*"
if docker_cmd "$@"; then
success "Succeeded on attempt $attempt"
log "Succeeded on attempt $attempt"
return 0
else
warn "Attempt $attempt failed"