- Playlist URLs download each track to per-artist folders (CLI + REST API).
One playlist = one job; done if >=1 track succeeds ("Downloaded N/M tracks").
- REST API /fetch now routes URL/playlist queries to download jobs.
- Lidarr metadata/quality profiles selected by name with env overrides
(LIDARR_METADATA_PROFILE/LIDARR_QUALITY_PROFILE), no more position-luck.
Defensive access guards against download_single returning ok=True
without title/artist keys, avoiding a KeyError in the job worker.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Playlists download each track to per-track artist folders (CLI + REST API,
one job per playlist, done if >=1 track succeeds). Profile selection by name
with env overrides (LIDARR_METADATA_PROFILE/LIDARR_QUALITY_PROFILE).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- FastAPI async job-based REST API wrapping musicfetch (X-API-Key auth,
Siri-friendly messages, dockerized for the Lidarr stack).
- Smarter Lidarr search: MusicBrainz track->album resolution + exact
mbid: lookup (prefers own-artist studio album), no fuzzy ranking.
- Bug fixes from live testing: single first-artist tag (no doubling).
Add musicbrainz_best_album() that resolves an artist+track pair to its
best studio album via the MusicBrainz search API, with a 1 req/sec
courtesy rate-limiter. Prefers plain studio albums over compilations,
singles, and live releases; falls back to any release group when no
studio album is found. Never raises — returns None on any failure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop fuzzy difflib scoring: MusicBrainz resolves track->album release-group
MBID, Lidarr album/lookup?term=mbid:<id> returns the exact album. Live-verified
against the user's Lidarr.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Scored best-first lidarr_search with MusicBrainz track->album resolution,
difflib scoring, preserved YouTube fallback. Fixes noninteractive API
picking junk (Pignickel) over the real album.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Live end-to-end test surfaced two bugs in youtube tagging:
- `--replace-in-metadata artist .* NAME` matched twice and doubled the
artist tag (e.g. "SLVMLORDSLVMLORD"). Anchor with ^.*$ to match once.
- Use only the first artist when several are present (SLVMLORD, not
"SLVMLORD, Travis Bradley, ...") for both the embedded tag and the
spoken/echoed API messages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Async job-based HTTP wrapper around the musicfetch binary, dockerized for the
Lidarr stack, X-API-Key auth, Siri-friendly human messages, port via
MUSICFETCH_PORT (default 6769).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
--debug for debug mode
--search-all will search all music sources as soon as the artist is added to Lidarr. The default behavior is to not search all sources.