diff --git a/crates/scrobbler/src/musicbrainz/mod.rs b/crates/scrobbler/src/musicbrainz/mod.rs index eee969fe..daaf689f 100644 --- a/crates/scrobbler/src/musicbrainz/mod.rs +++ b/crates/scrobbler/src/musicbrainz/mod.rs @@ -1,3 +1,5 @@ +use anyhow::Error; + use crate::musicbrainz::{recording::Recordings, release::Release}; use std::cmp::Ordering; @@ -179,6 +181,26 @@ fn date_key(d: Option<&str>) -> i32 { 9_999_01_01 } +pub fn normalize_date(d: Option<&str>) -> Result, Error> { + if let Some(d) = d { + let mut parts = d.split('-'); + let y = parts.next().unwrap_or("9999"); + let m = parts.next().unwrap_or("01"); + let day = parts.next().unwrap_or("01"); + + let y: i32 = y.parse().unwrap_or(9999); + let m: i32 = m.parse().unwrap_or(1); + let day: i32 = day.parse().unwrap_or(1); + + if y == 9999 { + return Err(Error::msg("Invalid date")); + } + + return Ok(Some(format!("{:04}-{:02}-{:02}", y, m, day))); + } + Ok(None) +} + fn is_live_release(rel: &Release) -> bool { let t_live = rel.title.to_ascii_lowercase().contains("live"); let d_live = rel @@ -211,6 +233,16 @@ mod tests { assert_eq!(date_key(Some("invalid-date")), 99990101); } + #[test] + fn test_normalize_date() -> Result<(), Error> { + assert_eq!(normalize_date(Some("2020-5-3"))?, Some("2020-05-03".into())); + assert_eq!(normalize_date(Some("2020-05"))?, Some("2020-05-01".into())); + assert_eq!(normalize_date(Some("2020"))?, Some("2020-01-01".into())); + assert_eq!(normalize_date(None)?, None); + assert!(normalize_date(Some("invalid-date")).is_err()); + Ok(()) + } + #[test] fn test_is_single() { let rel1 = Release { diff --git a/crates/scrobbler/src/types.rs b/crates/scrobbler/src/types.rs index 7e7b55a5..038dff1f 100644 --- a/crates/scrobbler/src/types.rs +++ b/crates/scrobbler/src/types.rs @@ -1,6 +1,9 @@ use serde::{Deserialize, Serialize}; -use crate::{musicbrainz, spotify, xata}; +use crate::{ + musicbrainz::{self, normalize_date}, + spotify, xata, +}; #[derive(Debug, Deserialize, Clone)] pub struct Scrobble { @@ -77,7 +80,10 @@ impl From for Track { .first() .map(|release| release.title.clone()) .unwrap_or_default(); - let release_date = releases.first().and_then(|release| release.date.clone()); + let release_date = releases + .first() + .and_then(|release| release.date.clone()) + .and_then(|date| normalize_date(Some(&date)).unwrap_or(None)); Track { title: recording.title.clone(), album, diff --git a/crates/webscrobbler/src/musicbrainz/mod.rs b/crates/webscrobbler/src/musicbrainz/mod.rs index eee969fe..daaf689f 100644 --- a/crates/webscrobbler/src/musicbrainz/mod.rs +++ b/crates/webscrobbler/src/musicbrainz/mod.rs @@ -1,3 +1,5 @@ +use anyhow::Error; + use crate::musicbrainz::{recording::Recordings, release::Release}; use std::cmp::Ordering; @@ -179,6 +181,26 @@ fn date_key(d: Option<&str>) -> i32 { 9_999_01_01 } +pub fn normalize_date(d: Option<&str>) -> Result, Error> { + if let Some(d) = d { + let mut parts = d.split('-'); + let y = parts.next().unwrap_or("9999"); + let m = parts.next().unwrap_or("01"); + let day = parts.next().unwrap_or("01"); + + let y: i32 = y.parse().unwrap_or(9999); + let m: i32 = m.parse().unwrap_or(1); + let day: i32 = day.parse().unwrap_or(1); + + if y == 9999 { + return Err(Error::msg("Invalid date")); + } + + return Ok(Some(format!("{:04}-{:02}-{:02}", y, m, day))); + } + Ok(None) +} + fn is_live_release(rel: &Release) -> bool { let t_live = rel.title.to_ascii_lowercase().contains("live"); let d_live = rel @@ -211,6 +233,16 @@ mod tests { assert_eq!(date_key(Some("invalid-date")), 99990101); } + #[test] + fn test_normalize_date() -> Result<(), Error> { + assert_eq!(normalize_date(Some("2020-5-3"))?, Some("2020-05-03".into())); + assert_eq!(normalize_date(Some("2020-05"))?, Some("2020-05-01".into())); + assert_eq!(normalize_date(Some("2020"))?, Some("2020-01-01".into())); + assert_eq!(normalize_date(None)?, None); + assert!(normalize_date(Some("invalid-date")).is_err()); + Ok(()) + } + #[test] fn test_is_single() { let rel1 = Release { diff --git a/crates/webscrobbler/src/types.rs b/crates/webscrobbler/src/types.rs index 654c810d..b40403c8 100644 --- a/crates/webscrobbler/src/types.rs +++ b/crates/webscrobbler/src/types.rs @@ -1,6 +1,9 @@ use serde::{Deserialize, Serialize}; -use crate::{musicbrainz, spotify, xata}; +use crate::{ + musicbrainz::{self, normalize_date}, + spotify, xata, +}; #[derive(Deserialize, Debug, Clone)] pub struct Connector { @@ -161,7 +164,10 @@ impl From for Track { .map(|credit| credit.name.clone()) .unwrap_or_default(); let releases = recording.releases.unwrap_or_default(); - let release_date = releases.first().and_then(|release| release.date.clone()); + let release_date = releases + .first() + .and_then(|release| release.date.clone()) + .and_then(|date| normalize_date(Some(&date)).unwrap_or(None)); let album_artist = releases .first() .and_then(|release| {