diff options
Diffstat (limited to 'src/trajectory.rs')
| -rw-r--r-- | src/trajectory.rs | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/trajectory.rs b/src/trajectory.rs new file mode 100644 index 0000000..214e16c --- /dev/null +++ b/src/trajectory.rs @@ -0,0 +1,98 @@ +use serde::{Deserialize, Serialize}; +use std::{collections::HashSet, time::SystemTime}; + +use crate::learner::Learning; + +#[derive(Serialize, Deserialize, Debug)] +struct LastData { + timestamp: SystemTime, + album: String, +} + +#[derive(Serialize, Deserialize, Default)] +pub struct Trajectory { + last_data: Option<LastData>, + streak_kind: Option<Action>, + history: Vec<String>, +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +pub enum Action { + Skip, + More, +} + +impl From<Option<&Learning>> for Action { + fn from(learning: Option<&Learning>) -> Action { + if let Some(ts) = learning { + match ts { + Learning::SkipExtend | Learning::MoreToSkip(_, _) => Action::Skip, + Learning::MoreExtend(_, _) | Learning::SkipToMore(_, _) => Action::More, + } + } else { + Action::Skip + } + } +} + +impl Trajectory { + pub fn prune(&mut self, valid: &HashSet<String>) { + self.history.retain_mut(|x| valid.contains(x)); + + if let Some(ref last_data) = self.last_data + && !valid.contains(&last_data.album) + { + self.last_data = None + } + } + + pub fn slice(&self) -> &[String] { + &self.history + } + + pub fn log(&mut self, new_album: &str) { + self.last_data = Some(LastData { + timestamp: SystemTime::now(), + album: new_album.to_string(), + }) + } + + pub fn step(&mut self, skip_window_secs: u64) -> Option<Learning> { + if let Some(ref last_data) = self.last_data { + let action = if SystemTime::now() + .duration_since(last_data.timestamp) + .ok() + .is_some_and(|d| d.as_secs() < skip_window_secs) + { + Action::Skip + } else { + Action::More + }; + + let last_album = last_data.album.clone(); + let current_streak = self.history.clone(); + + let learning = if let Some(ref kind) = self.streak_kind + && kind == &action + { + self.history.push(last_album.clone()); + match action { + Action::Skip => Learning::SkipExtend, + Action::More => Learning::MoreExtend(current_streak, last_album), + } + } else { + self.history.clear(); + self.history.push(last_album.clone()); + match action { + Action::Skip => Learning::MoreToSkip(current_streak, last_album), + Action::More => Learning::SkipToMore(current_streak, last_album), + } + }; + + self.streak_kind = Some(action); + Some(learning) + } else { + None + } + } +} |
