Commit graph

13 commits

Author SHA1 Message Date
dlynas
78041ab66a feat: raise discography limit to 500 and paginate Discogs artist releases
Raise the album fetch limit from 50 to 500 across all three call sites
(artist-detail page, discography download modal, source-detail view).
Deezer/iTunes/Spotify already paginate internally; Discogs previously
fetched a single page capped at 200 raw rows.

Discogs is updated to paginate all pages (100 per request, Discogs max)
before filtering, so the limit applies to qualified albums rather than
raw API rows. The early-exit guard respects limit=0 as unlimited.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 23:35:08 -04:00
Broque Thomas
cc7a3f76ac Surface silent exceptions in metadata clients — 37 sites
- spotify_client.py: 15 sites (mostly `publish_spotify_status` + cache
  parse fallbacks)
- deezer_client.py: 10 sites (cache get/store + dataclass parsing)
- itunes_client.py: 4 sites (cache parsing + lookup fallback)
- discogs_client.py: 3 sites (cache parsing + token-from-config)
- tidal_client.py: 2 sites (used `_e` to avoid shadowing `e` from a
  sibling `except` clause in the same function — defensive)
- deezer_download_client.py: 3 sites

All converted to `logger.debug("...: %s", e)` with lazy formatter.
No control-flow changes.

Refs #369
2026-05-07 09:33:38 -07:00
Broque Thomas
4b23bee4a9 Add Discogs collection as a Your Albums source
Discord request: pull user's Discogs collection into the Your Albums
section on Discover, similar to how Spotify Liked Albums works.
Implementation extends the existing 3-source pipeline (Spotify /
Tidal / Deezer) to a 4-source pipeline with click-context dispatch —
Discogs-only albums open with rich Discogs release detail (vinyl/CD
format, year, label, country, tracklist). Mirrors the per-source
dispatch pattern from enhanced/global search.

Discogs client (`core/discogs_client.py`):
- New `get_authenticated_username()` resolves the username for the
  configured personal token via Discogs's `/oauth/identity` endpoint.
  Cached on the instance so subsequent collection page-fetches don't
  re-hit it.
- New `get_user_collection(username=None, folder_id=0, per_page=100,
  max_pages=50)` walks all pages of `/users/{username}/collection/
  folders/{folder_id}/releases`. Returns normalized dicts ready for
  upsert_liked_album. folder_id=0 = Discogs's "All" folder.
  Pagination cap of max_pages*per_page = 5000 releases — bounds
  runtime on heavy collections.
- New `get_release(release_id)` thin wrapper for `/releases/{id}` —
  returns the raw API response so the album-detail endpoint can
  render rich context.
- Both methods defensive: missing token → empty list, malformed
  responses → skipped, falsy ids → None. Disambiguation suffix
  stripping (`Madonna (3)` → `Madonna`) so Discogs artist names
  match what Spotify/Tidal/Deezer use.

Schema (`database/music_database.py`):
- New `discogs_release_id TEXT` column on `liked_albums_pool`.
  Migration uses the established `try SELECT, except ALTER TABLE`
  pattern. Idempotent; safe on existing installs.
- Added the column to the canonical CREATE TABLE for fresh installs.
- `upsert_liked_album` extended with `'discogs': 'discogs_release_id'`
  in BOTH the INSERT and UPDATE id-column maps so Discogs source_id
  routes to the new column. INSERT statement column count + value
  count updated together.

Backend (`web_server.py`):
- `/api/discover/your-albums/sources` — adds Discogs to the
  `connected` list when `discogs.token` config is set.
- `_fetch_liked_albums` — new branch for Discogs. Lazy-imports
  DiscogsClient, respects the `enabled_sources` config, walks the
  collection, upserts each release. Same try/except shape as the
  existing source branches.
- `/api/discover/album/<source>/<album_id>` — new `discogs` branch
  fetches the release via DiscogsClient.get_release, normalizes the
  Discogs tracklist format, parses Discogs's `MM:SS`/`HH:MM:SS`
  duration strings to milliseconds, returns the same response shape
  as the Spotify/Deezer/iTunes branches.

Frontend (`webui/static/discover.js`):
- `openYourAlbumsSourcesModal` — adds Discogs to `sourceInfo` with
  the vinyl emoji icon. Existing toggle/save plumbing handles it.
- `openYourAlbumDownload` — restructured the per-source dispatch:
  builds an ordered list of (source, id) tuples, tries each in turn,
  breaks on the first successful response. Pure-Discogs albums go
  straight to the Discogs detail endpoint → modal opens with Discogs
  context. Multi-source albums prefer Spotify/Deezer first since
  their tracklists carry proper streaming IDs ready for download.

Tests: `tests/test_discogs_collection_source.py` — 12 cases:
- get_user_collection: empty without token, normalizes response
  shape, strips disambiguation suffix, handles missing year, skips
  malformed releases, paginates correctly, caps at max_pages,
  uses explicit username when provided.
- get_release: passes id through to /releases/{id}, returns None
  for invalid ids without API call.
- liked_albums_pool: discogs_release_id round-trips through upsert
  + get; multi-source dedup carries both Spotify and Discogs IDs
  on the same row.

Verified: full suite 1825 pass (12 new), ruff clean, smoke test
populating + reading the discogs_release_id column round-trips
correctly via the real DB.

