Commit Graph
899 Commits
Author SHA1 Message Date
vicrodh 9ba09ff37b fix(share): handle Odesli entities with numeric IDs (Bandcamp)
Odesli's API returns entity IDs as integers for some platforms (e.g.
Bandcamp) while others return strings. The Entity.id field was typed as
String which caused serde deserialization to fail on numeric values.

Add a custom deserializer that accepts both strings and numbers.
Also show actual backend error in LinkResolverModal for easier debugging.
2026-02-20 16:31:02 -06:00
vicrodh e581508946 fix(link-resolver): search Qobuz catalog instead of relying on Odesli platform map
Odesli does NOT include Qobuz in its linksByPlatform response, so the
previous approach of extracting platforms["qobuz"] would always fail.

New strategy: use Odesli to identify the content (title/artist), then
search the Qobuz catalog via CoreBridge to find the matching album or
track. Falls back from track search to album search if needed.
2026-02-20 15:54:33 -06:00
vicrodh b78b67fa8c feat(link-resolver): cross-platform music link resolution via Odesli
Ctrl+L now accepts URLs from Spotify, Apple Music, Tidal, Deezer, and
song.link/album.link in addition to Qobuz. Non-Qobuz track/album URLs
are resolved to their Qobuz equivalent via the existing Odesli API
integration. Playlist URLs redirect to the Playlist Importer.

- Add MusicResource/MusicProvider enums and detect_music_resource()
- Add detect_resource() to each provider (spotify, apple, tidal, deezer)
- Add v2_resolve_music_link command with Odesli-based cross-resolution
- Upgrade LinkResolverModal with platform icon detection and playlist redirect
- Update i18n keys in all 4 locales (en, es, de, fr)
2026-02-20 15:27:49 -06:00
vicrodh 417ece2fb9 fix(library): clean up deleted files during scan refresh
Library scan now automatically removes tracks whose files no longer
exist on disk, both for full scans and single-folder scans. Previously,
deleted files would remain in the library until the user manually ran
"Cleanup missing files" from Settings.

Fixes #93
2026-02-20 14:54:00 -06:00
vicrodh 2d2df20c45 fix(context): add DailyQ, WeeklyQ, LabelTop playback context types
DailyQ and WeeklyQ were incorrectly using 'home_list' context type.
LabelTop was defined in frontend but missing from Rust backend.

- Add LabelTop, DailyQ, WeeklyQ variants to Rust ContextType enum
- Add match arms in commands_v2.rs and display_info()
- Update frontend ContextType union and display strings
- DynamicSuggestView now uses 'daily_q' context type
- WeeklySuggestView now uses 'weekly_q' context type
2026-02-20 03:55:39 -06:00
vicrodh 585053bd42 feat(label): redesign label detail view with Android-style sections
Replace the flat album grid LabelView with a rich detail page featuring:
- Header with label image, name, description, and play button
- Popular Tracks section (5/10/all expand, same UX as ArtistDetailView)
- Releases horizontal scroll row with "See all" → LabelReleasesView
- Critics' Picks section from second releases container
- Playlists, Artists, and More Labels sections

Backend: add /label/page and /label/explore API endpoints with V2
commands (v2_get_label_page, v2_get_label_explore). Models use
serde_json::Value for flexible section parsing.

Old LabelView renamed to LabelReleasesView for the "See all" flow.
i18n keys added to all 4 locales (en, es, de, fr).
2026-02-20 02:51:47 -06:00
vicrodh 494ddce28b feat(v2): register purchases-get-ids, purchases-get-by-type, and dynamic-suggest commands
New V2 Tauri commands:
- v2_purchases_get_ids: fetch purchase IDs with optional type filter
- v2_purchases_get_by_type: fetch all albums or tracks with download status
- v2_dynamic_suggest: typed dynamic suggestions from Qobuz API
- v2_dynamic_suggest_raw: raw JSON variant for debugging

Registered all four in the Tauri invoke handler.
2026-02-20 00:15:12 -06:00
vicrodh a7ffe13469 feat(api): add purchases-by-type, purchase-ids, and dynamic-suggest endpoints
New API client methods:
- get_user_purchases_page_typed: fetch purchases filtered by type (album/track)
- get_user_purchases_ids_page_typed: fetch purchase IDs by type
- get_user_purchases_all_typed: paginated fetch for a single purchase type
- get_user_purchases_ids_page: generic purchase IDs page
- get_dynamic_suggest / get_dynamic_suggest_raw: Qobuz dynamic suggestions

