Commit graph

4 commits

Author SHA1 Message Date
Broque Thomas
d7e232e01c MusicBrainz: Artist-first browse for albums + tracks, keep text fallback
Bare name queries (typing 'metallica') now resolve to an artist MBID via
the fuzzy search added in the previous commit, then BROWSE that artist's
release-groups and recordings instead of text-searching release/recording
titles. That's the only way to fix the core garbage-results issue: MB
indexes release/recording titles, not artist names, so 'recording:metallica'
matches random tracks literally titled 'Metallica' (all scoring 100).

Structure:

- `_split_structured_query` — detects 'Artist - Title' / 'Artist – Title' /
  'Artist — Title' shapes. When present, text-search is correct (user
  gave an explicit title to match).
- `_resolve_top_artist` — memoized per-instance lookup for the top-scoring
  artist MBID. Backend fires artists/albums/tracks searches in parallel
  against one shared client instance, and albums+tracks both need the
  same artist lookup. Cache + lock means one HTTP call instead of three.
- `_release_group_to_album` / `_recording_to_track` — shared projection
  helpers between the browse and text paths so both paths return the
  same dataclass shape.

Search flow per kind:

- `search_albums('metallica')` → resolve top artist → browse release-groups
  with `type=album|ep|single|compilation` → sort by type priority then
  release date desc → Album dataclasses for top N.
- `search_tracks('metallica')` → resolve top artist → browse recordings
  with `inc=releases+artist-credits` → dedupe by normalized title (MB
  has many live/compilation variants of the same song) → sort by release
  date desc → Track dataclasses for top N.
- `search_albums('foo - bar')` → structured query → text-search path
  (unchanged behavior, now score-filtered to 80+).
- `search_tracks('foo - bar')` → same.
- Both text-search paths also dedupe through `_search_albums_text` /
  `_search_tracks_text` helpers, which apply the 80-score filter that
  the artist-first path gets free from the resolver's threshold.

Also dedupes text-path tracks through the new `_recording_to_track`
helper, replacing ~60 lines of inline projection code. Net change is
more lines overall (browse + helpers) but the text paths shrank and
the garbage-results issue is fixed.

Credit: kettui flagged the missing Artists section + unusable track
results during PR #371 review.
2026-04-24 08:13:40 -07:00
Broque Thomas
434d1c382c MusicBrainz: Re-enable real artist search (was returning empty)
`MusicBrainzSearchClient.search_artists` has been a `return []` stub
since the feature landed, with a comment claiming the MB tab 'doesn't
show artists.' That's why kettui saw a missing Artists section on the
search page — not a missing render, a hardcoded empty list.

Re-enable it properly:

- New `strict=False` parameter on `MusicBrainzClient.search_artist`
  sends a bare Lucene query instead of `artist:"..."`. MusicBrainz
  matches bare queries against alias+artist+sortname indexes together,
  which is the right behavior for user-facing fuzzy search (finds
  typos, aliases, sortname variants). `strict=True` remains the
  default for enrichment/AcoustID callers that want exact matches.

- Adapter filters results to `score >= 80`. MB assigns a 0-100 Lucene
  score on every hit; the true artist + close variants score 100,
  tribute bands and lookalikes typically land in the 40-65 range.
  The cutoff keeps "Metallica" (100) and drops "Black Metallica
  Tribute Band" (60) without hand-curated lists.

- Results returned as the same `Artist` dataclass used elsewhere in
  the search-tab adapter layer. `popularity` carries the MB score
  (0-100) so the frontend can sort/highlight top matches if desired.
2026-04-24 08:09:51 -07:00
Broque Thomas
3c48508c3f MusicBrainz: Add project URL to User-Agent per API requirements
MusicBrainz mandates a meaningful User-Agent with contact info, warning
that bare strings can trigger IP blocking under load. Our client was
sending `SoulSync/2.3` with no contact — and the search adapter passed
an app version hard-coded at "2.3" that's now stale (UI is at 2.40).

Fix: default contact to the project URL (`https://github.com/Nezreka/SoulSync`)
when no email is supplied, so every request lands as
`SoulSync/<version> ( https://github.com/Nezreka/SoulSync )`. Drop the
search-adapter version suffix to a generic "2" since the exact UI minor
version would add noise to every MB request without helping operators
track issues.

Reference: https://musicbrainz.org/doc/MusicBrainz_API — "it is
important that your application sets a proper User-Agent string."
2026-04-24 08:06:50 -07:00
Broque Thomas
4f5025d526 Add MusicBrainz search tab, wider global search, bump to v2.32
New MusicBrainz tab in Enhanced and Global search — finds tracks and
albums on MusicBrainz's community database with Cover Art Archive
images. Covers obscure tracks that Spotify/Deezer/iTunes miss.

- core/musicbrainz_search.py: search adapter with Track/Artist/Album
  dataclasses, Cover Art Archive integration, smart query parsing
- Albums deduplicated (keeps best version with date and art)
- No artist results shown (MusicBrainz has no artist images)
- Album detail with full tracklist for download modal
- Smart word-boundary splitting for queries without separators
- Global search results container widened from 620px to 920px
- UI version bumped to 2.32
2026-04-18 02:06:27 -07:00