1use super::{
2 files::MediaFile,
3 ids::{EpisodeID, LibraryId, MovieBatchId, MovieID, SeasonID, SeriesID},
4 numbers::{EpisodeNumber, SeasonNumber},
5 titles::{MovieTitle, SeriesTitle},
6 urls::{EpisodeURL, MovieURL, SeasonURL, SeriesURL},
7};
8use std::fmt;
9
10#[cfg(feature = "rkyv")]
11use crate::media_id::ArchivedMediaID;
12#[cfg(feature = "rkyv")]
13use crate::rkyv_wrappers::DateTimeWrapper;
14use crate::{
15 EnhancedMovieDetails, EnhancedSeriesDetails, EpisodeDetails, SeasonDetails,
16 chrono::{DateTime, Utc},
17};
18#[derive(Clone, PartialEq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21#[cfg_attr(
22 feature = "rkyv",
23 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
24)]
25#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, PartialEq, Eq)))]
26pub enum Media {
27 Movie(Box<MovieReference>),
29 Series(Box<Series>),
31 Season(Box<SeasonReference>),
33 Episode(Box<EpisodeReference>),
35}
36
37#[derive(Clone, PartialEq)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40#[cfg_attr(
41 feature = "rkyv",
42 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
43)]
44#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, PartialEq, Eq)))]
45pub struct MovieReference {
46 pub id: MovieID,
47 pub library_id: LibraryId,
48 #[cfg_attr(
49 feature = "serde",
50 serde(skip_serializing_if = "Option::is_none", default)
51 )]
52 pub batch_id: Option<MovieBatchId>,
53 pub tmdb_id: u64,
54 pub title: MovieTitle,
55 pub details: EnhancedMovieDetails,
56 pub endpoint: MovieURL,
57 pub file: MediaFile,
58 #[cfg_attr(
59 feature = "serde",
60 serde(skip_serializing_if = "Option::is_none")
61 )]
62 pub theme_color: Option<String>, }
64
65#[derive(Clone, PartialEq)]
67#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
68#[cfg_attr(
69 feature = "rkyv",
70 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
71)]
72#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, PartialEq, Eq)))]
73pub struct Series {
74 pub id: SeriesID,
75 pub library_id: LibraryId,
76 pub tmdb_id: u64,
77 pub title: SeriesTitle,
78 pub details: EnhancedSeriesDetails,
79 pub endpoint: SeriesURL,
80 #[cfg_attr(feature = "serde", serde(default = "Utc::now"))]
82 #[cfg_attr(feature = "rkyv", rkyv(with = DateTimeWrapper))]
83 pub discovered_at: DateTime<Utc>,
84 #[cfg_attr(feature = "serde", serde(default = "Utc::now"))]
86 #[cfg_attr(feature = "rkyv", rkyv(with = DateTimeWrapper))]
87 pub created_at: DateTime<Utc>,
88 #[cfg_attr(
89 feature = "serde",
90 serde(skip_serializing_if = "Option::is_none")
91 )]
92 pub theme_color: Option<String>, }
94
95#[derive(Clone, PartialEq)]
97#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
98#[cfg_attr(
99 feature = "rkyv",
100 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
101)]
102#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, PartialEq, Eq)))]
103pub struct SeasonReference {
104 pub id: SeasonID,
105 pub library_id: LibraryId,
106 pub season_number: SeasonNumber,
107 pub series_id: SeriesID, pub tmdb_series_id: u64,
109 pub details: SeasonDetails,
110 pub endpoint: SeasonURL,
111 #[cfg_attr(feature = "serde", serde(default = "Utc::now"))]
113 #[cfg_attr(feature = "rkyv", rkyv(with = DateTimeWrapper))]
114 pub discovered_at: DateTime<Utc>,
115 #[cfg_attr(feature = "serde", serde(default = "Utc::now"))]
117 #[cfg_attr(feature = "rkyv", rkyv(with = DateTimeWrapper))]
118 pub created_at: DateTime<Utc>,
119 #[cfg_attr(
120 feature = "serde",
121 serde(skip_serializing_if = "Option::is_none")
122 )]
123 pub theme_color: Option<String>, }
125
126#[derive(Clone, PartialEq)]
128#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
129#[cfg_attr(
130 feature = "rkyv",
131 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
132)]
133#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, PartialEq, Eq)))]
134pub struct EpisodeReference {
135 pub id: EpisodeID,
136 pub library_id: LibraryId,
137 pub episode_number: EpisodeNumber,
138 pub season_number: SeasonNumber,
139 pub season_id: SeasonID, pub series_id: SeriesID, pub tmdb_series_id: u64,
142 pub details: EpisodeDetails,
143 pub endpoint: EpisodeURL,
144 pub file: MediaFile,
145 #[cfg_attr(feature = "serde", serde(default = "Utc::now"))]
147 #[cfg_attr(feature = "rkyv", rkyv(with = DateTimeWrapper))]
148 pub discovered_at: DateTime<Utc>,
149 #[cfg_attr(feature = "serde", serde(default = "Utc::now"))]
151 #[cfg_attr(feature = "rkyv", rkyv(with = DateTimeWrapper))]
152 pub created_at: DateTime<Utc>,
153}
154
155impl fmt::Debug for Media {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 match self {
158 Media::Movie(movie) => {
159 f.debug_tuple("Media::Movie").field(movie).finish()
160 }
161 Media::Series(series) => {
162 f.debug_tuple("Media::Series").field(series).finish()
163 }
164 Media::Season(season) => {
165 f.debug_tuple("Media::Season").field(season).finish()
166 }
167 Media::Episode(episode) => {
168 f.debug_tuple("Media::Episode").field(episode).finish()
169 }
170 }
171 }
172}
173
174impl fmt::Debug for MovieReference {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 f.debug_struct("MovieReference")
177 .field("id", &self.id)
178 .field("library_id", &self.library_id)
179 .field("batch_id", &self.batch_id)
180 .field("tmdb_id", &self.tmdb_id)
181 .field("title", &self.title)
182 .field("endpoint", &self.endpoint)
183 .field("theme_color", &self.theme_color)
184 .field("details", &self.details)
185 .field("file", &self.file)
186 .finish()
187 }
188}
189
190impl fmt::Debug for Series {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 f.debug_struct("SeriesReference")
193 .field("id", &self.id)
194 .field("library_id", &self.library_id)
195 .field("tmdb_id", &self.tmdb_id)
196 .field("title", &self.title)
197 .field("discovered_at", &self.discovered_at)
198 .field("created_at", &self.created_at)
199 .field("endpoint", &self.endpoint)
200 .field("theme_color", &self.theme_color)
201 .field("details", &self.details)
202 .finish()
203 }
204}
205
206impl fmt::Debug for SeasonReference {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 f.debug_struct("SeasonReference")
209 .field("id", &self.id)
210 .field("library_id", &self.library_id)
211 .field("season_number", &self.season_number)
212 .field("series_id", &self.series_id)
213 .field("tmdb_series_id", &self.tmdb_series_id)
214 .field("discovered_at", &self.discovered_at)
215 .field("created_at", &self.created_at)
216 .field("endpoint", &self.endpoint)
217 .field("details", &self.details)
218 .finish()
219 }
220}
221
222impl fmt::Debug for EpisodeReference {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 f.debug_struct("EpisodeReference")
225 .field("id", &self.id)
226 .field("library_id", &self.library_id)
227 .field("season_number", &self.season_number)
228 .field("episode_number", &self.episode_number)
229 .field("season_id", &self.season_id)
230 .field("series_id", &self.series_id)
231 .field("tmdb_series_id", &self.tmdb_series_id)
232 .field("discovered_at", &self.discovered_at)
233 .field("created_at", &self.created_at)
234 .field("endpoint", &self.endpoint)
235 .field("details", &self.details)
236 .field("file", &self.file)
237 .finish()
238 }
239}
240
241impl MovieReference {
242 pub fn rating(&self) -> Option<f32> {
244 self.details.vote_average
245 }
246
247 pub fn genres(&self) -> Vec<&str> {
249 self.details
250 .genres
251 .iter()
252 .map(|genre| genre.name.as_str())
253 .collect()
254 }
255}
256
257impl Series {
258 pub fn year(&self) -> Option<u16> {
260 self.details
261 .first_air_date
262 .as_ref()
263 .and_then(|date| date.split('-').next())
264 .and_then(|year| year.parse().ok())
265 }
266
267 pub fn rating(&self) -> Option<f32> {
269 self.details.vote_average
270 }
271
272 pub fn genres(&self) -> Vec<&str> {
274 self.details
275 .genres
276 .iter()
277 .map(|genre| genre.name.as_str())
278 .collect()
279 }
280}
281
282impl SeasonReference {
283 pub fn year(&self) -> Option<u16> {
285 self.details
286 .air_date
287 .as_ref()
288 .and_then(|date| date.split('-').next())
289 .and_then(|year| year.parse().ok())
290 }
291
292 pub fn rating(&self) -> Option<f32> {
294 None
296 }
297
298 pub fn genres(&self) -> Option<Vec<&str>> {
300 None
301 }
302}
303
304impl EpisodeReference {
305 pub fn year(&self) -> Option<u16> {
307 self.details
308 .air_date
309 .as_ref()
310 .and_then(|date| date.split('-').next())
311 .and_then(|year| year.parse().ok())
312 }
313
314 pub fn rating(&self) -> Option<f32> {
316 self.details.vote_average
317 }
318
319 pub fn genres(&self) -> Option<Vec<&str>> {
321 None
324 }
325}
326
327#[cfg(feature = "rkyv")]
328impl ArchivedMedia {
329 pub fn archived_media_id(&self) -> ArchivedMediaID {
330 match self {
331 Self::Movie(movie) => ArchivedMediaID::Movie(movie.id),
332 Self::Series(series) => ArchivedMediaID::Series(series.id),
333 Self::Season(season) => ArchivedMediaID::Season(season.id),
334 Self::Episode(episode) => ArchivedMediaID::Episode(episode.id),
335 }
336 }
337}