fix(award): normalize award.id as string end-to-end so /award/* calls stop sending 'null'
The log showed 'award=null' reaching /award/getAlbums and Qobuz replying '400 Bad Request: Invalid argument: award_id (accepted type are number)'. Root cause: AlbumAward.id was typed Option<u64> and /album/get returns award ids as strings; serde dropped them to None, frontend stringified null → 'null', we sent that as the query param. Fix: - AlbumAward.id becomes Option<String> with a custom deserializer that accepts both string and integer JSON values. - TS types + AlbumDetailView Award interface + pickAlbumRibbon all use string id (compared as '88'/'151' now). - Sidebar button is disabled when id is falsy; handleAwardClick early-returns on empty id so we never navigate to award 'null'. - Better body/status logging in get_award_albums stays so future 4xx responses are visible in the log. Also switches /award/page and /award/getAlbums to signed_get_auth (app_id + user token). Mobile does the same — catalog visibility is region-scoped and the unsigned variant returns 400. cc
This commit is contained in:
7 files changed
+117
-33
No files matched your search
@@ -969,17 +969,29 @@ pub struct PageArtistAward {
|
||||
}
|
||||
|
||||
/// Tolerant award struct used in Album responses where Qobuz is
|
||||
/// inconsistent about optional id and awarded_at types.
|
||||
/// inconsistent about field types. id is emitted as String downstream.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct AlbumAward {
|
||||
#[serde(default)]
|
||||
pub id: Option<u64>,
|
||||
#[serde(default, deserialize_with = "deserialize_album_award_id")]
|
||||
pub id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub name: String,
|
||||
#[serde(default, deserialize_with = "deserialize_album_awarded_at")]
|
||||
pub awarded_at: Option<String>,
|
||||
}
|
||||
|
||||
fn deserialize_album_award_id<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let value = Option::<serde_json::Value>::deserialize(deserializer)?;
|
||||
Ok(match value {
|
||||
Some(serde_json::Value::String(s)) if !s.is_empty() => Some(s),
|
||||
Some(serde_json::Value::Number(n)) => Some(n.to_string()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn deserialize_album_awarded_at<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
|
||||
Reference in new issue
Block a user