Commit Graph
897 Commits
Author SHA1 Message Date
vicrodh e6e0b18f83 fix: start playback after radio queue creation
All three radio commands (album, artist, track) were setting the queue
but not triggering playback. Add bridge.play_index(0) after set_queue.
2026-03-10 00:26:13 -06:00
vicrodh 9780948ca8 feat: add Essentials [Genre] section to For You tab
Add v2_reco_get_top_genres command that queries the user's most-played
genres from reco_events. Frontend loads top genre and fetches
ideal-discography featured albums filtered by that genre.
2026-03-10 00:05:25 -06:00
vicrodh b34b809ad5 feat: add album suggestions and forgotten favorites backend commands
Add v2_get_album_suggestions (album/suggest endpoint with blacklist filtering)
and v2_reco_get_forgotten_favorites (favorites not played in N days) for the
For You tab's Similar to and Rediscover your Library sections.
2026-03-09 23:50:45 -06:00
vicrodh 12fec1979f feat: re-enable all scene discovery caches
- Metadata cache (artist location/genres, 30-day TTL)
- Scene cache (full discovery response for first page, 30-day TTL)
- Qobuz validation cache (per-artist name match, 30-day TTL)

Second visit to same scene loads instantly from cache.
2026-03-09 19:15:14 -06:00
vicrodh faa68d1079 feat: real progress bar and improved loading state for scene discovery
Backend emits 'scene-discovery-progress' events with phase, progress
percentage, and detail. Frontend listens and shows a real progress bar
(0-40% MB search, 40-95% Qobuz validation, 100% done).

Loading state: hides header, cycles icons (Music/Globe/Network) at
1.5s intervals in a 96px pulse circle, shows progress bar with
percentage text.
2026-03-09 17:29:14 -06:00
vicrodh da225499ef fix: pass known MBID from scene discovery to artist detail view
When navigating from scene discovery to artist detail, pass the
MBID we already have from MusicBrainz instead of resolving by
name. Fixes wrong metadata for homonymous artists (e.g. The
Warning MX vs The Warning US).

Also improve Qobuz validation to request 5 results and pick
the best match by albums_count for name collisions.
2026-03-09 16:21:19 -06:00
vicrodh 74b75c144d feat: filter overly broad genre tags from scene discovery queries
Tags like "latin", "rock", "pop", "electronic" return the entire
country's catalog as noise. These are now excluded from MB search
queries but kept for affinity scoring. If ALL genres are broad,
falls back to using them to avoid empty results.
2026-03-09 15:30:16 -06:00
vicrodh eb199c9ba1 feat: add country_code to ArtistLocation, fix scene label
Store ISO 3166-1 alpha-2 country code (lowercase) in ArtistLocation
for flag display. Scene label now shows just country name instead of
"Country, City scene".
2026-03-09 14:15:05 -06:00
vicrodh e065af4d7e revert: show precise birth/founding location in sidebar
Restore "Born in: United Kingdom, Brixton" / "Founded in: United
Kingdom, Leyton" in the artist sidebar. The scene discovery search
uses country-level queries regardless, so the sidebar should show
the precise MB location data.
2026-03-09 14:08:07 -06:00
vicrodh 35b1626a7b simplify: search by country instead of subdivision in Lucene
MB Lucene is literal text match only - no hierarchy. Searching by
subdivision (England, California) misses most artists. Now search
directly by country: tag:"heavy metal" AND area:"United Kingdom".
Scoring handles regional relevance.
2026-03-09 14:06:51 -06:00
vicrodh 84bb4f387c feat: include country in Lucene area search for broader results
MB artists have beginarea as specific city (London, Birmingham) and
area as country (United Kingdom), never the subdivision (England).
Now the Lucene query includes the country: tag:"heavy metal" AND
(beginarea:"England" OR area:"England" OR area:"United Kingdom").
This finds all UK heavy metal artists instead of just the 9 that
literally have "England" as their area.
2026-03-09 14:01:43 -06:00
vicrodh 07961504f4 fix: load-more duplicates and stale metadata cache
- Add next_offset to LocationDiscoveryResponse for correct pagination
- Frontend uses MB-level offset instead of displayed artist count
- Frontend deduplicates by mbid when appending load-more results
- Stable sort by score desc + mbid asc for deterministic ordering
- Temporarily disable metadata cache (had stale display_name values)
2026-03-09 13:47:27 -06:00
vicrodh b20f5cd20e feat: show resolved subdivision in artist sidebar instead of birth city
Resolve city to top-level subdivision at metadata time so the artist
sidebar shows "United Kingdom, England" instead of "United Kingdom,
Brixton". Label changed from "Born in"/"Founded in" to "From" to
match the broader regional context of scene discovery.
2026-03-09 13:36:17 -06:00
vicrodh d6796fbe27 feat: walk UP to top-level subdivision for area resolution
Rewrite resolve_parent_subdivision to iteratively walk the hierarchy
until finding the subdivision whose parent is the country.
Brixton -> Lambeth -> Greater London -> England (under UK).
Los Angeles -> California (under US).
Max 5 hops to prevent infinite loops.

