Containerized workers for Sonarr, Radarr, and Lidarr.
Current scripts in this repo:
sonarr_missing_searcher.py: searches Sonarr series (monitored, norsstag) per seriesradarr_missing_searcher.py: searches Radarr movies (monitored, norsstag) per movielidarr_missing_searcher.py: searches Lidarr artists (monitored, norsstag) per artist
The Sonarr worker:
- Calls Sonarr
GET /api/v3/series - Filters to monitored shows without the excluded tag (default
rss) - Triggers
POST /api/v3/commandwithSeriesSearchfor each selected show
This is useful for periodic search passes while keeping the logic outside Sonarr.
- Loads the library from Sonarr/Radarr/Lidarr API endpoints (
/series,/movie,/artist) - Filters to monitored items without excluded tags (default
rss) - Ranks eligible items by release date (newest first, best effort)
- Targets the newest
1000eligible items per run by default (TARGET_MISSING_RECORDS) - If fewer than the target exist, it uses all eligible items
- Deduplicates records into unique ARR entity IDs before queuing searches
- Skips items whose series has an excluded Sonarr tag (default:
rss) - After a successful
SeriesSearchqueue, tags that series withrssso future runs skip it - Processes series from newest release to oldest release (
series.firstAired, fallbackyear) - Sends a
SeriesSearchcommand per series - Sleeps between series searches to avoid hammering Sonarr/indexers
- Repeats on a configurable interval (or runs once and exits)
SONARR_URL(required): Sonarr base URL, e.g.http://sonarr:8989orhttp://host:8989/sonarrSONARR_API_KEY(required): Sonarr API keySONARR_API_VERSION(default:v3)EXCLUDED_TAGS(default:rss) comma-separated Sonarr tag labels to skip, e.g.rss,manual-onlyPROCESSED_TAG_LABEL(default:rss) Sonarr tag label to add after a series is processed; keep this tag inEXCLUDED_TAGSso future runs skip itTARGET_MISSING_RECORDS(default:1000) newest eligible untagged monitored items to process per run after exclusions (name retained for backward compatibility)CHECK_INTERVAL_SECONDS(default:21600) how often to run (6h)SEARCH_DELAY_SECONDS(default:2) delay betweenSeriesSearchcommandsSERIES_SEARCH_COOLDOWN_MINUTES(default:720) avoid re-searching the same show too often while the container stays upPAGE_SIZE(default:1000) legacy setting retained for compatibility (not used in current library-scan mode)MAX_SERIES_PER_RUN(default:0)0means unlimitedREQUEST_TIMEOUT_SECONDS(default:30)RUN_ONCE(default:false) run a single cycle and exitDRY_RUN(default:false) log what would be searched without calling SonarrLOG_LEVEL(default:INFO)
- Edit
.envand set the three URLs and API keys:SONARR_URL/SONARR_API_KEYRADARR_URL/RADARR_API_KEYLIDARR_URL/LIDARR_API_KEY
- Start all three workers:
docker compose up -d --buildThis starts:
- one container:
arr-missing-searchers - inside it, a small supervisor starts
sonarr,radarr, andlidarrworkers
docker build -t arr-missing-searchers -f Dockerfile.all .
docker run -d --name arr-missing-searchers \
--env-file .env \
arr-missing-searchersdocker run --rm \
--env-file .env \
-e RUN_ONCE=true \
arr-missing-searchers- The workers scan the Sonarr/Radarr/Lidarr libraries and only process monitored items that do not have the excluded tag(s).
- Before searching, it resolves Sonarr tag IDs and excludes series tagged with
EXCLUDED_TAGS(defaultrss). - After queuing a
SeriesSearch, it addsPROCESSED_TAG_LABEL(defaultrss) to the series via Sonarr so the series is skipped in future runs. - It ranks eligible untagged monitored items by release date and processes the newest
TARGET_MISSING_RECORDS. - It sorts queued series by newest release first, then works toward older series.
- It triggers
SeriesSearchper show (not per episode). - Aggressive searching can hit indexer rate limits; tune
CHECK_INTERVAL_SECONDS,SEARCH_DELAY_SECONDS, andMAX_SERIES_PER_RUN.
Files:
radarr_missing_searcher.pyDockerfile.all(shared single-container image)
What changes vs Sonarr:
- Uses
RADARR_URL,RADARR_API_KEY,RADARR_API_VERSION(defaultv3) - Searches per movie using Radarr
MoviesSearch - Tags processed movies with
PROCESSED_TAG_LABEL(defaultrss) and excludesEXCLUDED_TAGS - Sorts movies newest-to-oldest by release date (
physicalRelease/digitalRelease/inCinemas, fallbackyear) - Uses
MAX_MOVIES_PER_RUNandMOVIE_SEARCH_COOLDOWN_MINUTES
Radarr uses the shared .env file (see .env.example). Relevant keys:
RADARR_URL=http://radarr:7878
RADARR_API_KEY=replace-me
RADARR_API_VERSION=v3
EXCLUDED_TAGS=rss
PROCESSED_TAG_LABEL=rss
TARGET_MISSING_RECORDS=1000
PAGE_SIZE=1000
MAX_MOVIES_PER_RUN=0
MOVIE_SEARCH_COOLDOWN_MINUTES=720
CHECK_INTERVAL_SECONDS=21600
SEARCH_DELAY_SECONDS=2
RUN_ONCE=false
DRY_RUN=false
LOG_LEVEL=INFOFiles:
lidarr_missing_searcher.pyDockerfile.all(shared single-container image)
What changes vs Sonarr:
- Uses
LIDARR_URL,LIDARR_API_KEY,LIDARR_API_VERSION(defaultv1) - Scans monitored artists without excluded tags and searches per artist
- Searches per artist using Lidarr
ArtistSearch - Tags processed artists with
PROCESSED_TAG_LABEL(defaultrss) and excludesEXCLUDED_TAGS - Sorts artists newest-to-oldest by best available release date metadata (fallback
year) - Uses
MAX_ARTISTS_PER_RUNandARTIST_SEARCH_COOLDOWN_MINUTES
Lidarr uses the shared .env file (see .env.example). Relevant keys:
LIDARR_URL=http://lidarr:8686
LIDARR_API_KEY=replace-me
LIDARR_API_VERSION=v1
EXCLUDED_TAGS=rss
PROCESSED_TAG_LABEL=rss
TARGET_MISSING_RECORDS=1000
PAGE_SIZE=1000
MAX_ARTISTS_PER_RUN=0
ARTIST_SEARCH_COOLDOWN_MINUTES=720
CHECK_INTERVAL_SECONDS=21600
SEARCH_DELAY_SECONDS=2
RUN_ONCE=false
DRY_RUN=false
LOG_LEVEL=INFO