1use std::cmp;
2use std::fmt;
3use std::str::FromStr;
4
5use csv;
6use serde::{Deserialize, Deserializer, Serialize};
7
8use crate::error::Error;
9
10#[derive(Clone, Debug, Deserialize)]
16pub struct Title {
17 #[serde(rename = "tconst")]
22 pub id: String,
23 #[serde(rename = "titleType")]
25 pub kind: TitleKind,
26 #[serde(rename = "primaryTitle")]
28 pub title: String,
29 #[serde(rename = "originalTitle")]
31 pub original_title: String,
32 #[serde(rename = "isAdult", deserialize_with = "number_as_bool")]
34 pub is_adult: bool,
35 #[serde(rename = "startYear", deserialize_with = "csv::invalid_option")]
45 pub start_year: Option<u32>,
46 #[serde(rename = "endYear", deserialize_with = "csv::invalid_option")]
51 pub end_year: Option<u32>,
52 #[serde(
54 rename = "runtimeMinutes",
55 deserialize_with = "csv::invalid_option"
56 )]
57 pub runtime_minutes: Option<u32>,
58 #[serde(rename = "genres")]
60 pub genres: String,
61}
62
63#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
72#[allow(missing_docs)]
73pub enum TitleKind {
74 #[serde(rename = "movie")]
75 Movie,
76 #[serde(rename = "short")]
77 Short,
78 #[serde(rename = "tvEpisode")]
79 TVEpisode,
80 #[serde(rename = "tvMiniSeries")]
81 TVMiniSeries,
82 #[serde(rename = "tvMovie")]
83 TVMovie,
84 #[serde(rename = "tvSeries")]
85 TVSeries,
86 #[serde(rename = "tvShort")]
87 TVShort,
88 #[serde(rename = "tvSpecial")]
89 TVSpecial,
90 #[serde(rename = "video")]
91 Video,
92 #[serde(rename = "videoGame")]
93 VideoGame,
94}
95
96impl TitleKind {
97 pub fn as_str(&self) -> &'static str {
102 use self::TitleKind::*;
103 match *self {
104 Movie => "movie",
105 Short => "short",
106 TVEpisode => "tvEpisode",
107 TVMiniSeries => "tvMiniSeries",
108 TVMovie => "tvMovie",
109 TVSeries => "tvSeries",
110 TVShort => "tvShort",
111 TVSpecial => "tvSpecial",
112 Video => "video",
113 VideoGame => "videoGame",
114 }
115 }
116
117 pub fn is_tv_series(&self) -> bool {
119 use self::TitleKind::*;
120
121 match *self {
122 TVMiniSeries | TVSeries => true,
123 _ => false,
124 }
125 }
126}
127
128impl fmt::Display for TitleKind {
129 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
130 write!(f, "{}", self.as_str())
131 }
132}
133
134impl Ord for TitleKind {
135 fn cmp(&self, other: &TitleKind) -> cmp::Ordering {
136 self.as_str().cmp(other.as_str())
137 }
138}
139
140impl PartialOrd for TitleKind {
141 fn partial_cmp(&self, other: &TitleKind) -> Option<cmp::Ordering> {
142 Some(self.cmp(other))
143 }
144}
145
146impl FromStr for TitleKind {
147 type Err = Error;
148
149 fn from_str(ty: &str) -> Result<TitleKind, Error> {
150 use self::TitleKind::*;
151
152 match &*ty.to_lowercase() {
153 "movie" => Ok(Movie),
154 "short" => Ok(Short),
155 "tvepisode" | "episode" => Ok(TVEpisode),
156 "tvminiseries" | "miniseries" => Ok(TVMiniSeries),
157 "tvmovie" => Ok(TVMovie),
158 "tvseries" | "tvshow" | "show" => Ok(TVSeries),
159 "tvshort" => Ok(TVShort),
160 "tvspecial" | "special" => Ok(TVSpecial),
161 "video" => Ok(Video),
162 "videogame" | "game" => Ok(VideoGame),
163 unk => Err(Error::unknown_title(unk)),
164 }
165 }
166}
167
168#[derive(Clone, Debug, Deserialize)]
174pub struct AKA {
175 #[serde(rename = "titleId")]
177 pub id: String,
178 #[serde(rename = "ordering")]
180 pub order: i32,
181 #[serde(rename = "title")]
183 pub title: String,
184 #[serde(rename = "region")]
186 pub region: String,
187 #[serde(rename = "language")]
189 pub language: String,
190 #[serde(rename = "types")]
192 pub types: String,
193 #[serde(rename = "attributes")]
195 pub attributes: String,
196 #[serde(
199 rename = "isOriginalTitle",
200 deserialize_with = "optional_number_as_bool"
201 )]
202 pub is_original_title: Option<bool>,
203}
204
205#[derive(Clone, Debug, Deserialize)]
212pub struct Episode {
213 #[serde(rename = "tconst")]
215 pub id: String,
216 #[serde(rename = "parentTconst")]
218 pub tvshow_id: String,
219 #[serde(
221 rename = "seasonNumber",
222 deserialize_with = "csv::invalid_option"
223 )]
224 pub season: Option<u32>,
225 #[serde(
228 rename = "episodeNumber",
229 deserialize_with = "csv::invalid_option"
230 )]
231 pub episode: Option<u32>,
232}
233
234#[derive(Clone, Debug, Deserialize)]
236pub struct Rating {
237 #[serde(rename = "tconst")]
239 pub id: String,
240 #[serde(rename = "averageRating")]
242 pub rating: f32,
243 #[serde(rename = "numVotes")]
245 pub votes: u32,
246}
247
248fn number_as_bool<'de, D>(de: D) -> Result<bool, D::Error>
249where
250 D: Deserializer<'de>,
251{
252 i32::deserialize(de).map(|n| n != 0)
253}
254
255fn optional_number_as_bool<'de, D>(de: D) -> Result<Option<bool>, D::Error>
256where
257 D: Deserializer<'de>,
258{
259 Ok(i32::deserialize(de).map(|n| Some(n != 0)).unwrap_or(None))
260}