@@ -39,38 +39,110 @@ pub fn ArtistDetailView(artist_id: String, server_id: String) -> Element {
3939 let mut now_playing = use_context :: < Signal < Option < Song > > > ( ) ;
4040 let mut is_playing = use_context :: < crate :: components:: IsPlayingSignal > ( ) . 0 ;
4141 let shuffle_enabled = use_context :: < crate :: components:: ShuffleEnabledSignal > ( ) . 0 ;
42- let visible_album_count = use_signal ( || ARTIST_ALBUM_BATCH_SIZE ) ;
42+ let mut visible_album_count = use_signal ( || ARTIST_ALBUM_BATCH_SIZE ) ;
43+ let mut current_artist_id = use_signal ( || artist_id. clone ( ) ) ;
44+ let mut current_server_id = use_signal ( || server_id. clone ( ) ) ;
4345
44- let artist_server = servers ( ) . into_iter ( ) . find ( |s| s. id == server_id) ;
45- let artist_server_for_artist = artist_server. clone ( ) ;
46- let artist_server_for_top = artist_server. clone ( ) ;
46+ use_effect ( {
47+ let artist_id = artist_id. clone ( ) ;
48+ let server_id = server_id. clone ( ) ;
49+ move || {
50+ if current_artist_id ( ) != artist_id {
51+ eprintln ! (
52+ "[artist-detail.route] artist_id change {} -> {}" ,
53+ current_artist_id( ) ,
54+ artist_id
55+ ) ;
56+ current_artist_id. set ( artist_id. clone ( ) ) ;
57+ visible_album_count. set ( ARTIST_ALBUM_BATCH_SIZE ) ;
58+ }
59+ if current_server_id ( ) != server_id {
60+ eprintln ! (
61+ "[artist-detail.route] server_id change {} -> {}" ,
62+ current_server_id( ) ,
63+ server_id
64+ ) ;
65+ current_server_id. set ( server_id. clone ( ) ) ;
66+ visible_album_count. set ( ARTIST_ALBUM_BATCH_SIZE ) ;
67+ }
68+ }
69+ } ) ;
70+
71+ let artist_server = servers ( ) . into_iter ( ) . find ( |s| s. id == current_server_id ( ) ) ;
4772
4873 let artist_data = use_resource ( move || {
49- let server = artist_server_for_artist. clone ( ) ;
50- let artist_id = artist_id. clone ( ) ;
74+ let server_id = current_server_id ( ) ;
75+ let artist_id = current_artist_id ( ) ;
76+ let server = servers ( ) . into_iter ( ) . find ( |s| s. id == server_id) ;
5177 async move {
5278 if let Some ( server) = server {
79+ eprintln ! (
80+ "[artist-detail.fetch.start] artist_id={} server_id={}" ,
81+ artist_id, server_id
82+ ) ;
5383 let client = NavidromeClient :: new ( server) ;
54- client. get_artist ( & artist_id) . await . ok ( )
84+ match client. get_artist ( & artist_id) . await {
85+ Ok ( ( artist, albums) ) => {
86+ eprintln ! (
87+ "[artist-detail.fetch.ok] requested_artist_id={} returned_artist_id={} server_id={} albums={}" ,
88+ artist_id,
89+ artist. id,
90+ server_id,
91+ albums. len( )
92+ ) ;
93+ Some ( ( artist, albums) )
94+ }
95+ Err ( err) => {
96+ eprintln ! (
97+ "[artist-detail.fetch.err] artist_id={} server_id={} err={}" ,
98+ artist_id, server_id, err
99+ ) ;
100+ None
101+ }
102+ }
55103 } else {
104+ eprintln ! (
105+ "[artist-detail.fetch.skip] missing server artist_id={} server_id={}" ,
106+ artist_id, server_id
107+ ) ;
56108 None
57109 }
58110 }
59111 } ) ;
60112
61113 let top_songs_data = use_resource ( {
62- let server = artist_server_for_top. clone ( ) ;
63114 let artist_data = artist_data. clone ( ) ;
64115 move || {
65- let server = server. clone ( ) ;
116+ let server_id = current_server_id ( ) ;
117+ let server = servers ( ) . into_iter ( ) . find ( |s| s. id == server_id) ;
66118 let artist_name = artist_data ( )
67119 . and_then ( |value| value. map ( |( artist, _) | artist. name . clone ( ) ) )
68120 . filter ( |name| !name. is_empty ( ) ) ;
69121 async move {
70122 match ( server, artist_name) {
71123 ( Some ( server) , Some ( artist_name) ) => {
124+ eprintln ! (
125+ "[artist-detail.top.start] artist_name='{}' server_id={}" ,
126+ artist_name, server_id
127+ ) ;
72128 let client = NavidromeClient :: new ( server) ;
73- client. get_top_songs ( & artist_name, 20 ) . await . ok ( )
129+ match client. get_top_songs ( & artist_name, 20 ) . await {
130+ Ok ( songs) => {
131+ eprintln ! (
132+ "[artist-detail.top.ok] artist_name='{}' songs={}" ,
133+ artist_name,
134+ songs. len( )
135+ ) ;
136+ Some ( songs)
137+ }
138+ Err ( err) => {
139+ eprintln ! (
140+ "[artist-detail.top.err] artist_name='{}' err={}" ,
141+ artist_name, err
142+ ) ;
143+ None
144+ }
145+ }
74146 }
75147 _ => None ,
76148 }
@@ -151,42 +223,61 @@ pub fn ArtistDetailView(artist_id: String, server_id: String) -> Element {
151223 {
152224 match artist_data( ) {
153225 Some ( Some ( ( artist, albums) ) ) => {
154- let top_songs = top_songs_data( ) . flatten( ) . unwrap_or_default( ) ;
155- let cover_url = artist_server. as_ref( ) . and_then( |server| {
156- let client = NavidromeClient :: new( server. clone( ) ) ;
157- artist
158- . cover_art
159- . as_ref( )
160- . map( |ca| client. get_cover_art_url( ca, 500 ) )
161- } ) ;
162-
163- let total_albums = albums. len( ) ;
164- let total_songs: u32 = albums. iter( ) . map( |a| a. song_count) . sum( ) ;
165- let current_album_limit = visible_album_count( ) . min( total_albums) ;
166- let remaining_albums = total_albums. saturating_sub( current_album_limit) ;
167- let cover_element = match cover_url {
168- Some ( url) => rsx! {
169- img {
170- src: "{url}" ,
171- alt: "{artist.name}" ,
172- class: "w-full h-full object-cover" ,
173- loading: "lazy" ,
226+ let requested_artist_id = current_artist_id( ) ;
227+ let requested_server_id = current_server_id( ) ;
228+ let server_matches = artist. server_id. is_empty( )
229+ || artist. server_id == requested_server_id;
230+ if artist. id != requested_artist_id || !server_matches {
231+ eprintln!(
232+ "[artist-detail.stale] requested_artist_id={} requested_server_id={} returned_artist_id={} returned_server_id={}" ,
233+ requested_artist_id,
234+ requested_server_id,
235+ artist. id,
236+ artist. server_id
237+ ) ;
238+ rsx! {
239+ div { class: "flex flex-col items-center justify-center py-20" ,
240+ div { class: "w-16 h-16 rounded-full border-2 border-zinc-700 border-t-emerald-500 animate-spin mb-4" }
241+ p { class: "text-zinc-400" , "Loading artist..." }
174242 }
175- } ,
176- None => rsx! {
177- div { class: "w-full h-full flex items-center justify-center bg-gradient-to-br from-emerald-600 to-teal-700" ,
178- Icon {
179- name: "artist" . to_string( ) ,
180- class: "w-24 h-24 text-white/70" . to_string( ) ,
243+ }
244+ } else {
245+ let top_songs = top_songs_data( ) . flatten( ) . unwrap_or_default( ) ;
246+ let cover_url = artist_server. as_ref( ) . and_then( |server| {
247+ let client = NavidromeClient :: new( server. clone( ) ) ;
248+ artist
249+ . cover_art
250+ . as_ref( )
251+ . map( |ca| client. get_cover_art_url( ca, 500 ) )
252+ } ) ;
253+
254+ let total_albums = albums. len( ) ;
255+ let total_songs: u32 = albums. iter( ) . map( |a| a. song_count) . sum( ) ;
256+ let current_album_limit = visible_album_count( ) . min( total_albums) ;
257+ let remaining_albums = total_albums. saturating_sub( current_album_limit) ;
258+ let cover_element = match cover_url {
259+ Some ( url) => rsx! {
260+ img {
261+ src: "{url}" ,
262+ alt: "{artist.name}" ,
263+ class: "w-full h-full object-cover" ,
264+ loading: "lazy" ,
181265 }
182- }
183- } ,
184- } ;
266+ } ,
267+ None => rsx! {
268+ div { class: "w-full h-full flex items-center justify-center bg-gradient-to-br from-emerald-600 to-teal-700" ,
269+ Icon {
270+ name: "artist" . to_string( ) ,
271+ class: "w-24 h-24 text-white/70" . to_string( ) ,
272+ }
273+ }
274+ } ,
275+ } ;
185276
186- rsx! {
187- div { class: "flex flex-col md:flex-row gap-8 mb-12" ,
188- div { class: "w-48 h-48 md:w-64 md:h-64 rounded-full bg-zinc-800 overflow-hidden shadow-2xl flex-shrink-0 mx-auto md:mx-0" ,
189- { cover_element}
277+ rsx! {
278+ div { class: "flex flex-col md:flex-row gap-8 mb-12" ,
279+ div { class: "w-48 h-48 md:w-64 md:h-64 rounded-full bg-zinc-800 overflow-hidden shadow-2xl flex-shrink-0 mx-auto md:mx-0" ,
280+ { cover_element}
190281 }
191282 div { class: "flex flex-col justify-end text-center md:text-left" ,
192283 p { class: "text-sm text-zinc-400 uppercase tracking-wide mb-2 font-medium" ,
@@ -354,6 +445,7 @@ pub fn ArtistDetailView(artist_id: String, server_id: String) -> Element {
354445 }
355446 }
356447 }
448+ }
357449 Some ( None ) => rsx! {
358450 div { class: "flex flex-col items-center justify-center py-20" ,
359451 Icon {
0 commit comments