aboutsummaryrefslogtreecommitdiff
path: root/src/trajectory.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/trajectory.rs')
-rw-r--r--src/trajectory.rs98
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
+ }
+ }
+}