Skip to content

Cleanup Rejected Downloads Script

Overview

Automatically removes files from /mnt/nfs_media/downloads/ that Sonarr/Radarr have rejected from importing.

Location: /home/monxas/scripts/cleanup-rejected-downloads.sh

Why This Exists

Sonarr and Radarr reject downloads for various reasons: - Quality downgrade - You already have better quality (e.g., 1080p exists, new file is 720p) - Already imported - Episode/movie already in library - Wrong format - Doesn't match quality profile - Not monitored - Series/movie not being tracked

These rejected files sit in downloads forever, wasting space. This script automatically cleans them up.

What It Does

  1. Queries Sonarr - Checks which files in /data/downloads are rejected
  2. Queries Radarr - Same for movies
  3. Age check - Only deletes files older than 3 days (safety buffer)
  4. Cleanup - Removes rejected files and their parent directories
  5. Non-media cleanup - Removes old non-video files (>7 days)

Usage

Manual Run

# Dry run (see what would be deleted)
./scripts/cleanup-rejected-downloads.sh true

# Actually delete rejected files
./scripts/cleanup-rejected-downloads.sh

Automatic (Cron)

# Install daily cron job (runs at 4 AM)
./scripts/install-cleanup-cron.sh

# View installed cron jobs
crontab -l

# Check logs
tail -f /var/log/cleanup-downloads.log

How It Works

Rejection Detection

# Sonarr API call
GET /api/v3/manualimport?folder=/data/downloads&filterExistingFiles=true

# Returns JSON with rejections:
{
  "path": "/data/downloads/Show.S01E01.mkv",
  "rejections": [{
    "reason": "Not an upgrade for existing episode file(s). Existing quality: Bluray-1080p. New Quality Bluray-720p.",
    "type": "permanent"
  }]
}

File Deletion Logic

IF file is rejected by Sonarr/Radarr
  AND file age > 3 days
  AND not in dry-run mode
THEN delete file (or parent directory if in folder)

Common Rejection Reasons

Reason Meaning Action
Not an upgrade Better quality already exists Safe to delete
Unknown Series/Movie Not tracked in Sonarr/Radarr Check if you want to add it first
Quality not wanted Doesn't match quality profile Safe to delete
Already imported File already in library Safe to delete

Safety Features

  1. 3-day minimum age - Won't delete fresh downloads
  2. Dry-run mode - Test before deleting
  3. Logging - All actions logged to /var/log/cleanup-downloads.log
  4. API verification - Only deletes what *arr apps explicitly reject

Configuration

Edit /home/monxas/scripts/cleanup-rejected-downloads.sh:

MIN_AGE_DAYS=3          # Minimum age before deletion
DOWNLOADS_PATH="/mnt/nfs_media/downloads"
SONARR_URL="http://localhost:8989"
RADARR_URL="http://localhost:7878"

Example Output

=== Cleanup Rejected Downloads ===

Checking Sonarr rejected downloads...
⚠ REJECTED: Scrubs S08E08 My Love 720p BluRay
  Reason: Not an upgrade. Existing: Bluray-1080p. New: Bluray-720p
  Age: 4 days
✓ Deleted directory: www.UIndex.org - Scrubs S08E08...

✓ Cleaned up 4 rejected file(s) from Sonarr

Checking Radarr rejected downloads...
✓ No rejected files in Radarr

Cleanup complete!

Troubleshooting

Script finds no rejections but files are stuck

Check API connectivity:

curl -s "http://localhost:8989/api/v3/manualimport?folder=/data/downloads&apikey=YOUR_KEY" | jq '.'

Verify paths: - Host path: /mnt/nfs_media/downloads/ - Sonarr sees: /data/downloads/ - Script converts between them

Files are too new to delete

Change MIN_AGE_DAYS in the script or wait until they're older than 3 days.

API key errors

API keys are read from: - Sonarr: /home/monxas/appdata/sonarr/config.xml - Radarr: /home/monxas/appdata/radarr/config.xml

Integration with Other Tools

Works alongside: - Sonarr/Radarr - Uses their APIs for rejection status - Plundrio-scanner - Cleans up after scanner marks files - VM health check - Can be called from health checks

Cron Schedule

Default: Daily at 4:00 AM

0 4 * * * /home/monxas/scripts/cleanup-rejected-downloads.sh >> /var/log/cleanup-downloads.log 2>&1

Why 4 AM? - Low activity time - Before morning media requests - After Watchtower updates (4 AM default)

Future Enhancements

Potential improvements: - [ ] Notification on cleanup (via ntfy) - [ ] Configurable age per rejection type - [ ] Lidarr support - [ ] Grafana dashboard integration - [ ] Move to quarantine instead of delete