Swaparr

February 23, 2026 · View on GitHub

Radarr, Sonarr and the other Starrs currently lack a built-in mechanism to handle stalled downloads, this project aims to solve that.

Swaparr is inspired by a Reddit thread "I wrote a script that repl.." from Douglas96.

⭐ Show Your Support for Open Source!

If Swaparr has been helpful to you and you appreciate the power of open-source software, please consider giving this repository a star. Your gesture will greatly support our efforts and help others discover Swaparr!

Stargazers

What is Swaparr?

Swaparr quietly operates in the background, offering full customization options and clear visibility through console logs. Its primary function is to address the issue of stalled downloads in starr instances.

Key Features:

  • Automatic Detection: Swaparr scans through all active downloads in your starr instances every 10 minutes (adjustable) to identify potential slowdowns.
  • Strike System: Identified downloads are given a strike, and this evaluation cycle repeats periodically. If a download accumulates the maximum allowed strikes, Swaparr automatically removes it from your instance.
  • Customization: Swaparr offers customization options to fine-tune striking behaviour.

Getting Started

Warning

Swaparr is still in beta, things might change before reaching version 1.0.0

Prerequisites

Docker and it's compose plugin are required, below is a matrix on how to install both for your system:

Operating SystemOfficial Instructions
Linuxdocs.docker.com/../linux-install
MacOSdocs.docker.com/.../mac-install
Windowsdocs.docker.com/.../windows-install

Configurations

Start with the provided compose file as a foundation, and customize it by excluding or adjusting any services.

version: '3'
services:

  radarr:
    image: ghcr.io/thijmengthn/swaparr:latest
    container_name: swaparr-radarr
    restart: unless-stopped
    environment:
      - BASEURL=http://127.0.0.1:7878 # IP or FQDN           (Required)
      - APIKEY=7f3a8..cbc07           # Radarr API Key       (Required)                
      - PLATFORM=radarr               # "radarr", "sonarr".. (Optional) default: radarr
      - MAX_STRIKES=3                 # Positive number      (Optional) default: 3     
      - SCAN_INTERVAL=10m             # 1d, 6h, 30m, etc..   (Optional) default: 10m   
      - MAX_DOWNLOAD_TIME=2h          # 1d, 6h, 30m, etc..   (Optional) default: 2h    
      - IGNORE_ABOVE_SIZE=25GB        # 1TB, 1GB, 1MB, etc.. (Optional) default: 25GB  
      - REMOVE_FROM_CLIENT=true       # Boolean              (Optional) default: true
      - STRIKE_QUEUED=false           # Boolean              (Optional) default: false
      - DRY_RUN=false                 # Boolean              (Optional) default: false

  # -- (Optional)
  sonarr:
    image: ghcr.io/thijmengthn/swaparr:latest
    container_name: swaparr-sonarr
    restart: unless-stopped
    environment:
      - BASEURL=http://127.0.0.1:8989 # IP or FQDN           (Required)
      - APIKEY=7f3a8..cbc07           # Sonarr API Key       (Required)
      - PLATFORM=sonarr               # "radarr", "sonarr".. (Optional) default: radarr
      - MAX_STRIKES=3                 # Positive number      (Optional) default: 3
      - SCAN_INTERVAL=10m             # 1d, 6h, 30m, etc..   (Optional) default: 10m
      - MAX_DOWNLOAD_TIME=2h          # 1d, 6h, 30m, etc..   (Optional) default: 2h
      - IGNORE_ABOVE_SIZE=25GB        # 1TB, 1GB, 1MB, etc.. (Optional) default: 25GB
      - REMOVE_FROM_CLIENT=true       # Boolean              (Optional) default: true
      - STRIKE_QUEUED=false           # Boolean              (Optional) default: false
      - DRY_RUN=false                 # Boolean              (Optional) default: false
