Commit Graph
100 Commits
Author SHA1 Message Date
vicrodh 77b269f346 fix(label): load releases from v2_get_label for carousel
The /label/page endpoint releases containers were unreliable.
Now fetches 20 albums from v2_get_label (same as old LabelView)
for the releases carousel. Also loads description as fallback.
Critics' picks still parsed from /label/page containers.
2026-02-20 03:56:45 -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 df3b203875 fix(label): playlist images, artist images, jump-nav gap
- Switch from SearchPlaylistCard to QobuzPlaylistCard (matches HomeView)
- Add getPlaylistImage() handling rectangle/covers/images300 formats
- Improve getArtistImageUrl() with picture field and medium size fallback
- Fix jump-nav gap: set padding-top:0 to match ArtistDetailView
- Add debug logging for raw playlist/artist data
2026-02-20 03:51:42 -06:00
vicrodh 4f223ba31a fix(label): jump-nav below header, track play resilience, description fallback
1. Move jump-nav below header (was above), match ArtistDetailView margins
2. Wrap handleTrackPlay context/queue in try-catch so onTrackPlay always fires
3. Add description fallback: fetch from v2_get_label if label/page omits it
4. Add detailed console logging for track play debugging
2026-02-20 03:45:07 -06:00
vicrodh 4c2a63239e fix(label): rewrite track row, add jump-nav, fix description border
- Replace track row with ArtistDetailView pattern (favorites, TrackMenu, radio)
- Add sticky jump-nav bar with IntersectionObserver for all sections
- Fix description border leak with CSS reset
- Make "More labels" containers round
- Wire onTrackAddFavorite prop in +page.svelte
- Add i18n keys: label.about, label.otherLabels (all 4 locales)
2026-02-20 03:29:13 -06:00
vicrodh e414121273 fix(label): polish label detail view UI
- Add back button with ArrowLeft icon
- Make header label image circular (border-radius: 50%)
- Remove play pill button from header (redundant with player bar)
- Replace artist circles with Search-style cards (160x220, bg-secondary)
- Fix artist image extraction (prioritize image.large over portrait hash)
- Replace QobuzPlaylistCard with SearchPlaylistCard for proper collage images
- Add missing action-btn-circle CSS for Popular Tracks controls
- Fix duplicate color property in label card placeholder
2026-02-20 03:11:53 -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 318318a3ab feat(purchases): create quality subfolder for downloads
Append a subfolder named after the selected format quality
(e.g. "FLAC 24-bit - 96 kHz") to the user-chosen destination.
Different quality downloads of the same album no longer overwrite
each other.
2026-02-20 02:06:10 -06:00
vicrodh d8f28385d9 fix(purchases): persist download progress across navigation
Move download state from component-local $state() to a persistent
module-level Svelte store (purchaseDownloadStore). Downloads continue
in the background when navigating away from album detail, and
progress bars are restored when returning.

