A free, open-source bridge between Lidarr and YouTube that fills the gaps in your self-hosted music library. Powered by yt-dlp, MusicBrainz, iTunes, and AcoustID, it searches YouTube for your missing albums, scores the best audio match, downloads it at up to 320 kbps, writes complete ID3 metadata with embedded artwork, and triggers a Lidarr import — all from a clean web UI that runs on any Docker host (NAS, Synology, Unraid, Raspberry Pi, VPS).
Quick Start · Features · How It Works · Configuration · Screenshots · FAQ
RefreshArtist; background paginated sync of wanted/missing for instant UI/wanted/missing endpoint into a local SQLite cache so the dashboard loads instantly.yt-dlp queries YouTube and returns the top 15 candidates.fpcalc and matched against the expected MusicBrainz recording ID before acceptance.RefreshArtist command is sent so Lidarr scans and picks up the new tracks.Instead of pushing finished files into Lidarr, you can register this app inside Lidarr as a native download path. Lidarr then drives the whole flow — search, grab, monitor and import — exactly like it would with a real Usenet indexer + SABnzbd client.
It works by exposing two emulated protocols:
| Surface | Emulates | Endpoint |
|---|---|---|
| Indexer | Newznab | /api/newznab/api |
| Download client | SABnzbd | /api/sabnzbd |
When Lidarr searches for a wanted album, the indexer matches it against the locally-synced missing-albums cache and returns one "release" pointing back at this app. Lidarr grabs it and hands it to the SABnzbd client, which enqueues the album in the normal download engine, downloads from YouTube into the download folder, and reports completion so Lidarr imports the files itself.
music), and Save.http://<this-app-host>:<port> (e.g. http://192.168.1.x:5005)/api/newznab/api/api/sabnzbdmusic)Note: In this mode the app leaves downloaded files in the download folder (under the category) for Lidarr to import — it does not copy to the Lidarr music path or send
RefreshArtistitself. Make sure the download folder is visible to Lidarr at the same path (or via a remote path mapping). Job state is kept in memory, so a restart mid-download will look "removed" to Lidarr, which will simply re-search.Indexer feed & RSS: When Lidarr queries the indexer with no search terms (its connection Test and periodic RSS sync), the feed returns your currently-synced missing albums (newest first). This is what makes the indexer Test pass — so let the missing-albums sync finish first (the dashboard should list missing albums). With RSS sync enabled, Lidarr will then grab missing albums automatically; the feed shrinks as albums stop being missing. If you only want downloads on explicit/automatic search, disable Enable RSS on the indexer in Lidarr.
No retry loops: An album that was just attempted (and a download currently in progress) is held back from the indexer feed and from new grabs for a cooldown window — controlled by
scheduler_retry_after_hours(default 24h) — so a failing album is not re-grabbed and re-downloaded endlessly. After the cooldown it is offered again (with a fresh release id) so transient failures still get retried. Set the value to0only if you want no cooldown.
services:
lidarr-downloader:
image: angrido/lidarr-downloader:latest
container_name: lidarr-downloader
ports:
- "5005:5000"
volumes:
- ./config:/config
- /DATA/Downloads:/DATA/Downloads
- /DATA/Media/Music:/music
environment:
- LIDARR_URL=http://192.168.1.XXX:8686
- LIDARR_API_KEY=your_api_key_here
- DOWNLOAD_PATH=/DATA/Downloads
- LIDARR_PATH=/music
- PUID=1000
- PGID=1000
- UMASK=002
restart: unless-stopped
Open the web UI at http://localhost:5005 and configure the rest from the Settings page.
| Variable | Example | Description |
|---|---|---|
LIDARR_URL |
http://192.168.1.10:8686 |
Lidarr base URL (use LAN IP) |
LIDARR_API_KEY |
abc123… |
Lidarr → Settings → General |
DOWNLOAD_PATH |
/DATA/Downloads |
Where new tracks are saved |
LIDARR_PATH |
/music |
Final music library path |
Most other settings (audio format, concurrent tracks, match score threshold, forbidden words, scheduler, notifications, AcoustID, yt-dlp tuning) live in the Settings page of the web UI.
If YouTube returns "Sign in to confirm you're not a bot", supply a cookies file:
cookies.txtYT_COOKIES_FILE:volumes:
- ./cookies.txt:/cookies/cookies.txt
environment:
- YT_COOKIES_FILE=/cookies/cookies.txt
⚠️ Never use your main Google account — cookies expire and accounts can be flagged.
Enable in the Settings page and provide an AcoustID API key. The container already ships with fpcalc (chromaprint).
Is this a replacement for a real music indexer?
No — it's a fallback when albums are unavailable through standard Lidarr indexers. Audio quality is limited to YouTube's source.
Does it work with Plex, Jellyfin, or Navidrome?
Yes. Files are imported into Lidarr's library, which any music server can then index.
What audio formats are supported?
MP3 (default, up to 320 kbps), M4A, and Opus — selectable in Settings.
Will it download playlists or single YouTube videos?
Yes. The YouTube page accepts any YouTube or YouTube Music URL, including full playlists, with metadata preview before queuing.
Does it run on Synology / Unraid / Raspberry Pi?
Yes — any platform that runs Docker. The image is multi-arch.
Is yt-dlp kept up to date?
You can upgrade yt-dlp from the Settings page with a single click; the UI shows the installed and latest PyPI versions.
Versions before SQLite stored state in JSON files. Migrate with:
docker exec -it lidarr-downloader python3 tools/migrate_json_to_db.py --config-dir /config
The originals are renamed to *.json.migrated.
git clone https://github.com/Angrido/Lidarr-YouTube-Downloader.git
cd Lidarr-YouTube-Downloader
pip install -r requirements.txt
python app.py # http://localhost:5000
# Run tests:
source .venv/bin/activate && python -m pytest tests/ -v
This project is provided for personal, educational use to manage your own music library. Users are solely responsible for complying with copyright laws and YouTube's Terms of Service.
Made with ❤️ for the self-hosted music community
$ claude mcp add Lidarr-YouTube-Downloader \
-- python -m otcore.mcp_server <graph>