Commit Graph
100 Commits
Author SHA1 Message Date
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 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 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
vicrodh 8ac5ba92fd refactor(v2): enforce backend purity and stabilize playback runtime
cx
2026-02-16 07:45:43 -06:00
vicrodh d64e0f38d7 chore(v2): apply phase-2 legacy cut-off for auth playback queue and context surface
cx
2026-02-16 04:14:13 -06:00
vicrodh 9e126a0c59 chore(v2): apply legacy invoke cut-off markers in handler with rollback notes
cx
2026-02-16 04:08:22 -06:00
vicrodh ee5998533d refactor(v2): route library flows through shared impls and remove command-to-command calls
cx
2026-02-16 04:05:16 -06:00
vicrodh d2a13ba95e refactor(v2): internalize notification offline playlist reset and reco training flows
cx
2026-02-16 04:02:52 -06:00
vicrodh 0aecda77e5 refactor(v2): migrate remaining unknown frontend invokes to v2 commands
cx
2026-02-16 03:53:24 -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 54af46fea8 refactor(v2): close missing command surface for cast, library, offline and radio
cx
2026-02-16 03:35:52 -06:00
vicrodh d4b5dedc90 chore(v2): add migration guardrails for backend purity and invoke audit
cx
2026-02-16 03:29:02 -06:00
vicrodh 432dd828c1 refactor(v2): add native settings/cache/plex command surface
cx
2026-02-16 03:28:47 -06:00
vicrodh fafa98c46a refactor(v2): remove post-cutoff backend wrapper wave and restore pure v2 surface
cx
2026-02-16 03:10:21 -06:00
vicrodh 65632f08d5 refactor(frontend): migrate Library and Offline commands to V2
Update frontend to use v2_library_* and v2_get_pending_playlists.
Progress: 138 legacy commands remaining.
2026-02-16 02:52:15 -06:00
vicrodh 8d3627b743 feat(v2): add Library and Offline V2 command wrappers
Add V2 wrappers for frequently used commands:
- Library: play_track, get_albums, get_tracks_by_ids, check_folder_accessible,
  set_album_hidden, get_scan_progress, clear_artwork_cache,
  clear_thumbnails_cache, remove_folder, set_album_artwork
- Offline: get_pending_playlists, playlist_get_all_local_track_counts
2026-02-16 02:49:31 -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 12246ea2ad feat(v2): add more playlist V2 command wrappers
Add V2 wrappers for playlist commands:
- get_settings, get_all_settings
- get_stats, get_all_stats, increment_play_count
- get_favorites, get_local_tracks, get_local_tracks_with_position
- get_custom_order, has_custom_order, get_tracks_with_local_copies
- import_preview, import_execute
2026-02-16 02:28:33 -06:00
vicrodh 1de7c7830e refactor(frontend): migrate Cast/DLNA/AirPlay commands to V2
Update all casting invocations to use v2_* commands:
- castStore: connect, disconnect, play, pause, stop, seek, volume
- CastPicker: device discovery
2026-02-16 02:25:32 -06:00
vicrodh 3ede4e2fc6 refactor(frontend): migrate Plex commands to V2
Update all Plex invocations to use v2_plex_* commands:
- SettingsView: auth, ping, cache operations
- LocalLibraryView: albums, tracks, search, hydration
- playerStore/playbackService: play_track
2026-02-16 01:47:33 -06:00
vicrodh 5dbd383bab feat(v2): add Plex V2 command wrappers
Wrap all 18 Plex commands with V2 RuntimeError handling:
- Network: ping, get_music_sections, get_section_tracks, get_track_metadata
- Auth: auth_pin_start, auth_pin_check, open_auth_url
- Cache: get_sections, save_sections, get_tracks, get_albums,
  get_album_tracks, search_tracks, save_tracks, update_track_quality,
  get_tracks_needing_hydration, clear
- Playback: play_track

Completes the Plex category of V2 migration.
2026-02-16 01:03:45 -06:00
vicrodh e565b964a5 feat(v2): add Other V2 commands
Add V2 commands for miscellaneous categories:

Audio Backends (7):
- v2_get_available_backends, v2_get_devices_for_backend
- v2_get_alsa_plugins, v2_check_alsa_utils_installed
- v2_get_default_device_name, v2_get_linux_distro
- v2_query_dac_capabilities

Audio Diagnostics (3):
- v2_get_hardware_audio_status
- v2_start_bitdepth_capture, v2_stop_bitdepth_capture

Radio (5):
- v2_create_artist_radio, v2_create_track_radio
- v2_refill_radio_queue, v2_get_queue_remaining
- v2_create_infinite_radio