Also: bump per_genre_limit to 200, display limit to 50,
fix misleading log (showed original city instead of resolved name).
2026-03-09 13:32:07 -06:00
vicrodh 7aa707e7ee feat: smart area resolution for scene discovery
Resolve cities UP to subdivision level via MB area relations API:
- Leyton -> England, Los Angeles -> California, Brixton -> England
- Uses direction:"forward" to walk "part of" chain upward
- Two-level inline lookup for districts/boroughs (avoids recursive async)
- Bump per_genre_limit to 100 for broader coverage
2026-03-09 13:16:58 -06:00
vicrodh 9696b1d4f4 fix: pass city name separately for MB Lucene search, not compound display_name
Was searching beginarea:"United States, Los Angeles" which returns 0
results. Now passes just "Los Angeles" for the search query and builds
"United States, Los Angeles" display separately for the UI header.
2026-03-09 13:01:08 -06:00
vicrodh 694fd8dd9b feat: rewrite discovery to use genre+area Lucene search instead of blind browse
The browse API returns ALL artists from an area alphabetically with no
genre filtering. For LA that's 15K+ random artists. Now we search
tag:"thrash metal" AND beginarea:"Los Angeles" for each genre, giving
genre-relevant results directly from MusicBrainz.

Also adds dynamic loading messages that cycle through discovery steps
and temporarily disables all scene/validation caching for tuning.
2026-03-09 12:55:17 -06:00
vicrodh 82775ce63a feat: implement v2_discover_artists_by_location pipeline
Full scene discovery pipeline:
1. Resolve area MBID (if not provided) via MB area search
2. Check 30-day scene cache
3. Browse MB artists by area with tags
4. Score candidates with genre affinity algorithm
5. Validate top results against Qobuz catalog
6. Cache validation results individually (30-day TTL)
7. Cache full scene response for offset=0
2026-03-09 12:27:13 -06:00
vicrodh 3eb106493f feat: add v2_musicbrainz_get_artist_metadata command
Exposes artist location, life span, and affinity seeds to the
frontend. Caches results for 30 days. Reuses the existing
get_artist_with_relations API call, extracting area fields
that were previously ignored.
2026-03-09 12:07:17 -06:00
vicrodh 96ca640313 feat: add MusicBrainz location discovery backend foundation
- models.rs: Area, ArtistMetadata, ArtistLocation, LocationPrecision,
  AffinitySeeds, LocationCandidate, LocationDiscoveryResponse,
  ArtistBrowseResponse, AreaSearchResponse structs. Added area and
  begin_area fields to ArtistFullResponse and ArtistResult.

- client.rs: browse_artists_by_area (MB browse API by area MBID),
  search_area (resolve area name to MBID).

- cache.rs: mb_artist_metadata (30d), mb_scene_cache (30d),
  mb_qobuz_validation (30d) tables with get/set methods.

- genre_normalization.rs: normalize_genre, noisy tag filtering,
  extract_affinity_seeds, genre_summary. Covers rock, metal,
  electronic, hip-hop, jazz, and other genre families.

- location_discovery.rs: extract_metadata from ArtistFullResponse,
  resolve_location with city/state/country precision, country code
  to name mapping, affinity scoring, scene cache key builder,
  MB date formatting.
