A Python script that intelligently manages Plex trash by:
- Identifying media items in trash
- Checking which files actually exist on the operating system
- Rescanning items that exist on disk until Plex recognizes them
- Emptying trash only for items that truly don't exist
- Smart Detection: Differentiates between files that are truly missing vs. files that Plex just can't see
- Automatic Rescanning: Attempts to rescan files that exist on disk but Plex shows as unavailable
- Enhanced TV Show Rescanning: Rescans entire TV shows instead of individual episodes for better reliability
- Library-wide Rescanning: Automatically triggers full library scans when >30% of items are in trash
- Safe Deletion: Only removes items from trash that don't exist anywhere
- Dry Run Mode: Preview changes before making them
- Report Generation: Creates detailed reports of all operations
- Docker Support: Easy deployment with Docker Compose
- Continuous Operation: Can run continuously on a configurable cycle
- Unattended Mode: Supports fully automatic operation with safety checks
The script uses environment variables for configuration. You can set these in a .env file or pass them as environment variables.
Create a .env file in the project root (see .env.example for a complete template):
# Required: Plex Server Configuration
PLEX_URL=http://your-plex-server:32400
PLEX_TOKEN=your_plex_token_here# Time in seconds between scans (default: 3600 = 1 hour)
SLEEP_DURATION=3600
# Run continuously in a loop (true) or run once and exit (false)
RUN_CONTINUOUSLY=true# Master switch: Enable automatic approval of all actions
AUTO_APPROVE=false
# Automatically approve rescanning items that exist on OS
AUTO_RESCAN=true
# Automatically approve emptying trash (USE WITH CAUTION!)
AUTO_EMPTY_TRASH=false
# Safety thresholds for auto-emptying trash
REQUIRE_MIN_ITEMS_FOR_TRASH=10
# TV Show rescan strategy settings
LIBRARY_RESCAN_THRESHOLD=30 # Trigger library scan if >30% in trash
MAX_SHOW_RESCAN_ATTEMPTS=3 # Max attempts to rescan a TV show
USE_SHOW_RESCAN=true # Enable show-level rescanning for TV
MAX_TRASH_PERCENTAGE=50# Run without making any changes - only reports what would be done
DRY_RUN=false
# Only generate report file without any rescan or trash operations
REPORT_ONLY=false
# Skip rescanning items that exist on OS but Plex doesn't recognize
NO_RESCAN=false
# Skip emptying trash even for items that truly don't exist
NO_EMPTY_TRASH=false# Maximum rescan attempts per item
MAX_RETRIES=3
# Maximum backoff multiplier for failed cycles (exponential backoff)
MAX_BACKOFF_MULTIPLIER=8
# Number of consecutive failures before sending alert
ALERT_AFTER_FAILURES=3
# Optional: Specific library name to check (leave empty to check all)
DEFAULT_LIBRARY=You can find your Plex authentication token by following Plex's official guide.
- Clone the repository
- Copy
.env.exampleto.envand configure your settings:cp .env.example .env # Edit .env with your Plex URL and token - Run with Docker Compose:
- For continuous operation (recommended):
docker-compose up -d
- For a single run:
docker-compose run --rm missingmediascanner
- For continuous operation (recommended):
-
Install dependencies with uv:
uv sync
-
Create your
.envfile:cp .env.example .env # Edit .env with your settings -
Run the script:
python src/main.py
All environment variables can be overridden with command-line arguments:
python src/main.py [OPTIONS]
Options:
--dry-run Only check and report, don't make changes
--report-only Only generate report file without any actions
--library NAME Check only a specific library
--no-rescan Skip rescanning items that exist on OS
--no-empty-trash Skip emptying trash
--max-retries N Maximum rescan attempts per item (default: 3)
--plex-url URL Plex server URL
--plex-token TOKEN Plex authentication token
--run-once Run once and exit (overrides RUN_CONTINUOUSLY)Dry run to see what would happen:
python src/main.py --dry-runCheck only a specific library:
python src/main.py --library "Movies"Generate report without making any changes:
python src/main.py --report-onlyUsing environment variable for dry run:
DRY_RUN=true python src/main.py- Identify Trash Items: Queries Plex for all items marked as trash/unavailable
- Check Library Trash Percentage: Calculates what percentage of each library is in trash
- Library-wide Rescan (if needed): If >30% of a library is in trash, performs full library scan first
- Check File Existence: Verifies if files actually exist on the operating system
- Categorize Items:
- Items that exist on OS but Plex doesn't see → Will attempt to rescan
- Items that don't exist anywhere → Can be safely removed
- Items that Plex recognizes → No action needed
- Smart Rescanning:
- TV Shows: Rescans entire shows instead of individual episodes for better reliability
- Movies/Music: Rescans individual items
- Empty Trash: Removes only items that truly don't exist
- Generate Report: Creates detailed report of all operations
The script generates detailed reports in the project directory with filenames like:
plex_trash_report_YYYYMMDD_HHMMSS.txt
Reports include:
- Summary of items processed
- Files that exist on OS but not in Plex
- Successfully rescanned items
- Items that don't exist anywhere
- Items that are OK in Plex
The Docker setup includes:
- Python 3.13 base image
- UV package manager for fast dependency installation
- Tini for proper signal handling
- Read-only mount of media directory
Update the compose.yaml volume mapping to match your media directory:
volumes:
- /mnt/user/data/media:/data/media:ro- The
.envfile contains sensitive credentials and is excluded from Git - Never commit your
.envfile to version control - The
.dockerignorefile prevents.envfrom being included in Docker images - Use environment variables in production (Docker Compose already does this)
Built with:
- Python 3.13+
- PlexAPI for Plex server interaction
- python-dotenv for environment variable management
- UV for fast dependency management