PDF loading was failing because pdfjs-dist cannot fetch from
static.qobuz.com due to CORS restrictions in the WebView.
Added v2_fetch_url_bytes command that fetches URL bytes through
Rust's reqwest (no CORS), then passes the binary data to pdfjs.
Also added rotation support (R key or toolbar button) for
vertical booklets.
Modal PDF viewer for album booklets with page navigation,
zoom controls, and keyboard shortcuts. Uses pdfjs-dist to
render PDF pages from URL in canvas.
All animations default to 60fps. Each panel reads its own setting
from userStorage via shared fpsConfig utility. Settings UI shows
a collapsed section with per-panel dropdowns:
- Background Blur, Spectrum, X/Y (Lissajous), Oscilloscope,
Energy Bands, Transient Pulse, Album Reactive, Spectral Ribbon
Options: Disabled, 15, 30, 60, 120 FPS
i18n keys added to all 4 locales (en, es, de, fr)
WebKit's WebProcess was crashing (SIGABRT) during EGL/GPU resource
cleanup when the app exited with the miniplayer window still alive.
Now explicitly destroy the miniplayer window before the main process
exits, giving WebKit time to clean up gracefully.
Remove unnecessary get() wrapper from svelte/store when calling the
i18n translate function. Direct $t() works correctly in regular
functions (only $derived is problematic per ADR-001). Removes unused
get import from GenreFilterButton, FavoritesView, PlaylistDetailView,
PurchaseAlbumDetailView, PurchasesView, and SettingsView.
Add dev-ghost-doctor.sh (t-shadow check + runtime clean + restart) and
dev-ultra-restore.sh (deep clean with --full/--no-start/--check flags).
Improve check-no-t-shadow.sh patterns for broader t-variable detection.
Clean-dev-runtime now runs guardrail check automatically. Remove --force
from vite dev. Add npm script shortcuts for all new tools.
- Allow dead_code on TokenValidationResponse.code (deserialized but not read)
- Remove unused MusicProvider import in commands_v2.rs
- Restore #[allow(non_snake_case)] on v2_plex_cache_get_tracks
- Replace drop(tokens) with let _ = tokens (drop on reference is no-op)
Mirror the album cover context menu options: right-clicking the artist
photo now shows Open in Browser and Save As below the existing
custom image options, separated by a divider.
Detect maximized state via Tauri window API. When the window is not
maximized (floating), apply 8px border-radius and a soft box-shadow.
Body/html backgrounds set to transparent so corners show through
the Tauri transparent window.
Remove isFavoriteOverride={true} that forced all hearts filled,
preventing the toggle from having any visible effect. Subscribe to
favoritesStore so unfavorited tracks animate out (slide+fade) and
are removed from the list after 300ms without requiring a refresh.
Shuffle favorite artists randomly so all get a fair chance (was
deterministic, first artist dominated). Cap at 2 albums per artist.
Shuffle final results for variety on each load.
Add #[allow(non_snake_case)] to V2 command functions and structs that
use camelCase parameter names for Tauri frontend compatibility.
Renaming to snake_case would break the frontend-backend contract.
Replace scroll-based section navigation with tab-based rendering where
only one section is visible at a time. Merge Offline Mode into Downloads
tab. Move Remote Control into Developer tab. Uncollapse previously
collapsed sections (Downloads, Storage, Developer). Add Developer to
nav tabs.
When the titlebar search is active, the search input inside SearchView
is redundant. Hide it so only the tabs and results remain. The query
still syncs from the titlebar via the shared searchState store.
Search input can now live in the titlebar instead of the sidebar,
controlled by a new toggle in Settings > Appearance. When the custom
titlebar is hidden or system titlebar is active, search stays in the
sidebar regardless of the toggle.
- New searchBarLocationStore with localStorage persistence
- TitleBar accepts search props and exposes focusSearch()
- Sidebar hides its search container when titlebar search is active
- Ctrl+F focuses the active search input in both modes
- Titlebar height increased from 32px to 36px to fit the search field
- Translations added to all 4 locale files (en, es, de, fr)
Rename t -> item/track in .map()/.filter() callbacks in
favoritesStore.ts and queueStore.ts to comply with ADR-001
and prevent intermittent PostCSS extraction failures.
cc
Expand the sidebar automatically when Ctrl+F is pressed while it's
collapsed. Also replace setTimeout with Svelte's tick() in focusSearch
to properly wait for DOM updates before focusing the input.
Closes#124
cc
Playlist search tab was invoking legacy 'search_playlists' command
which no longer exists. Updated both initial search and load-more
to use 'v2_search_playlists', matching the other search tabs.
Closes#129
cc
Previously, the section displayed the user's own favorite albums — the
same albums they had already marked as favorites. Now it resolves the
artists behind those favorite albums (and favorite tracks), fetches
their catalogs from the Qobuz API (parallel, max 8 artists, 25 albums
each), and filters out albums the user already has in favorites or
recently played. Results are cached in reco_album_meta for instant
future lookups.
Closes#122
After clicking Add to Local Library, the in-memory download state is
cleared so the progress bar and button disappear. Also triggers a
background scan of the added folder so the library indexes the new
files without requiring a manual refresh.
Download checkmarks now only show for the currently selected format.
In-memory store tracks formatId per album download, and the album
detail view checks track.downloaded_format_ids from backend against
the selected format dropdown. Switching quality hides checkmarks
from a different format's downloads.
Migrate downloaded_purchases to compound PK (track_id, format_id) so
the same track downloaded in MP3 and FLAC are tracked separately.
Album detail endpoint now returns downloaded_format_ids per track.