Closes #90
2026-02-20 02:04:27 -06:00
vicrodh 1ba4622828 fix(purchases): add stopPropagation to per-track download buttons in album detail
Clicking the download icon on a track row also triggered row playback
due to event bubbling. Add e.stopPropagation() to both the normal
download and failed-retry download buttons.
2026-02-20 01:43:21 -06:00
vicrodh 7bdaa2976f fix(purchases): wire track download button in tracks tab
The download button in the tracks tab had no onclick handler, so
clicking it triggered the row's playback handler instead. Now it
opens the native folder picker, downloads with the best available
format, and shows download status (spinner/checkmark). Artist link
also uses stopPropagation to avoid triggering playback. Fixes #91.
2026-02-20 01:38:31 -06:00
vicrodh 62e2aaea51 fix: replace info tooltip hover with click-to-show popup
Title attribute doesn't work reliably. Now the (i) icon opens a
tooltip on click, auto-dismisses after 2 seconds or on click anywhere.
2026-02-20 01:31:02 -06:00
vicrodh ca3f43614b feat: add back button, info tooltip, duration, fix context for mixes
- Add back navigation button to both DailyQ and WeeklyQ views
- Replace subtitle with home card descriptions
- Remove cache/live source text, add total playback duration
- Remove refresh button from WeeklyQ (regenerates weekly on Fridays)
- Fix weekly cache to use Friday-based key instead of daily
- Add algorithm info icon with tooltip on both views
- Fix playback context: align queue index with blacklist-filtered tracks
- Change header label from "Playlists" to "Your mixes"
- Add algorithmInfo i18n key to all 4 locales
2026-02-20 01:26:21 -06:00
vicrodh 5ef0d56cb4 feat: wire full playback system for DailyQ and WeeklyQ views
Add parent-driven track playback with queue setup, playback context,
context menus, offline cache status, and artist blacklist filtering.
Both views now behave like normal playlist views.
2026-02-20 01:20:47 -06:00
vicrodh f8a62afcaa style: use transform-based silk animation with rotation and scale
Replaced background-position animation with a ::before pseudo-element
(inset -40%) animated via transform (translate + rotate + scale).
GPU-composited, zero repaints. Each card has its own keyframes
(silk-daily 30s, silk-weekly 34s) with different movement patterns
so they never look synchronized.
2026-02-20 01:11:20 -06:00
vicrodh 376c789f8e style: make silk animation longer and more erratic
Increased duration to 25s with 7 irregularly spaced keyframe stops
to make the loop less predictable. WeeklyQ offset at -11s for
desync. Same CPU cost — still just background-position interpolation.
2026-02-20 01:09:26 -06:00
vicrodh e0770eb4fa style: add highlight and shadow streaks to mix gradients
Two narrow linear-gradient bands (3% spread each) layered on top:
a bright highlight streak and a dark shadow streak. They shift with
the silk animation creating visible contrast lines across the surface.
2026-02-20 01:08:57 -06:00
vicrodh fcac8294bc style: add silk-shift animation to mix gradient backgrounds
Slow background-position animation on 200% oversized gradients
creates a subtle flowing silk effect. 10s cycle, alternate
direction. Applied to Home cards and detail view artworks.
2026-02-20 01:07:18 -06:00
vicrodh a114693993 fix: align mix card labels bottom, add badge spacing, reserve 3 lines
Restored justify-content: flex-end so qobuz/name stay at bottom of
gradient. Added margin-bottom between badge and name for separation.
Set min-height on description to 3 lines so cards stay aligned.
2026-02-20 01:06:05 -06:00
vicrodh 1dee84c0ac style: redesign mix cards with descriptions and top-aligned labels
Replaced redundant title/owner below cards with descriptive text
(DailyQ: customized selection, WeeklyQ: every Friday emphasis).
Moved qobuz badge and mix name to top of gradient card. Added
yourMixes/weeklyMixes i18n sections to de.json and fr.json.
2026-02-20 01:04:50 -06:00
vicrodh 5475ea0095 style: replace mix videos with CSS gradients, remove nav buttons
Replaced video backgrounds with layered radial/linear CSS gradients
matching the iOS Qobuz style. DailyQ uses gold/amber tones, WeeklyQ
uses purple/lilac. Cards overlay "qobuz" badge and mix name on the
gradient. Removed HorizontalScrollRow wrapper since only two cards
exist. Deleted video assets from static/video/.
2026-02-20 01:01:12 -06:00
vicrodh 10edb92c0c fix: enable scroll on DailyQ and WeeklyQ views
Added height: 100%, overflow-y: auto, and padding-bottom to the
container so the track list is scrollable.
2026-02-20 00:56:58 -06:00
vicrodh 8aa9c472fa feat(dailyq): revamp DailyQ/WeeklyQ views and add video assets
Redesigned DynamicSuggestView and WeeklySuggestView with updated
VirtualizedTrackList. Added looping video backgrounds for mix cards.
2026-02-20 00:54:45 -06:00
vicrodh fc5da6cfc4 feat(home): add Your Mixes section with DailyQ and WeeklyQ cards
Static section (no API call) with video-background cards that navigate
to DynamicSuggestView and WeeklySuggestView. Positioned after Qobuz
Playlists in default Home order, toggleable via Home Settings.
2026-02-20 00:54:08 -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 f9313c2d80 feat(weeklyq): add WeeklyQ view scaffold and i18n labels
cx
2026-02-20 00:01:43 -06:00
vicrodh ea9051409a feat(dailyq): add generated DailyQ view and dynamic suggest client
cx
2026-02-20 00:01:31 -06:00
vicrodh 741559184d feat(purchases): load purchases by type and ids metadata
cx
2026-02-20 00:01:27 -06:00
vicrodh 2fad220bc9 feat(label): add API-side search within label view
Use v2_search_albums with post-filter by label ID instead of client-side
filtering. This finds albums across the full Qobuz catalog for the label,
not just the ones already loaded via infinite scroll.
2026-02-19 21:03: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 6f612e699f feat(purchases): add playback support to purchases views
Purchased tracks are streamable via normal Qobuz API. Reuse existing
handleDisplayTrackPlay/playAlbumById infrastructure to enable click-to-play
on track rows and a Play button on album detail header. Active track
highlights with accent color and animated playing bars.
2026-02-19 16:57:16 -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 183a0ec50d chore(types): add track_number and description to interfaces
Add optional track_number to QobuzTrack and description to QobuzAlbum.

