Commit graph

3179 commits

Author SHA1 Message Date
Broque Thomas
43ed30b4d2 fix(musicbrainz): user-facing search recall + album-detail 404
Two bugs surfacing on the Fix popup and enhanced-search MB tab:

1. Strict Lucene phrase queries (`recording:"X" AND artist:"Y"`) killed
   recall on user-facing manual search — diacritics ("Bjork" vs canonical
   "Björk"), bracketed suffixes like "(Live)", and any AND-clause
   mismatch returned zero results. Added `strict: bool = True` param to
   `search_release` / `search_recording`; when False, sends a bare query
   joining title + artist so MB hits alias/sortname indexes with
   diacritic folding. `/api/musicbrainz/search` (Fix popup) and
   `core/library/service_search.py` (service tabs) now pass strict=False.
   Enrichment workers stay on strict mode — precision matters there
   because they auto-accept the top hit above a confidence threshold.

2. Every MB album click was silently 404-ing — `_render_release_as_album`
   passed `cover-art-archive` as an MB `inc` param, but it's not a valid
   include for the /release resource (MB rejects with 400). The CAA flags
   come back on every release response by default, so dropping the bad
   include preserves the image-scope picker logic intact.
2026-05-19 15:38:24 -07:00
Broque Thomas
478bcc5d3b fix(amazon): search albums/artists and track numbers for t2tunes
t2tunes uses HTTP 400 for transient Amazon-side failures instead of 5xx.
The first API call in a fresh session hit this every time, so album and
artist searches always failed while the track search (called 0.5 s later)
got through.

- _get_json: retry up to 3 times (1 s, 2 s backoff) on t2tunes-specific
  400 "Failed to search" responses
- All search_raw calls switched from types="track,album" to types="track"
  — t2tunes album-type queries are currently broken server-side; albums
  and artists are now derived from track result metadata instead
- search_albums: drop is_album filter, extract album fields from track hits
- get_album_tracks: fall back to stream index (1-based) when t2tunes tags
  omit trackNumber, preventing every track landing as track 01
2026-05-19 14:04:26 -07:00
Broque Thomas
1575ba4684 Fix stale _artistDetailGoingBack flag when back lands on non-artist page
If history.back() navigated away from artist-detail entirely (e.g. to
library), _artistDetailGoingBack stayed true. The next forward artist
navigation would then pop the label stack instead of pushing, causing
the back-button label to show plain Back instead of the correct page.

Guard the pop with currentPage === artist-detail; clear the flag
unconditionally in the else branch.
2026-05-19 12:55:38 -07:00
Broque Thomas
e7ba5408aa Restore smart back-button label on artist detail page
PR #644 removed the back-button label logic as collateral when removing
the full originStack. The label is independent of the stack — restore it
without restoring the old click-handler navigation (browser history handles
that now).

- _artistDetailLabelStack: module-level stack of {type:'page',pageId} or
  {type:'artist',name} entries, pushed on forward navigation, popped on back
- _artistDetailGoingBack flag: set by the back button click handler so
  navigateToArtistDetail knows to pop instead of push when called by the
  React route on browser-history navigation
- Backfill currentArtistName from the API response so URL-driven entries
  (which pass '' for name) have real names on state before the next similar-
  artist navigation pushes them onto the stack
