mal-cli-rs 0.2.1

CLI tool for myanimelist
Documentation
use crate::config::app_config::{AppConfig, MangaDisplayType, TitleLanguage};

use super::*;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};

#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr, Display)]
#[strum(serialize_all = "snake_case")]
pub enum MangaRankingType {
    All,
    Manga,
    Novels,
    #[strum(serialize = "oneshots")]
    OneShots,
    Doujinshi,
    Manhwa,
    Manhua,
    #[strum(serialize = "bypopularity")]
    ByPopularity,
    Favorite,
    Other(String),
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RankingMangaPair {
    pub node: Manga,
    pub ranking: RankingInfo,
}

#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum MangaMediaType {
    Unknown,
    Manga,
    Novel,
    OneShot,
    Doujinshi,
    Manhwa,
    Manhua,
    #[strum(serialize = "oel")]
    OEL,
    Other(String),
}

#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum MangaStatus {
    Finished,
    CurrentlyPublishing,
    NotYetPublished,
    Other(String),
}

#[derive(Clone, Debug, PartialEq, EnumString, Display, EnumIter, IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum UserReadStatus {
    Reading,
    Completed,
    OnHold,
    Dropped,
    PlanToRead,
    #[strum(serialize = "add")]
    Other(String),
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct UserMangaListStatus {
    pub status: UserReadStatus,
    pub score: u8,
    pub num_volumes_read: u64,
    pub num_chapters_read: u64,
    pub is_rereading: bool,
    pub start_date: Option<DateWrapper>,
    pub finish_date: Option<DateWrapper>,
    pub priority: Option<u8>,
    pub num_times_reread: Option<u8>,
    pub reread_value: Option<u8>,
    pub tags: Option<Vec<String>>,
    pub comments: Option<String>,
    pub updated_at: DateTimeWrapper,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Manga {
    pub id: u64,
    pub title: String,
    pub main_picture: Option<Picture>,
    pub alternative_titles: Option<AlternativeTitles>,
    pub start_date: Option<DateWrapper>,
    pub end_date: Option<DateWrapper>,
    pub synopsis: Option<String>,
    pub background: Option<String>,
    pub mean: Option<f64>,
    pub rank: Option<u64>,
    pub popularity: Option<u64>,
    pub num_list_users: Option<u64>,
    pub num_scoring_users: Option<u64>,
    pub nsfw: Option<NSFW>,
    pub genres: Option<Vec<Genre>>,
    pub created_at: Option<DateTimeWrapper>,
    pub updated_at: Option<DateTimeWrapper>,
    pub media_type: Option<MangaMediaType>,
    pub status: Option<MangaStatus>,
    pub my_list_status: Option<UserMangaListStatus>,
    pub num_volumes: Option<u64>,
    pub num_chapters: Option<u64>,
    pub authors: Option<Vec<PersonRole>>,
    pub related_anime: Option<Vec<RelatedAnime>>,
    pub related_manga: Option<Vec<RelatedManga>>,
    pub recommendations: Option<Vec<MangaRecommendation>>,
    pub serialization: Option<Vec<Serialization>>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Serialization {
    pub node: Magasine,
    pub role: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Magasine {
    pub id: u64,
    pub name: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RelatedManga {
    pub node: Manga,
    pub relation_type: String,
    pub relation_type_formatted: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MangaRecommendation {
    pub node: Manga,
    pub num_recommendations: u64,
}

impl Manga {
    pub fn get_title(&self, app_config: &AppConfig, both: bool) -> Vec<String> {
        if both {
            vec![
                self.title.clone(),
                self.alternative_titles
                    .as_ref()
                    .map_or("None".to_string(), |alt| {
                        alt.clone().en.map_or("None".to_string(), |e| e)
                    }),
            ]
        } else {
            match app_config.title_language {
                TitleLanguage::Japanese => vec![self.title.clone()],
                TitleLanguage::English => {
                    if let Some(ref alternative_titles) = self.alternative_titles {
                        if let Some(en) = &alternative_titles.en {
                            if !en.is_empty() {
                                vec![en.clone()]
                            } else {
                                vec![self.title.clone()]
                            }
                        } else {
                            vec![self.title.clone()]
                        }
                    } else {
                        vec![self.title.clone()]
                    }
                }
            }
        }
    }
    pub fn get_num(&self, app_config: &AppConfig) -> String {
        match app_config.manga_display_type {
            MangaDisplayType::Vol => self.num_volumes.map_or("N/A vol".to_string(), |n| {
                if n == 0 {
                    "N/A".to_string()
                } else {
                    format!("{} vol", n)
                }
            }),
            MangaDisplayType::Ch => self.num_chapters.map_or("N/A ch".to_string(), |n| {
                if n == 0 {
                    "N/A".to_string()
                } else {
                    format!("{} ch", n)
                }
            }),
            MangaDisplayType::Both => format!(
                "{}, {}",
                self.num_volumes
                    .map_or("N/A vol".to_string(), |n| if n == 0 {
                        "N/A".to_string()
                    } else {
                        format!("{} vol", n)
                    }),
                self.num_chapters
                    .map_or("N/A ch".to_string(), |n| if n == 0 {
                        "N/A".to_string()
                    } else {
                        format!("{} ch", n)
                    })
            ),
        }
    }
}