New models: DynamicSuggestRequest/Response/Track, DynamicTrackToAnalyse,
PurchaseIdsResponse, lenient serde deserializers for robust API parsing.
2026-02-20 00:15:05 -06:00
vicrodh 3a297c0b2b style: apply cargo fmt across codebase
Automated formatting pass covering 79 Rust source files.
No logic changes -- only line wrapping, import ordering,
and match/closure reformatting.
2026-02-20 00:14:58 -06:00
vicrodh 867b1dfbe0 perf(share): eliminate Odesli API call, construct song.link URLs directly
ISRC/UPC paths now use a single Deezer API request instead of two
sequential requests (Deezer + Odesli). The song.link/album.link URL
is constructed directly from the Deezer ID (e.g. song.link/d/12345).

This cuts latency from ~2-5s (often timing out) to ~200ms.
The Odesli fallback is kept only for get_by_url (no ISRC/UPC).
2026-02-19 18:47:44 -06:00
vicrodh 844bd60319 fix(share): use Deezer ID + platform param for faster Odesli lookups
Instead of passing a full Deezer URL to Odesli (which requires URL
resolution), use platform=deezer&type=song&id=XXX params directly.
This is faster since Odesli skips URL parsing.

Also fix album sharing (get_by_upc) — Odesli no longer accepts ?upc=
directly, same Deezer resolution approach applied.

Bump request timeout from 10s to 20s with 5s connect timeout.
2026-02-19 18:42:14 -06:00
vicrodh cfa66ef316 fix(share): restore Song.link sharing via Deezer ISRC resolution
Odesli no longer accepts ISRC as a direct query param or Spotify search
URLs. Replace with a two-step approach: resolve ISRC to a real Deezer
track URL via Deezer's free API, then pass that URL to Odesli.

Also fix error display in frontend — RuntimeError objects were shown as
[object Object] instead of extracting the details message.
2026-02-19 18:22:25 -06:00
vicrodh cbc2ff0b26 feat(audio): add PipeWire force bit-perfect mode
Add experimental toggle to force PipeWire clock.force-quantum alongside
clock.force-rate for true bit-perfect playback. Quantum is matched to
sample rate (1024 for <=48kHz, 2048 for <=96kHz, etc). Both values
reset to 0 on stop and pause-suspend to avoid affecting other apps.

Requires DAC Passthrough to be enabled, PipeWire backend only.
2026-02-19 18:01:42 -06:00
vicrodh 98ffd3dff2 chore: bump version to 1.1.15-rc-2 2026-02-19 16:57:19 -06:00
vicrodh 9bd8aec91b fix(purchases): add lenient deserialization for non-vital fields
If the Qobuz API returns an unexpected type for optional fields like
purchased_at, label, genre, quality metadata, etc., the field silently
defaults to None instead of crashing the entire purchases fetch.

cc
2026-02-19 16:36:07 -06:00
vicrodh 45ca758f47 fix(purchases): deserialize purchased_at as i64 unix timestamp
The Qobuz API returns purchased_at as a Unix timestamp integer, not a
string. Updated Rust structs, TypeScript types, and frontend date
formatting to handle numeric timestamps correctly.

Fixes #88

cc
2026-02-19 16:29:13 -06:00
vicrodh 3d497a33b0 fix(desktop): add %u to Exec and complete tarball .desktop for URI handling
The Tauri .desktop template was missing %u in the Exec line, preventing
the desktop environment from passing qobuzapp:// URIs as arguments when
launched from the browser. The tarball .desktop was also missing MimeType,
StartupWMClass, and StartupNotify fields.

Closes #44

cc
2026-02-19 16:17:25 -06:00
vicrodh a6cfa36a8d fix(packaging): compile binary as qbz instead of qbz-nix
Add [[bin]] section to Cargo.toml so cargo produces target/release/qbz
directly. Update all packaging references (workflows, PKGBUILD, Flatpak
manifest, AUR desktop file) to use the new binary name. This fixes DEB
and RPM packages installing the binary as /usr/bin/qbz-nix instead of
/usr/bin/qbz.
2026-02-18 16:45:10 -06:00
vicrodh 0055aef515 fix(plex): backfill album_key for existing cached tracks on migration
Existing plex_cache_tracks rows had NULL album_key after the column
migration, causing plex_cache_get_album_tracks WHERE clause to return
zero results until a full re-sync. Now computes and fills album_key
for all NULL rows on DB open.
2026-02-18 15:16:21 -06:00
vicrodh d26af4b7dd feat(plex): add disc/track number support and album track search
- Parse track_number (index) and disc_number (parentIndex) from Plex XML
- Add track_number, disc_number, album_key columns to plex_cache_tracks
- Fix plex_cache_get_album_tracks: add WHERE album_key clause (was
  returning all tracks) and sort by disc/track number instead of title
