Commit Graph
344 Commits
Author SHA1 Message Date
vicrodh 5a0d4c50a1 feat(session): re-enable session restore and add startup page setting
Re-enable queue/track restore on startup (visual only, paused at 0:00).
Update saveSessionBeforeClose to persist current view with context IDs.
Add "Startup page" dropdown in Settings > Appearance (Home / Where you
left off) that controls whether the last view is restored on launch.
i18n keys added to all 4 locale files.
2026-02-20 20:02:26 -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 04eeaefdce fix(context-nav): add click navigation for DailyQ and WeeklyQ contexts
The context icon showed correct tooltip on hover but clicking did
nothing for daily_q and weekly_q types. Add missing switch cases
to navigate to the respective views.
2026-02-20 10:39:17 -06:00
vicrodh 6849a9b3d6 fix(label): add playlist action buttons, increase section spacing
Wire onPlaylistPlay, onPlaylistPlayNext, onPlaylistPlayLater,
onPlaylistCopyToLibrary, onPlaylistShareQobuz through LabelView Props
to QobuzPlaylistCard. Increase section spacing from 48px to 64px.
2026-02-20 04:13:22 -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 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 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 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 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 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 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 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 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 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 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 131c6703ab fix(v2): stabilize queue panel sync and shuffle counters
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 8ac5ba92fd refactor(v2): enforce backend purity and stabilize playback runtime
cx
2026-02-16 07:45:43 -06:00
vicrodh d02b8a9628 refactor(v2): eliminate legacy frontend invokes and close remaining v2 command gaps
cx
2026-02-16 03:51:01 -06:00
vicrodh e4fe4598d0 refactor(frontend): migrate playlist and settings commands to V2
Batch migrate frontend invocations to V2:
- Playlist commands (22 commands)
- Settings/preferences commands
- Cache and audio commands
- API commands (radio, genres, tags, etc.)

Progress: reduced legacy commands from ~228 to ~152
2026-02-16 02:40:50 -06:00
vicrodh 8d26f547d1 fix(frontend): resolve all remaining TypeScript errors
- HomeView: fix OfflineCacheStatus type for getTrackOfflineCacheStatus prop
- PlaylistDetailView: fix trackToReplace null access in console.log
- SearchView: add id and isViewMore to Album/Artist interfaces
- Toast: add 'warning' type support
- playbackContextStore: add 'search' to ContextType union
- queueStore: add trackId to QueueTrack interface
- trackActions: add queueDisplayTrackNext/Later and buildQueueTrackFromDisplayTrack
- +page.svelte: fix numerous type issues including:
  - selectedAlbum closure captures for TypeScript narrowing
  - handleDisplayTrackDownload signature for DisplayTrack
  - handleSearchTrackDownload for SearchView's Track type
  - ImportSummary callback signature
  - QobuzTrack hires_streamable property usage
  - album.tracks.items instead of .data

npm run check now passes with 0 errors (138 warnings remain, mostly a11y)
2026-02-15 17:20:05 -06:00
vicrodh deece54bcb fix: eliminate double-brain session lifecycle (legacy vs V2)
Backend:
- v2_auto_login/v2_manual_login now FAIL if activate_session fails
  (was: log and continue with success:true, causing "logged in but not ready")
- Session activation is now REQUIRED, not optional

Frontend:
- Remove duplicate activate_user_session call from handleLoginSuccess
  (V2 login already activates session internally)
- Remove duplicate deactivate_user_session call from handleLogout
  (v2_logout already deactivates session internally)
- LoginView now uses runtime_bootstrap as SINGLE SOURCE OF TRUTH
  (was: v2_init_client + legacy is_logged_in/get_user_info checks)
- PlaylistDetailView uses runtime_get_status for user_id
  (was: legacy get_current_user_id)

This eliminates the "double-brain" where frontend used both legacy
and V2 paths, causing state divergence and intermittent failures.
2026-02-15 14:39:44 -06:00
vicrodh e70c577181 refactor: centralize session lifecycle, make runtime_bootstrap autocontenido
Addresses multiple review findings for V2 architecture:

1. Create session_lifecycle.rs module:
   - activate_session(): Full session activation callable from anywhere
   - deactivate_session(): Full teardown with proper runtime state cleanup
   - activate_offline_session(): Minimal session for offline/local-only use

2. Make runtime_bootstrap autocontenido:
   - Now activates session after successful auth (Step 4)
   - No longer delegates to frontend for session activation

3. Fix v2_login to be canonical:
   - Performs full flow: legacy auth -> corebridge auth -> session activation
   - Updates all runtime state flags

4. Fix v2_logout to be canonical:
   - Calls deactivate_session (teardown stores + clear runtime state)
   - Proper cleanup of legacy and corebridge auth

5. Fix deactivate_session:
   - Now clears session_activated flag (was missing)
   - Now clears corebridge_auth flag (was missing)
   - Emits UserSessionDeactivated event

6. Add v2_set_repeat_mode runtime check:
   - Now requires RequiresUserSession like other queue mutations

7. Fix LoginView early session activation:
   - Removed premature activate_user_session call before auto-login confirmed
   - ToS check uses localStorage fallback if no session

8. Fix offline mode:
   - Add v2_activate_offline_session command
   - Offline mode now activates minimal session so queue commands work
2026-02-15 10:53:49 -06:00
vicrodh cfe931e8ee fix: address critical login state and queue command issues
Issue 1 (HIGH): Fix UI/backend login state divergence
- Move setLoggedIn() AFTER successful activate_user_session
- Prevents UI entering logged-in state when backend fails

Issue 2 (HIGH): Fix userId fallback to 0
- Add validation in LoginView for both auto_login and manual_login
- Reject success responses with invalid user_id (0 or missing)

Issue 3 (HIGH): Add runtime requirement checks to queue commands
- All queue mutation commands now require authenticated user session
- CoreBridge-based commands require RequiresCoreBridgeAuth
- AppState-based commands require RequiresUserSession

Issue 6 (MEDIUM): Remove V1 auth surface
- Remove login, logout, auto_login from invoke_handler
- Frontend must use v2_login, v2_logout, v2_auto_login
2026-02-15 10:30:47 -06:00
vicrodh 87d03d427a refactor(frontend): migrate get_audio_settings to v2_get_audio_settings
Migrate all frontend get_audio_settings invoke calls to use V2:
- +page.svelte (normalization state loading)
- SettingsView.svelte (audio settings page)
- ExpandedPlayer.svelte (DAC passthrough status)
- AudioOutputBadges.svelte (output device status)
2026-02-15 04:12:37 -06:00
vicrodh 8a844612ff feat(v2): migrate audio settings commands to V2
- Add V2 audio settings commands (output device, exclusive mode, DAC
  passthrough, sample rate, backend type, ALSA plugin, gapless,
  normalization, streaming only, quality limiting, etc.)
- Update frontend SettingsView to use V2 audio commands
- Update +page.svelte to use V2 normalization command
2026-02-15 03:52:48 -06:00
vicrodh daf5372c34 feat(v2): migrate logout to v2_logout 2026-02-15 00:46:35 -06:00
vicrodh 846da0270e feat(v2): migrate playlist commands to V2 architecture
- Add playlist methods to QbzCore (get_user_playlists, get_playlist,
  add_tracks_to_playlist, remove_tracks_from_playlist)
- Add playlist methods to CoreBridge
- Create V2 Tauri commands for all playlist operations
- Update frontend to use V2 playlist commands
- Support both playlistTrackIds and trackIds in remove command
  (with automatic resolution like legacy)
2026-02-15 00:41:48 -06:00
vicrodh dbad90718a fix(miniplayer): use correct QueueState property name 'queue' 2026-02-14 23:29:09 -06:00
vicrodh 6cea4149c0 Migrate all queue operations to V2 commands
- Add V2 queue commands: v2_set_shuffle, v2_move_queue_track,
  v2_add_tracks_to_queue, v2_add_tracks_to_queue_next,
  v2_remove_upcoming_track
- Migrate queueStore.ts to use all V2 queue commands
- Update all view components to use V2 queue commands:
  - HomeView, SearchView, ArtistDetailView, FavoritesView
  - LocalLibraryView, PlaylistDetailView
