From 1dcb7765d338f45042f2899f1ec7663ec4b17c99 Mon Sep 17 00:00:00 2001 From: vicrodh <103399283+vicrodh@users.noreply.github.com> Date: Sun, 26 Apr 2026 11:43:23 -0600 Subject: [PATCH] refactor(v2): migrate get_artist_albums to v2 Path C: legacy command projected `Artist.albums` from client.get_artist_with_pagination(with_albums=true). The existing v2_get_artist_with_albums returns the full Artist envelope, so add a dedicated v2_get_artist_albums in QbzCore that performs the same projection and exposes only ArtistAlbums to match what the two callsites destructure. cc --- crates/qbz-core/src/core.rs | 27 +++++++++++++- src-tauri/src/commands_v2/catalog.rs | 36 ++++++++++++++++--- src-tauri/src/core_bridge.rs | 19 ++++++++-- src-tauri/src/lib.rs | 1 + .../views/ArtistsByLocationView.svelte | 2 +- src/lib/components/views/FavoritesView.svelte | 2 +- 6 files changed, 77 insertions(+), 10 deletions(-) diff --git a/crates/qbz-core/src/core.rs b/crates/qbz-core/src/core.rs index 615de3e87..9f722541e 100644 --- a/crates/qbz-core/src/core.rs +++ b/crates/qbz-core/src/core.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use tokio::sync::RwLock; use qbz_models::{ - Album, Artist, CoreEvent, DiscoverAlbum, DiscoverData, DiscoverPlaylistsResponse, + Album, Artist, ArtistAlbums, CoreEvent, DiscoverAlbum, DiscoverData, DiscoverPlaylistsResponse, DiscoverResponse, FrontendAdapter, GenreInfo, LabelExploreResponse, LabelGetListResponse, LabelListPage, LabelPageData, LabelStoryResponse, PageArtistResponse, Playlist, PlaylistTag, Quality, QueueState, QueueTrack, RepeatMode, SearchResultsPage, @@ -841,6 +841,31 @@ impl QbzCore { .map_err(CoreError::Api) } + /// Get an artist's albums collection (paginated `ArtistAlbums` only). + /// + /// Equivalent to `get_artist_with_albums` but projects only the `albums` + /// field for callers that don't need the full artist envelope. + pub async fn get_artist_albums( + &self, + artist_id: u64, + limit: Option, + offset: Option, + ) -> Result { + let client = self.client.read().await; + let client = client.as_ref().ok_or(CoreError::NotInitialized)?; + + let artist = client + .get_artist_with_pagination(artist_id, true, limit, offset) + .await + .map_err(CoreError::Api)?; + + artist + .albums + .ok_or_else(|| CoreError::Api(qbz_qobuz::ApiError::ApiResponse( + "No albums in artist response".to_string(), + ))) + } + /// Get label page (aggregated: top tracks, releases, playlists, artists) pub async fn get_label_page(&self, label_id: u64) -> Result { let client = self.client.read().await; diff --git a/src-tauri/src/commands_v2/catalog.rs b/src-tauri/src/commands_v2/catalog.rs index 6510c35fd..17d3baf1a 100644 --- a/src-tauri/src/commands_v2/catalog.rs +++ b/src-tauri/src/commands_v2/catalog.rs @@ -1,10 +1,10 @@ use tauri::State; use qbz_models::{ - Album, Artist, AwardPageData, DiscoverAlbum, DiscoverData, DiscoverPlaylistsResponse, - DiscoverResponse, GenreInfo, LabelExploreResponse, LabelGetListResponse, LabelListPage, - LabelPageData, LabelStoryResponse, PageArtistResponse, Playlist, PlaylistTag, - SearchResultsPage, Track, + Album, Artist, ArtistAlbums, AwardPageData, DiscoverAlbum, DiscoverData, + DiscoverPlaylistsResponse, DiscoverResponse, GenreInfo, LabelExploreResponse, + LabelGetListResponse, LabelListPage, LabelPageData, LabelStoryResponse, PageArtistResponse, + Playlist, PlaylistTag, SearchResultsPage, Track, }; use crate::artist_blacklist::BlacklistState; @@ -399,6 +399,34 @@ pub async fn v2_get_artist_with_albums( .map_err(RuntimeError::Internal) } +/// Get an artist's albums collection (V2 - returns only the `ArtistAlbums` envelope). +#[tauri::command] +#[allow(non_snake_case)] +pub async fn v2_get_artist_albums( + artistId: u64, + limit: Option, + offset: Option, + bridge: State<'_, CoreBridgeState>, + runtime: State<'_, RuntimeManagerState>, +) -> Result { + runtime + .manager() + .check_requirements(CommandRequirement::RequiresCoreBridgeAuth) + .await?; + + log::info!( + "[V2] get_artist_albums: {} limit={:?} offset={:?}", + artistId, + limit, + offset + ); + let bridge = bridge.get().await; + bridge + .get_artist_albums(artistId, limit, offset) + .await + .map_err(RuntimeError::Internal) +} + /// Get label page (aggregated: top tracks, releases, playlists, artists) #[tauri::command] #[allow(non_snake_case)] diff --git a/src-tauri/src/core_bridge.rs b/src-tauri/src/core_bridge.rs index 4fd9c8bf3..1bf7a78eb 100644 --- a/src-tauri/src/core_bridge.rs +++ b/src-tauri/src/core_bridge.rs @@ -13,9 +13,9 @@ use tokio::sync::RwLock; use qbz_audio::{settings::AudioSettingsStore, AudioDiagnostic, AudioSettings, VisualizerTap}; use qbz_core::QbzCore; use qbz_models::{ - Album, Artist, DiscoverAlbum, DiscoverData, DiscoverPlaylistsResponse, DiscoverResponse, - GenreInfo, LabelExploreResponse, LabelGetListResponse, LabelListPage, LabelPageData, - LabelStoryResponse, PageArtistResponse, Playlist, PlaylistTag, Quality, + Album, Artist, ArtistAlbums, DiscoverAlbum, DiscoverData, DiscoverPlaylistsResponse, + DiscoverResponse, GenreInfo, LabelExploreResponse, LabelGetListResponse, LabelListPage, + LabelPageData, LabelStoryResponse, PageArtistResponse, Playlist, PlaylistTag, Quality, QueueState, QueueTrack, RepeatMode, SearchResultsPage, StreamUrl, Track, UserSession, }; use qbz_player::{PlaybackState, Player}; @@ -555,6 +555,19 @@ impl CoreBridge { .map_err(|e| e.to_string()) } + /// Get an artist's albums collection (paginated `ArtistAlbums` only). + pub async fn get_artist_albums( + &self, + artist_id: u64, + limit: Option, + offset: Option, + ) -> Result { + self.core + .get_artist_albums(artist_id, limit, offset) + .await + .map_err(|e| e.to_string()) + } + /// Get label page (aggregated: top tracks, releases, playlists, artists) pub async fn get_label_page(&self, label_id: u64) -> Result { self.core diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 4b9bebd4b..d16b5885f 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1703,6 +1703,7 @@ pub fn run() { commands_v2::v2_get_artist_page, commands_v2::v2_get_similar_artists, commands_v2::v2_get_artist_with_albums, + commands_v2::v2_get_artist_albums, commands_v2::v2_get_label_page, commands_v2::v2_get_label_explore, commands_v2::v2_get_label_albums, diff --git a/src/lib/components/views/ArtistsByLocationView.svelte b/src/lib/components/views/ArtistsByLocationView.svelte index dd59595f7..01c81b2fa 100644 --- a/src/lib/components/views/ArtistsByLocationView.svelte +++ b/src/lib/components/views/ArtistsByLocationView.svelte @@ -342,7 +342,7 @@ albumsError = null; try { - const result = await invoke<{ items: QobuzAlbum[] }>('get_artist_albums', { + const result = await invoke<{ items: QobuzAlbum[] }>('v2_get_artist_albums', { artistId: artist.id, limit: 500, offset: 0, diff --git a/src/lib/components/views/FavoritesView.svelte b/src/lib/components/views/FavoritesView.svelte index 8917fb666..9173ed96a 100644 --- a/src/lib/components/views/FavoritesView.svelte +++ b/src/lib/components/views/FavoritesView.svelte @@ -938,7 +938,7 @@ artistAlbumsError = null; try { - const result = await invoke<{ items: QobuzAlbum[]; total: number }>('get_artist_albums', { + const result = await invoke<{ items: QobuzAlbum[]; total: number }>('v2_get_artist_albums', { artistId: artist.id, limit: 500, // Fetch more to ensure we have enough Discography albums after filtering offset: 0