cc
2026-02-19 16:19:02 -06:00
vicrodh 45116707bf fix(player): add null guard for seek target position
TypeScript narrowing for seekTargetPosition after the initial null
check to prevent potential runtime error.

cc
2026-02-19 16:19:01 -06:00
vicrodh e245b702bd fix(ui): improve error message formatting in LoginView
Extract structured error messages from objects instead of raw
String(err) which shows [object Object].

cc
2026-02-19 16:19:00 -06:00
vicrodh e375826fa3 fix(ui): ADR-001 compliance in SpectralRibbon, remove unused AlsaUtilsHelpModal
Rename t variable to interpWeight in SpectralRibbon to avoid shadowing
the i18n store. Delete unused AlsaUtilsHelpModal component.

cc
2026-02-19 16:18:58 -06:00
vicrodh 2508ea9e55 chore(dev): improve dev scripts and runtime cleanup
Add svelte-kit sync + --force to dev script, add clean-runtime script,
bind vite to 127.0.0.1 explicitly.

cc
2026-02-19 16:18:53 -06:00
vicrodh 33aa848dcf fix(flatpak): improve metainfo for Flathub compliance
Shorten summary, add branding colors, add xml:lang to screenshot
captions, remove redundant Features heading.

cc
2026-02-19 16:18:52 -06:00
vicrodh c380434619 fix(ci): skip RC tags in AUR workflow
Only trigger AUR package update on stable version tags, not release
candidates.

cc
2026-02-19 16:18:47 -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 13d9ec3724 refactor(ui): convert queue panel from overlay to inline sidebar
Queue now pushes main content instead of overlaying it, fixing the
search header z-index conflict. Lyrics sidebar height fixed to 100%
to fill parent container correctly. Queue and lyrics are now mutually
exclusive - opening one closes the other.
2026-02-19 08:55:09 -06:00
vicrodh 5b76530a4d docs: add glibc 2.38+ requirement for DEB/RPM packages
Ubuntu 24.04 build target (required for Snap Store) means native
packages need glibc 2.38+. Older distros should use Flatpak, Snap,
or AppImage instead.
2026-02-18 16:52:30 -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 3e2b493e28 merge(feature): integrate purchased downloads into pre-release
cx
2026-02-17 20:11:21 -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 861a9e0311 revert(purchases): remove mock FastAPI server from repository
cx
2026-02-17 19:36:22 -06:00
vicrodh 415a9d93f3 fix: hide cover art on unavailable albums so overlay text is readable 2026-02-17 18:58:08 -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 eb6830430e feat: move unavailable banner to artwork overlay, add hide-downloaded filter with persistence 2026-02-17 18:44:56 -06:00
vicrodh 3cabd95ff4 refactor: use portal file picker instead of mock text input for download folder 2026-02-17 18:36:34 -06:00
vicrodh c14754d4ef refactor: reuse existing UI patterns in purchases views
- Toolbar: FavoritesView pattern (control-btn, dropdown-menu, dropdown-item)
- Albums: grid/list toggle, group by (Off/A-Z/Artist), sort with direction
- Filter panel: LocalLibraryView pattern (checkbox for hide unavailable, Hi-Res)
- Tracks: group by (Off/Artist/Album/Name A-Z)
- Format selector: standard Dropdown component instead of custom pill
- Download All: global action-btn-circle instead of custom button
- Quality in track rows: plain text (12/192) instead of QualityBadge images
- QualityBadge compact only in album header and list mode
- Add filter.availability and filter.hideUnavailable i18n keys (4 locales)
2026-02-17 18:31:21 -06:00
vicrodh c7752cc1c1 style: polish purchases views to match app design language
Rewrite PurchasesView and PurchaseAlbumDetailView to match existing
views (FavoritesView, AlbumDetailView). Consistent header, sticky nav,
expandable search, scrollbar, table headers, track rows, and spacing.
2026-02-17 18:06:49 -06:00
vicrodh 58101a27f5 fix: add generic type parameters to invoke calls in purchases service 2026-02-17 17:56:03 -06:00
vicrodh 0599493a5a feat: add purchases i18n keys to all 4 locales
Keys added to en.json, es.json, de.json, fr.json:
- nav.purchases
- settings.appearance.showPurchases/showPurchasesDesc
- purchases.* section with tabs, search, filters, sorts,
  download actions, progress, formats, and empty states