2026-03-09 12:04:51 -06:00
vicrodh 05f1a5ec13 chore: bump version to 1.1.19
- Cargo.toml, tauri.conf.json, package.json, snapcraft.yaml
- Regenerate Cargo.lock and package-lock.json
- Add metainfo release entry for 1.1.19
2026-03-09 00:35:42 -06:00
vicrodh 26f20ceb3f fix: resolve tauri version mismatch and track Cargo.lock
- Update @tauri-apps/api from 2.9.1 to 2.10.1 (matches Rust crate 2.10.x)
- Update @tauri-apps/cli from 2.9.6 to 2.10.1
- Remove Cargo.lock from .gitignore (binary projects should track it)
- Fixes build errors for distro packagers (NixOS, etc.)

Closes #151
2026-03-09 00:23:49 -06:00
vicrodh a07ee71090 feat: tag-scoped thumbs down for discovery recommendations
Add dismissal system for "You May Also Like" discovery artists. Dismissals
are scoped to the genre tag used for the search, so dismissing AC/DC from
electronic recommendations won't affect metal recommendations.

- New discovery_dismissals table in reco DB (tag + normalized artist name)
- v2_dismiss_discovery_artist command persists dismissal per tag
- Discovery pipeline filters dismissed artists for both primary and secondary tags
- Backend returns 8 results (frontend shows 6, keeps 2 reserves)
- Thumbs-down button appears on hover, instantly replaces with reserve
- Returns primaryTag in DiscoveryResponse for frontend dismiss context
2026-03-08 22:49:06 -06:00
vicrodh 776987856a fix: tray icon path for Flatpak and titlebar double-click maximize
- Fix Flatpak tray icon path (com.blitzfc.qbz, not com.blitzkriegfc.qbz)
- Fix titlebar double-click: prevent JS handler from firing on native
  drag regions, which caused double toggleMaximize (maximize then
  immediate restore)
- Improve tray click handlers to properly detect minimized state
2026-03-08 21:43:30 -06:00
vicrodh 572d23b935 feat: replace ListenBrainz co-listening with MusicBrainz tag-based discovery
ListenBrainz similar-artists returned mainstream crossover artists (SOAD,
Led Zeppelin for Metallica) instead of genre-accurate results. Now uses
MusicBrainz tag search to find artists sharing the seed's primary genre tag
(e.g. "thrash metal" returns Megadeth, Slayer, Kreator, etc).

- Add search_artists_by_tag to MusicBrainz client
- Deterministic shuffle using seed MBID hash for variety across artists
- Secondary tag fallback when primary yields fewer than 5 results
- Rename label to "You May Also Like", limit results to 6
- Add Last.fm get_similar_artists method (unused, for future use)
- Add tags field to ArtistFullResponse model
- Tighten local history exclusion to play_count > 2
2026-03-08 21:30:01 -06:00
vicrodh cd0615350f refactor: switch discovery to ListenBrainz Labs similar-artists API
Replace lb-radio endpoint (popularity-based) with Labs similar-artists
POST endpoint that returns actual similarity scores. Add 85% threshold
filtering and expose similarityPercent field in DiscoveryArtist model.
2026-03-08 15:47:17 -06:00
vicrodh 501546fb55 feat: add ListenBrainz discovery pipeline for Artist Network sidebar
Add v2_get_discovery_artists command that uses ListenBrainz lb-radio API
to find novel artist recommendations. Pipeline: fetch candidates from
ListenBrainz, filter out seed/similar/local-history artists, resolve on
Qobuz, filter blacklisted, return top 8 by affinity score.
2026-03-08 14:51:30 -06:00
vicrodh 309c4b2cc2 fix: clear reco meta caches when image cache is cleared
When the user clears the image cache from settings, also clear
reco_album_meta, reco_track_meta, and reco_artist_meta tables.
This forces re-resolution from Tier 2/3 with the correct (small)
image URLs instead of keeping stale large (600px) URLs in Tier 1.
2026-03-08 12:56:35 -06:00
vicrodh 63b1161afe perf: optimize ML/reco module for home view loading
- Add composite indexes on reco_events for GROUP BY + ORDER BY queries
  (event_type + album_id/track_id/artist_id + created_at DESC)
- Add composite index on reco_scores for scored lookups
  (score_type + item_type + score DESC)
- Eliminate duplicate fallback queries in get_home_seeds_internal
  by inlining the empty check into the scored branch
