fix(search): resolve notification loops causing multiple API requests

- Make auth_token() public for catalog/search endpoint authentication
- Fix setSearchQuery to skip notification when value unchanged
- Fix setSearchState to only notify listeners when query actually changed
- Add title case transformation for better most_popular API results
- Add stale result detection to ignore outdated search responses
- Preserve most_popular when API returns inconsistent results
- Clean up debug logging
This commit is contained in:
vicrodh committed 2026-02-01 02:41:55 -06:00
1 parent d8bd93374f
commit f699cf0e63
4 files changed
+90 -19

No files matched your search

+2 -2
View File
@@ -187,8 +187,8 @@ impl QobuzClient {
self.session.read().await.as_ref().map(|s| s.user_id)
}
/// Get user auth token header value
async fn auth_token(&self) -> Result<String> {
/// Get user auth token header value (public for catalog search)
pub async fn auth_token(&self) -> Result<String> {
self.session
.read()
.await
+25 -1
View File
@@ -75,14 +75,17 @@ pub async fn search_all(
query: String,
state: State<'_, AppState>,
) -> Result<SearchAllResults, String> {
log::debug!("search_all called with query: {}", query);
let client = state.client.lock().await;
// Use catalog/search endpoint which returns everything including most_popular
let url = endpoints::build_url(paths::CATALOG_SEARCH);
let response: Value = client
.get_http()
.get(&url)
.header("X-App-Id", client.app_id().await.map_err(|e| e.to_string())?)
.header("X-User-Auth-Token", client.auth_token().await.map_err(|e| e.to_string())?)
.query(&[
("query", query.as_str()),
("limit", "30"),
@@ -119,7 +122,28 @@ pub async fn search_all(
.and_then(|mp| mp.get("items"))
.and_then(|items| items.as_array())
.and_then(|arr| arr.first())
.and_then(|item| serde_json::from_value(item.clone()).ok());
.and_then(|item| {
let item_type = item.get("type")?.as_str()?;
let content = item.get("content")?;
log::debug!("most_popular type: {}, content keys: {:?}",
item_type,
content.as_object().map(|o| o.keys().collect::<Vec<_>>())
);
match item_type {
"tracks" => serde_json::from_value::<Track>(content.clone())
.ok()
.map(MostPopularItem::Tracks),
"albums" => serde_json::from_value::<Album>(content.clone())
.ok()
.map(MostPopularItem::Albums),
"artists" => serde_json::from_value::<Artist>(content.clone())
.ok()
.map(MostPopularItem::Artists),
_ => None,
}
});
Ok(SearchAllResults {
albums,