- Update +page.svelte to use V2 shuffle, repeat, and remove commands

No legacy queue commands are called from frontend anymore.
2026-02-14 23:21:19 -06:00
vicrodh c4b28e37ea fix(session): prevent false login state with userId=0
Addresses race condition and invalid state issues identified by Codex diagnostic:

1. CoreBridge: Add try_get() and is_initialized() methods to gracefully
   handle uninitialized state instead of panicking

2. auth.rs: Use try_get() for V2 auth in login/auto_login/logout to
   avoid panic if CoreBridge init is still in progress

3. LoginView.svelte: Reject userId=0 as fallback - if userInfo or userId
   is missing/invalid, don't call onLoginSuccess (require re-login)

4. +page.svelte:
   - Move get_audio_settings call to after sessionReady is set
   - Add explicit userId > 0 check before activate_user_session
   - Return early if activation fails to prevent sessionReady from
     being set in broken state

These are tactical fixes aligned with ADR_RUNTIME_SESSION_CONTRACT.md
invariants. Full runtime state machine implementation to follow.
2026-02-14 22:59:20 -06:00
vicrodh b12a06fff3 feat(v2): expand V2 commands with playback and dual event emission
V2 Commands expanded:
- Add searchType parameter to search commands
- Add blacklist filtering to V2 search commands
- Add V2 playback commands (pause, resume, stop, seek, volume, state)

TauriAdapter dual emission:
- Emit both "core-event" (new) and legacy events during migration
- Legacy events: queue:updated, queue:shuffle-changed, queue:repeat-changed
- Legacy events: auth:logged-in, auth:logged-out, error

Frontend migration (partial soft-delete test):
- SearchView, ArtistDetailView, LocalLibraryView use v2_search_*
- HomeView, +page.svelte use v2_get_album, v2_get_track
- TrackReplacementModal uses v2_search_tracks

Old commands remain registered but are no longer called by migrated
frontend code. This enables testing V2 architecture while keeping
fallback available.
2026-02-14 20:10:58 -06:00
vicrodh 752c236c11 fix(queue): correct index calculation when no track is playing
- When current_index is None, upcoming starts at index 0, not 1
- Add syncQueueState() after removing track to refresh UI
2026-02-13 14:23:00 -06:00
vicrodh 8dcad203c7 fix(queue): correct remove-from-queue index and add history context menu
- Add remove_upcoming_track command that correctly maps upcoming index
  to actual queue index (handles shuffle mode properly)
- Update frontend to use remove_upcoming_track instead of remove_from_queue
- Add working context menu for history tracks (Add to Playlist, Track Info)
- Remove unused .track-menu CSS class
2026-02-13 13:29:30 -06:00
vicrodh 51a24de9cb Fix async listener leak on fast unmount/HMR
Apply disposed flag pattern to prevent listener leaks when component
unmounts before async listen() calls complete.

+page.svelte:
- Add disposed flag for tray/media control listeners
- Check disposed after each await listen(), cleanup immediately if true
- Set disposed=true at start of cleanup function

offlineCacheState.ts:
- Add listenersDisposed flag
- Check flag after each listener registration
- Cleanup any registered listeners if disposed during async sequence
- Set flag in stopOfflineCacheEventListeners()

This prevents memory leaks during HMR and fast navigation.
2026-02-12 13:27:00 -06:00
vicrodh 9c5245f2ce Add context menu for queue tracks
QueuePanel:
- Add vertical ... icon to the right of track duration
- Context menu with 3 options:
  - Remove from Queue (calls backend remove_from_queue)
  - Add to Playlist (reuses existing playlist modal)
  - Show Track Info (reuses existing track info modal)
- Menu shows on button click, closes on click outside

+page.svelte:
- Add handlers: handleRemoveFromQueue, handleQueueTrackAddToPlaylist,
  handleQueueTrackInfo
- Wire up new QueuePanel props