- Parallelize resolve_favorites with recent albums, tracks, and
  artists (4-way tokio::try_join instead of 3 + sequential)
- Batch cache writes: collect all Tier 3 API results first, then
  write to API cache and reco meta with single lock acquisitions
  instead of locking per-item inside spawned tasks
2026-03-08 12:52:52 -06:00
vicrodh 8a2c12ee41 perf: parallelize artist resolution and use small images for cards
Resolve albums, tracks, and artists concurrently with tokio::try_join
instead of sequentially. Artists were waiting behind album/track
resolution unnecessarily. Also change get_image() to prefer small
(230px) over large (600px) for card contexts, reducing download size.
2026-03-08 12:41:00 -06:00
vicrodh e8d6aa4f4f feat: add image cache backend with LRU eviction
- ImageCacheService: disk-based cache keyed by MD5 hash of URL
- LRU eviction by last-access time (not creation time)
- ImageCacheSettings: configurable max size (default 200MB), can disable
- v2 commands: get_cached_image, get/set settings, stats, clear cache
- Cache stored at ~/.cache/qbz/images/ with SQLite metadata
2026-03-08 10:37:42 -06:00
vicrodh 57702afc37 fix: respect force_dmabuf as full GPU opt-in for compositing too (#127)
When user enables Force DMA-BUF in Developer Settings, skip the
NVIDIA+Wayland compositing disable. This setting signals "I want
full GPU acceleration" and should grant both DMA-BUF and compositing.
2026-03-08 09:43:57 -06:00
vicrodh 4a4a9a4213 fix: defensive graphics fixes for Flatpak Wayland blur stutter (#127)
- Detect Flatpak sandbox at startup and log it
- In Flatpak on Wayland, unset DISPLAY to prevent WebKitGTK from
  falling back to XWayland internally (causes CPU-GPU texture
  round-trips that degrade CSS blur performance)
- Per-GPU Wayland paths: only disable compositing and DMA-BUF for
  NVIDIA on Wayland. AMD/Intel get full GPU acceleration on native
  Wayland (compositing enabled, DMA-BUF enabled)
- Change GitHub Releases Flatpak manifest from --socket=x11 to
  --socket=fallback-x11 to match Flathub and prevent XWayland
  on Wayland sessions
2026-03-08 09:32:56 -06:00
vicrodh 976fa201d5 docs: update README and link resolver comment for Spotify embed scraping
Remove Spotify API credential setup from README since playlist import
now uses embed scraping. Update resolve_via_odesli_and_search doc
comment to reflect the new Spotify data path.
2026-03-06 13:33:36 -06:00
vicrodh 727e5288e7 refactor(spotify): remove API dependency, use embed scraping only
Spotify client_credentials API access ends 2026-03-06. Remove all
API token/proxy code and the paginated fetch_playlist_with_token
function. Playlist imports now go straight to embed page scraping
(limited to ~50 tracks, no ISRC/album data).

Link resolver for Spotify tracks/albums also switched from API to
embed page scraping via new fetch_embed_metadata function.

Remove Spotify credentials from .env.example since they are no
longer needed.
2026-03-06 13:30:44 -06:00
vicrodh 786ce883ac fix(library): extract track/disc number from file tags during backfill import
insert_qobuz_cached_track_direct was hardcoding track_number to 0,
causing all imported tracks to show wrong numbers. Now accepts
track_number and disc_number params, and both callers (backfill
downloads and offline cache sync) extract metadata from the audio
file via MetadataExtractor before inserting.

Also fix LocalLibraryView to use || instead of ?? for track_number
fallback, so 0 correctly falls back to index-based numbering.

Closes #147
2026-03-06 11:08:32 -06:00
vicrodh 5b9f5a75c2 feat(ui): add explicit content badge across entire app
Display parental_warning badge (E icon) next to track titles in all
views: TrackRow, QueuePanel, NowPlayingBar, ImmersivePlayer with all
13 visualizer panels, MiniPlayer surfaces, and AlbumDetailView.

Propagate parental_warning field through the full data chain from
Rust backend (qbz-models, queue, commands_v2, session_store, API
server) to frontend stores, adapters, and UI components. Badge uses
CSS mask technique with explicit.svg for theme compatibility.
2026-03-06 08:48:51 -06:00
vicrodh 01fc32e611 feat(audio): enable gapless playback on ALSA Direct and default ON
ALSA Direct playback thread now supports gapless via mpsc channel:
when current source ends, it checks for a queued next source and
transitions seamlessly without draining the PCM buffer.

Format mismatch still blocks gapless (bit-perfect has priority).
Gapless now defaults to enabled for all backends.
2026-03-05 11:45:32 -06:00
vicrodh f1e2c99b5b fix(audio): hot-reload gapless and normalization settings to player
v2_set_audio_gapless_enabled, v2_set_audio_normalization_enabled, and
v2_set_audio_normalization_target now call player.reload_settings()
after writing to SQLite, so changes take effect immediately without
requiring an app restart.
2026-03-05 11:19:50 -06:00
vicrodh 43df8a40e4 fix(purchases): restructure download paths to Artist/Album [FORMAT][Quality]/track
Embeds quality in album folder name instead of subfolder, so each
quality variant appears as a separate album in the local library.
Adds download error toast and fixes format labels to bracket notation.
Closes #116
2026-03-05 11:12:39 -06:00
vicrodh d431581f16 fix(notifications): normalize ashpd artwork icon payload
Normalize notification artwork to square PNG (max 512x512, <=4 MiB) before sending Icon::Bytes via ashpd portal, so album art renders reliably without legacy fallback.\n\ncx
2026-03-03 23:31:31 -06:00
vicrodh 70adee9f16 fix(notifications): restore album artwork via native D-Bus path
The XDG portal notification spec's icon field doesn't support inline
album artwork the way freedesktop Notifications does with image-path.

Dual-path approach:
- Native (non-Flatpak): use org.freedesktop.Notifications D-Bus
  interface directly with image-path hint for album artwork
- Flatpak (sandboxed): use ashpd portal (Flathub requirement)

Uses ashpd::is_sandboxed() for detection and ashpd's re-exported
zbus for the direct D-Bus call, avoiding extra dependencies.
2026-03-03 22:46:43 -06:00
vicrodh d3cad99bd9 fix(notifications): send artwork as bytes instead of file URI
The XDG portal was not displaying album artwork when passed as a
file:// URI (showed KDE default icon instead). Send artwork as
Icon::Bytes so the portal receives the image data directly.
2026-03-03 22:41:08 -06:00
vicrodh 69aed4e1ad feat(notifications): migrate from notify-rust to ashpd XDG Portal
Replace direct D-Bus notifications (notify-rust) with XDG Desktop
Portal notifications (ashpd) for Flathub compliance. Portal
notifications use the app's .desktop file identity and don't require
--talk-name=org.freedesktop.Notifications permission.

- Replace notify-rust dep with ashpd (linux-only, tokio+notification)
- Use NotificationProxy for portal-based notifications
- Use stable ID "track-now-playing" to replace instead of stacking
- Convert artwork path to file:// URI via ashpd::Uri
- Graceful fallback when portal is unavailable
2026-03-03 22:25:59 -06:00
vicrodh 00675de6b8 feat(snap): add snap sandbox detection and welcome modal wiring
Detect when QBZ runs inside a Snap sandbox (via SNAP env var) and show
a one-time welcome modal with required plug connection commands. Adds a
Snap Sandbox section in Settings with copyable commands, mirroring the
existing Flatpak pattern.

Backend: snap.rs module, DB table snap_welcome_shown, V2 commands.
Frontend: updatesService, +page.svelte modal queue, SettingsView section.
2026-03-02 11:10:50 -06:00
vicrodh b49d0b3e3b chore(release): bump version to 1.1.19-rc-1
cx
2026-03-01 18:59:24 -06:00
vicrodh 55a1ef25e6 fix(ui): polish mini/immersive layout and queue favorite behavior
cx
2026-03-01 18:56:23 -06:00
vicrodh 9c6265abd8 fix(linux): default main window to opaque for shutdown stability
cx
2026-03-01 17:21:49 -06:00
vicrodh 75254d26a9 fix(linux): apply WebKit EGL shutdown stability workarounds
cx
2026-03-01 17:13:42 -06:00
vicrodh b95edec754 fix(shutdown): avoid forced exit(0) during main window close
cx
2026-03-01 16:55:16 -06:00