Share (3):
- v2_get_qobuz_track_url/album_url/artist_url

Additional (7):
- v2_is_visualizer_enabled
- v2_get_current_queue_track, v2_peek_next_track
- v2_get_shuffle, v2_get_repeat
- v2_get_current_user_id
- v2_has_saved_credentials, v2_save_credentials

Total 25 new V2 commands.
2026-02-16 01:00:18 -06:00
vicrodh d39fe148ed feat(v2): add Cast/DLNA/AirPlay V2 commands
Add 39 V2 commands for casting:

Chromecast (14):
- v2_cast_start_discovery, v2_cast_stop_discovery
- v2_cast_get_devices, v2_cast_connect, v2_cast_disconnect
- v2_cast_get_status, v2_cast_get_position
- v2_cast_play_track, v2_cast_play_local_track
- v2_cast_play, v2_cast_pause, v2_cast_stop
- v2_cast_seek, v2_cast_set_volume

DLNA (14):
- v2_dlna_start_discovery, v2_dlna_stop_discovery
- v2_dlna_get_devices, v2_dlna_connect, v2_dlna_disconnect
- v2_dlna_get_status, v2_dlna_get_position
- v2_dlna_play_track, v2_dlna_load_media
- v2_dlna_play, v2_dlna_pause, v2_dlna_stop
- v2_dlna_seek, v2_dlna_set_volume

AirPlay (11):
- v2_airplay_start_discovery, v2_airplay_stop_discovery
- v2_airplay_get_devices, v2_airplay_connect
- v2_airplay_disconnect, v2_airplay_get_status
- v2_airplay_load_media
- v2_airplay_play, v2_airplay_pause, v2_airplay_stop
- v2_airplay_set_volume

All commands wrap existing implementations with RuntimeError.
2026-02-16 00:52:57 -06:00
vicrodh d269acc709 feat(v2): add playlist custom V2 commands
Add 10 V2 commands for playlist customization:
- v2_playlist_set_sort
- v2_playlist_set_artwork
- v2_playlist_add_local_track
- v2_playlist_remove_local_track
- v2_playlist_set_hidden
- v2_playlist_set_favorite
- v2_playlist_reorder (reorder playlists in sidebar)
- v2_playlist_init_custom_order
- v2_playlist_set_custom_order
- v2_playlist_move_track

All commands wrap existing library implementations with
proper type signatures and RuntimeError handling.
2026-02-16 00:50:57 -06:00
vicrodh a405954846 feat(v2): add V2 commands for cache management (clear cache, artist cache, vector store, offline cache, credentials) 2026-02-16 00:11:21 -06:00
vicrodh 477b032abe feat(v2): add V2 commands for settings (tray, graphics, window, developer, playback, favorites prefs, visualizer, blacklist, locale) 2026-02-16 00:07:12 -06:00
vicrodh 18e7303aaf fix: update remaining sync_cached_favorite_tracks to V2 2026-02-15 22:07:51 -06:00
vicrodh 68aec71fdf fix(v2): migrate favorites cache, session, and context stores to V2 commands
- Add v2_save_session_state and v2_load_session_state commands
- Update favoritesStore to use V2 cache commands
- Update albumFavoritesStore to use V2 cache commands
- Update artistFavoritesStore to use V2 cache commands
- Update sessionService to use V2 session commands
- Update playbackContextStore to use V2 context commands
2026-02-15 21:55:15 -06:00
vicrodh 35758d07df feat(v2): add V2 commands for playback context, session, and favorites cache
- Add ContextType::Search variant
- Add V2 playback context commands (get, set, clear, has)
- Add V2 session persistence commands (save position/volume/mode, clear)
- Add V2 favorites cache commands (get/sync/add/remove for tracks/albums/artists)
- Register all new commands in lib.rs
2026-02-15 21:41:43 -06:00
vicrodh 7337b7e026 fix(v2): match V2QueueTrack field names to frontend interface
Remove serde rename attributes that caused mismatch:
- Frontend sends 'duration_secs', backend expected 'duration'
- Frontend sends 'artwork_url', backend expected 'artwork'

Now V2QueueTrack field names match BackendQueueTrack exactly.
2026-02-15 20:36:47 -06:00
vicrodh 045cf24a61 fix(v2): unify queue architecture - all commands use CoreBridge
Previously, V2 queue commands had a dual-queue bug:
- Writes (v2_set_queue, v2_add_to_queue, etc.) went to AppState.queue (legacy)
- Reads (v2_get_queue_state) came from CoreBridge/QbzCore queue
- Result: frontend sets queue, syncs, gets empty/stale data

