use std::cmp;
use std::fmt;
use std::str::FromStr;
use csv;
use serde::{Deserialize, Deserializer, Serialize};
use crate::error::Error;
#[derive(Clone, Debug, Deserialize)]
pub struct Title {
#[serde(rename = "tconst")]
pub id: String,
#[serde(rename = "titleType")]
pub kind: TitleKind,
#[serde(rename = "primaryTitle")]
pub title: String,
#[serde(rename = "originalTitle")]
pub original_title: String,
#[serde(rename = "isAdult", deserialize_with = "number_as_bool")]
pub is_adult: bool,
#[serde(rename = "startYear", deserialize_with = "csv::invalid_option")]
pub start_year: Option<u32>,
#[serde(rename = "endYear", deserialize_with = "csv::invalid_option")]
pub end_year: Option<u32>,
#[serde(
rename = "runtimeMinutes",
deserialize_with = "csv::invalid_option"
)]
pub runtime_minutes: Option<u32>,
#[serde(rename = "genres")]
pub genres: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[allow(missing_docs)]
pub enum TitleKind {
#[serde(rename = "movie")]
Movie,
#[serde(rename = "short")]
Short,
#[serde(rename = "tvEpisode")]
TVEpisode,
#[serde(rename = "tvMiniSeries")]
TVMiniSeries,
#[serde(rename = "tvMovie")]
TVMovie,
#[serde(rename = "tvSeries")]
TVSeries,
#[serde(rename = "tvShort")]
TVShort,
#[serde(rename = "tvSpecial")]
TVSpecial,
#[serde(rename = "video")]
Video,
#[serde(rename = "videoGame")]
VideoGame,
}
impl TitleKind {
pub fn as_str(&self) -> &'static str {
use self::TitleKind::*;
match *self {
Movie => "movie",
Short => "short",
TVEpisode => "tvEpisode",
TVMiniSeries => "tvMiniSeries",
TVMovie => "tvMovie",
TVSeries => "tvSeries",
TVShort => "tvShort",
TVSpecial => "tvSpecial",
Video => "video",
VideoGame => "videoGame",
}
}
pub fn is_tv_series(&self) -> bool {
use self::TitleKind::*;
match *self {
TVMiniSeries | TVSeries => true,
_ => false,
}
}
}
impl fmt::Display for TitleKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Ord for TitleKind {
fn cmp(&self, other: &TitleKind) -> cmp::Ordering {
self.as_str().cmp(other.as_str())
}
}
impl PartialOrd for TitleKind {
fn partial_cmp(&self, other: &TitleKind) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl FromStr for TitleKind {
type Err = Error;
fn from_str(ty: &str) -> Result<TitleKind, Error> {
use self::TitleKind::*;
match &*ty.to_lowercase() {
"movie" => Ok(Movie),
"short" => Ok(Short),
"tvepisode" | "episode" => Ok(TVEpisode),
"tvminiseries" | "miniseries" => Ok(TVMiniSeries),
"tvmovie" => Ok(TVMovie),
"tvseries" | "tvshow" | "show" => Ok(TVSeries),
"tvshort" => Ok(TVShort),
"tvspecial" | "special" => Ok(TVSpecial),
"video" => Ok(Video),
"videogame" | "game" => Ok(VideoGame),
unk => Err(Error::unknown_title(unk)),
}
}
}
#[derive(Clone, Debug, Deserialize)]
pub struct AKA {
#[serde(rename = "titleId")]
pub id: String,
#[serde(rename = "ordering")]
pub order: i32,
#[serde(rename = "title")]
pub title: String,
#[serde(rename = "region")]
pub region: String,
#[serde(rename = "language")]
pub language: String,
#[serde(rename = "types")]
pub types: String,
#[serde(rename = "attributes")]
pub attributes: String,
#[serde(
rename = "isOriginalTitle",
deserialize_with = "optional_number_as_bool"
)]
pub is_original_title: Option<bool>,
}
#[derive(Clone, Debug, Deserialize)]
pub struct Episode {
#[serde(rename = "tconst")]
pub id: String,
#[serde(rename = "parentTconst")]
pub tvshow_id: String,
#[serde(
rename = "seasonNumber",
deserialize_with = "csv::invalid_option"
)]
pub season: Option<u32>,
#[serde(
rename = "episodeNumber",
deserialize_with = "csv::invalid_option"
)]
pub episode: Option<u32>,
}
#[derive(Clone, Debug, Deserialize)]
pub struct Rating {
#[serde(rename = "tconst")]
pub id: String,
#[serde(rename = "averageRating")]
pub rating: f32,
#[serde(rename = "numVotes")]
pub votes: u32,
}
fn number_as_bool<'de, D>(de: D) -> Result<bool, D::Error>
where
D: Deserializer<'de>,
{
i32::deserialize(de).map(|n| n != 0)
}
fn optional_number_as_bool<'de, D>(de: D) -> Result<Option<bool>, D::Error>
where
D: Deserializer<'de>,
{
Ok(i32::deserialize(de).map(|n| Some(n != 0)).unwrap_or(None))
}