WHATS_NEW entry under '2.4.2' dev cycle.
2026-05-03 21:27:46 -07:00
Antti Kettunen
a759f778b6
Move metadata API into package
- add package-owned metadata API, cache, registry, and lookup modules
- keep legacy metadata_service and metadata_cache paths as explicit shims
- update metadata call sites and tests to use package-owned helpers
2026-04-29 08:10:18 +03:00
Broque Thomas
240dd87727 Fix Discogs cache — add field extractor, wire worker caching, browser UI
- Add _extract_discogs_fields to metadata cache — handles Discogs field
  names (title vs name, images array, Artist - Title format)
- Worker uses _fetch_and_cache_artist/_fetch_and_cache_album helpers
  that cache raw data while returning it for enrichment
- All search/lookup methods cache results for repeat queries
- Cache browser: Discogs stat pill, source filter, clear button, badge
- Fixes albums showing as 'Unknown' and artists missing images in cache
2026-04-02 19:47:36 -07:00
Broque Thomas
69a09826f4 Fix Discogs album lookups — try master ID before release ID
- get_album and get_album_tracks now try /masters/{id} first, fall back
  to /releases/{id} — artist discography returns master IDs which are
  in a different namespace than release IDs
- Fixes wrong album showing in download modal (master ID 3664443 for
  GNX was hitting /releases/3664443 which is a different album)
- Add Discogs source override to all 6 artist/album/track endpoints
- Add discogs_id to _resolve_db_album_id lookup
2026-04-02 18:35:20 -07:00
Broque Thomas
d98d3b33c4 Fix Discogs artist page load time — lazy track count loading
- Remove upfront master detail fetching (was 15+ API calls, 40+ seconds)
- Discography loads from releases list only (~1 second, 2 API calls)
- Track counts populate on-demand via get_album_tracks when clicking album
- New get_album_tracks method: tries /masters first, falls back to /releases,
  returns Spotify-compatible format with proper disc/track numbering
- Album type defaults to 'album' for masters without format metadata —
  Discogs limitation, singles only detectable from individual release format
2026-04-02 18:22:02 -07:00
Broque Thomas
39d11602ce Fix Discogs format field parsing — handle list or string type
- Search results return format as list ['Vinyl', 'LP'] while artist
  releases return comma-separated string — handle both
- Fixes "'list' object has no attribute 'lower'" error
2026-04-02 18:09:11 -07:00
Broque Thomas
f8b774e22d Fetch master release details for accurate track counts and album types
- Master releases now fetch /masters/{id} to get actual tracklist,
  genres, styles, and images — fixes 0/0 track count display
- Album type re-evaluated with real track count: 1-3 = single,
  4-6 = EP, 7+ = album
- Cover art from master detail used when search results have none
- Tested: Kendrick Lamar shows correct track counts, proper types,
  and images for all albums
2026-04-02 18:08:17 -07:00
Broque Thomas
92befdb029 Filter featured releases from Discogs artist discography
- Fetch artist name first, then compare against each release's primary
  artist — skip releases where the artist is listed after Feat./Ft./&
- "Beyoncé Feat. Kendrick Lamar" → skipped (Kendrick is featured)
- "Kendrick Lamar Feat. Rihanna" → kept (Kendrick is primary)
- Fixes artist pages showing unrelated albums from other artists
- Add _normalize_name helper and re import to DiscogsClient
2026-04-02 18:01:14 -07:00
Broque Thomas
5b23905973 Fix Discogs artist albums — prefer masters, filter features, fix types
- Prefer master releases over individual pressings to avoid duplicates
  (multiple pressings of same album showing separately)
- Individual releases only included if no master exists for that title
- Skip non-main roles (appearances, features, remixes by others)
- Better album type detection from format string: catches LP, Album,
  EP, Single, Compilation from comma-separated format field
- Fetch more results (3x limit) to compensate for filtering
2026-04-02 17:54:22 -07:00
Broque Thomas
a9eccfe1c5 Fix Discogs source display, album types, and track search
- Fix source name mapping so sidebar/dashboard shows 'Discogs' instead
  of falling through to 'iTunes'
- Fix album type detection: parse format string from artist releases
  endpoint (e.g. "File, FLAC, Single, 320") to correctly identify
  singles, EPs, albums, compilations — was defaulting everything to
  'single' because track count was 0
- Remove fake track search that returned albums as tracks — Discogs
  has no track-level search API, so tracks section is empty (honest)
- Track data available via album tracklists instead
2026-04-02 17:48:57 -07:00
Broque Thomas
c787d56500 Add Discogs API client for music metadata (#244)
- Full parity with iTunes/Deezer clients — same Track/Artist/Album
  dataclasses, same method signatures (search_artists, search_albums,
  search_tracks, get_artist, get_album, get_artist_albums)
- 25 req/min unauthenticated, 60 req/min with free personal token
- Rate limited via same decorator pattern with API call tracking
- Unique data: 400+ genre/style taxonomy, label info, catalog numbers,
  community ratings, artist bios
- Smart "Artist - Title" parsing for search results
- Release deduplication (Discogs has many pressings of same album)
- Track search via release tracklist extraction
- Tested: artist/album/track search, artist detail with bio, album
  detail with full tracklist + genres + styles + label
2026-04-02 15:59:15 -07:00