Add full banner headers to all scripts across the codebase
Every script now has the established header format: PURPOSE with ─────── separator, OPERATIONAL MODEL, DESIGN PRINCIPLES, OPERATIONAL SAFEGUARDS, CONFIGURATION, and RUNTIME MODES — structured with full ====== banner sections throughout. Orchestrators converted from compact ── inline format to full banners. Stale emby-fallback and dirty sync references removed from Plugin/user_script_plug-in.sh.
This commit is contained in:
@@ -28,6 +28,24 @@
|
||||
# 3. Trigger new search — finds a different release automatically
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Hands-Free Recovery
|
||||
# The script completes the full recovery cycle autonomously — blocklist, remove,
|
||||
# re-search. No operator decision required. A failed import at midnight resolves
|
||||
# itself before morning without any intervention.
|
||||
#
|
||||
# Age Gate Before Action
|
||||
# Items newer than ARR_IMPORT_RECOVERY_AGE are skipped. Arrs have their own
|
||||
# retry logic — acting immediately would race against it. The age gate gives
|
||||
# the arr time to self-resolve before this script escalates.
|
||||
#
|
||||
# Blocklist First
|
||||
# The bad release is blocklisted before removal and re-search. Without this,
|
||||
# the re-search can re-grab the same release that just failed.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -27,6 +27,25 @@
|
||||
# classification these would be deleted — breaking Lidarr and Emby display.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# API as Ground Truth
|
||||
# What Lidarr tracks is authoritative. Files not in the API response are
|
||||
# orphans — Lidarr has no record of them and they serve no purpose.
|
||||
# The script never infers ownership from directory structure alone.
|
||||
#
|
||||
# Age Gate Before Deletion
|
||||
# Files under LIDARR_ORPHAN_AGE are left alone regardless of tracked status.
|
||||
# Lidarr's import pipeline writes files before registering them — acting
|
||||
# immediately would delete files mid-import.
|
||||
#
|
||||
# Seven-Gate Safety Model
|
||||
# Multiple independent sanity checks must all pass before any file is touched.
|
||||
# No single check is trusted in isolation — a misconfigured path returning an
|
||||
# empty API response must not result in a wiped library.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -25,6 +25,25 @@
|
||||
# album/artist directories.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Additive Only
|
||||
# The script only adds missing files — it never overwrites existing artwork
|
||||
# or touches audio files. Re-running after a partial fetch completes exactly
|
||||
# where it left off with no side effects.
|
||||
#
|
||||
# Source Fallback Chain
|
||||
# Multiple sources are tried in order of quality preference. fanart.tv is
|
||||
# primary; fallbacks exist so partial coverage is better than none. A failed
|
||||
# primary never blocks the fallback from running.
|
||||
#
|
||||
# External API Courtesy
|
||||
# Rate limiting and parallel job caps prevent hammering fanart.tv and other
|
||||
# external APIs. Burst behaviour during large initial runs would risk
|
||||
# temporary blocks that break future scheduled fetches.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -43,6 +43,24 @@
|
||||
# Media profile also removes: *.iso *.lrc
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Pre-Scan Cleanup
|
||||
# Runs before arr cleanup scripts so orphan detection only encounters actual
|
||||
# media files. Scene debris and download artifacts would otherwise appear as
|
||||
# untracked files and inflate false-positive orphan counts.
|
||||
#
|
||||
# Profile Separation
|
||||
# Anime and media share different cleanup patterns because their content
|
||||
# differs. *.lrc (lyrics) and *.iso belong in media cleanup but not anime.
|
||||
# Separate profiles prevent cross-contamination of rules.
|
||||
#
|
||||
# Conservative by Default
|
||||
# Only explicitly listed patterns are removed. The script never guesses
|
||||
# at file intent — if a pattern is not in the list, the file is untouched.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -14,6 +14,24 @@
|
||||
# or unRAID environment resets after updates.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Daily Failsafe, Not Enforcer
|
||||
# Wrong ownership is a symptom of something else — a misconfigured container,
|
||||
# a manual copy, an rsync without --chown. This script corrects the symptom
|
||||
# daily rather than hunting the root cause. A persistent high correction count
|
||||
# is the signal to investigate the source.
|
||||
#
|
||||
# Runs First in the Window
|
||||
# Arr cleanup scripts depend on correct ownership to rename and delete files.
|
||||
# Permissions must be correct before cleanup runs — ordering is not optional.
|
||||
#
|
||||
# Separate Passes for Directories and Files
|
||||
# Directories need execute permission for traversal; files do not. Applying
|
||||
# the same mode to both is a common mistake this script avoids by design.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -33,6 +33,38 @@
|
||||
# The higher tick count wins.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Newest Timestamp Wins
|
||||
# No merge logic, no conflict resolution — the server with the most recent
|
||||
# LastPlayedDate is simply authoritative. Simple rules produce predictable
|
||||
# outcomes users can reason about.
|
||||
#
|
||||
# No Data Loss
|
||||
# The sync only pushes state forward — it never clears a Played flag or
|
||||
# resets a resume position to zero. A watch record on any server always
|
||||
# propagates outward, never disappears.
|
||||
#
|
||||
# Provider ID Matching
|
||||
# Items are matched by external IDs (IMDb, TVDB, MusicBrainz), not by
|
||||
# title or file path. This makes matching robust across library reorganisation,
|
||||
# renames, and multi-server path differences.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
# PLAY_SYNC_ENABLED gate — exits cleanly when disabled; no partial runs
|
||||
# PARTNERSHIP gate — skips remote sync when partnership is inactive
|
||||
# Per-server reachability — unreachable servers are skipped individually;
|
||||
# one offline server does not abort the entire sync
|
||||
# User match required — a user missing from a server is skipped for that
|
||||
# server; no cross-account state pollution
|
||||
# acquire_lock — prevents concurrent runs from racing on the same
|
||||
# items during the 30-minute critical window
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION (host*.conf, aliased by detect_hosts)
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -60,27 +60,23 @@
|
||||
# Configure HOST*_LASTFM_API_KEY in host*.conf
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION (master.conf)
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# LIDARR_DISCOVERY_THRESHOLD — minimum score for Stage 1 seeds and Stage 2 adds (default: 70)
|
||||
# LIDARR_DISCOVERY_LOOKBACK_DAYS — Emby play history window in days (default: 7)
|
||||
# LIDARR_DISCOVERY_MIN_PLAYS — min plays to be evaluated in Stage 1 (default: 3)
|
||||
# LIDARR_DISCOVERY_MAX_ADDS — max seeds (Stage 1) and max adds (Stage 2) (default: 5)
|
||||
# LIDARR_DISCOVERY_USER_CAP_PCT — max % any one user contributes to play weight (default: 35)
|
||||
# LIDARR_DISCOVERY_REJECT_COOLDOWN — days before re-evaluating a Stage 2 reject (default: 30)
|
||||
# LIDARR_DISCOVERY_HISTORY — history/state file path
|
||||
# Playback as Intent Signal
|
||||
# What users actually listen to is a stronger signal than what they follow or
|
||||
# own. The scoring model weights demonstrated listening behaviour — recency,
|
||||
# play count, user breadth — over passive library membership.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
# Selective by Design
|
||||
# 0–5 adds per week is the target, not bulk imports. A high score threshold
|
||||
# combined with MAX_ADDS ensures only high-confidence recommendations are
|
||||
# acted on. Volume is not the goal — meaningful discovery is.
|
||||
#
|
||||
# playback_aware_lidarr_discovery.sh — normal run
|
||||
# playback_aware_lidarr_discovery.sh --dry-run — score and rank, no Lidarr changes
|
||||
# playback_aware_lidarr_discovery.sh --log — verbose output
|
||||
# playback_aware_lidarr_discovery.sh --status — show config and exit
|
||||
#
|
||||
# Recommended schedule: weekly (WEEKLY_MAINTENANCE_SCRIPTS in master.conf)
|
||||
# Two-Stage Filtering
|
||||
# Stage 1 rejects weak seeds before they drive Stage 2. Low-quality seeds
|
||||
# produce low-quality similar-artist recommendations. Filtering at the seed
|
||||
# stage improves the entire output, not just the top of the list.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
@@ -110,6 +106,29 @@
|
||||
# runs. Safe to delete — next run starts fresh with no memory.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION (master.conf)
|
||||
# ==============================================================================================
|
||||
#
|
||||
# LIDARR_DISCOVERY_THRESHOLD — minimum score for Stage 1 seeds and Stage 2 adds (default: 70)
|
||||
# LIDARR_DISCOVERY_LOOKBACK_DAYS — Emby play history window in days (default: 7)
|
||||
# LIDARR_DISCOVERY_MIN_PLAYS — min plays to be evaluated in Stage 1 (default: 3)
|
||||
# LIDARR_DISCOVERY_MAX_ADDS — max seeds (Stage 1) and max adds (Stage 2) (default: 5)
|
||||
# LIDARR_DISCOVERY_USER_CAP_PCT — max % any one user contributes to play weight (default: 35)
|
||||
# LIDARR_DISCOVERY_REJECT_COOLDOWN — days before re-evaluating a Stage 2 reject (default: 30)
|
||||
# LIDARR_DISCOVERY_HISTORY — history/state file path
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# playback_aware_lidarr_discovery.sh — normal run
|
||||
# playback_aware_lidarr_discovery.sh --dry-run — score and rank, no Lidarr changes
|
||||
# playback_aware_lidarr_discovery.sh --log — verbose output
|
||||
# playback_aware_lidarr_discovery.sh --status — show config and exit
|
||||
#
|
||||
# Recommended schedule: weekly (WEEKLY_MAINTENANCE_SCRIPTS in master.conf)
|
||||
#
|
||||
# ==============================================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
|
||||
@@ -59,29 +59,23 @@
|
||||
# Free key at: https://www.themoviedb.org/settings/api
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION (master.conf)
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# RADARR_DISCOVERY_THRESHOLD — minimum score to add a candidate (default: 52)
|
||||
# RADARR_DISCOVERY_LOOKBACK_DAYS — Emby watch history window in days (default: 30)
|
||||
# RADARR_DISCOVERY_MAX_SEEDS — max seed movies from Stage 1 (default: 5)
|
||||
# RADARR_DISCOVERY_MAX_ADDS — max movies to add per run (default: 5)
|
||||
# RADARR_DISCOVERY_MIN_VOTE_COUNT — min TMDB votes for a candidate (default: 100)
|
||||
# RADARR_DISCOVERY_MIN_RATING — min TMDB vote_average × 10 (default: 60 = 6.0/10)
|
||||
# RADARR_DISCOVERY_REJECT_COOLDOWN — days before re-evaluating a rejected movie (default: 60)
|
||||
# RADARR_DISCOVERY_SEED_LIBRARIES — Emby library names to draw seeds from (default: ("Movies"))
|
||||
# RADARR_DISCOVERY_HISTORY — history/state file path
|
||||
# Playback as Intent Signal
|
||||
# Recently watched movies are a stronger signal than what is in the library or
|
||||
# on watchlists. The scoring model weights demonstrated viewing behaviour —
|
||||
# recency, rating, vote confidence — over passive ownership.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
# Selective by Design
|
||||
# 0–5 adds per run is the target, not bulk imports. A score threshold combined
|
||||
# with MAX_ADDS ensures only high-confidence recommendations are acted on.
|
||||
# Volume is not the goal — meaningful discovery is.
|
||||
#
|
||||
# playback_aware_radarr_discovery.sh — normal run
|
||||
# playback_aware_radarr_discovery.sh --dry-run — score and rank, no Radarr changes
|
||||
# playback_aware_radarr_discovery.sh --log — verbose output
|
||||
# playback_aware_radarr_discovery.sh --status — show config and exit
|
||||
#
|
||||
# Recommended schedule: weekly (WEEKLY_MAINTENANCE_SCRIPTS in master.conf)
|
||||
# Two-Stage Filtering
|
||||
# Stage 1 rejects weak seeds before they drive Stage 2. Low-quality or
|
||||
# low-confidence watched movies produce poor recommendations. Filtering at
|
||||
# the seed stage improves the entire output.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
@@ -111,6 +105,31 @@
|
||||
# runs. Safe to delete — next run starts fresh with no memory.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION (master.conf)
|
||||
# ==============================================================================================
|
||||
#
|
||||
# RADARR_DISCOVERY_THRESHOLD — minimum score to add a candidate (default: 52)
|
||||
# RADARR_DISCOVERY_LOOKBACK_DAYS — Emby watch history window in days (default: 30)
|
||||
# RADARR_DISCOVERY_MAX_SEEDS — max seed movies from Stage 1 (default: 5)
|
||||
# RADARR_DISCOVERY_MAX_ADDS — max movies to add per run (default: 5)
|
||||
# RADARR_DISCOVERY_MIN_VOTE_COUNT — min TMDB votes for a candidate (default: 100)
|
||||
# RADARR_DISCOVERY_MIN_RATING — min TMDB vote_average × 10 (default: 60 = 6.0/10)
|
||||
# RADARR_DISCOVERY_REJECT_COOLDOWN — days before re-evaluating a rejected movie (default: 60)
|
||||
# RADARR_DISCOVERY_SEED_LIBRARIES — Emby library names to draw seeds from (default: ("Movies"))
|
||||
# RADARR_DISCOVERY_HISTORY — history/state file path
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# playback_aware_radarr_discovery.sh — normal run
|
||||
# playback_aware_radarr_discovery.sh --dry-run — score and rank, no Radarr changes
|
||||
# playback_aware_radarr_discovery.sh --log — verbose output
|
||||
# playback_aware_radarr_discovery.sh --status — show config and exit
|
||||
#
|
||||
# Recommended schedule: weekly (WEEKLY_MAINTENANCE_SCRIPTS in master.conf)
|
||||
#
|
||||
# ==============================================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
|
||||
@@ -66,31 +66,23 @@
|
||||
# Free key at: https://www.themoviedb.org/settings/api
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION (master.conf)
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# SONARR_DISCOVERY_THRESHOLD — minimum score to add a candidate (default: 52)
|
||||
# SONARR_DISCOVERY_LOOKBACK_DAYS — Emby watch history window in days (default: 14)
|
||||
# SONARR_DISCOVERY_MAX_SEEDS — max seed series from Stage 1 (default: 5)
|
||||
# SONARR_DISCOVERY_MAX_ADDS — max shows to add per run (default: 3)
|
||||
# SONARR_DISCOVERY_MIN_VOTE_COUNT — min TMDB votes for a candidate (default: 50)
|
||||
# SONARR_DISCOVERY_MIN_RATING — min TMDB vote_average × 10 (default: 65 = 6.5/10)
|
||||
# SONARR_DISCOVERY_REJECT_COOLDOWN — days before re-evaluating a rejected show (default: 60)
|
||||
# SONARR_DISCOVERY_USER_EPISODE_CAP — max episodes per user in seed scoring (default: 8)
|
||||
# SONARR_DISCOVERY_MONITOR_MODE — Sonarr monitor mode on add: "all" or "future" (default: "all")
|
||||
# SONARR_EMBY_LIBRARIES — Emby library names to draw seeds from
|
||||
# SONARR_DISCOVERY_HISTORY — history/state file path
|
||||
# Playback as Intent Signal
|
||||
# Recently watched episodes are a stronger signal than what is in the library.
|
||||
# User diversity across a series is weighted above a single user binge —
|
||||
# broad household interest is a better predictor of a good addition than
|
||||
# one person's session.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
# Selective by Design
|
||||
# 0–3 adds per run is the target. TV is a larger commitment than movies —
|
||||
# a lower MAX_ADDS cap reflects that. Volume is not the goal.
|
||||
#
|
||||
# playback_aware_sonarr_discovery.sh — normal run
|
||||
# playback_aware_sonarr_discovery.sh --dry-run — score and rank, no Sonarr changes
|
||||
# playback_aware_sonarr_discovery.sh --log — verbose output
|
||||
# playback_aware_sonarr_discovery.sh --status — show config and exit
|
||||
#
|
||||
# Recommended schedule: weekly (WEEKLY_MAINTENANCE_SCRIPTS in master.conf)
|
||||
# Two-Stage Filtering
|
||||
# Stage 1 rejects weak seeds before they drive Stage 2. A poorly-watched
|
||||
# or niche series produces poor recommendations. Filtering at the seed
|
||||
# stage improves the entire output.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
@@ -125,6 +117,33 @@
|
||||
# runs. Safe to delete — next run starts fresh with no memory.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION (master.conf)
|
||||
# ==============================================================================================
|
||||
#
|
||||
# SONARR_DISCOVERY_THRESHOLD — minimum score to add a candidate (default: 52)
|
||||
# SONARR_DISCOVERY_LOOKBACK_DAYS — Emby watch history window in days (default: 14)
|
||||
# SONARR_DISCOVERY_MAX_SEEDS — max seed series from Stage 1 (default: 5)
|
||||
# SONARR_DISCOVERY_MAX_ADDS — max shows to add per run (default: 3)
|
||||
# SONARR_DISCOVERY_MIN_VOTE_COUNT — min TMDB votes for a candidate (default: 50)
|
||||
# SONARR_DISCOVERY_MIN_RATING — min TMDB vote_average × 10 (default: 65 = 6.5/10)
|
||||
# SONARR_DISCOVERY_REJECT_COOLDOWN — days before re-evaluating a rejected show (default: 60)
|
||||
# SONARR_DISCOVERY_USER_EPISODE_CAP — max episodes per user in seed scoring (default: 8)
|
||||
# SONARR_DISCOVERY_MONITOR_MODE — Sonarr monitor mode on add: "all" or "future" (default: "all")
|
||||
# SONARR_EMBY_LIBRARIES — Emby library names to draw seeds from
|
||||
# SONARR_DISCOVERY_HISTORY — history/state file path
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# playback_aware_sonarr_discovery.sh — normal run
|
||||
# playback_aware_sonarr_discovery.sh --dry-run — score and rank, no Sonarr changes
|
||||
# playback_aware_sonarr_discovery.sh --log — verbose output
|
||||
# playback_aware_sonarr_discovery.sh --status — show config and exit
|
||||
#
|
||||
# Recommended schedule: weekly (WEEKLY_MAINTENANCE_SCRIPTS in master.conf)
|
||||
#
|
||||
# ==============================================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
|
||||
@@ -31,6 +31,25 @@
|
||||
# Emby removes ghost entries immediately — no user-facing file-not-found errors.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# API as Ground Truth
|
||||
# What Radarr tracks is authoritative. Files not in the API response are
|
||||
# orphans — Radarr has no record of them and they serve no purpose.
|
||||
# The script never infers ownership from directory structure alone.
|
||||
#
|
||||
# Age Gate Before Deletion
|
||||
# Files under RADARR_ORPHAN_AGE are left alone regardless of tracked status.
|
||||
# Radarr's import pipeline writes files before registering them — acting
|
||||
# immediately would delete files mid-import.
|
||||
#
|
||||
# Emby Cleanup Is Part of the Job
|
||||
# Deleting a file without telling Emby leaves ghost entries that show as
|
||||
# broken items. Triggering the Emby clean is not optional — it completes
|
||||
# the deletion from the user's perspective.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -24,6 +24,25 @@
|
||||
# Per-deletion output is always visible — deletions are never silently swallowed.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Health Error Hygiene
|
||||
# status="deleted" entries can never be monitored or downloaded — they only
|
||||
# generate persistent health errors. Removing them is maintenance, not
|
||||
# data loss: the content never existed on disk for most of these entries.
|
||||
#
|
||||
# Conservative File Handling
|
||||
# Files are not deleted by default because most TMDb-removed entries are
|
||||
# announced-but-never-released films with no files. The --delete-files flag
|
||||
# is an explicit opt-in, not the default path.
|
||||
#
|
||||
# Exclusion List Prevents Re-add
|
||||
# Removed entries are added to Radarr's import exclusion list by default.
|
||||
# Without this, the same deleted entry can be re-added by lists or searches
|
||||
# and immediately generate the same health error again.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -31,6 +31,25 @@
|
||||
# Emby removes ghost entries immediately — no user-facing file-not-found errors.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# API as Ground Truth
|
||||
# What Sonarr tracks is authoritative. Files not in the API response are
|
||||
# orphans — Sonarr has no record of them and they serve no purpose.
|
||||
# The script never infers ownership from directory structure alone.
|
||||
#
|
||||
# Age Gate Before Deletion
|
||||
# Files under SONARR_ORPHAN_AGE are left alone regardless of tracked status.
|
||||
# Sonarr's import pipeline writes files before registering them — acting
|
||||
# immediately would delete files mid-import.
|
||||
#
|
||||
# Emby Cleanup Is Part of the Job
|
||||
# Deleting a file without telling Emby leaves ghost entries that show as
|
||||
# broken items. Triggering the Emby clean is not optional — it completes
|
||||
# the deletion from the user's perspective.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -23,6 +23,25 @@
|
||||
# Per-deletion output is always visible — deletions are never silently swallowed.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Health Error Hygiene
|
||||
# status="deleted" series can never be monitored or downloaded — they only
|
||||
# generate persistent health errors. Removing them is maintenance, not
|
||||
# data loss: most have no associated files.
|
||||
#
|
||||
# Conservative File Handling
|
||||
# Files are not deleted by default. A TVDB-removed series may still have
|
||||
# episodes on disk that the user wants to keep. The --delete-files flag
|
||||
# is an explicit opt-in, not the default path.
|
||||
#
|
||||
# Exclusion List Prevents Re-add
|
||||
# Removed entries are added to Sonarr's import exclusion list by default.
|
||||
# Without this, the same deleted series can be re-added by lists or searches
|
||||
# and immediately generate the same health error again.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
|
||||
@@ -23,6 +23,67 @@
|
||||
# If WEBHOOK_PORT is 0: exits cleanly (disables the listener).
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL MODEL
|
||||
# ==============================================================================================
|
||||
#
|
||||
# 1. Check WEBHOOK_PORT — exit cleanly if 0 (listener disabled)
|
||||
# 2. Check WEBHOOK_SECRET — generate and persist one if empty
|
||||
# 3. exec node webhook_listener.js — replaces this process; PID stays the same
|
||||
#
|
||||
# exec is intentional: array_started.sh tracks the PID of this script to check
|
||||
# whether the listener is running. exec preserves that PID across the hand-off
|
||||
# to node.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Node.js Over php -S
|
||||
# php -S on Unraid PHP 8.4 silently drops POST request bodies — webhooks arrive
|
||||
# empty and the handler has no payload to act on. Node.js handles POST bodies
|
||||
# correctly and has no equivalent silent-drop behaviour.
|
||||
#
|
||||
# Runs Outside nginx
|
||||
# The listener binds directly to WEBHOOK_PORT — no nginx proxy, no session auth.
|
||||
# The shared secret in the URL query string is the only gate. This keeps the
|
||||
# webhook path independent of the auth stack.
|
||||
#
|
||||
# exec Preserves PID
|
||||
# The script execs into node rather than forking it. array_started.sh stores the
|
||||
# PID of this script to check liveness — exec ensures that PID continues to
|
||||
# refer to the running node process after the hand-off.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
# WEBHOOK_PORT=0 gate — exits cleanly before any setup if the listener is disabled
|
||||
# Secret auto-generate — WEBHOOK_SECRET generated via openssl rand if empty;
|
||||
# persisted to master.conf immediately so restarts reuse it
|
||||
# Shared secret gate — webhook URL must include ?key=<WEBHOOK_SECRET>;
|
||||
# requests without a valid key are rejected by the Node.js server
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION
|
||||
# ==============================================================================================
|
||||
#
|
||||
# master.conf
|
||||
#
|
||||
# WEBHOOK_PORT — port the listener binds to; 0 = disabled
|
||||
# WEBHOOK_SECRET — shared secret for URL auth; auto-generated if empty
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# start_webhook_listener.sh
|
||||
# Started automatically at array start via ARRAY_START_SCRIPTS.
|
||||
# Exits immediately if WEBHOOK_PORT=0.
|
||||
#
|
||||
# To stop:
|
||||
# pkill -f webhook_listener.js
|
||||
#
|
||||
# ==============================================================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
|
||||
@@ -15,7 +15,56 @@
|
||||
# begin searching — a search it will never win because we already have it.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# USAGE
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Closes the Propagation Window
|
||||
# arr_sync runs every 4 hours. Without this handler, a remote node that already
|
||||
# has the old version sees the upgrade tagged in arr_sync but the new file not
|
||||
# yet on disk, and initiates a redundant quality search — a search it will never
|
||||
# win because this host already has the file. Immediate push eliminates that window.
|
||||
#
|
||||
# Rescan as Ground Truth
|
||||
# Pushing the file is not enough — the remote arr must also be told the file
|
||||
# exists. Triggering a rescan makes the remote accept the pushed file as the
|
||||
# current version without starting a new search.
|
||||
#
|
||||
# Cache-First API Key Lookup
|
||||
# Remote arr API keys are read from conf if cached; otherwise fetched via SSH
|
||||
# from the remote's config.xml. This avoids storing secrets redundantly while
|
||||
# keeping API calls fast on hosts where the key is already known.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Arg validation — exits with usage message if arr_type or item_path missing
|
||||
# Path existence — exits if item_path is not a directory on disk
|
||||
# Tailscale resolution — skips a node if its Tailscale IP cannot be resolved
|
||||
# rsync exit check — rescan is only triggered if rsync succeeded; a failed
|
||||
# transfer does not cause the remote arr to scan a partial file
|
||||
# SSH fallback — if no cached API key, falls back to SSH to read config.xml
|
||||
# on the remote rather than failing the rescan step
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION
|
||||
# ==============================================================================================
|
||||
#
|
||||
# host*.conf
|
||||
#
|
||||
# HOST* — host names used to discover remote nodes
|
||||
# HOST*_SONARR_API_KEY — cached API key for direct HTTP rescan (optional)
|
||||
# HOST*_RADARR_API_KEY — cached API key for direct HTTP rescan (optional)
|
||||
# HOST*_LIDARR_API_KEY — cached API key for direct HTTP rescan (optional)
|
||||
#
|
||||
# master.conf
|
||||
#
|
||||
# SSH_KEY — SSH key path for rsync and SSH fallback
|
||||
# ARR_SYNC_CONNECT_TIMEOUT — SSH connect timeout in seconds
|
||||
# DOCKER_APPDATA_BASE — base path for reading arr config.xml on remote
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# upgrade_webhook_handler.sh <arr_type> <item_path>
|
||||
@@ -25,7 +74,7 @@
|
||||
# (series.path from Sonarr, movie.folderPath from Radarr,
|
||||
# artist.path from Lidarr)
|
||||
#
|
||||
# Called by webhook.php — not intended for direct invocation outside testing.
|
||||
# Called by webhook_listener.js — not intended for direct invocation outside testing.
|
||||
#
|
||||
# ==============================================================================================
|
||||
|
||||
|
||||
Reference in New Issue
Block a user