- Update all SELECT/INSERT queries to include new columns
- Add inline track search to album detail view with search icon toggle
- Update PlexCachedTrack frontend interface and mapPlexTrack mapping
- Add i18n keys for search placeholder in all 4 locales
2026-02-18 15:14:31 -06:00
vicrodh 11b3486c63 fix(v2): close frontend/backend command audit gaps
- add/register missing v2 commands surfaced by audit
- migrate frontend invokes to v2 equivalents
- eliminate legacy invoke callsites in audit report
- harden invoke audit parser for generic/multiline invoke usage

cx
2026-02-18 12:59:28 -06:00
vicrodh ba09345aa3 chore(release): prepare 1.1.15-rc-1 and beta checklist
cx
2026-02-17 20:13:30 -06:00
vicrodh 1472fb2dcc feat(purchases): implement real V2 purchases API and clean mock remnants
cx
2026-02-17 20:03:41 -06:00
vicrodh 42915197e3 feat: add downloaded purchases registry in SQLite backend with V2 commands
- downloaded_purchases table in library DB (permanent, per-user)
- V2 commands: mark_downloaded, remove_downloaded, get_downloaded_track_ids
- Frontend enriches purchase data with download status from backend
- Grid overlay for unavailable albums centered on artwork
- Quality filter expanded: All / Hi-Res / CD / Lossy (radio group)
- Album download status derived from track-level registry
2026-02-17 18:57:24 -06:00
vicrodh ceaf299558 feat(immersive): add spectral ribbon and fix home blacklist filtering
- add Spectral Ribbon analyzer/render path and immersive panel
- tune ribbon density/interpolation and bars edge-bin rendering
- apply artist blacklist filtering to discover index home containers
- include supporting i18n/settings/player wiring changes

cx
2026-02-17 17:28:32 -06:00
vicrodh 7e0c54c9f8 fix(playlists): restore suggestions and duplicate-check commands in v2
cx
2026-02-17 11:22:27 -06:00
vicrodh 76cf401a3a perf: separate library DB connection for download post-processing
Add a second LibraryDatabase connection to OfflineCacheState dedicated
to download post-processing writes. SQLite WAL mode natively handles
concurrent reads (UI via main connection) and writes (downloads via
this separate connection), eliminating app-level mutex contention that
caused progressive UI lag during bulk downloads.

Init after library.init_at() in both activate_session and
activate_offline_session. Teardown before main offline_cache teardown.
2026-02-17 11:02:02 -06:00
vicrodh 644571f82a perf: add batch offline cache command to replace sequential IPC loops
Add v2_cache_tracks_batch_for_offline command that inserts all tracks
in a single SQLite transaction and spawns download tasks in one IPC
call. Extract spawn_track_cache_download helper shared by both single
and batch commands.

Replace sequential for-of loops with batch calls in PlaylistDetailView
and +page.svelte (downloadAlbumById, handleDownloadAlbum,
handleReDownloadAlbum, reDownloadAlbumById). Single-track handlers
remain unchanged.

Reduces 75 IPC round-trips to 1 for bulk downloads.
2026-02-17 10:59:02 -06:00
vicrodh 343bfff357 perf: add 200ms time throttle to download progress events
Add a minimum 200ms interval between progress emissions per track,
on top of the existing 2% change filter. Always emits at 100%.
Limits events to max 5/sec/track, reducing IPC pressure during
concurrent downloads.
2026-02-17 10:55:09 -06:00
vicrodh bc8300ea62 fix: add WAL mode to api_cache and favorites_preferences SQLite connections
These two databases were missing PRAGMA journal_mode=WAL and
PRAGMA synchronous=NORMAL, which could cause UI lag from lock
contention during concurrent reads/writes.
2026-02-17 10:22:33 -06:00
vicrodh d4bc1fe677 fix(immersive): improve visualizer panels per feedback
Energy Bands + Oscilloscope:
- Constrain drawing area to 85% of screen height, vertically centered

Oscilloscope:
- Change from bottom-left info to centered artwork layout (like Bars)

Transient Pulse:
- Lower backend threshold 0.15 -> 0.04, cooldown 6 -> 3 frames
- Use raw (un-smoothed) bass-weighted RMS for sharper detection
- Add frontend-side supplementary beat detection from energy data

Album Reactive:
- Fix glow layer centering (was anchored to top-left, now inset: 0)
- Double scale effect (0.04 -> 0.08) and glow spread (40 -> 80)
- Fast attack / medium decay smoothing for visible reactivity
2026-02-17 08:22:56 -06:00
vicrodh 6c4eaef9a5 feat(immersive): add 4 new visualizer tabs
Backend:
- Emit viz:energy with 5-band RMS (sub-bass, bass, mids, presence, air)
- Emit viz:transient with attack detection (threshold + cooldown)

