Files
musicfetch/README.md
zebra 9fd4c8585b Rewrite musicfetch as v2: dual-source search with interactive picker
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>
2026-06-08 19:30:47 -07:00

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), with yt-dlp scraping 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+
  • requests
  • ytmusicapi (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' from requests, 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) and ffmpeg (for -x extraction / 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_URL is reachable.
  • Wrong album art from YouTube: install ytmusicapi so MusicFetch can resolve proper YouTube Music URLs and metadata.
  • yt-dlp errors: update with yt-dlp -U; ensure ffmpeg is installed for extraction/embedding.
  • idna import error: pip install --force-reinstall idna requests.
  • Permission denied writing files: ensure the output root exists and is writable (-o/--root or MUSICFETCH_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