- No-history fallback navigates to the recorded origin page
2026-05-19 12:53:37 -07:00
Broque Thomas
4bfa43bece Fix MusicBrainz artist detail showing MBID as name
URL-driven routing (PR #644) no longer passes the display name as a query
param to the artist-detail endpoint. The source-only detail builder fell back
to artist_id when artist_name was empty, surfacing the raw MBID as the page
title for MusicBrainz artists.

Two fixes in build_source_only_artist_detail:
- Drop the artist_id fallback in resolved_name so an MBID can never become
  the display name
- Add a musicbrainz elif branch (matching the Spotify/Deezer/iTunes pattern)
  that calls MusicBrainzSearchClient.get_artist() to resolve the real name
  and genres from the MBID when no name is provided
2026-05-19 12:34:35 -07:00
BoulderBadgeDad
c02cf15fdf
Merge pull request #644 from kettui/refactor/artist-detail-react-route
Centralize artist-detail page hand-off logic, make it URL-driven
2026-05-19 12:07:12 -07:00
Antti Kettunen
37f1adef4a
fix(stats): remove non-existent artist_source 2026-05-19 21:23:11 +03:00
Antti Kettunen
54efb85240
fix(webui): guard similar artist bubbles
- avoid calling buildArtistDetailPath when a similar artist has no usable id
- render a disabled bubble instead so empty MusicBrainz IDs do not crash the panel
2026-05-19 21:21:02 +03:00
Antti Kettunen
fa0ac4ced3
refactor(webui): simplify similar artists cleanup
- no need for a separate effect since we can use the existing one
- no need to cancel the similar artists query upon entering, since the
  unregister callback already does it
2026-05-19 10:40:41 +03:00
Antti Kettunen
0d683d87c0
refactor(webui): link artist detail navigation
- replace click-driven artist-detail hops with semantic links
- keep SPA transitions via shell bridge interception for /artist-detail/:source/:id
- drop legacy page helper wrappers and dead bridge plumbing
2026-05-19 10:22:59 +03:00
Antti Kettunen
30c687ae7b
refactor(webui): cancel similar-artists in route
- expose a shell-bridge cancel primitive for similar-artists loading
- stop stale similar-artists streams from the artist-detail route lifecycle
- keep the legacy loader abort-only and make abort logs page-agnostic
- update bridge and route tests for the new cleanup path
2026-05-19 09:28:05 +03:00
Antti Kettunen
5e39f1ee09
refactor(webui): centralize artist-detail handoff
- add a canonical TanStack route for artist-detail and keep the legacy page as the renderer target
- expose page-level artist-detail navigation on the shell bridge for legacy callers
- remove artist-detail-specific routing, origin stack, and back-label logic from the shared shell helpers
2026-05-19 09:26:10 +03:00
Antti Kettunen
728481db31
refactor(webui): route artist-detail handoff
- add canonical /artist-detail/:source/:id TanStack route
- hand the legacy page off through the shell bridge
- remove artist-detail branching from generic shell helpers
2026-05-19 08:14:13 +03:00
Broque Thomas
56eff933d4 Delete pr_description.md 2026-05-18 21:56:59 -07:00
Broque Thomas
e0e31079e6 Update test: get_release includes cover-art-archive 2026-05-18 21:20:57 -07:00
Broque Thomas
f7dfc3aab2 Fix MusicBrainz cover art using release-level CAA scope when available
Include cover-art-archive in the get_release call so _render_release_as_album
can check whether the representative release actually has front art before
building the URL. Prefer release-scope when confirmed present; fall back to
release-group scope otherwise. Prevents storing a release-group URL that CAA
reports as having no art.
2026-05-18 21:16:35 -07:00
Broque Thomas
19307630d1 Fix missing album art for non-Spotify sources + animate Downloads nav icon
- watchlist_scanner: fall back to album.image_url when album object has no
  images list (affects MusicBrainz CAA URLs, iTunes, Deezer — all use
  image_url on the Album dataclass, not the Spotify-style images array)
- Pulse Downloads nav icon while active downloads are in progress, same
  pattern as watchlist scan animation
2026-05-18 20:24:13 -07:00
Broque Thomas
8dd39dee65 Pulse watchlist nav icon during active watchlist scan 2026-05-18 20:13:50 -07:00
Broque Thomas
3ae0ac9d55 Fix musicbrainz test button 2026-05-18 20:08:24 -07:00
Broque Thomas
bbeec87f39 2.5.6 2026-05-18 20:06:48 -07:00
BoulderBadgeDad
801cd10134
Merge pull request #640 from Nezreka/codex/musicbrainz-metadata-source
Codex/musicbrainz metadata source
2026-05-18 19:36:21 -07:00
Broque Thomas
24d0482697 Update diagnose_itunes_discover.py 2026-05-18 19:31:36 -07:00
Broque Thomas
f3ad65de34 Complete MusicBrainz watchlist source parity
Add MusicBrainz watchlist artist ID storage, badges, linked-provider editing, and per-artist preferred source support.

Backfill watchlist MusicBrainz matches from already-enriched library artists so existing MusicBrainz worker matches appear in watchlist cards and settings.

Extend bulk watchlist add, liked artist matching, artist map source picking, and service status labels to recognize MusicBrainz, with regression tests for watchlist ID persistence and backfill.
2026-05-18 19:19:25 -07:00
Broque Thomas
5bc5fbb662 Add MusicBrainz as a metadata source
Register MusicBrainz as a first-class metadata source alongside Deezer, iTunes, Spotify, Discogs, and Hydrabase. Expose the shared client through metadata services, add the settings option, and expand the MusicBrainz search adapter with source-compatible artist, album, track, and detail methods.

Carry MusicBrainz IDs through similar-artist discovery, recommended artists, artist map serialization, and personalized playlist selection. Update DB migrations and lookup filters so similar_artist_musicbrainz_id is preserved on older schemas and used for source requirements and library exclusion.

Normalize MusicBrainz album adapter output for import context and add regression coverage for registry mapping, typed album conversion, and similar-artist filtering. Verified by user with 120 focused tests passing.
2026-05-18 18:47:13 -07:00
Broque Thomas
aaf312cd34 Honor manual library matches across source labels
Manual matches can be created from sync history as mirrored while wishlist and download flows later see the same track as wishlist or a provider source. Add a shared track-level lookup that falls back from exact source/id to source_track_id and title/artist, then use it for wishlist adds, cleanup, and download analysis so mapped tracks are not re-added or redownloaded.

Add coverage for mirrored-source matches being honored by wishlist cleanup and download batches, including the internal wishlist force-download path.
2026-05-18 16:32:38 -07:00
Broque Thomas
52dcdbe0f7 Harden Amazon worker schema migration
Ensure the Amazon enrichment worker verifies its required columns before querying pending work or progress, preventing upgraded installs from spamming no-such-column errors when amazon_match_status is missing.

Add regression coverage for legacy databases without Amazon enrichment columns.
2026-05-18 15:47:04 -07:00
BoulderBadgeDad
33673a6e3a
Merge pull request #636 from Nezreka/feat/artist-detail-deep-link
Feat/artist detail deep link
2026-05-18 15:38:22 -07:00
Broque Thomas
098c787861 Add release art fallback for artist detail hero
Use the first available album, EP, or single artwork when an artist portrait is missing or fails to load, keeping artist detail pages visually populated across library and source-only artists.

Refresh the PR description for the artist detail deep-link branch.
2026-05-18 15:07:09 -07:00
Broque Thomas
a6282b3009 Fix source artist detail navigation from discover modals
Preserve source metadata for seasonal and cached discover album modals so artist links use real provider IDs instead of falling back to library/name routes.

Treat source-only artist detail discographies as clickable missing releases and skip library-only ownership/enhancement checks.
2026-05-18 13:50:10 -07:00
Broque Thomas
3a4017ea2b feat: artist-detail deep linking — /artist-detail/:source/:id
Artist detail pages previously always pushed /artist-detail to the URL,
so refreshing the page or sharing a link would drop users on a broken
empty page with no artist loaded.

URL format is now /artist-detail/:source/:id (e.g.
/artist-detail/spotify/4tZwfgrHOc3mvqsCAfo4LT or
/artist-detail/library/42). The source segment lets the backend
synthesize a response from the right metadata client without a DB hit.

Changes:

Client routing (legacy shell + TanStack bridge)
- buildArtistDetailPath / _getDeepLinkArtistDetail added to init.js;
  parse both new :source/:id and legacy bare :id formats so old
  bookmarks still work
- navigateToPage passes artistId + artistSource through to the router
  bridge, which builds the dynamic href instead of hardcoding route.path
- resolveShellPageFromPath / resolveLegacyShellPageFromPath use a prefix
  match so /artist-detail/* resolves to artist-detail page-id
- globals.d.ts typed for artistId / artistSource options
- activateLegacyPath and syncActivePageFromLocation (popstate) both
  restore artist from URL using skipRouteChange:true to avoid a
  re-navigation loop back to /artist-detail
- loadInitialData restores artist from URL on page load (router not yet
  mounted at DOMContentLoaded so legacy path runs unconditionally)
- Same-artist guard in navigateToArtistDetail prevents double-fetch
  when the router fires activateLegacyPath after the initial navigation

Server
- artist_source_detail.build_source_only_artist_detail now resolves
  artist name from the source API when none is supplied, so deep-link
  restores with an empty name string still render correctly

Tests
- test_spa_deep_linking: /artist-detail/42 and /artist-detail/spotify/ID
  both serve index.html
- bridge.test.ts: source-aware URL building and library fallback
- route-manifest.test.ts: prefix path resolution
- artist_source_detail: name resolved from source when input is empty
2026-05-18 13:07:54 -07:00
Broque Thomas
e061f12a05 Filter owned artists from discovery recommendations 2026-05-18 11:40:12 -07:00
Broque Thomas
04adbf01e2 Update index.html 2026-05-18 09:56:39 -07:00
BoulderBadgeDad
25a3bcda62
Merge pull request #633 from Nezreka/codex/quarantine-followups
Harden quarantine approval flows
2026-05-18 08:44:16 -07:00
Broque Thomas
f25433ea57 Harden quarantine approval flows 2026-05-18 08:37:11 -07:00
BoulderBadgeDad
fc00d0311e
Merge pull request #632 from Nezreka/codex/source-aware-artist-detail-links
Preserve source when opening artist detail
2026-05-18 07:55:08 -07:00
Broque Thomas
cd715f8697 Preserve source when opening artist detail 2026-05-17 23:40:39 -07:00
Broque Thomas
6af5d191cd Release 2.5.5 — Manual Library Match
Bump version to 2.5.5. Collapse WHATS_NEW to 2.5.5 block (Manual Library
Match entry only). Remove subreddit link from README.
2026-05-17 23:18:59 -07:00
BoulderBadgeDad
ed01a1af8c
Merge pull request #626 from Nezreka/codex/full-release-date-tags
Preserve full release dates in audio tags
2026-05-17 23:11:10 -07:00
Broque Thomas
54dbd150cb Preserve full release dates in audio tags 2026-05-17 23:02:41 -07:00
BoulderBadgeDad
3e67ac6887
Merge pull request #625 from Nezreka/codex/artist-owned-album-matching
Tighten artist discography soundtrack matching
2026-05-17 22:59:40 -07:00
Broque Thomas
025007b97f Tighten artist discography soundtrack matching 2026-05-17 22:51:38 -07:00
BoulderBadgeDad
1cf85987dc
Merge pull request #624 from Nezreka/codex/quarantine-button-escaping
Fix quarantine action button escaping
2026-05-17 22:03:19 -07:00
Broque Thomas
52ee406a6c Fix quarantine action button escaping 2026-05-17 21:47:56 -07:00
BoulderBadgeDad
de560cac85
Merge pull request #623 from Nezreka/codex/manual-library-match
Codex/manual library match
2026-05-17 21:18:30 -07:00
Broque Thomas
0345478361 Skip wishlist adds for manual library matches 2026-05-17 20:50:55 -07:00
Broque Thomas
3e7eeb7c9c Honor manual matches in automatic wishlist cleanup 2026-05-17 20:43:04 -07:00
Broque Thomas
94f6c950cb Polish manual library match tool card 2026-05-17 20:32:18 -07:00
Broque Thomas
42f4aa5eac Add manual library track matching 2026-05-17 20:27:05 -07:00
BoulderBadgeDad
4d882180bb
Merge pull request #622 from Nezreka/codex/missing-track-import
Codex/missing track import
2026-05-17 14:27:12 -07:00
Broque Thomas
f3d5ef6528 Test missing-track existing file imports
Add service-level coverage for the Enhanced Library I Have This flow: copying an existing source file, writing the target album DB row, preserving source audio, inheriting album identity tags, and migrating older track tables that lack disc_number.
2026-05-17 14:18:17 -07:00