diff --git a/Deployment/host.conf.template b/Deployment/host.conf.template index ec05091..e27d74c 100644 --- a/Deployment/host.conf.template +++ b/Deployment/host.conf.template @@ -235,13 +235,11 @@ # ━━━ HOSTN Rsync Profile — hostn-appdata ━━━ # Host-specific appdata sync profile. + # Retry/sleep/container-delay omitted — this profile uses the master.conf defaults for all three. PROFILE_RSYNC_OPTS[hostn-appdata]="-av --info=progress2 --bwlimit=${PROFILE_BW_LIMIT[hostn-appdata]:-8000}" PROFILE_BW_LIMIT[hostn-appdata]=8000 - PROFILE_RETRY_COUNT[hostn-appdata]=3 - PROFILE_SLEEP[hostn-appdata]=300 PROFILE_CRITICAL_CONTAINER_NAMES[hostn-appdata]="" PROFILE_DELAYED_CONTAINERS[hostn-appdata]="" - PROFILE_CONTAINER_DELAY[hostn-appdata]=5 PROFILE_EXCLUDE_DIRS[hostn-appdata]="logs *.tmp" # ============================================================================================== diff --git a/Deployment/master.conf.template b/Deployment/master.conf.template index 9e31b3a..0edb34a 100644 --- a/Deployment/master.conf.template +++ b/Deployment/master.conf.template @@ -605,8 +605,10 @@ # important-data — NextCloud + Postgres — NextCloud delayed start after Postgres # emby — weekly clean sync — both Emby stopped, full mirror # called by weekly_sync_maintenance.sh only — do NOT schedule separately -# emby-fallback — dirty sync — Emby stays running, WAL excluded -# called by critical_sync_maintenance.sh every 30min +# +# Every profile lookup falls back to the global default when a key is absent +# (${PROFILE_X[name]:-$DEFAULT}), so the value/delay/retry/sleep arrays below only list +# profiles that differ from the default — anything not listed inherits it. declare -A PROFILE_RSYNC_OPTS=( [arrs_stack]="-av --info=progress2 --human-readable --bwlimit=$BW_LIMIT --delete --inplace" @@ -614,7 +616,6 @@ [critical-fallback]="-av --human-readable --bwlimit=$BW_LIMIT --delete --inplace --no-whole-file" [important-data]="-av --human-readable --bwlimit=$BW_LIMIT" [emby]="-av --human-readable --bwlimit=$BW_LIMIT --delete --inplace --no-whole-file" - [emby-fallback]="-av --human-readable --bwlimit=$BW_LIMIT --delete --inplace --no-whole-file" ) # Per-profile bandwidth limits in KB/s @@ -624,27 +625,11 @@ [critical-fallback]=9500 # high — small dataset, sync fast [important-data]=9500 # high — database sync [emby]=8000 # medium — large full mirror - [emby-fallback]=9500 # high — small critical dataset ) -# Retry attempts per profile - declare -A PROFILE_RETRY_COUNT=( - [arrs_stack]=3 - [critical-data]=3 - [critical-fallback]=3 - [important-data]=3 - [emby]=3 - [emby-fallback]=3 - ) - -# Seconds between retry attempts +# Seconds between retry attempts — only non-default profiles listed (default SLEEP applies otherwise) declare -A PROFILE_SLEEP=( - [arrs_stack]=300 - [critical-data]=300 [critical-fallback]=120 # shorter — frequent dirty sync, retry faster - [important-data]=300 - [emby]=300 - [emby-fallback]=120 # shorter — frequent dirty sync, retry faster ) # Containers stopped on BOTH LOCAL and REMOTE before rsync. @@ -657,7 +642,6 @@ [critical-fallback]="" # dirty sync — auth stays running both sides [important-data]="" # e.g. "Postgres NextCloud" [emby]="Emby" - [emby-fallback]="" # dirty sync — Emby stays running both sides ) # Containers needing a delay after rsync before starting. @@ -668,17 +652,12 @@ [critical-fallback]="" [important-data]="NextCloud" # wait for Postgres [emby]="" - [emby-fallback]="" ) -# Seconds before starting delayed containers +# Seconds before starting delayed containers — only non-default profiles listed (default CONTAINER_DELAY applies otherwise) declare -A PROFILE_CONTAINER_DELAY=( - [arrs_stack]=5 [critical-data]=15 # Mariadb + Redis need time to accept connections - [critical-fallback]=5 [important-data]=10 # Postgres needs time before NextCloud - [emby]=5 - [emby-fallback]=5 ) # Directories excluded from rsync per profile. @@ -689,16 +668,14 @@ [critical-fallback]="logs *.tmp *.log nginx/temp nginx/cache __pycache__ notification.txt *.db-wal *.db-shm" [important-data]="logs *.tmp" [emby]="logs transcodes cache crash*" - [emby-fallback]="logs transcodes cache metadata *.db-wal *.db-shm crash* plugins root" ) # Remote restart after dirty sync — restart these on remote IF they were running before sync. # Same logic as stop/start — was stopped = stays stopped, was running = gets restarted. -# Used by dirty sync profiles (critical-fallback, emby-fallback) so remote picks up changes. +# Used by dirty sync profiles (critical-fallback) so remote picks up changes. # SPACE-SEPARATED STRINGS — converted to array at runtime declare -A PROFILE_REMOTE_RESTART_CONTAINERS=( [critical-fallback]="" # containers to restart on remote after dirty sync - [emby-fallback]="Emby" ) # Note: disk check is auto-detected from disks.ini — no PROFILE_SKIP_DISK_CHECK needed. @@ -733,9 +710,10 @@ # ━━━ Play State Sync ━━━ PLAY_SYNC_ENABLED=true PLAY_SYNC_REMOTE=true # sync across hosts via Tailscale - PLAY_SYNC_DAYS=90 # days back to check for played items (0 = all time) PLAY_SYNC_TYPES="Movie,Episode" # Audio excluded — music library too large; favorites handled separately PLAY_SYNC_FAV_TYPES="MusicArtist,MusicAlbum,Movie,Series" # union sync — never unmarks; Audio tracks future + PLAY_SYNC_PROBE=true # hash fetched state, skip per-item comparison when nothing changed + PLAY_SYNC_PROBE_MAX_AGE_HOURS=24 # force a full comparison when the fingerprint is older than this # ━━━ Play State Sync — Handback ━━━ # play_state_sync runs before DNS cutover so users land on current watch state. @@ -1052,40 +1030,10 @@ '*sync-conflict*' # Syncthing conflict copies ) + # Media = the anime set plus two media-specific extras. Defined by composition so the + # shared patterns can never drift between the two lists. MEDIA_FILE_PATTERNS=( - # ── Checksums ──────────────────────────────────────────────────────────────────────── - '*.sfv' '*.md5' '*.sha1' # verification files — useless post-download - - # ── Scene / download metadata ───────────────────────────────────────────────────────── - '*.url' '*.lnk' # scene links - '*.info' '*.diz' # scene description files - '*.nzb' # usenet download files - '*.torrent' # torrent files left by download clients - - # ── Archives and segments ───────────────────────────────────────────────────────────── - '*.rar' '*.zip' '*.7z' '*.ace' # archives — source files not needed after extract - '*.r00' '*.r01' '*.r02' '*.r03' # multi-part rar segments - '*.r04' '*.r05' '*.r06' '*.r07' - '*.r08' '*.r09' '*.srr' # scene repair files - '*.001' '*.002' '*.003' # split archive parts - '*.gz' '*.tar' '*.bz2' # linux archives - - # ── Scene samples and proofs ────────────────────────────────────────────────────────── - '*.sample*' '*.proof*' # scene samples — never needed in library - - # ── Executables and scripts ─────────────────────────────────────────────────────────── - '*.exe' '*.scr' '*.com' # Windows executables - '*.bat' '*.cmd' '*.vbs' '*.ps1' # Windows scripts - '*.msi' '*.dll' '*.sys' # Windows installers and system files - '*.sh' # shell scripts in media folders = suspicious - - # ── Incomplete downloads ────────────────────────────────────────────────────────────── - '*.!ut' '*.!qB' # uTorrent / qBittorrent incomplete markers - '*.crdownload' '*.opdownload' # Chrome / Opera incomplete downloads - '*.part' # partial download files - - # ── Sync conflicts ──────────────────────────────────────────────────────────────────── - '*sync-conflict*' # Syncthing conflict copies + "${ANIME_FILE_PATTERNS[@]}" # ── Media-specific extras ───────────────────────────────────────────────────────────── '*.iso' # disc images — extracted content is in library @@ -1235,24 +1183,9 @@ RADARR_MOVE_POLL_TIMEOUT=3600 # seconds to wait for a single async MoveMovie command to # reach "completed" — mirrors SONARR_MOVE_POLL_TIMEOUT RADARR_EXTENSIONS=("mkv" "mp4" "avi" "m4v" "wmv" "mov") - RADARR_PROTECTED_PATTERNS=( - # Subtitles - "*.srt" "*.sub" "*.ass" "*.ssa" "*.idx" "*.vtt" - # Metadata - "*.nfo" "*.tbn" - # Images - "*.jpg" "*.jpeg" "*.png" "*.webp" "*.svg" - "poster.*" "fanart.*" "backdrop.*" "clearlogo.*" - "banner.*" "thumb.*" "landscape.*" - # Kodi/Emby extras — not tracked by Radarr API - "*-trailer.*" "*-featurette.*" "*-behindthescenes.*" - "*-interview.*" "*-scene.*" "*-short.*" "*-deleted.*" - "*-clip.*" "*-other.*" - # Theme songs — stored in movie folder, not tracked by arr - "theme.mp3" "theme.flac" "theme.wav" "theme.m4a" "theme.mka" - "theme.mkv" "theme.mp4" - "trailer.*" "trailer *.*" "trailer-*.*" - ) + # Identical protected set to Sonarr's (sidecars/artwork/extras the arr doesn't track are + # the same for movies and shows). Reused by reference so the two can never drift. + RADARR_PROTECTED_PATTERNS=("${SONARR_PROTECTED_PATTERNS[@]}") # Radarr/Sonarr TMDb/TVDB removed entry cleanup RADARR_DROPPED_ADD_EXCLUSION=true # add removed movies to import exclusion list diff --git a/Rsync/rsync.sh b/Rsync/rsync.sh index 1d447e9..eb240d4 100755 --- a/Rsync/rsync.sh +++ b/Rsync/rsync.sh @@ -464,7 +464,7 @@ fi # ============================================================================================== # ━━━ Remote Restart (dirty sync profiles) ━━━ # ============================================================================================== -# For dirty sync profiles (critical-fallback, emby-fallback) — restart containers on remote +# For dirty sync profiles (critical-fallback) — restart containers on remote # that were running before sync so they pick up config changes from the dirty sync window. # Was running → restart. Was stopped → leave stopped. if [[ ${#REMOTE_RESTART_CONTAINERS[@]} -gt 0 ]]; then diff --git a/common.sh b/common.sh index 21eb14c..ae44845 100755 --- a/common.sh +++ b/common.sh @@ -68,7 +68,7 @@ # Fixes: ZFS cache pools not detected when share is not at pool root # # v3.3 PROFILE_REMOTE_RESTART_CONTAINERS support added -# Dirty sync profiles (critical-fallback, emby-fallback) restart remote +# Dirty sync profiles (critical-fallback) restart remote # containers after sync if they were running before — picks up config changes # Was stopped → stays stopped. Was running → gets restarted. ✅ #