A decentralized music tracking and discovery platform built on AT Protocol 🎵

fix: update Media struct to use Option types for position and tracks, improving handling of missing data

+33 -14
+19
crates/scrobbler/src/musicbrainz/mod.rs
··· 296 296 assert_eq!(best.status.as_deref(), Some("Bootleg")); 297 297 assert_eq!(best.country.as_deref(), Some("XW")); 298 298 299 + assert_eq!( 300 + normalize_date(best.date.as_deref()).unwrap(), 301 + Some("2017-01-01".into()) 302 + ); 303 + 304 + assert_eq!( 305 + best.media 306 + .as_ref() 307 + .and_then(|media| media.first()) 308 + .and_then(|media| { 309 + media 310 + .track 311 + .as_ref() 312 + .and_then(|tracks| tracks.first()) 313 + .map(|track| track.number.parse::<u32>().unwrap()) 314 + }), 315 + Some(1) 316 + ); 317 + 299 318 let query = format!( 300 319 r#"recording:"{}" AND artist:"{}" AND status:Official"#, 301 320 "Don't Stay", "Linkin Park"
+5 -5
crates/scrobbler/src/musicbrainz/release.rs
··· 65 65 #[serde(rename = "format-id")] 66 66 pub format_id: Option<String>, 67 67 pub discs: Option<Vec<Disc>>, 68 - pub position: u32, 69 - pub tracks: Option<Vec<Track>>, 68 + pub position: Option<u32>, 69 + pub track: Option<Vec<Track>>, 70 70 #[serde(rename = "track-offset")] 71 71 pub track_offset: u32, 72 72 pub title: Option<String>, ··· 85 85 86 86 #[derive(Debug, Deserialize, Clone)] 87 87 pub struct Track { 88 - pub length: i64, 88 + pub length: Option<i64>, 89 89 pub id: String, 90 - pub position: u32, 90 + pub position: Option<u32>, 91 91 pub title: String, 92 - pub recording: Recording, 92 + pub recording: Option<Recording>, 93 93 #[serde(rename = "artist-credit")] 94 94 pub artist_credit: Option<Vec<ArtistCredit>>, 95 95 pub number: String,
+2 -2
crates/scrobbler/src/types.rs
··· 105 105 .and_then(|media| media.first()) 106 106 .and_then(|media| { 107 107 media 108 - .tracks 108 + .track 109 109 .as_ref() 110 110 .and_then(|tracks| tracks.first()) 111 111 .map(|track| track.number.parse::<u32>().unwrap()) ··· 119 119 .media 120 120 .as_ref() 121 121 .and_then(|media| media.first()) 122 - .map(|media| media.position) 122 + .map(|media| media.position.unwrap_or(1) as u32) 123 123 }) 124 124 .unwrap_or_default(), 125 125 ..Default::default()
+5 -5
crates/webscrobbler/src/musicbrainz/release.rs
··· 65 65 #[serde(rename = "format-id")] 66 66 pub format_id: Option<String>, 67 67 pub discs: Option<Vec<Disc>>, 68 - pub position: u32, 69 - pub tracks: Option<Vec<Track>>, 68 + pub position: Option<u32>, 69 + pub track: Option<Vec<Track>>, 70 70 #[serde(rename = "track-offset")] 71 71 pub track_offset: u32, 72 72 pub title: Option<String>, ··· 85 85 86 86 #[derive(Debug, Deserialize, Clone)] 87 87 pub struct Track { 88 - pub length: i64, 88 + pub length: Option<i64>, 89 89 pub id: String, 90 - pub position: u32, 90 + pub position: Option<u32>, 91 91 pub title: String, 92 - pub recording: Recording, 92 + pub recording: Option<Recording>, 93 93 #[serde(rename = "artist-credit")] 94 94 pub artist_credit: Option<Vec<ArtistCredit>>, 95 95 pub number: String,
+2 -2
crates/webscrobbler/src/types.rs
··· 200 200 .and_then(|media| media.first()) 201 201 .and_then(|media| { 202 202 media 203 - .tracks 203 + .track 204 204 .as_ref() 205 205 .and_then(|tracks| tracks.first()) 206 206 .map(|track| track.number.parse::<u32>().unwrap()) ··· 214 214 .media 215 215 .as_ref() 216 216 .and_then(|media| media.first()) 217 - .map(|media| media.position) 217 + .map(|media| media.position.unwrap_or(1) as u32) 218 218 }) 219 219 .unwrap_or_default(), 220 220 ..Default::default()