mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-03 16:41:26 +01:00
feat(core,app): a history page
Every played episode, newest first, under Today, Yesterday, a weekday or a date. A row shows the still (which plays it), the title (which opens it), the episode, and where it stopped or that it was finished. Removing a row resets that file to never played, with an Undo. History sits second in the top bar, so Ctrl+1 to Ctrl+5 now run Library, History, Shares, Downloads, Settings.
This commit is contained in:
1 parent
39866bee8d
commit
e7eeaa518f
9 files changed
+372
-28
No files matched your search
@@ -369,6 +369,26 @@ impl Library {
|
||||
titles
|
||||
}
|
||||
|
||||
/// Every episode that has been started or finished, most recently
|
||||
/// touched first. The history page.
|
||||
///
|
||||
/// An episode marked unwatched keeps a row with position zero, which is
|
||||
/// "never played" for every purpose here, so it is left out.
|
||||
pub fn history(&self) -> Vec<(&Title, &Episode)> {
|
||||
let mut played: Vec<(&Title, &Episode)> = self
|
||||
.titles
|
||||
.iter()
|
||||
.flat_map(|title| title.episodes().map(move |episode| (title, episode)))
|
||||
.filter(|(_, episode)| {
|
||||
episode
|
||||
.watch
|
||||
.is_some_and(|watch| watch.watched || watch.position_secs > 0.0)
|
||||
})
|
||||
.collect();
|
||||
played.sort_by_key(|(_, episode)| std::cmp::Reverse(episode.last_played()));
|
||||
played
|
||||
}
|
||||
|
||||
/// Substring match over the display name and every filename under it, so
|
||||
/// searching for a release group or an episode name finds its title.
|
||||
pub fn search(&self, query: &str) -> Vec<&Title> {
|
||||
@@ -517,6 +537,41 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn history_is_every_played_episode_newest_first_across_titles() {
|
||||
let watch_state = HashMap::from([
|
||||
(
|
||||
("s".to_string(), "a".to_string()),
|
||||
watch(600.0, 1400.0, false, 10),
|
||||
),
|
||||
(
|
||||
("s".to_string(), "c".to_string()),
|
||||
watch(1400.0, 1400.0, true, 30),
|
||||
),
|
||||
// Marked unwatched again: a row at zero, which is not a play.
|
||||
(
|
||||
("s".to_string(), "b".to_string()),
|
||||
watch(0.0, 1400.0, false, 40),
|
||||
),
|
||||
]);
|
||||
let library = Library::build(
|
||||
vec![
|
||||
node("s", "a", "Show - S01E01", Some(1), Some(1)),
|
||||
node("s", "b", "Show - S01E02", Some(1), Some(2)),
|
||||
node("s", "c", "Film", None, None),
|
||||
node("s", "d", "Other - S01E01", Some(1), Some(1)),
|
||||
],
|
||||
&watch_state,
|
||||
);
|
||||
|
||||
let order: Vec<&str> = library
|
||||
.history()
|
||||
.iter()
|
||||
.map(|(_, episode)| episode.node.link_id.as_str())
|
||||
.collect();
|
||||
assert_eq!(order, ["c", "a"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn groups_episodes_into_seasons() {
|
||||
let nodes = vec![
|
||||
|
||||
Reference in new issue
Block a user