# Media Scripts that maintain the health, cleanliness, and consistency of your media library. Permissions, junk file removal, and orphaned file cleanup across Lidarr, Sonarr, and Radarr. These scripts are run sequentially by `Orchestrators/media_management.sh` — not individually scheduled. The orchestrator handles ordering, pass/fail tracking, and the combined summary. --- ## Why Order Matters ``` 1. media_shares_permissions.sh ← permissions first 2. media_cleaner.sh anime ← clean junk before arr scripts scan 3. media_cleaner.sh media ← same 4. lidarr_cleanup.sh ← arr cleanup last 5. sonarr_cleanup.sh 6. radarr_cleanup.sh ``` **Permissions before everything else** — arr cleanup scripts need correct ownership to delete files. If a file is owned by root and the script runs as nobody, the delete fails silently. **Cleaner before arr cleanup** — junk files (.sfv, .rar, .txt etc.) mixed in with media files create noise in the orphan detection logic. Clean the junk first so arr cleanup only deals with real media files. **Arr cleanup last** — depends on clean folders and correct permissions to work reliably. --- ## Scripts ### `media_shares_permissions.sh` Applies correct ownership and permissions recursively to all configured media shares. ```bash # Called by media_management.sh — not scheduled directly # Run manually when needed: /mnt/user/appdata/unraid_scripts/Media/media_shares_permissions.sh /mnt/user/appdata/unraid_scripts/Media/media_shares_permissions.sh --dry-run ``` **What it applies:** ```bash PERMISSIONS_MODE="777" # chmod applied recursively PERMISSIONS_OWNER="nobody:users" # chown applied recursively ``` `777` and `nobody:users` is the standard for unRAID media shares accessible by Docker containers. All media server containers (Emby, Tdarr, arr stack) run as `nobody:users` — this ensures they can read, write, and delete files without permission errors. **Why recursive takes time:** On a large library with millions of files this can run for 20-30 minutes. This is expected and normal. Run it overnight via the orchestrator — not during peak usage hours. **Add or remove shares** in `Master.conf` under `MEDIA_PERMISSION_SHARES`. The script reads this list at runtime — no script changes needed. --- ### `media_cleaner.sh` Removes junk files from media shares using configurable file pattern lists. Two profiles with independent folder lists and patterns. ```bash # Called by media_management.sh with profile argument # Run manually with profile required: /mnt/user/appdata/unraid_scripts/Media/media_cleaner.sh anime /mnt/user/appdata/unraid_scripts/Media/media_cleaner.sh media /mnt/user/appdata/unraid_scripts/Media/media_cleaner.sh anime --dry-run /mnt/user/appdata/unraid_scripts/Media/media_cleaner.sh media --dry-run ``` **Always --dry-run first** — especially on first use or after adding new patterns. #### Anime Profile ```bash ANIME_CLEAN_FOLDERS=( /mnt/user/Anime_Movies /mnt/user/Anime_Movies-Old /mnt/user/Anime_Shows /mnt/user/Anime_Shows-Old ) ANIME_FILE_PATTERNS=( '*.sfv' '*.md5' '*.sha1' '*.txt' '*.url' '*.lnk' '*.rar' '*.zip' '*.info' '*.torrent' '*.sample*' '*.proof*' '*sync-conflict*' '*.scr' '*.srr' '*.exe' '*.webp' '*.log' '*.json' ) ``` Anime downloads from groups commonly include verification files (`.sfv`, `.md5`), RAR archives after extraction, proof files, and samples. These are safe to delete after the video files have been imported. #### Media Profile ```bash MEDIA_CLEAN_FOLDERS=( /mnt/user/Kids_Movies /mnt/user/Kids_Tv_Shows /mnt/user/Movies /mnt/user/Music /mnt/user/Sports /mnt/user/stand-up_comedy /mnt/user/Tv_Shows ) ``` The media profile includes `*.iso` and `*.lrc` in addition to the anime patterns — ISO disc images after ripping and lyric files that aren't needed in the media folders. #### Adding New Patterns Add to the appropriate array in `Master.conf` — no script changes needed: ```bash ANIME_FILE_PATTERNS=( '*.sfv' '*.md5' ... '*.new-pattern' # ← just add here ) ``` #### Safety Note The cleaner deletes by pattern — it does not check what arr thinks about the files. It runs before arr cleanup specifically so arr cleanup sees clean folders. Do not add patterns that match media files you want to keep (`.mkv`, `.mp4` etc.). --- ### `lidarr_cleanup.sh` Removes orphaned music files from the library that Lidarr no longer tracks. ```bash # Called by media_management.sh # Always test first: /mnt/user/appdata/unraid_scripts/Media/lidarr_cleanup.sh --dry-run --log /mnt/user/appdata/unraid_scripts/Media/lidarr_cleanup.sh ``` **How it works:** 1. Queries the Lidarr API for all tracked file paths 2. Walks `LIDARR_MUSIC_ROOT` on disk 3. Classifies every file found: | Classification | Condition | Action | |---------------|-----------|--------| | TRACKED | Lidarr API knows this exact path | Leave alone | | PROTECTED | Matches `LIDARR_PROTECTED_PATTERNS` | Never delete | | ORPHAN | Music extension, not tracked, older than `LIDARR_ORPHAN_AGE` days | Delete | | JUNK | Not a music extension, not protected | Delete regardless of age | | RECENT | Not tracked, under `LIDARR_ORPHAN_AGE` days | Skip — may be mid-import | **Why protected patterns are critical:** Lidarr generates cover art (`*.jpg`), metadata (`*.nfo`), and lyrics (`*.lrc`) alongside your music files. These do not appear in Lidarr's tracked file API response — they would be classified as orphans and deleted without the protected patterns list. This would break artwork display in Emby and Lidarr itself. ```bash LIDARR_PROTECTED_PATTERNS=("*.jpg" "*.jpeg" "*.png" "*.nfo" "*.lrc") ``` Never remove patterns from this list without understanding what Lidarr generates in your specific setup. **Why the age threshold matters:** When Lidarr downloads a file it exists on disk before it's fully processed and imported. The `LIDARR_ORPHAN_AGE=7` day window ensures files that are mid-import are never touched. 7 days is conservative — adjust if your import workflow takes longer than expected. **Configuration:** ```bash LIDARR_URL="http://192.168.50.2:8686" LIDARR_API_KEY="your-api-key" LIDARR_MUSIC_ROOT="/mnt/user/Music-New" # must match Lidarr root path exactly LIDARR_ORPHAN_AGE=7 LIDARR_EXTENSIONS=("flac" "mp3" "m4a" "wav" "aac" "ogg" "opus" "wma") LIDARR_PROTECTED_PATTERNS=("*.jpg" "*.jpeg" "*.png" "*.nfo" "*.lrc") ``` `LIDARR_MUSIC_ROOT` must match the root path configured in Lidarr Settings → Media Management → Root Folders exactly. A mismatch means all files appear untracked and everything gets deleted. --- ### `sonarr_cleanup.sh` Removes orphaned TV episode files from the library that Sonarr no longer tracks. ```bash # Always test first: /mnt/user/appdata/unraid_scripts/Media/sonarr_cleanup.sh --dry-run --log /mnt/user/appdata/unraid_scripts/Media/sonarr_cleanup.sh ``` Same classification logic as `lidarr_cleanup.sh` applied to TV files. **Protected patterns cover:** - Show artwork (`*.jpg`, `*.png`) — Sonarr generates per-series and per-episode artwork - Metadata (`*.nfo`) — Sonarr generates NFO files for media center compatibility - Subtitles (`*.srt`, `*.sub`, `*.ass`, `*.ssa`) — managed by Bazarr via Sonarr ```bash SONARR_URL="http://192.168.50.2:8989" SONARR_API_KEY="your-api-key" SONARR_TV_ROOT="/mnt/user/Tv_Shows" SONARR_ORPHAN_AGE=7 SONARR_EXTENSIONS=("mkv" "mp4" "avi" "m4v" "ts" "wmv" "mov") SONARR_PROTECTED_PATTERNS=("*.jpg" "*.jpeg" "*.png" "*.nfo" "*.srt" "*.sub" "*.ass" "*.ssa") ``` **`.ts` in extensions:** Transport stream files from Live TV recordings. These are tracked by Sonarr for recorded episodes — include this extension to allow cleanup of orphaned recordings. --- ### `radarr_cleanup.sh` Removes orphaned movie files from the library that Radarr no longer tracks. ```bash # Always test first: /mnt/user/appdata/unraid_scripts/Media/radarr_cleanup.sh --dry-run --log /mnt/user/appdata/unraid_scripts/Media/radarr_cleanup.sh ``` Same classification logic applied to movie files. **Protected patterns cover:** - Movie artwork (`*.jpg`, `*.png`) - Metadata (`*.nfo`) - Subtitles (`*.srt`, `*.sub`, `*.ass`, `*.ssa`) — managed by Bazarr ```bash RADARR_URL="http://192.168.50.2:7878" RADARR_API_KEY="your-api-key" RADARR_MOVIES_ROOT="/mnt/user/Movies" RADARR_ORPHAN_AGE=7 RADARR_EXTENSIONS=("mkv" "mp4" "avi" "m4v" "wmv" "mov") RADARR_PROTECTED_PATTERNS=("*.jpg" "*.jpeg" "*.png" "*.nfo" "*.srt" "*.sub" "*.ass" "*.ssa") ``` --- ## Safe Testing Procedure The arr cleanup scripts permanently delete files. Always test before running live — especially on first use, after API key changes, or after root path changes. **Step 1 — Dry run with logging:** ```bash /mnt/user/appdata/unraid_scripts/Media/lidarr_cleanup.sh --dry-run --log /mnt/user/appdata/unraid_scripts/Media/sonarr_cleanup.sh --dry-run --log /mnt/user/appdata/unraid_scripts/Media/radarr_cleanup.sh --dry-run --log ``` `--log` enables verbose output showing every file classification decision. Review carefully: - Are TRACKED files the ones you expect? - Are ORPHAN files actually orphans or recently downloaded files? - Are PROTECTED files being correctly identified? - Is the root path correct — no files showing as orphans that shouldn't be? **Step 2 — Check the numbers make sense:** If dry run shows 50,000 files as orphans on a library you know is healthy — something is wrong. Common causes: - Root path mismatch between Master.conf and arr settings - API key incorrect — returns empty tracked list - Arr library scan not complete — recently added files not yet indexed **Step 3 — Run live:** ```bash /mnt/user/appdata/unraid_scripts/Media/lidarr_cleanup.sh ``` **Step 4 — Verify in arr UI:** After running, check the arr's library count hasn't dropped unexpectedly. A healthy cleanup removes a small number of genuinely orphaned files — not a significant percentage of your library. --- ## Configuration Quick Reference All configuration in `Master.conf` under `── MEDIA ──` section. ```bash # Permissions PERMISSIONS_MODE="777" PERMISSIONS_OWNER="nobody:users" MEDIA_PERMISSION_SHARES=(...) # Cleaner ANIME_CLEAN_FOLDERS=(...) MEDIA_CLEAN_FOLDERS=(...) ANIME_FILE_PATTERNS=(...) MEDIA_FILE_PATTERNS=(...) # Orchestrator job order MEDIA_MAINTENANCE_JOBS=( "Media/media_shares_permissions.sh" "Media/media_cleaner.sh anime" "Media/media_cleaner.sh media" "Media/lidarr_cleanup.sh" "Media/sonarr_cleanup.sh" "Media/radarr_cleanup.sh" ) # Arr cleanup — per arr LIDARR_URL / LIDARR_API_KEY / LIDARR_MUSIC_ROOT LIDARR_ORPHAN_AGE / LIDARR_EXTENSIONS / LIDARR_PROTECTED_PATTERNS # (same pattern for SONARR_ and RADARR_) ``` --- ## Adding a New Arr To add Readarr or any other arr cleanup to the ecosystem: 1. Copy `radarr_cleanup.sh` as the template — same classification logic applies 2. Update the API endpoint, variable names, and root path 3. Add configuration variables to `Master.conf` 4. Add the script to `MEDIA_MAINTENANCE_JOBS` in `Master.conf` 5. Test with `--dry-run --log` before running live The orchestrator picks it up automatically — no changes to `media_management.sh` needed.