From cb5ce3df62ede93b75135bac21d08bdab7dd7ff0 Mon Sep 17 00:00:00 2001 From: zarzet <42882290+zarzet@users.noreply.github.com> Date: Sun, 20 Sep 2026 17:21:01 +0700 Subject: [PATCH] perf(metadata): move normalized Rust values into response envelopes Move normalized maps and track arrays into response envelopes instead of serializing them into another Value tree. Cover JSON parity, Unicode, track numbering and cancellation. --- .../src/backend/provider_metadata.rs | 26 ++++++++++---- .../backend/provider_metadata/value_tests.rs | 35 +++++++++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/rust_backend/crates/extensions/src/backend/provider_metadata.rs b/rust_backend/crates/extensions/src/backend/provider_metadata.rs index 98df916f..57c2bb2f 100644 --- a/rust_backend/crates/extensions/src/backend/provider_metadata.rs +++ b/rust_backend/crates/extensions/src/backend/provider_metadata.rs @@ -392,10 +392,17 @@ fn response(kind: &str, value: &Value, check: &Check<'_>) -> Result json!({"track":track(value, "", 0)}), - "album" => { - json!({"album_info":album(value, true),"track_list":tracks(array(value,"tracks"),cover,check)?}) - } + // Move normalized values into the envelope. json! serializes borrowed + // expressions, duplicating every field of an already-built track list. + "track" => Map::from_iter([("track".into(), track(value, "", 0))]).into(), + "album" => Map::from_iter([ + ("album_info".into(), album(value, true)), + ( + "track_list".into(), + tracks(array(value, "tracks"), cover, check)?, + ), + ]) + .into(), "playlist" => { let mut info = strings( value, @@ -413,7 +420,14 @@ fn response(kind: &str, value: &Value, check: &Check<'_>) -> Result { let cover = text(value, "image_url"); @@ -439,7 +453,7 @@ fn response(kind: &str, value: &Value, check: &Check<'_>) -> Result 0 { info.insert("listeners".into(), value["listeners"].clone()); } - let mut result = json!({"artist_info":info}); + let mut result = Value::Object(Map::from_iter([("artist_info".into(), info.into())])); for key in ["albums", "releases"] { let values = array(value, key); if key == "albums" || !values.is_empty() { diff --git a/rust_backend/crates/extensions/src/backend/provider_metadata/value_tests.rs b/rust_backend/crates/extensions/src/backend/provider_metadata/value_tests.rs index ecb718a0..c2b24427 100644 --- a/rust_backend/crates/extensions/src/backend/provider_metadata/value_tests.rs +++ b/rust_backend/crates/extensions/src/backend/provider_metadata/value_tests.rs @@ -49,6 +49,41 @@ fn fixture() -> (tempfile::TempDir, Backend) { (root, backend) } +#[test] +fn response_envelopes_preserve_json_and_cancellation() { + let value = json!({ + "id": "collection", "name": "音楽 🎵", "artists": "Artist Café", + "cover_url": "https://example.invalid/cover.jpg", + "tracks": [ + {"id": "first", "name": "One", "external_links": {"example": "link"}}, + {"id": "second", "name": "Two", "explicit": true, "track_number": 9}, + ], + }); + let check = || Ok(()); + let cover = text(&value, "cover_url"); + let expected = json!({ + "album_info": album(&value, true), + "track_list": tracks(array(&value, "tracks"), cover, &check).unwrap(), + }); + let actual = response("album", &value, &check).unwrap(); + assert_eq!(actual.to_string(), expected.to_string()); + let playlist = response("playlist", &value, &check).unwrap(); + assert_eq!(playlist["track_list"], expected["track_list"]); + assert_eq!(playlist["playlist_info"]["owner"]["name"], "Artist Café"); + assert_eq!(playlist["track_list"][0]["track_number"], 1); + assert_eq!(playlist["track_list"][1]["track_number"], 9); + assert_eq!( + response("track", &value, &check).unwrap().to_string(), + json!({"track": track(&value, "", 0)}).to_string(), + ); + for kind in ["album", "playlist", "artist", "track"] { + assert_eq!( + response(kind, &value, &|| Err("cancelled".into())), + Err(ResolverError::Cancelled("cancelled".into())), + ); + } +} + #[test] fn artist_metadata_preserves_logo_separately_from_portrait() { let (_root, backend) = fixture();