use std::ops::{Deref, DerefMut};
use chrono::prelude::*;
use serde::{de::Error, Deserialize, Deserializer, Serialize};
use strum::IntoStaticStr;
use super::Html;
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct AnimePage {
pub page: u64,
pub total_amount: u64,
pub anime: Vec<Anime>,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Anime {
pub id: String,
pub title: String,
pub route: String,
#[serde(default, deserialize_with = "jpn_datetime_opt")]
pub premier: Option<DateTime<FixedOffset>>,
pub sub_premier: Option<DateTime<Utc>>,
pub dub_premier: Option<DateTime<Utc>>,
pub month: Option<Month>,
pub year: Option<u64>,
pub season: Season,
pub delayed_timetable: Option<DelayedTimetable>,
pub delayed_from: DateTime<Utc>,
pub delayed_until: DateTime<Utc>,
pub sub_delayed_timetable: Option<DateTime<Utc>>,
pub sub_delayed_from: Option<DateTime<Utc>>,
pub sub_delayed_until: Option<DateTime<Utc>>,
pub dub_delayed_timetable: Option<DelayedTimetable>,
pub dub_delayed_from: Option<DateTime<Utc>>,
pub dub_delayed_until: Option<DateTime<Utc>>,
pub delayed_desc: Option<String>,
#[serde(deserialize_with = "jpn_datetime")]
pub jpn_time: DateTime<FixedOffset>,
pub sub_time: DateTime<Utc>,
pub dub_time: DateTime<Utc>,
pub description: Html,
pub genres: Vec<Category>,
pub studios: Vec<Category>,
pub sources: Vec<Category>,
pub media_types: Vec<Category>,
pub episodes: Option<u64>,
pub length_min: Option<u64>,
pub status: AirStatus,
pub image_version_route: String,
pub stats: Stats,
pub days: Option<Days>,
pub names: Option<Names>,
pub relations: Option<Relations>,
pub websites: Websites,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Season {
pub title: String,
pub year: String,
pub season: String,
pub route: String,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(transparent)]
pub struct Categories(pub Vec<Category>);
impl Deref for Categories {
type Target = Vec<Category>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Categories {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Deserialize, Clone, Debug)]
pub struct Category {
pub name: String,
pub route: String,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Stats {
pub average_score: f64,
pub rating_count: u64,
pub tracked_count: u64,
pub tracked_rating: u64,
pub color_light_mode: String,
pub color_dark_mode: String,
}
#[derive(Deserialize, Clone, IntoStaticStr, Debug, PartialEq)]
pub enum AirStatus {
Upcoming,
Ongoing,
Delayed,
Finished,
}
#[derive(Serialize, Clone, IntoStaticStr, Debug, PartialEq)]
#[serde(rename_all(serialize = "lowercase"))]
pub enum AirStatusQuery {
Upcoming,
Ongoing,
Finished,
}
#[derive(Deserialize, Clone, Debug)]
pub struct Days {
pub sunday: bool,
pub monday: bool,
pub tuesday: bool,
pub wednesday: bool,
pub thursday: bool,
pub friday: bool,
pub saturday: bool,
}
#[derive(Deserialize, Clone, Debug)]
pub struct Names {
pub romaji: Option<String>,
pub english: Option<String>,
pub native: Option<String>,
pub abbreviation: Option<String>,
pub synonyms: Option<Vec<String>>,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Relations {
pub sequels: Option<Vec<String>>,
pub prequels: Option<Vec<String>>,
pub parents: Option<Vec<String>>,
pub alternatives: Option<Vec<String>>,
pub other: Option<Vec<String>>,
pub side_stories: Option<Vec<String>>,
pub spinoffs: Option<Vec<String>>,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Websites {
pub official: Option<String>,
pub mal: Option<String>,
pub ani_list: Option<String>,
pub kitsu: Option<String>,
pub anime_planet: Option<String>,
pub anidb: Option<String>,
pub crunchyroll: Option<String>,
pub funimation: Option<String>,
pub wakanim: Option<String>,
pub amazon: Option<String>,
pub hidive: Option<String>,
pub hulu: Option<String>,
pub youtube: Option<String>,
pub netflix: Option<String>,
}
#[derive(Deserialize, Clone, Debug)]
pub struct Streams {
pub crunchyroll: Option<String>,
pub funimation: Option<String>,
pub wakanim: Option<String>,
pub amazon: Option<String>,
pub hidive: Option<String>,
pub hulu: Option<String>,
pub youtube: Option<String>,
pub netflix: Option<String>,
}
#[derive(Serialize, Clone, IntoStaticStr, Debug, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum StreamsQuery {
Crunchyroll,
Funimation,
Wakanim,
Amazon,
Hidive,
Hulu,
Youtube,
Netflix,
}
#[derive(Deserialize, Clone, IntoStaticStr, Debug, PartialEq)]
pub enum Month {
January,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December,
}
#[derive(Deserialize, Clone, IntoStaticStr, Debug, PartialEq)]
pub enum DelayedTimetable {
Delayed,
#[serde(rename = "On Break")]
OnBreak,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(transparent)]
pub struct Timetables(pub Vec<TimetableAnime>);
impl Deref for Timetables {
type Target = Vec<TimetableAnime>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Timetables {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TimetableAnime {
pub title: String,
pub route: String,
pub romaji: Option<String>,
pub english: Option<String>,
pub native: Option<String>,
pub delayed_text: Option<String>,
pub delayed_from: Option<String>,
pub delayed_until: Option<DateTime<Utc>>,
pub status: AirStatus,
pub episode_date: DateTime<Utc>,
pub episode_number: u64,
pub subtracted_episode_number: Option<u64>,
pub episodes: Option<u64>,
pub length_min: u64,
pub donghua: bool,
pub air_type: AirType,
pub media_types: Vec<Category>,
pub image_version_route: String,
pub streams: Streams,
pub airing_status: AiringStatus,
}
#[derive(Deserialize, Clone, IntoStaticStr, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum AirType {
Raw,
Sub,
Dub,
}
#[derive(Serialize, Copy, Clone, IntoStaticStr, Debug, PartialEq)]
#[strum(serialize_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum AirTypeQuery {
Raw,
Sub,
Dub,
All,
}
#[derive(Deserialize, Clone, IntoStaticStr, Debug, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum AiringStatus {
Airing,
Aired,
Unaired,
DelayedAir,
}
#[derive(Serialize, Clone, IntoStaticStr, Debug, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub enum MatchType {
Any,
#[default]
All,
}
#[derive(Serialize, Clone, IntoStaticStr, Debug, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub enum SortingType {
#[default]
Popularity,
Score,
Alphabetic,
ReleaseDate,
}
#[derive(Serialize, Clone, IntoStaticStr, Debug, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum SeasonQuery {
Spring,
Summer,
Fall,
Winter,
}
fn jpn_datetime_opt<'de, D>(deserializer: D) -> Result<Option<DateTime<FixedOffset>>, D::Error>
where
D: Deserializer<'de>,
{
Ok(Some(jpn_datetime(deserializer)?))
}
fn jpn_datetime<'de, D>(deserializer: D) -> Result<DateTime<FixedOffset>, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
let japan_tz = FixedOffset::east_opt(9 * 3600).unwrap();
let datetime = s
.parse::<DateTime<Utc>>()
.map_err(|e| Error::custom(e.to_string()))?;
let datetime = datetime.with_timezone(&japan_tz);
Ok(datetime)
}