This commit fixes the architecture:
- All V2 queue commands now use CoreBridge methods
- Added queue methods to QbzCore: add_track, add_tracks, add_track_next,
  set_queue, remove_track, remove_upcoming_track, move_track, play_index,
  next_track, previous_track, peek_upcoming
- Added corresponding methods to CoreBridge
- Fixed v2_set_shuffle to use CoreBridge (was using legacy AppState)
- Fixed runtime requirements: v2_toggle_shuffle and v2_clear_queue now
  use RequiresUserSession like other queue commands (consistency)
- Prefetch now gets upcoming tracks from CoreBridge, not legacy queue
- Updated tests to match V2 behavior (v2_toggle_shuffle, available field)
2026-02-15 20:07:01 -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 e7d617d46d fix(frontend): additional type error fixes
- SearchView.svelte: Fix async onMount pattern to properly return cleanup
- vite.config.js: Add ts-nocheck to suppress Node.js global errors

Reduces npm run check errors from 42 to 40.
2026-02-15 16:29:57 -06:00
vicrodh 8becf36842 fix(frontend): resolve type errors in multiple components
- miniplayerService.ts: Use PhysicalSize/PhysicalPosition classes instead of plain objects
- AudioOutputBadges.svelte: Add null checks for settings
- SettingsView.svelte: Add gapless_enabled to AudioSettings interface, fix return types
- SearchView.svelte: Fix variable declaration ordering for $derived dependencies
- LocalLibraryView.svelte: Add tick import, fix loadAlbums -> loadLibraryData, wrap onclick handler

Reduces npm run check errors from 66 to 42.
2026-02-15 16:27:53 -06:00
vicrodh 81e9279add fix(v2): proper teardown for V2 integration state
ListenBrainzV2State::clear_credentials() now resets internal client to
fresh state, not just wrapper fields.

LastFmV2State:
- Added clear_session() method that clears session_key AND pending_token
- init_with_session(None) now calls clear_session() instead of no-op

Ensures no credentials leak across sessions on logout/deactivate.

Closes Must-Fix #2 from MUST_FIX_BEFORE_RELEASE_RUNTIME_V2.md
2026-02-15 16:06:43 -06:00
vicrodh af910c4617 fix(v2): add transactional auth rollback on login failures
Added rollback_auth_state() helper that clears legacy_auth, corebridge_auth,
and emits AuthChanged event on partial login failures.

Applied to all error paths in v2_auto_login, v2_manual_login, and v2_login:
- CoreBridge auth failure now rolls back
- Session activation failure now rolls back

Ensures runtime_get_status never reports half-authenticated state.

Closes Must-Fix #1 from MUST_FIX_BEFORE_RELEASE_RUNTIME_V2.md
2026-02-15 16:06:37 -06:00
vicrodh 233d3c87ef refactor(frontend): migrate all integration calls to V2 commands
Complete frontend migration eliminating "double brain" pattern:

- bootstrap.ts: Last.fm session restore uses v2_lastfm_set_session
- playbackService.ts: All scrobbling uses V2 ListenBrainz and Last.fm
- SettingsView.svelte: All integration settings use V2 commands
  - Last.fm auth flow: v2_lastfm_get_auth_url, v2_lastfm_complete_auth
  - ListenBrainz: v2_listenbrainz_get_status, connect, disconnect
  - MusicBrainz: v2_musicbrainz_is_enabled, set_enabled
  - Audio reinit: removed legacy reinit_audio_device, V2 only

Frontend now uses ZERO legacy integration commands.
2026-02-15 15:37:16 -06:00
vicrodh 130c95dbdf feat(v2): add MusicBrainz metadata support to ListenBrainz commands
V2 ListenBrainz now_playing and scrobble commands now accept optional
MusicBrainz identifiers (recording_mbid, release_mbid, artist_mbids),
ISRC, and duration_ms parameters for richer scrobbles.

The AdditionalInfo struct is populated when any metadata is provided,
automatically including QBZ media player identification.
2026-02-15 15:37:10 -06:00
vicrodh 53927b5c6f Add missing V2 commands and deprecate legacy integration commands
New V2 commands:
- v2_lastfm_set_session: Set session key for restored sessions
- v2_listenbrainz_queue_listen: Queue listen for offline (uses legacy cache)

