Skip to main content

ferrex_model/
watch.rs

1use uuid::Uuid;
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6/// Episode identity independent of files
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9pub struct EpisodeKey {
10    pub tmdb_series_id: u64,
11    pub season_number: u16,
12    pub episode_number: u16,
13}
14
15/// Season identity independent of files
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18pub struct SeasonKey {
19    pub tmdb_series_id: u64,
20    pub season_number: u16,
21}
22
23/// Reason chosen for the next episode pick
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
27pub enum NextReason {
28    ResumeInProgress,
29    FirstUnwatched,
30}
31
32/// Description of the next episode to play
33#[derive(Debug, Clone, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35pub struct NextEpisode {
36    pub key: EpisodeKey,
37    /// If available, a specific playable episode reference (media UUID)
38    pub playable_media_id: Option<Uuid>,
39    pub reason: NextReason,
40}
41
42/// Per-episode watch status
43#[derive(Debug, Clone, Copy, PartialEq)]
44#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
45#[cfg_attr(feature = "serde", serde(tag = "state", rename_all = "snake_case"))]
46pub enum EpisodeStatus {
47    Unwatched,
48    InProgress { progress: f32 },
49    Completed,
50}
51
52impl EpisodeStatus {
53    pub fn is_completed(&self) -> bool {
54        matches!(self, EpisodeStatus::Completed)
55    }
56}
57
58/// Aggregated season watch status
59#[derive(Debug, Clone)]
60#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
61pub struct SeasonWatchStatus {
62    pub key: SeasonKey,
63    pub total: u32,
64    pub watched: u32,
65    pub in_progress: u32,
66    pub is_completed: bool,
67    /// Map of episode number -> status
68    pub episodes: std::collections::HashMap<u16, EpisodeStatus>,
69}
70
71/// Aggregated series watch status with next-episode hint
72#[derive(Debug, Clone)]
73#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
74pub struct SeriesWatchStatus {
75    pub tmdb_series_id: u64,
76    pub total_episodes: u32,
77    pub watched: u32,
78    pub in_progress: u32,
79    pub seasons: std::collections::HashMap<u16, SeasonWatchStatus>,
80    pub next_episode: Option<NextEpisode>,
81}