mal/api/model/
manga.rs

1use crate::config::app_config::{AppConfig, MangaDisplayType, TitleLanguage};
2
3use super::*;
4use serde::{Deserialize, Serialize};
5use std::fmt::Debug;
6use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
7
8#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr, Display)]
9#[strum(serialize_all = "snake_case")]
10pub enum MangaRankingType {
11    All,
12    Manga,
13    Novels,
14    #[strum(serialize = "oneshots")]
15    OneShots,
16    Doujinshi,
17    Manhwa,
18    Manhua,
19    #[strum(serialize = "bypopularity")]
20    ByPopularity,
21    Favorite,
22    Other(String),
23}
24
25#[derive(Clone, Debug, Serialize, Deserialize)]
26pub struct RankingMangaPair {
27    pub node: Manga,
28    pub ranking: RankingInfo,
29}
30
31#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr)]
32#[strum(serialize_all = "snake_case")]
33pub enum MangaMediaType {
34    Unknown,
35    Manga,
36    Novel,
37    OneShot,
38    Doujinshi,
39    Manhwa,
40    Manhua,
41    #[strum(serialize = "oel")]
42    OEL,
43    Other(String),
44}
45
46#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr)]
47#[strum(serialize_all = "snake_case")]
48pub enum MangaStatus {
49    Finished,
50    CurrentlyPublishing,
51    NotYetPublished,
52    Other(String),
53}
54
55#[derive(Clone, Debug, PartialEq, EnumString, Display, EnumIter, IntoStaticStr)]
56#[strum(serialize_all = "snake_case")]
57pub enum UserReadStatus {
58    Reading,
59    Completed,
60    OnHold,
61    Dropped,
62    PlanToRead,
63    #[strum(serialize = "add")]
64    Other(String),
65}
66
67#[derive(Clone, Debug, Deserialize, Serialize)]
68pub struct UserMangaListStatus {
69    pub status: UserReadStatus,
70    pub score: u8,
71    pub num_volumes_read: u64,
72    pub num_chapters_read: u64,
73    pub is_rereading: bool,
74    pub start_date: Option<DateWrapper>,
75    pub finish_date: Option<DateWrapper>,
76    pub priority: Option<u8>,
77    pub num_times_reread: Option<u8>,
78    pub reread_value: Option<u8>,
79    pub tags: Option<Vec<String>>,
80    pub comments: Option<String>,
81    pub updated_at: DateTimeWrapper,
82}
83
84#[derive(Clone, Debug, Deserialize, Serialize)]
85pub struct Manga {
86    pub id: u64,
87    pub title: String,
88    pub main_picture: Option<Picture>,
89    pub alternative_titles: Option<AlternativeTitles>,
90    pub start_date: Option<DateWrapper>,
91    pub end_date: Option<DateWrapper>,
92    pub synopsis: Option<String>,
93    pub background: Option<String>,
94    pub mean: Option<f64>,
95    pub rank: Option<u64>,
96    pub popularity: Option<u64>,
97    pub num_list_users: Option<u64>,
98    pub num_scoring_users: Option<u64>,
99    pub nsfw: Option<NSFW>,
100    pub genres: Option<Vec<Genre>>,
101    pub created_at: Option<DateTimeWrapper>,
102    pub updated_at: Option<DateTimeWrapper>,
103    pub media_type: Option<MangaMediaType>,
104    pub status: Option<MangaStatus>,
105    pub my_list_status: Option<UserMangaListStatus>,
106    pub num_volumes: Option<u64>,
107    pub num_chapters: Option<u64>,
108    pub authors: Option<Vec<PersonRole>>,
109    pub related_anime: Option<Vec<RelatedAnime>>,
110    pub related_manga: Option<Vec<RelatedManga>>,
111    pub recommendations: Option<Vec<MangaRecommendation>>,
112    pub serialization: Option<Vec<Serialization>>,
113}
114
115#[derive(Clone, Debug, Serialize, Deserialize)]
116pub struct Serialization {
117    pub node: Magasine,
118    pub role: String,
119}
120
121#[derive(Clone, Debug, Serialize, Deserialize)]
122pub struct Magasine {
123    pub id: u64,
124    pub name: String,
125}
126
127#[derive(Clone, Debug, Serialize, Deserialize)]
128pub struct RelatedManga {
129    pub node: Manga,
130    pub relation_type: String,
131    pub relation_type_formatted: String,
132}
133
134#[derive(Clone, Debug, Serialize, Deserialize)]
135pub struct MangaRecommendation {
136    pub node: Manga,
137    pub num_recommendations: u64,
138}
139
140impl Manga {
141    pub fn get_title(&self, app_config: &AppConfig, both: bool) -> Vec<String> {
142        if both {
143            vec![
144                self.title.clone(),
145                self.alternative_titles
146                    .as_ref()
147                    .map_or("None".to_string(), |alt| {
148                        alt.clone().en.map_or("None".to_string(), |e| e)
149                    }),
150            ]
151        } else {
152            match app_config.title_language {
153                TitleLanguage::Japanese => vec![self.title.clone()],
154                TitleLanguage::English => {
155                    if let Some(ref alternative_titles) = self.alternative_titles {
156                        if let Some(en) = &alternative_titles.en {
157                            if !en.is_empty() {
158                                vec![en.clone()]
159                            } else {
160                                vec![self.title.clone()]
161                            }
162                        } else {
163                            vec![self.title.clone()]
164                        }
165                    } else {
166                        vec![self.title.clone()]
167                    }
168                }
169            }
170        }
171    }
172    pub fn get_num(&self, app_config: &AppConfig) -> String {
173        match app_config.manga_display_type {
174            MangaDisplayType::Vol => self.num_volumes.map_or("N/A vol".to_string(), |n| {
175                if n == 0 {
176                    "N/A".to_string()
177                } else {
178                    format!("{} vol", n)
179                }
180            }),
181            MangaDisplayType::Ch => self.num_chapters.map_or("N/A ch".to_string(), |n| {
182                if n == 0 {
183                    "N/A".to_string()
184                } else {
185                    format!("{} ch", n)
186                }
187            }),
188            MangaDisplayType::Both => format!(
189                "{}, {}",
190                self.num_volumes
191                    .map_or("N/A vol".to_string(), |n| if n == 0 {
192                        "N/A".to_string()
193                    } else {
194                        format!("{} vol", n)
195                    }),
196                self.num_chapters
197                    .map_or("N/A ch".to_string(), |n| if n == 0 {
198                        "N/A".to_string()
199                    } else {
200                        format!("{} ch", n)
201                    })
202            ),
203        }
204    }
205}