Deprecated legacy commands (with #[deprecated] markers):
- ListenBrainz: get_status, is_enabled, set_enabled, connect, disconnect,
  now_playing, scrobble, queue_listen
- Last.fm: is_authenticated, get_auth_url, authenticate, set_session,
  disconnect, scrobble, now_playing
- MusicBrainz: is_enabled, set_enabled
- Audio: reinit_audio_device

All deprecated commands point to their V2 replacements in the note.
Frontend migration to V2 commands is next.
2026-02-15 15:29:59 -06:00
vicrodh 943f886637 Add V2 integration states to session lifecycle
Integrates ListenBrainzV2State, MusicBrainzV2State, and LastFmV2State
from qbz-integrations crate into the session activation/deactivation
lifecycle.

In activate_session:
- After legacy integrations init (which loads from SQLite), sync
  credentials to V2 states
- ListenBrainz V2: gets token, user_name, enabled from legacy client
- MusicBrainz V2: gets enabled state (use_proxy defaults to true)
- LastFm V2: initialized to clean state (no legacy equivalent)

In deactivate_session:
- Clear V2 state credentials to prevent cross-user leaks
- Reset states to defaults

This ensures V2 commands (using qbz-integrations crate) have access
to the same credentials as legacy commands, enabling a smooth
migration path.
2026-02-15 15:06:59 -06:00
vicrodh 856ceb796d Enforce ToS gate in backend for all login entrypoints
Add centralized require_tos_accepted() helper function that checks
ToS acceptance before any authentication attempt. This prevents
non-UI clients (TUI/CLI/tests) from bypassing the ToS gate.

Affected commands:
- v2_auto_login: Returns tos_not_accepted error code
- v2_manual_login: Returns tos_not_accepted error code
- v2_login: Returns RuntimeError::Internal

The ToS check was already in runtime_bootstrap, but these commands
could be called directly. Now the gate is enforced at the backend
level regardless of entry point.

Also updates obsolete comment about frontend handling ToS.
2026-02-15 15:02:15 -06:00
vicrodh d0fb30a5b1 fix(auth): enforce ToS gate and session activation severity parity
Fixes login consistency issues:

1. ToS gate enforcement:
   - LegalSettingsState now initialized GLOBALLY at app startup (not per-session)
   - runtime_bootstrap checks ToS BEFORE attempting auto-login
   - If ToS not accepted, skip auto-login and return to login screen

2. Session activation severity parity:
   - runtime_bootstrap now treats activate_session failure as FATAL
   - On failure: rollback auth state, set degraded, return error
   - Matches behavior of v2_auto_login/v2_manual_login

3. LegalSettings is now truly global:
   - Removed from session_lifecycle activate/deactivate
   - ToS acceptance persists across sessions
   - Can be checked before user is logged in

Acceptance criteria:
- ToS false + credentials -> no auto-login
- ToS true + credentials + activation OK -> session restored
- ToS true + credentials + activation fails -> error, no session
2026-02-15 14:55:14 -06:00
vicrodh 63994c0a20 refactor(cast): extract qbz-cast crate
Extract casting functionality (Chromecast, AirPlay, DLNA) to standalone
qbz-cast crate. This crate is Tauri-agnostic and can be used by TUI/CLI
clients.

- Move device connection, discovery, threading, and media server to crate
- Keep only Tauri commands in src-tauri/src/cast/
- Thin re-exports in src-tauri for backwards compatibility
- Remove duplicate dependencies from src-tauri Cargo.toml
2026-02-15 14:51:06 -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 59e3141aa6 fix: address 7 code review findings for V2 architecture
HIGH priority fixes:
- Enable WAL mode in qbz-integrations caches (ADR-002)
- v2_auto_login/v2_manual_login now call activate_session()
- RequiresUserSession allows offline sessions (only checks session_activated)

MEDIUM priority fixes:
- Consolidate lifecycle: legacy commands delegate to session_lifecycle
- ListenBrainz teardown now calls disconnect() to clear tokens
- Add SessionActivationFailed degraded reason and emit event on failure
2026-02-15 12:21:17 -06:00
vicrodh d6e4b3349b feat(qbz-library): extract local library management to standalone crate
Create qbz-library crate with:
- LibraryScanner: directory scanning for audio files
- MetadataExtractor: audio metadata extraction via lofty
- LibraryDatabase: SQLite persistence with WAL mode
- CueParser: CUE sheet parsing for single-file albums
- Thumbnails: artwork extraction and thumbnail generation
- Tag sidecar: album metadata override files

src-tauri re-exports from qbz-library for backwards compatibility.
Enables TUI/headless clients to manage local libraries without Tauri.
2026-02-15 12:12:52 -06:00
vicrodh 384459d4d7 feat(qbz-cache): extract audio caching to standalone crate
Create qbz-cache crate with:
- AudioCache: L1 in-memory LRU cache (~300MB)
- PlaybackCache: L2 disk-based cache (~500MB)
- LRU eviction with spillover from L1 to L2

src-tauri now re-exports from qbz-cache for backwards compatibility.
This enables TUI/headless clients to use caching without Tauri.
2026-02-15 11:27:38 -06:00
vicrodh a66d5a2af3 refactor(v2): use RuntimeError in remaining V2 commands
Convert all remaining V2 commands from Result<T, String> to Result<T, RuntimeError>:
- runtime_get_status, v2_is_logged_in
- v2_login, v2_logout, v2_activate_offline_session
- v2_play_track, v2_get_discover_albums
- Search commands: v2_search_albums, v2_search_tracks, v2_search_artists
- Catalog commands: v2_get_album, v2_get_track, v2_get_artist
- Favorites commands: v2_get_favorites, v2_add_favorite, v2_remove_favorite
- Playlist commands: full suite including CRUD operations
- Extended catalog: v2_get_tracks_batch, v2_get_genres, v2_get_discover_*
- Artist commands: v2_get_artist_page, v2_get_similar_artists, v2_get_artist_with_albums
- v2_get_label

Only v2_auto_login/v2_manual_login retain String (intentional - use V2LoginResponse error fields)
and download_audio (internal utility wrapped by callers).
2026-02-15 11:23:16 -06:00
vicrodh 8a6050f2f3 refactor(v2): use RuntimeError in queue and playback commands
Convert queue commands (16) and playback commands (10) from String
errors to typed RuntimeError:
- Queue: get_queue_state, set_repeat_mode, toggle_shuffle, etc.
- Playback: pause, resume, stop, seek, volume, get_state, etc.

Runtime checks now use direct ? propagation instead of map_err.
Bridge method errors wrapped with RuntimeError::Internal.
2026-02-15 11:15:13 -06:00
vicrodh 0c50c67a61 feat(v2): add integrations V2 commands using qbz-integrations crate
Wire qbz-integrations to Tauri via new V2 commands:

ListenBrainz V2:
- v2_listenbrainz_get_status, is_enabled, set_enabled
- v2_listenbrainz_connect, disconnect
- v2_listenbrainz_now_playing, scrobble

MusicBrainz V2:
- v2_musicbrainz_is_enabled, set_enabled
- v2_musicbrainz_resolve_track, resolve_artist

Last.fm V2:
- v2_lastfm_get_auth_url, complete_auth
- v2_lastfm_is_authenticated, disconnect
- v2_lastfm_now_playing, scrobble

New module integrations_v2.rs provides Tauri state wrappers for the
Tauri-independent clients from qbz-integrations crate.
2026-02-15 11:11:35 -06:00
vicrodh 6310e9b216 chore: add qbz-integrations crate dependency
Wire qbz-integrations to src-tauri Cargo.toml. The crate provides
Tauri-independent implementations of Last.fm, ListenBrainz, and
MusicBrainz integrations.

Next step: Create V2 commands that use the new crate, then gradually
deprecate the existing in-tree implementations.
2026-02-15 11:05:33 -06:00
vicrodh fbb7f3c226 refactor(v2): use RuntimeError in audio settings commands
Replace String errors with typed RuntimeError variants across all 17
audio settings V2 commands for consistent error handling:
- Lock errors: RuntimeError::Internal
- Session not active: RuntimeError::UserSessionNotActivated
- Store errors: RuntimeError::Internal

This aligns with the runtime contract (ADR_RUNTIME_SESSION_CONTRACT.md)
for typed errors that clients can pattern match.
2026-02-15 10:58:09 -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 bd30e7cf24 feat(qbz-integrations): create third-party integrations crate
New crate for Last.fm, ListenBrainz, and MusicBrainz integrations.
Designed to work WITHOUT Tauri for TUI/headless clients.

Modules:
- lastfm: Scrobbling and now-playing via Cloudflare Workers proxy
- listenbrainz: Direct API client with user token auth
- musicbrainz: Entity resolution with rate limiting

Features:
- `cache` (default): SQLite persistence for offline support
  - ListenBrainz: Credential storage, offline listen queue
  - MusicBrainz: Resolved entity cache with TTL

Architecture:
- Pure async Rust, no Tauri dependencies
- Shared error types via IntegrationError enum
- Rate limiting for MusicBrainz (1 req/sec direct, faster via proxy)
2026-02-15 10:36:53 -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 efb707d972 feat(v2): add v2_get_discover_albums command
Add get_discover_albums to qbz-core, CoreBridge, and commands_v2.
Supports endpoints: newReleases, idealDiscography, mostStreamed,
qobuzissimes, albumOfTheWeek, pressAward.

Migrate DiscoverBrowseView to use v2_get_discover_albums.
2026-02-15 05:32:33 -06:00
vicrodh 214f578618 fix(frontend): use V2 favorites commands in QueuePanel
The toggleCurrentTrackFavorite function was calling non-existent
add_track_to_favorites/remove_track_from_favorites commands.
Updated to use v2_add_favorite/v2_remove_favorite with proper params.
2026-02-15 04:34:14 -06:00
vicrodh 20580b170c feat(frontend): migrate discover and playlist commands to V2
- HomeView: use v2_get_discover_index and v2_get_discover_playlists
- DiscoverPlaylistsBrowseView: use v2_get_discover_playlists
- PlaylistModal: use v2_delete_playlist

Part of V2 migration to enable TUI/headless usage without Tauri.
2026-02-15 04:30:38 -06:00
vicrodh 2f7cae58f4 feat(v2): add extended catalog and playlist V2 commands
Add missing API methods to QbzCore, CoreBridge, and V2 commands:
- Playlist management: create, delete, update, search
- Catalog: genres, discover index/playlists, playlist tags, featured albums
- Artists: artist page, similar artists, artist with albums pagination
- Labels: label details
- Tracks: batch fetch

All methods follow the V2 architecture with RuntimeManager requirements.
2026-02-15 04:25:31 -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 1416bed807 refactor(frontend): migrate get_favorites calls to v2_get_favorites
Migrate all frontend get_favorites invoke calls to use V2 command:
- FavoritesView.svelte
- ArtistDetailView.svelte
- favoritesStore.ts
- albumFavoritesStore.ts
- artistFavoritesStore.ts
- playbackService.ts

All favorites API calls now go through CoreBridge V2 architecture.
2026-02-15 04:10:30 -06:00
vicrodh ed80981852 feat(runtime): add requirement checks to catalog and playback commands
Add RuntimeManagerState and check_requirements to:
- v2_get_album/track/artist (RequiresCoreBridgeAuth)
- v2_pause/resume/stop_playback (RequiresClientInit)
- v2_seek, v2_set_volume (RequiresClientInit)

Playback commands use RequiresClientInit since they operate on
the local player and don't need API auth, just initialized state.
2026-02-15 04:08:06 -06:00
vicrodh 645cfe9194 feat(runtime): apply check_requirements to critical V2 commands
Add RuntimeManagerState parameter and CommandRequirement check to:
- v2_play_track (RequiresCoreBridgeAuth)
- v2_search_albums/tracks/artists (RequiresCoreBridgeAuth)
- v2_get_favorites/add_favorite/remove_favorite (RequiresCoreBridgeAuth)
- v2_get_user_playlists/get_playlist (RequiresCoreBridgeAuth)
- v2_add_tracks_to_playlist/remove_tracks_from_playlist (RequiresCoreBridgeAuth)

This enforces the ADR Runtime Session Contract at the command level.
V2 commands now fail with typed RuntimeError if auth state is invalid.
2026-02-15 04:05:38 -06:00
vicrodh 58f1957a05 feat(runtime): implement phased V2 login commands for runtime contract
Add V2 commands that implement the ADR Runtime Session Contract:
- v2_init_client: Phase 1 - init client only (bundle tokens)
- v2_auto_login: Phase 2 - auto-login with blocking V2 auth
- v2_manual_login: Manual login with blocking V2 auth

This allows frontend to control ToS check between init and auth:
1. v2_init_client() -> InitializedNoAuth
2. activate_user_session() -> restore session
3. loadTosAcceptance() -> check ToS
4. v2_auto_login() or v2_manual_login() -> Ready

V2 CoreBridge auth is now REQUIRED per ADR - login fails if V2 fails.

Migrate LoginView.svelte to use new V2 commands:
- Replace init_client with v2_init_client
- Replace auto_login with v2_auto_login
- Replace login with v2_manual_login

Add i18n keys for V2 auth errors in all 4 locales.
2026-02-15 04:02:34 -06:00
vicrodh 854088c3de fix(v2): make CoreBridge auth blocking per ADR
- auto_login now fails if V2 CoreBridge auth fails
- runtime_bootstrap now fails if V2 CoreBridge auth fails
- Add V2AuthFailed and V2NotInitialized runtime error variants
- Consistent with login command which was already blocking
2026-02-15 03:54:27 -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 7a133e2915 Add V2 favorites commands using QbzCore
- Add get_favorites, add_favorite, remove_favorite to QbzCore
- Add favorites methods to CoreBridge
- Add v2_get_favorites, v2_add_favorite, v2_remove_favorite commands
- Migrate favoritesStore, artistFavoritesStore, albumFavoritesStore
- Migrate ArtistDetailView favorites toggle

Favorites operations now flow through V2 architecture.
2026-02-15 00:10:09 -06:00
vicrodh dbad90718a fix(miniplayer): use correct QueueState property name 'queue' 2026-02-14 23:29:09 -06:00
vicrodh 7ef7ff1c7d Make V2 auth required and integrate RuntimeManager with auth
- Login now requires V2 CoreBridge auth to succeed (per ADR)
- V2 auth failure returns typed error, not silent non-blocking warning
- Update RuntimeManager state on login/logout for canonical tracking
- Add runtime_manager parameter to login and logout commands

This implements Phase 4 of the runtime contract: Login Semantics Hardening
2026-02-14 23:24:42 -06:00
vicrodh f34882ccc5 Integrate RuntimeManager with session lifecycle
- Add RuntimeManagerState to activate_user_session
- Add RuntimeManagerState to deactivate_user_session
- Update runtime state on session activation/deactivation
- Add v2_remove_upcoming_track command

This implements Phase 2 of the runtime contract by ensuring session
state changes are reflected in the canonical RuntimeManager.
2026-02-14 23:22:45 -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 67ed397d02 feat(v2): add runtime contract and queue V2 commands
Runtime contract (ADR Phase 1+2):
- Add RuntimeManager with canonical state machine
- Add RuntimeStatus, RuntimeError (typed errors)
- Add RuntimeEvent for lifecycle events
- Add runtime_get_status and runtime_bootstrap commands

Queue V2 commands:
- v2_add_to_queue, v2_add_to_queue_next
- v2_set_queue, v2_remove_from_queue
- v2_next_track, v2_previous_track, v2_play_queue_index
- V2QueueTrack type with proper field mapping

All queue operations now have V2 equivalents.
Frontend migration to use these commands is next.
2026-02-14 23:13:21 -06:00
vicrodh d79e84fb9c fix(playback): emit events from V2 player when active
The event loop now checks both V2 (qbz-player) and legacy player states.
V2 player takes priority when it has an active track (track_id != 0).

This ensures the frontend receives correct playback position, duration,
sample rate, and bit depth when using v2_play_track commands.

Changes:
- Store V2 player SharedState after CoreBridge initializes
- Event loop checks V2 state first, falls back to legacy
- All playback event values now come from the active player
2026-02-14 23:04:17 -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 85757f186b fix(qbz-core): call client.init() to extract bundle tokens
QbzCore::init() was creating the QobuzClient but not calling init()
to extract bundle tokens. This caused "Client not initialized" errors
for all V2 API commands.
2026-02-14 22:52:37 -06:00
vicrodh c3a14c1c87 feat(v2): add v2_reinit_audio_device command
- Added v2_reinit_audio_device for V2 player device reinitialization
- SettingsView now calls both legacy and V2 reinit commands
- Converts legacy AudioSettings to qbz_audio::AudioSettings for reload
2026-02-14 22:48:03 -06:00
vicrodh fbba4f25c1 feat(v2): add automatic prefetch to v2_play_track
- Added spawn_v2_prefetch helper function
- v2_play_track now prefetches next 2 Qobuz tracks after playback starts
- Respects streaming_only mode (skips prefetch when enabled)
- Uses semaphore to limit concurrent prefetch downloads to 1
- Prefetch works with cache (offline, memory, disk) paths
2026-02-14 22:45:29 -06:00
vicrodh 82a81e1ded feat(v2): add MPRIS, gapless, and prefetch V2 commands
V2 Playback Features:
- v2_set_media_metadata: Update MPRIS metadata
- v2_play_next_gapless: Queue next track for gapless playback
- v2_prefetch_track: Pre-download track into memory cache

V2 Command Updates:
- v2_pause/resume/stop: Now update MPRIS state
- v2_seek: Updates MPRIS progress
- v2_get_playback_state: Updates MPRIS progress on poll

Frontend Migration:
- playbackService: Use v2_set_media_metadata
- playerStore: Use v2_play_next_gapless
2026-02-14 22:42:03 -06:00
vicrodh 6778ef4ba6 fix(auth): sync V2 CoreBridge authentication with legacy login
- Modified login/auto_login commands to also authenticate CoreBridge
- Modified logout command to also logout from CoreBridge
- Removed redundant v2_login call from LoginView.svelte frontend

This ensures both legacy AppState.client and V2 CoreBridge.QbzCore.client
are authenticated in sync, allowing V2 commands to work after login.
2026-02-14 22:38:26 -06:00
vicrodh 6b432586a7 feat(frontend): migrate playback commands to V2
Migrate all frontend playback invocations to V2 commands:
- play_track -> v2_play_track
- pause_playback -> v2_pause_playback
- resume_playback -> v2_resume_playback
- stop_playback -> v2_stop_playback
- seek -> v2_seek
- set_volume -> v2_set_volume

Updated files:
- playbackService.ts
- playerStore.ts
- playerStore.test.ts
- castStore.ts
- SettingsView.svelte

Frontend now uses V2 architecture for all Qobuz playback operations.
2026-02-14 22:17:36 -06:00
vicrodh 41c8acce38 feat(tauri): register v2_play_track command 2026-02-14 22:11:05 -06:00
vicrodh af0d88283a feat(v2): implement v2_play_track command
Core playback now flows through V2 architecture:
- Added get_stream_url to QbzCore and CoreBridge
- Implemented v2_play_track with full cache support:
  - Offline cache (persistent disk)
  - Memory cache (L1)
  - Playback cache (L2 - disk)
- Downloads from Qobuz via CoreBridge.get_stream_url()
- Plays via CoreBridge.player() (qbz-player crate)
- Respects quality limits and streaming_only settings

Still uses AppState.audio_cache for caching (to be migrated later).
No dependency on legacy player module for playback.
2026-02-14 22:10:36 -06:00
vicrodh ac26f2079b chore: mark legacy player and queue modules as deprecated
Added DEPRECATED headers to src-tauri/src/player/mod.rs and
src-tauri/src/queue/mod.rs indicating these will be removed
after migration to qbz-player crate is complete.

New code should use:
- qbz_player::Player (via CoreBridge -> QbzCore)
- qbz_player::QueueManager (via CoreBridge -> QbzCore)
2026-02-14 22:07:30 -06:00
vicrodh 0e85285e90 feat(core): wire Player from qbz-player through QbzCore
- QbzCore now accepts Player in constructor and owns playback
- Added playback methods to QbzCore (pause, resume, stop, seek, volume)
- CoreBridge loads audio settings and creates Player from qbz-player
- V2 playback commands use CoreBridge instead of AppState

This closes the "operational playback core" gap identified by Codex.
V2 commands now flow: frontend -> commands_v2 -> CoreBridge -> QbzCore -> Player

Legacy player in src-tauri/src/player/ remains as emergency fallback.
2026-02-14 20:20:37 -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 a8f56444ce feat(v2-commands): fix parameter names for frontend compatibility
- Use camelCase parameter names (albumId, trackId, artistId) to match
  frontend expectations
- Add #[allow(non_snake_case)] to suppress warnings

V2 commands are ready for testing. Full frontend migration pending:
- Search commands need searchType parameter
- Need to add get_user_info, login with full flow, etc.
2026-02-14 19:48:12 -06:00
vicrodh b930fa11ba fix(v2-commands): return SearchResultsPage for search commands
Update search commands to return full SearchResultsPage<T> with pagination
info instead of just Vec<T>. This makes V2 commands compatible with the
frontend's expected response format.
2026-02-14 19:46:16 -06:00
vicrodh 8ed8f02fcd Phase 7a: Replace src-tauri audio module with qbz-audio re-exports
- Remove duplicate audio module files from src-tauri
- Update audio/mod.rs to re-export from qbz_audio
- Single source of truth for audio types now in qbz-audio crate
- Compilation passes, types are aligned
2026-02-14 17:48:03 -06:00
vicrodh 71f8d09c41 feat(qbz-player): Phase 6.5 - export full Player module
Reorganize qbz-player to export the complete Player struct with all
playback functionality.

Changes:
- Restructure: mod.rs -> player/mod.rs with submodules
- Add rodio, serde, reqwest, qbz-qobuz dependencies
- Export Player, SharedState, PlaybackState, PlaybackEvent
- Export streaming types (BufferedMediaSource, etc.)

The Player module is now fully available from qbz-player crate.
Full workspace and src-tauri compile successfully.
2026-02-14 15:38:53 -06:00
vicrodh 0238b1c559 feat(qbz-nix): Phase 6.4 - add search and catalog V2 commands
Add search and catalog retrieval methods to QbzCore and V2 commands.

QbzCore methods added:
- search_albums, search_tracks, search_artists
- get_album, get_track, get_artist

V2 commands added:
- v2_search_albums, v2_search_tracks, v2_search_artists
- v2_get_album, v2_get_track, v2_get_artist

All commands registered in invoke_handler.
2026-02-14 15:16:31 -06:00