1use std::cmp::Ordering;
2use std::convert::TryFrom;
3
4use arrayvec::ArrayVec;
5use compact_str::CompactString;
6
7use crate::genre::Genre;
8use crate::EpisodeLink;
9use crate::Error;
10use crate::Title;
11use crate::TitleType;
12
13#[derive(Eq, PartialEq)]
14pub struct Show {
16 pub imdb_id: u32,
17 pub title: CompactString,
18 pub is_adult: bool,
19 pub start_year: u16,
20 pub end_year: Option<u16>,
21 pub runtime_minutes: Option<u16>,
22 pub genres: ArrayVec<Genre, 3>,
23 pub episodes: Vec<Episode>
24}
25
26impl std::fmt::Debug for Show {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 f.debug_struct("Show")
29 .field("imdb_id", &self.imdb_id)
30 .field("title", &self.title)
31 .field("is_adult", &self.is_adult)
32 .field("start_year", &self.start_year)
33 .field("end_year", &self.end_year)
34 .field("runtime_minutes", &self.runtime_minutes)
35 .field("genres", &self.genres)
36 .field("episodes", &self.episodes.len())
37 .finish()
38 }
39} impl Show {
42 pub(crate) fn from_wrapped_title(input: Result<Title, Error>) -> Result<Self, Error> {
43 Self::try_from(input?)
44 } }
46
47impl TryFrom<Title> for Show {
48 type Error = Error;
49 #[inline]
50 fn try_from(input: Title) -> Result<Self, Error> {
51 match input.title_type {
52 TitleType::TVSeries => Ok(Self{
53 imdb_id: input.imdb_id,
54 title: input.primary_title,
55 is_adult: input.is_adult,
56 start_year: match input.start_year {
57 Some(v) => v,
58 None => return Err(Error::YearMissing)
59 },
60 end_year: input.end_year,
61 runtime_minutes: input.runtime_minutes,
62 genres: input.genres,
63 episodes: Vec::new()
64 }),
65 _ => Err(Error::WrongMediaType(input.title_type.into(), "Show"))
66 }
67 }
68} #[derive(Clone, Debug, Eq, PartialEq)]
71pub struct Episode {
73 pub season: u16,
74 pub episode: u16,
75 pub imdb_id: u32,
76 pub title: CompactString,
77 pub year: Option<u16>,
78 pub runtime_minutes: Option<u16>
79}
80
81impl PartialOrd for Episode {
82 #[inline]
83 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
84 Some(self.cmp(other))
85 }
86} impl Ord for Episode {
89 #[inline]
90 fn cmp(&self, other: &Self) -> Ordering {
91 match self.season.cmp(&other.season) {
92 Ordering::Equal => self.episode.cmp(&other.episode),
93 v => v
94 }
95 }
96} impl Episode {
99 #[cfg(test)]
100 pub(crate) fn new(season: u16, episode: u16, imdb_id: u32, title: &str, year: Option<u16>, runtime_minutes: Option<u16>) -> Self {
101 Self{
102 season,
103 episode,
104 imdb_id,
105 title: CompactString::new(title),
106 year,
107 runtime_minutes
108 }
109 } #[inline]
112 pub(crate) fn from_title_and_link(title: Title, link: EpisodeLink) -> Result<Self, Error> {
113 match title.title_type {
114 TitleType::Episode => Ok(Self{
115 season: match link.season {
116 Some(v) => v,
117 None => return Err(Error::SeasonMissing)
118 },
119 episode: match link.episode {
120 Some(v) => v,
121 None => return Err(Error::EpisodeMissing)
122 },
123 imdb_id: title.imdb_id,
124 title: title.primary_title,
125 year: title.start_year,
126 runtime_minutes: title.runtime_minutes
127 }),
128 _ => Err(Error::WrongMediaType(title.title_type.into(), "Episode"))
129 }
130 } }
132
133#[inline]
134pub(crate) fn title_matches_show_name_and_year(title: &Result<Title, Error>, name: &str, year: u16) -> bool {
135 if let Ok(title) = title {
136 if(title.title_type != TitleType::TVSeries) {
137 return false;
138 }
139 if let Some(title_year) = title.start_year {
140 if(title_year != year) {
141 return false;
142 }
143 } else {
144 return false;
145 }
146 if(title.primary_title != name && title.original_title != name) {
147 return false;
148 }
149 return true;
150 }
151 false
152}