Frontend panels:
- EnergyBandsPanel: concentric glowing rings around centered artwork
- LissajousPanel: stereo X/Y phase plot with trail (watermark layout)
- TransientPulsePanel: expanding rings from center on beat detection
- AlbumReactivePanel: album art with breathing scale/glow from energy

All panels extract colors from album art, throttle at 30fps, and follow
the existing visualizer lifecycle (enable/disable backend on mount).

Focus tabs now: Coverflow, Static, Bars, Scope, Energy, X/Y, Pulse,
Reactive, Lyrics, Queue (keys 1-0).
2026-02-17 07:53:49 -06:00
vicrodh 3b94acd95e feat(visualizer): emit stereo waveform data for oscilloscope
Add viz:waveform event emission alongside existing viz:data FFT output.
De-interleaves L/R channels from the raw sample buffer and downsamples
to 256 points per channel (512 floats = 2048 bytes). Pre-allocates the
waveform buffer outside the hot loop to avoid per-frame allocations.
2026-02-17 03:40:13 -06:00
vicrodh f583092a76 chore(packaging): add qobuzapp scheme to desktop files
All 6 .desktop files now declare x-scheme-handler/qobuzapp in their
MimeType line, enabling OS-level link capture for qobuzapp:// URLs.
2026-02-17 00:25:09 -06:00
vicrodh d286aec9ef feat(core): forward scheme links from single-instance and launch args
Single-instance plugin now inspects args for qobuzapp:// or
play.qobuz.com URLs and emits link:resolved event. Launch args
are also checked on first startup with a 1.5s delay for frontend
readiness.
2026-02-17 00:24:49 -06:00
vicrodh 261d420540 feat(v2): add qobuzapp handler registration commands
v2_check_qobuzapp_handler, v2_register_qobuzapp_handler,
v2_deregister_qobuzapp_handler — use xdg-mime for scheme handler
registration and mimeapps.list editing for deregistration.
2026-02-17 00:24:02 -06:00
vicrodh 9006e64fa2 feat(v2): add v2_resolve_qobuz_link command
Thin Tauri command that calls qbz_qobuz::resolve_link(). Pure parsing,
no State params, no auth required. Registered in invoke_handler.
2026-02-17 00:23:16 -06:00
vicrodh 0c66a14249 fix(player): stabilize seek interaction and remove misleading secondary bar refs #75
cx
2026-02-16 22:48:39 -06:00
vicrodh 39bbbdc230 fix(playback): reduce mpris desync and stale playback event lag refs #85
cx
2026-02-16 21:36:07 -06:00
vicrodh c3696f02d4 fix(playback): harden auto-advance for long-track edge cases
cx
2026-02-16 20:08:34 -06:00
vicrodh 99877fa740 fix(v2): align immersive track info/radio and i18n history keys
cx
2026-02-16 19:27:47 -06:00
vicrodh 37db48ea3d fix(v2): complete command migration sweep and musician/blacklist flows
- migrate remaining frontend invokes to V2 names
- add missing V2 command registrations and implementations
- enforce commands_v2 backend purity (no legacy delegation)
- restore blacklist/relationships/musician flows in V2
- align playlist/local-library/settings invoke paths with V2

cx
2026-02-16 18:40:07 -06:00
vicrodh 45b98c40d4 fix(v2): harden session restore and favorites query params
cx
2026-02-16 17:16:41 -06:00
vicrodh 6f7b8e0aff Revert "fix(v2): harden session restore and favorites query params"
This reverts commit c20bb034ae.
2026-02-16 17:16:29 -06:00
vicrodh c20bb034ae fix(v2): harden session restore and favorites query params
cx
2026-02-16 17:15:58 -06:00
vicrodh 1037b59cfa refactor(v2): hard-delete unused legacy command files
cx
2026-02-16 17:11:24 -06:00
vicrodh ffd5c992b0 refactor(v2): shrink legacy command module to internal minimum
cx
2026-02-16 17:09:29 -06:00
vicrodh 43ebf19ae1 chore(v2): hard-cut legacy invoke handler surface
cx
2026-02-16 17:04:08 -06:00
vicrodh a58116212c fix(v2): stabilize plex playback control and shuffle reorder semantics
cx
2026-02-16 15:23:46 -06:00
vicrodh e51f367b31 fix(v2): restore Plex command surface for LocalLibrary
cx
2026-02-16 12:53:20 -06:00