Accept free-form queries (artist/album/title and combos) instead of strict "Artist - Track". Search Lidarr and YouTube Music concurrently, present a unified rich picker with bold keyword matching, and act on the chosen hit. - Normalize results via a Hit dataclass across both sources - Lidarr: /api/v1/search (album+artist) with album/artist lookup fallback - YouTube: ytmusicapi for accurate metadata + music.youtube.com URLs, yt-dlp scrape fallback; tag overrides from the chosen hit - Lidarr album pick adds artist+album monitored, runs interactive release search, and falls through to top YouTube hit when no indexer release exists - argparse CLI: -n/--noninteractive, -s/--ytsearch, -d/--dry-run, -q/--quality, --limit, --lidarr-only/--yt-only, -o/--root, --search-all - Config via LIDARR_URL / LIDARR_API_KEY / MUSICFETCH_ROOT env vars - Update README; add .gitignore for __pycache__ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.9 KiB
🎵 MusicFetch
MusicFetch is a smart command-line utility that finds music by searching Lidarr (your music collection manager) and YouTube Music at the same time, shows you the top hits in an interactive picker, and downloads/queues whatever you choose. It accepts:
- A free-form query: an artist, an album, a track title, or combos like
"Artist - Title"or"Artist - Album"(e.g."ODESZA - Bloom","Daft Punk","Discovery"). - A URL (e.g.
"https://music.youtube.com/watch?v=..."or a regular YouTube URL).
Lidarr is tried first by default. If you pick a Lidarr album but no indexer release is available, MusicFetch automatically falls through to the top YouTube hit. YouTube downloads prefer YouTube Music URLs so album art and tags are correct.
🚀 Features
- One unified picker showing the top hits from Lidarr and YouTube together, with matching keywords bolded.
- Lidarr-first flow: pick an album → adds artist+album (monitored) → interactive indexer search → falls through to YouTube only if no release is found.
- Accurate YouTube metadata via
ytmusicapi(real artist / album / year / album art), withyt-dlpscraping as a fallback. - Explicit tag overrides on download so files are tagged from the chosen hit, not from scraped titles.
- Non-interactive, YouTube-first, dry-run, quality, limit, and source-restriction flags.
📦 Dependencies & Installation
🐍 Python
- Python 3.10+
requestsytmusicapi(recommended — accurate YouTube Music metadata)rich(recommended — nicer picker table + bold keyword matching)
pip install requests ytmusicapi rich
Note: if you hit
ModuleNotFoundError: No module named 'idna'fromrequests, repair it with:pip install --force-reinstall idna requests
ytmusicapi and rich are optional — without them MusicFetch falls back to
yt-dlp search scraping and a plain ANSI picker.
📼 External Tools
yt-dlp(audio download/extraction) andffmpeg(for-xextraction / embedding).
pip install -U yt-dlp
sudo apt install ffmpeg # or your distro's equivalent
⚙️ Configuration
Set via environment variables:
| Variable | Default | Purpose |
|---|---|---|
LIDARR_API_KEY |
(required for Lidarr) | Lidarr API key. |
LIDARR_URL |
http://localhost:8686 |
Lidarr base URL. |
MUSICFETCH_ROOT |
/media/music |
Default output root folder. |
export LIDARR_API_KEY="your-lidarr-api-key"
🧑💻 Usage
./musicfetch [OPTIONS] QUERY...
Options
| Flag | Description |
|---|---|
-n, --noninteractive |
Auto-pick the top hit (no prompt). |
-s, --ytsearch |
Search/select YouTube first instead of Lidarr first. |
-d, --dry-run |
Show every action without executing it. |
-q, --quality {best,320,m4a,opus,flac} |
Audio quality/format (default best). |
--limit N |
Hits per source (default 10). |
--lidarr-only |
Skip YouTube. |
--yt-only |
Skip Lidarr. |
-o, --root PATH |
Output root folder (default /media/music). |
--search-all |
Search all albums when adding an artist to Lidarr. |
--debug |
Verbose output. |
Examples
# Interactive: combined Lidarr + YouTube picker
./musicfetch "ODESZA - Bloom"
# Just an artist / just an album / just a title all work
./musicfetch "Daft Punk"
./musicfetch "Discovery"
# YouTube first, auto-pick top hit
./musicfetch -s -n "Daft Punk - Harder Better Faster Stronger"
# Dry run — see what would happen, change nothing
./musicfetch -d "ODESZA - Bloom"
# YouTube only, lossless preferred
./musicfetch --yt-only -q flac "Bonobo - Kerala"
# Download by URL (YouTube Music URL preferred for correct art)
./musicfetch "https://music.youtube.com/watch?v=xxxxxxxxxxx"
📁 Output Structure
<root>/
├── Artist Name/
│ ├── Album Name/ (managed by Lidarr)
│ └── youtube/ (yt-dlp downloads / fallbacks)
❓ Troubleshooting
- No Lidarr hits / "LIDARR_API_KEY not set": export your key and confirm
LIDARR_URLis reachable. - Wrong album art from YouTube: install
ytmusicapiso MusicFetch can resolve proper YouTube Music URLs and metadata. yt-dlperrors: update withyt-dlp -U; ensureffmpegis installed for extraction/embedding.idnaimport error:pip install --force-reinstall idna requests.- Permission denied writing files: ensure the output root exists and is writable (
-o/--rootorMUSICFETCH_ROOT).
🛠️ Contributing
PRs welcome. This script is middleware around Lidarr + yt-dlp, not a Lidarr replacement. Keep it a single bash-friendly executable.
📜 License
GPL V3.0