1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
use serde::{Deserialize, Serialize};
use std::{collections::HashSet, time::SystemTime};
use crate::learner::Learning;
#[derive(Serialize, Deserialize)]
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)]
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::MoreToSkip(_, _) => Action::Skip,
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 learnt_nothing = self
.streak_kind
.as_ref()
.map(|kind| *kind == action)
.unwrap_or(false);
let learning = match (learnt_nothing, &action) {
(false, Action::Skip) => {
Some(Learning::MoreToSkip(current_streak, last_album.clone()))
}
(false, Action::More) => {
Some(Learning::SkipToMore(current_streak, last_album.clone()))
}
_ => None,
};
if !learnt_nothing {
self.history.clear();
};
self.history.push(last_album);
self.streak_kind = Some(action);
learning
} else {
None
}
}
}
|