🚩 Extended experimental support: Lidarr, Readarr and Whisparr
version: '3'
services:

  radarr:
    image: ghcr.io/thijmengthn/swaparr:latest
    container_name: swaparr-radarr
    restart: unless-stopped
    environment:
      - BASEURL=http://127.0.0.1:7878 # IP or FQDN           (Required)
      - APIKEY=7f3a8..cbc07           # Radarr API Key       (Required)                
      - PLATFORM=radarr               # "radarr", "sonarr".. (Optional) default: radarr
      - MAX_STRIKES=3                 # Positive number      (Optional) default: 3     
      - SCAN_INTERVAL=10m             # 1d, 6h, 30m, etc..   (Optional) default: 10m   
      - MAX_DOWNLOAD_TIME=2h          # 1d, 6h, 30m, etc..   (Optional) default: 2h    
      - IGNORE_ABOVE_SIZE=25GB        # 1TB, 1GB, 1MB, etc.. (Optional) default: 25GB  
      - REMOVE_FROM_CLIENT=true       # Boolean              (Optional) default: true
      - STRIKE_QUEUED=false           # Boolean              (Optional) default: false
      - DRY_RUN=false                 # Boolean              (Optional) default: false

  # -- (Optional)
  sonarr:
    image: ghcr.io/thijmengthn/swaparr:latest
    container_name: swaparr-sonarr
    restart: unless-stopped
    environment:
      - BASEURL=http://127.0.0.1:8989 # IP or FQDN           (Required)
      - APIKEY=7f3a8..cbc07           # Sonarr API Key       (Required)                
      - PLATFORM=sonarr               # "radarr", "sonarr".. (Optional) default: radarr
      - MAX_STRIKES=3                 # Positive number      (Optional) default: 3     
      - SCAN_INTERVAL=10m             # 1d, 6h, 30m, etc..   (Optional) default: 10m   
      - MAX_DOWNLOAD_TIME=2h          # 1d, 6h, 30m, etc..   (Optional) default: 2h    
      - IGNORE_ABOVE_SIZE=25GB        # 1TB, 1GB, 1MB, etc.. (Optional) default: 25GB  
      - REMOVE_FROM_CLIENT=true       # Boolean              (Optional) default: true
      - STRIKE_QUEUED=false           # Boolean              (Optional) default: false
      - DRY_RUN=false                 # Boolean              (Optional) default: false

  # -- (Optional)
  lidarr:
    image: ghcr.io/thijmengthn/swaparr:latest
    container_name: swaparr-lidarr
    restart: unless-stopped
    environment:
      - BASEURL=http://127.0.0.1:8989 # IP or FQDN           (Required)
      - APIKEY=7f3a8..cbc07           # Lidarr API Key       (Required)                
      - PLATFORM=lidarr               # "radarr", "sonarr".. (Optional) default: radarr
      - MAX_STRIKES=3                 # Positive number      (Optional) default: 3     
      - SCAN_INTERVAL=10m             # 1d, 6h, 30m, etc..   (Optional) default: 10m   
      - MAX_DOWNLOAD_TIME=2h          # 1d, 6h, 30m, etc..   (Optional) default: 2h    
      - IGNORE_ABOVE_SIZE=25GB        # 1TB, 1GB, 1MB, etc.. (Optional) default: 25GB  
      - REMOVE_FROM_CLIENT=true       # Boolean              (Optional) default: true
      - STRIKE_QUEUED=false           # Boolean              (Optional) default: false
      - DRY_RUN=false                 # Boolean              (Optional) default: false

  # -- (Optional)
  readarr:
    image: ghcr.io/thijmengthn/swaparr:latest
    container_name: swaparr-readarr
    restart: unless-stopped
    environment:
      - BASEURL=http://127.0.0.1:8989 # IP or FQDN           (Required)
      - APIKEY=7f3a8..cbc07           # Readarr API Key      (Required)                
      - PLATFORM=readarr              # "radarr", "sonarr".. (Optional) default: radarr
      - MAX_STRIKES=3                 # Positive number      (Optional) default: 3     
      - SCAN_INTERVAL=10m             # 1d, 6h, 30m, etc..   (Optional) default: 10m   
      - MAX_DOWNLOAD_TIME=2h          # 1d, 6h, 30m, etc..   (Optional) default: 2h    
      - IGNORE_ABOVE_SIZE=25GB        # 1TB, 1GB, 1MB, etc.. (Optional) default: 25GB  
      - REMOVE_FROM_CLIENT=true       # Boolean              (Optional) default: true
      - STRIKE_QUEUED=false           # Boolean              (Optional) default: false
      - DRY_RUN=false                 # Boolean              (Optional) default: false

  # -- (Optional)
  whisparr:
    image: ghcr.io/thijmengthn/swaparr:latest
    container_name: swaparr-whisparr
    restart: unless-stopped
    environment:
      - BASEURL=http://127.0.0.1:8989 # IP or FQDN           (Required)
      - APIKEY=7f3a8..cbc07           # Whisparr API Key     (Required)                
      - PLATFORM=whisparr             # "radarr", "sonarr".. (Optional) default: radarr
      - MAX_STRIKES=3                 # Positive number      (Optional) default: 3     
      - SCAN_INTERVAL=10m             # 1d, 6h, 30m, etc..   (Optional) default: 10m   
      - MAX_DOWNLOAD_TIME=2h          # 1d, 6h, 30m, etc..   (Optional) default: 2h    
      - IGNORE_ABOVE_SIZE=25GB        # 1TB, 1GB, 1MB, etc.. (Optional) default: 25GB  
      - REMOVE_FROM_CLIENT=true       # Boolean              (Optional) default: true
      - STRIKE_QUEUED=false           # Boolean              (Optional) default: false
      - DRY_RUN=false                 # Boolean              (Optional) default: false