i18n: Add toast messages for remove from queue (all 4 locales)
2026-02-12 13:20:08 -06:00
vicrodh 20ab229cfe Increase session save interval (30s -> 60s)
Reduces IPC overhead for large queues. Full queue serialization
every 30s was excessive; 60s provides same crash recovery with
half the overhead.
2026-02-12 13:02:25 -06:00
vicrodh 42034623be Disable MiniPlayer feature (incomplete)
- Hide MiniPlayer button in NowPlayingBar when not provided
- Comment out miniplayer IPC emissions in player state subscriber
- Removes unnecessary IPC overhead during playback

MiniPlayer needs significant work before re-enabling.
2026-02-12 12:59:16 -06:00
vicrodh 07f9f64a08 fix: persist volume and tray settings across restarts
Volume was saved to per-user localStorage but loaded from unscoped key
before login set the userId. Added resyncPersistedVolume() called after
login to re-read from the correct scoped key.

Close/minimize to tray read settings once at startup from the flat-path
DB, but user changes were saved to per-user DB after login. Changed
close-to-tray to read dynamically from state, and minimize-to-tray to
re-fetch before each action.
2026-02-10 06:23:05 -06:00
vicrodh b76b369d9b feat: wire up discover playlists browse page with navigation and i18n 2026-02-10 01:51:31 -06:00
vicrodh ba62057545 feat: add Qobuzissimes, Albums of the Week, Press Accolades browse pages
- Add 3 new Rust endpoint constants and command mappings for
  /discover/qobuzissims, /discover/albumOfTheWeek, /discover/pressAward
- Add 3 new navigation ViewType values and genre filter contexts
- Extend DiscoverBrowseView to handle the 3 new endpoint types
- Add See All links with chevron caret and pipe separator to all 6
  discover sections in HomeView (newReleases, mostStreamed,
  essentialDiscography, qobuzissimes, editorPicks, pressAwards)
- Wire up 3 new views in +page.svelte with full album action callbacks
- Rename Editor's Picks to Albums of the Week, Press Awards to Press
  Accolades across all 4 locale files (en, es, de, fr)
- Fix rank badge: top-right position, Impact font, 35px size
- See All styling: inline-flex with ChevronRight icon, pipe divider,
  15px gap before nav buttons, #666666 color matching nav buttons
2026-02-10 01:10:28 -06:00
vicrodh c9bdcae855 feat: add discover browse pages for New Releases, Ideal Discography, Top Albums
Add full-page browsing views for the three discover sections that were
previously only shown as limited carousels on the Home page.

Backend: add get_discover_albums Tauri command with endpoints for
newReleases, idealDiscography, and mostStreamed. Uses paginated API
calls with genre_ids filtering.

Frontend: new DiscoverBrowseView component with virtualized grid/list,
genre filter dropdown, client-side search, and infinite scroll.
VirtualizedFavoritesAlbumGrid gains ranking support (showRanking),
infinite scroll (onLoadMore), and loading indicator.

HomeView sections now show "See All" links that navigate to the
dedicated browse pages. i18n keys added to all 4 locales.
2026-02-10 00:46:39 -06:00
vicrodh 7b5a7d963d feat: move back-to-top to global layout level
Replaced the per-view back-to-top in PlaylistDetailView with a
global one in +page.svelte. Uses capture-phase scroll listener
on .main-content to track scroll from any child view. Appears
after 800px scroll on any view. Resets on view change.
2026-02-09 23:08:40 -06:00
vicrodh d1fd6e045f fix(lyrics): fallback to lyrics.ovh when LRCLIB fails
Network errors in LRCLIB were propagated as hard Err via ? operator,
preventing the lyrics.ovh fallback from ever being reached. Changed
provider functions to return Option instead of Result so errors are
treated as soft failures. Added 10s HTTP timeout. Fixed internal
LRCLIB fallback (GET failure now falls through to search). Replaced
hardcoded UI strings with i18n keys.
2026-02-09 15:02:57 -06:00
vicrodh 344579c849 chore: clean unused CSS selectors and add $state() to DOM refs
Remove 22 unused CSS selector blocks and wrap 28 bind:this variables
with $state() to suppress Svelte 5 dev-mode warnings.
2026-02-09 14:49:25 -06:00