From 37c64d252c230bcbcd6ba6ed42d6ec82e9b4fa6a Mon Sep 17 00:00:00 2001 From: vicrodh <103399283+vicrodh@users.noreply.github.com> Date: Tue, 14 Apr 2026 08:01:30 -0600 Subject: [PATCH] fix(api): project /favorite/getNewReleases envelope to SearchResultsPage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The endpoint returns V2GenericListDto which is just {has_more: bool, items: [...]} — no total/offset/limit. Our caller wants SearchResultsPage to stay compatible with the rest of the album-list flow, so map items through directly and synthesise total from has_more + items.len() + the offset we asked for. Endpoint itself returns 200 OK with a real feed now (confirmed in logs with Godsmack etc. on the test account). cc --- crates/qbz-qobuz/src/client.rs | 56 ++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/crates/qbz-qobuz/src/client.rs b/crates/qbz-qobuz/src/client.rs index 2b71da243..cff470aee 100644 --- a/crates/qbz-qobuz/src/client.rs +++ b/crates/qbz-qobuz/src/client.rs @@ -819,31 +819,41 @@ impl QobuzClient { let response: Value = serde_json::from_str(&body_text)?; - if let Some(obj) = response.as_object() { - log::info!( - "[API] get_release_watch response keys: {:?}", - obj.keys().collect::>() + // Shape is V2GenericListDto per x20/b.java — a thin + // pagination envelope: {has_more: bool, items: [...]}. No total/ + // offset/limit fields are returned. We only need items for the UI + // and the caller already knows the offset/limit it asked for, so + // we project onto SearchResultsPage to stay compatible with + // the rest of the album-list plumbing. + let items_value = response.get("items").cloned().unwrap_or(Value::Null); + let items: Vec = serde_json::from_value(items_value).map_err(|e| { + log::warn!( + "[API] get_release_watch items parse error: {}. Body (first 600 chars): {}", + e, + body_text.chars().take(600).collect::() ); - } + ApiError::ApiResponse(format!("get_release_watch items parse: {}", e)) + })?; - // Response is V2GenericListDto per x20/b.java. Qobuz - // wraps paginated album lists under `albums` by convention; try that - // first, fall back to root. - let page_value = response.get("albums").cloned().unwrap_or(response); - match serde_json::from_value::>(page_value) { - Ok(page) => Ok(page), - Err(e) => { - log::warn!( - "[API] get_release_watch response did not match SearchResultsPage: {}. Body (first 600 chars): {}", - e, - body_text.chars().take(600).collect::() - ); - Err(ApiError::ApiResponse(format!( - "get_release_watch deserialize: {}", - e - ))) - } - } + let has_more = response + .get("has_more") + .and_then(|v| v.as_bool()) + .unwrap_or(false); + + let total_hint = if has_more { + // We don't know the real total; signal "at least one more page" + // by bumping past the items we have. + offset + items.len() as u32 + 1 + } else { + offset + items.len() as u32 + }; + + Ok(SearchResultsPage:: { + items, + total: total_hint, + offset, + limit, + }) } /// Get list of genres