Starting Swaparr

To start Swaparr, run the following command:

docker compose up -d

Monitor

You can monitor Swaparr's activities and track the processing of downloads by executing the following command. Omit the <container_name> parameter to view logs for all platforms:

docker compose logs <container_name>
Instructions: Stop or Update Swaparr

Stop

To shutdown Swaparr, run the following command:

docker compose down

Update

Updating Swaparr is a breeze, pull the latest images and restart the service:

docker compose pull
docker compose down
docker compose up -d

Useful Information

A brief rundown to shed light on a couple of things for you:

Environment Variables
NameDefaultDescription
BASEURLhttp://127.0.0.1:7878The URL of a radarr, sonarr or other starr instance.
APIKEY7f3a8..cbc07The API key of a radarr, sonarr or other starr instance.
PLATFORMradarrIndicates the type of starr platform, either radarr, sonarr, lidarr, readarr or whisparr.
MAX_STRIKES3Maximum number of strikes a download can accumulate before it is removed.
SCAN_INTERVAL10mHow often Swaparr checks for stalled downloads.
MAX_DOWNLOAD_TIME2hMaximum allowed download time before it's considered stalled.
IGNORE_ABOVE_SIZE25GBFiles larger than this size will be ignored and not monitored.
REMOVE_FROM_CLIENTtrueRemove from both queue and download client (default) OR false only the queue of a starr instance.
STRIKE_QUEUEDfalseWhen enabled, queued downloads are eligible to be striked instead of being bypassed.
DRY_RUNfalseSandbox mode; try Swaparr without it performing destructive actions on your instances.
Status-Types Explained
StatusDescription
NormalDownload is proceeding as expected; no issues detected.
StrikedDownload flagged as slow or stalled; may be removed if it continues to accumulate strikes.
RemovedDownload has been attempted to be removed from the starr instance.
IgnoredDownload is not monitored because it falls outside the set thresholds (e.g., size or time limits).
QueuedDownload is in the queue within the download client waiting to start; will not be striked.
DelayedDownload is temporarily paused or scheduled for later processing as defined in a delay profile.
CompletedDownload has finished and is seeding; will not be striked.

✨ Swaparr is for everyone!

Whether you need help, want to pitch in, or found a bug that needs fixing, just open an issue. We're all ears and ready to collaborate with you!

Star History Chart