diff --git a/src/models.rs b/src/models.rs index 98f15de..57b1593 100644 --- a/src/models.rs +++ b/src/models.rs @@ -215,6 +215,8 @@ pub mod metadata { /// Scrobbles without timestamps are automatically assigned a timestamp of the current time when /// submitted via [`Scrobbler::scrobble`] or [`Scrobbler::scrobble_batch`]. Timestamps only need to be /// explicitly set when you are submitting a Scrobble at a point in the past, or in the future. + /// Scrobbles set with timestamps older than two weeks before the current moment will fail to + /// scrobble. /// /// [`Scrobble::new`]: struct.Scrobble.html#method.new /// [`Scrobbler::scrobble`]: struct.Scrobbler.html#method.scrobble diff --git a/src/scrobbler.rs b/src/scrobbler.rs index 4e4fbff..ad6a999 100644 --- a/src/scrobbler.rs +++ b/src/scrobbler.rs @@ -7,7 +7,7 @@ use crate::models::responses::{ use std::collections::HashMap; use std::result; -use std::time::UNIX_EPOCH; +use std::time::{Duration, UNIX_EPOCH}; type Result = result::Result; @@ -211,9 +211,18 @@ impl Scrobbler { let mut params = scrobble.as_map(); let current_time = UNIX_EPOCH.elapsed()?; - params + let timestamp = params .entry("timestamp".to_string()) - .or_insert_with(|| format!("{}", current_time.as_secs())); + .or_insert_with(|| format!("{}", current_time.as_secs())) + .parse::() + .map_err(|e| ScrobblerError::new(e.to_string().to_owned()))?; + + let two_weeks = Duration::from_secs(2 * 7 * 24 * 60 * 60); + let two_weeks_ago = current_time.saturating_sub(two_weeks); + + if Duration::from_secs(timestamp) < two_weeks_ago { + return Err(ScrobblerError::new("Scrobble older than 2 weeks.".to_owned())) + } Ok(self.client.send_scrobble(¶ms)?) } @@ -266,9 +275,19 @@ impl Scrobbler { for (i, scrobble) in batch.iter().enumerate() { let mut scrobble_params = scrobble.as_map(); let current_time = UNIX_EPOCH.elapsed()?; - scrobble_params + + let timestamp = scrobble_params .entry("timestamp".to_string()) - .or_insert_with(|| format!("{}", current_time.as_secs())); + .or_insert_with(|| format!("{}", current_time.as_secs())) + .parse::() + .map_err(|e| ScrobblerError::new(e.to_string().to_owned()))?; + + let two_weeks = Duration::from_secs(2 * 7 * 24 * 60 * 60); + let two_weeks_ago = current_time.saturating_sub(two_weeks); + + if Duration::from_secs(timestamp) < two_weeks_ago { + return Err(ScrobblerError::new("Scrobble older than 2 weeks.".to_owned())) + } for (key, val) in &scrobble_params { // batched parameters need array notation suffix ie. @@ -436,7 +455,7 @@ mod tests { "old bananas", "old bananas", ); - scrobble.with_timestamp(1337); + scrobble.with_timestamp(UNIX_EPOCH.elapsed().unwrap().as_secs()); let _m = mock("POST", mockito::Matcher::Any) .with_body(