2026-02-17 17:54:37 -06:00
vicrodh d57a27ad45 feat: wire purchases views into navigation, sidebar, and settings
- Add 'purchases' and 'purchase-album' to ViewType
- Add conditional ShoppingBag nav item in Sidebar (between Favorites and Playlists)
- Wire PurchasesView and PurchaseAlbumDetailView in +page.svelte
- Add Show Purchases toggle in Settings > Appearance
- Toggle persisted via purchasesStore, hidden by default
2026-02-17 17:52:05 -06:00
vicrodh 86593749ec feat: add PurchasesView and PurchaseAlbumDetailView components
PurchasesView: albums grid and tracks list with search, filter
(all/hires), sort (date/artist/album/quality), and download buttons.

PurchaseAlbumDetailView: album header, format picker, folder picker
(mock mode text input), per-track download buttons, progress bar,
multi-disc grouping, and post-download Add to Library button.
2026-02-17 17:49:26 -06:00
vicrodh eecaa624a8 feat: add purchase types, service layer, and store
- PurchaseResponse, PurchasedAlbum, PurchasedTrack, progress types
- Service layer with mock/real toggle via VITE_MOCK_PURCHASES env var
- purchasesStore for show/hide toggle persistence via userStorage
2026-02-17 17:46:12 -06:00
vicrodh 1d39d37a29 feat: add FastAPI mock server for purchase downloads
Lightweight mock API serving Qobuz-shaped purchase data with CORS
enabled for localhost:1420. Includes 8 albums (varied genres, one
multi-disc, one with downloadable:false), 5 individual tracks,
format options, search, and simulated download progress via SSE.
2026-02-17 17:45: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 e00d58949a fix: remove downloadStateVersion from each-block keys to stop flicker
The global downloadStateVersion counter was embedded in {#each} key
expressions, causing Svelte to destroy and recreate all DOM nodes
whenever the counter incremented during downloads. Track IDs alone
are stable and unique keys; download status reactivity is already
handled by props passed to TrackRow.

Also skip redundant notifyListeners() calls in setOfflineCacheState
when status and progress haven't actually changed, preventing
unnecessary downloadStateVersion++ cascades.
2026-02-17 11:38:36 -06:00
vicrodh 7b8e2d56ac feat(local-library): add Plex source filter and one-shot session sync
Add dedicated Plex source filter in albums view, header sync button when Plex is configured, and one-time auto-sync per session when Plex cache is empty.

cx
2026-02-17 11:38:24 -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 086f7f62e4 perf: rAF debounce for offline cache listener notifications
Coalesce all offline cache state notifications within a single
animation frame (~16ms) into one notification cycle. This caps
UI re-renders from hundreds/sec down to max 60/sec during bulk
downloads, preventing progressive UI lag from event storms.
2026-02-17 10:54:10 -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 cfd033e2bd fix(artist): lower jump-nav z-index from 40000 to 50 2026-02-17 09:55:49 -06:00
vicrodh 4c765617d5 fix(immersive): increase gap between reactive artwork and track info 2026-02-17 09:52:19 -06:00
vicrodh 86e3424c79 fix(immersive): track info inline with player, artwork right of text
Shrink player bar min-width 700→670px. Move track info block to
bottom: 24px (same level as player). Album art now sits to the right
of the text block (title/album/artist/badge). The info block is part
of the panel so it stays visible when player controls auto-hide.
2026-02-17 09:36:48 -06:00
vicrodh 39b2ccaa8b fix(immersive): 4-row track info + album art thumbnail on all viz panels
All 4 canvas panels (Oscilloscope, Energy, Pulse, X/Y) now share:
- Bottom-left: 72px album art thumbnail with rounded corners
- Bottom-right: 4 rows (title, album, artist, compact badge), right-aligned,
  max-width 400px for longer text
- Energy: removed 85% height constraint, rings use full canvas
2026-02-17 09:23:17 -06:00
vicrodh 4f7bc88155 fix(immersive): oscilloscope track info as 4 separate rows with wider max-width 2026-02-17 09:17:19 -06:00
vicrodh be9166d6d2 refactor(immersive): visualizer dropdown, compact track info, aggressive reactivity
Convert 6 visualizer tabs into a single dropdown menu in the header.
Remove album art and full quality badge from Oscilloscope, Energy,
Transient Pulse, and Lissajous panels. Replace with bottom-right
compact track info (title, artist/album, text-only quality badge).
Dramatically increase AlbumReactive sensitivity for heavy music
(faster attack/decay, 3x scale/glow multipliers).
2026-02-17 08:46:48 -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 5c11469c87 feat(immersive): add stereo oscilloscope visualizer tab
New OscilloscopePanel renders dual L/R waveforms from viz:waveform
event data. ALBUM_SECONDARY layout with small artwork bottom-left.
Colors extracted from album art with green tint (L) and blue tint (R).
Registered as focus tab with AudioWaveform icon and keyboard shortcut 4.
Renumbered focus tab shortcuts (1-6) to match new tab order.
2026-02-17 03:42:09 -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 06d0a9e471 fix(wizard): use pipewire stream.rules instead of pulse.rules for per-app config
The wizard step 6 was writing per-app bit-perfect rules to
pipewire-pulse.conf.d/pulse.rules, but QBZ uses pipewire-alsa (via
rodio/cpal), so those rules were never applied.

Changed to pipewire.conf.d/stream.rules which applies to ALL PipeWire
clients regardless of API (ALSA, PulseAudio, JACK). Also updated the
step indicator from "Pulse" to "Apps" in all 4 locale files.

Fixes #53 (wizard bug)
2026-02-17 02:42:17 -06:00
vicrodh 4ff8f65de0 fix(ui): correct Go button contrast in LinkResolverModal
Use --accent-primary instead of nonexistent --accent variable,
and #fff for button text to ensure visibility on all themes.
2026-02-17 02:15:29 -06:00
vicrodh 2ff17faaee fix(album): load album credits modal via v2_get_album
cx
2026-02-17 02:14:15 -06:00
vicrodh d2c9d88e4a feat(ui): add qobuzapp handler toggle in settings
Integrations section now shows a toggle to register/deregister QBZ as
the default handler for qobuzapp:// links. Checks current status on
mount, calls v2_register/v2_deregister commands on toggle.
2026-02-17 00:31:03 -06:00
vicrodh 107c222c7e feat(ui): add Ctrl+L keybinding for link resolver
New ui.openLink action in keybindingsStore (Ctrl+L default).
Registered in +page.svelte to open the link resolver modal.
2026-02-17 00:29:42 -06:00
vicrodh 55c5ea4013 feat(ui): wire link resolver into main page
Import LinkResolverModal, add handleResolvedLink() that dispatches to
handleAlbumClick/handleArtistClick/selectPlaylist. Listen for
link:resolved event from OS scheme handler. Render modal in template.
2026-02-17 00:29:15 -06:00
vicrodh 448c658996 feat(ui): add LinkResolverModal component
Svelte 5 modal with input field for pasting Qobuz URLs. Calls
v2_resolve_qobuz_link and forwards the resolved link to the parent.
Enter key submits, error displayed inline.
2026-02-17 00:27:51 -06:00
vicrodh 590b652649 feat(i18n): add link resolver translation keys
Added to all 4 locales (en, es, de, fr):
- settings.integrations.qobuzLinkHandler* keys for settings toggle
- linkResolver.* keys for the modal (title, placeholder, go, resolving, invalidLink)
2026-02-17 00:27:24 -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