Hey everyone,
I created scripting for moving movies (and TV shows) in and out of rotation on my Plex server. I only have so much storage, and wanted to make room for newer media.
Looking for feedback (please be nice!) and if this is something others can use, feel free.
Project Name: NAS Media Automation — cold storage & rotation
Repo/Website Link: https://github.com/chapdad031167/NAS-Media-Server-cold-storage-and-rotation
Description:
My 22 TB pool hit 83% and manual cleanup stopped scaling. This is the set of scripts I built to fix it, cleaned up and documented for anyone running the same Plex + Radarr + Sonarr + qBittorrent stack.
Three jobs:
Duplicate cleanup — finds movies with multiple files for the same title and year (including a .mkv/.mp4 pair), keeps the largest, flags the rest.
Torrent cleanup — removes finished torrents whose payload is already imported, gated on seeding goals (ratio/seed-time) and confirmed import. Filesystem version, plus a safer qBittorrent-API version that removes the torrent properly so you don't break seeds.
Cold storage rotation — the main event. A read-only scanner queries Radarr/Sonarr and writes a reviewable candidate list of aged media; a second script moves each item to a USB archive drive (rsync copy → checksum verify → delete source), records it in a manifest, and unmonitors it so it isn't re-downloaded. A restore script brings anything back the same way. Optional Tautulli guard skips anything you've actually watched recently.
A hard-won lesson baked in: v1 aged media by filesystem mtime. Then I migrated the library to a new volume, every mtime reset to "today," and the scanner found zero candidates forever. It now ages by TMDB release date (via Radarr/Sonarr) instead, which survives migrations.
Safety design (this stuff deletes/moves terabytes, so it's paranoid by default):
Everything defaults to a dry run; destructive actions require an explicit --run.
Kids-content hard exclusion — anything under /kids/ /kidstv/ is never archived, checked before any other rule.
Checksum-verified moves; a failed verify keeps the source untouched.
Protected-franchise list, free-space preflight, lock files, staleness guards.
Deployment:
Released under MIT (tagged release + CHANGELOG). Not a Docker app — these run directly on the NAS via cron / Synology Task Scheduler. A guided install.sh handles prerequisites, config, and a --doctor health check that live-tests Radarr/Sonarr connectivity; INSTALL.md is a full Synology (DSM) walkthrough. Python is stdlib-only; the shell scripts need common coreutils + rsync. Tested on Synology DSM with Radarr/Sonarr/qBittorrent/Plex. CI runs shellcheck + a pytest/shell suite + a secret scan on every push.
AI Involvement:
Transparent: the scripts started as my own working production scripts. I used an AI to help sanitize secrets out, refactor them for testability, build the test suite, write the docs, and run a couple of rounds of security-review hardening. Everything was reviewed by me and runs on my own hardware — the AI helped me clean it up for sharing.