1pub mod anime;
3pub use anime::*;
4pub mod manga;
6pub use manga::*;
7pub mod user;
9use serde::de::{self, Visitor};
10pub use user::*;
11
12use core::fmt;
13use serde::{Deserialize, Deserializer, Serialize, Serializer};
14use std::fmt::Debug;
15use std::str::FromStr;
16use strum_macros::{Display, EnumString, IntoStaticStr};
17use time::{
18 format_description::{
19 self,
20 well_known::{iso8601, Iso8601},
21 },
22 Date,
24 Month,
25 PrimitiveDateTime,
26 Time,
27};
28
29pub type Page<T> = PageableData<Vec<Node<T>>>;
30pub type Ranking<T> = PageableData<Vec<T>>;
31
32#[derive(Debug, Clone)]
33pub enum RankingType {
34 AnimeRankingType(AnimeRankingType),
35 MangaRankingType(MangaRankingType),
36}
37
38const CONFIG: iso8601::EncodedConfig = iso8601::Config::DEFAULT
40 .set_year_is_six_digits(false)
41 .encode();
42const FORMAT: Iso8601<CONFIG> = Iso8601::<CONFIG>;
43
44#[derive(Clone, Debug, Deserialize, Serialize)]
45pub struct Paging {
46 pub previous: Option<String>,
47 pub next: Option<String>,
48}
49
50#[derive(Clone, Debug, Deserialize, Serialize)]
51pub struct PageableData<D: Clone + Debug> {
52 pub data: D,
53 pub paging: Paging,
54}
55
56#[derive(Clone, Debug, Deserialize, Serialize)]
57pub struct Node<N: Clone + std::fmt::Debug> {
58 pub node: N,
59}
60
61pub enum Media<'a> {
62 Anime(&'a Anime),
63 Manga(&'a Manga),
64}
65
66#[derive(Clone, Debug, Deserialize, Serialize)]
67pub struct Picture {
68 pub large: Option<String>,
69 pub medium: Option<String>,
70}
71
72#[derive(Clone, Debug, Deserialize, Serialize)]
73pub struct AlternativeTitles {
74 pub synonyms: Option<Vec<String>>,
75 pub en: Option<String>,
76 pub jp: Option<String>,
77}
78
79#[derive(Clone, Debug, Deserialize, Serialize)]
80pub struct Genre {
81 pub id: u64,
82 pub name: String,
83}
84
85#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr, Display)]
86#[strum(serialize_all = "snake_case")]
87pub enum Season {
88 Winter,
89 Spring,
90 Summer,
91 Fall,
92 Other(String),
93}
94
95#[derive(Clone, Debug)]
96pub struct TimeWrapper {
97 pub time: Time,
98}
99#[derive(Clone, Debug)]
100pub struct DateWrapper {
101 pub date: Date,
102}
103
104#[derive(Clone, Debug)]
105pub struct DateTimeWrapper {
106 pub datetime: PrimitiveDateTime,
107}
108
109#[derive(Clone, Debug, Deserialize, Serialize)]
110pub struct Broadcast {
111 pub day_of_the_week: String,
112 pub start_time: Option<TimeWrapper>,
113}
114
115#[derive(Clone, Debug, Deserialize, Serialize)]
116pub struct Studio {
117 pub id: u64,
118 pub name: String,
119}
120#[derive(Clone, Debug, Deserialize, Serialize)]
121pub struct MediaDetailStatistics {
122 pub num_list_users: u64,
123 pub status: MediaDetailStatisticsStatus,
124}
125
126#[derive(Clone, Debug, Serialize, Deserialize)]
127pub struct MediaDetailStatisticsStatus {
128 #[serde(deserialize_with = "string_or_int")]
130 pub watching: String,
131 #[serde(deserialize_with = "string_or_int")]
132 pub completed: String,
133 #[serde(deserialize_with = "string_or_int")]
134 pub on_hold: String,
135 #[serde(deserialize_with = "string_or_int")]
136 pub dropped: String,
137 #[serde(deserialize_with = "string_or_int")]
138 pub plan_to_watch: String,
139}
140fn string_or_int<'de, D>(deserializer: D) -> Result<String, D::Error>
142where
143 D: Deserializer<'de>,
144{
145 struct StringOrIntVisitor;
146
147 impl Visitor<'_> for StringOrIntVisitor {
148 type Value = String;
149
150 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
151 formatter.write_str("an integer or a string")
152 }
153
154 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
155 where
156 E: de::Error,
157 {
158 Ok(value.to_string())
159 }
160
161 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
162 where
163 E: de::Error,
164 {
165 Ok(value.to_string())
166 }
167
168 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
169 where
170 E: de::Error,
171 {
172 Ok(value.to_string())
173 }
174 }
175
176 deserializer.deserialize_any(StringOrIntVisitor)
177}
178
179pub const ALL_ANIME_AND_MANGA_FIELDS: &str = "id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,genres,create_at,updated_at,media_type,status,my_list_status,num_episodes,broadcast,source,average_episode_duration,rating,pictures,background,related_anime,related_manga,recommendations,studios,statistics,num_volumes,num_chapters,authors,start_season";
180pub const ALL_USER_FIELDS: &str =
181 "id,name,picture,gender,birthday,location,joined_at,anime_statistics,time_zone,is_supporter";
182
183pub fn fields_to_string(fields: &[AnimeField]) -> String {
185 fields
186 .iter()
187 .map(|field| field.into())
188 .collect::<Vec<&str>>()
189 .join(",")
190}
191
192#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr)]
193#[strum(serialize_all = "snake_case")]
194pub enum NSFW {
195 White,
196 Gray,
197 Black,
198 Other(String),
199}
200
201#[derive(Clone, Debug, Serialize, Deserialize)]
202pub struct RankingInfo {
203 pub rank: u64,
204 pub previous_rank: Option<u64>,
205}
206
207#[derive(Clone, Debug, Deserialize, Serialize)]
208pub struct Person {
209 pub id: u64,
210 pub first_name: Option<String>,
211 pub last_name: Option<String>,
212}
213
214#[derive(Clone, Debug, Deserialize, Serialize)]
215pub struct PersonRole {
216 pub node: Person,
217 pub role: String,
218}
219
220macro_rules! impl_serialize_deserialize {
221 (for $( $t:ty ),+) => {
222 $(
223 impl Serialize for $t {
224 fn serialize<S>(
225 &self,
226 serializer: S,
227 ) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
228 where
229 S: Serializer,
230 {
231 serializer.serialize_str(self.into())
232 }
233 }
234
235 impl<'de> Deserialize<'de> for $t {
236 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
237 where
238 D: Deserializer<'de>,
239 {
240 let s = String::deserialize(deserializer)?;
241 match Self::from_str(s.as_str()) {
242 Ok(n) => Ok(n),
243 Err(_) => Ok(Self::Other(s)),
244 }
245 }
246
247 fn deserialize_in_place<D>(
248 deserializer: D,
249 place: &mut Self,
250 ) -> Result<(), <D as Deserializer<'de>>::Error>
251 where
252 D: Deserializer<'de>,
253 {
254 let s = String::deserialize(deserializer)?;
255 *place = match Self::from_str(s.as_str()) {
256 Ok(n) => n,
257 Err(_) => Self::Other(s),
258 };
259 Ok(())
260 }
261 }
262 )*
263 };
264}
265
266impl_serialize_deserialize!(
267 for
268 NSFW,
269 AnimeMediaType,
270 AnimeStatus,
271 UserWatchStatus,
272 AnimeRankingType,
273 MangaRankingType,
274 Season,
275 SortStyle,
276 UserReadStatus,
277 MangaMediaType,
278 MangaStatus,
279 RelationType
280);
281
282impl Serialize for Source {
283 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
284 where
285 S: Serializer,
286 {
287 serializer.serialize_str(self.into())
288 }
289}
290
291impl<'de> Deserialize<'de> for Source {
292 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
293 where
294 D: Deserializer<'de>,
295 {
296 let s = String::deserialize(deserializer)?;
297 match Self::from_str(s.as_str()) {
298 Ok(n) => Ok(n),
299 Err(_) => Ok(Self::Other),
300 }
301 }
302
303 fn deserialize_in_place<D>(
304 deserializer: D,
305 place: &mut Self,
306 ) -> Result<(), <D as Deserializer<'de>>::Error>
307 where
308 D: Deserializer<'de>,
309 {
310 let s = String::deserialize(deserializer)?;
311 *place = match Self::from_str(s.as_str()) {
312 Ok(n) => n,
313 Err(_) => Self::Other,
314 };
315 Ok(())
316 }
317}
318
319impl Serialize for TimeWrapper {
320 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
321 where
322 S: Serializer,
323 {
324 let format = format_description::parse("[hour]:[minute]:[second]").unwrap();
325 serializer.serialize_str(&self.time.format(&format).unwrap())
326 }
327}
328
329impl<'de> Deserialize<'de> for TimeWrapper {
330 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
331 where
332 D: Deserializer<'de>,
333 {
334 use serde::de::Error;
335 let s = String::deserialize(deserializer)?;
336 let re = regex::Regex::new(r"([0-9]+):([0-9]+)").unwrap();
337 if let Some(caps) = re.captures(&s) {
338 let hour = caps.get(1).unwrap();
339 let minute = caps.get(2).unwrap();
340 let hour = match hour.as_str().parse::<u8>() {
341 Ok(hour) => hour,
342 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
343 };
344 let minute = match minute.as_str().parse::<u8>() {
345 Ok(minute) => minute,
346 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
347 };
348 let time = match Time::from_hms(hour, minute, 0) {
349 Ok(time) => time,
350 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
351 };
352 Ok(TimeWrapper { time })
353 } else {
354 Err(D::Error::custom("Could not parse time"))
355 }
356 }
357
358 fn deserialize_in_place<D>(
359 deserializer: D,
360 place: &mut Self,
361 ) -> Result<(), <D as Deserializer<'de>>::Error>
362 where
363 D: Deserializer<'de>,
364 {
365 use serde::de::Error;
366 let s = String::deserialize(deserializer)?;
367 let format = format_description::parse("[hour]:[minute]:[second]").unwrap();
368 if let Ok(time) = Time::parse(&s, &format) {
369 place.time = time;
370 return Ok(());
371 }
372 let re = regex::Regex::new(r"([0-9]+):([0-9]+)").unwrap();
373 if let Some(caps) = re.captures(&s) {
374 let hour = caps.get(1).unwrap();
375 let minute = caps.get(2).unwrap();
376 let hour = match hour.as_str().parse::<u8>() {
377 Ok(hour) => hour,
378 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
379 };
380 let minute = match minute.as_str().parse::<u8>() {
381 Ok(minute) => minute,
382 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
383 };
384 place.time = match Time::from_hms(hour, minute, 0) {
385 Ok(time) => time,
386 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
387 };
388 Ok(())
389 } else {
390 Err(D::Error::custom("Could not parse time"))
391 }
392 }
393}
394
395impl Serialize for DateWrapper {
396 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
397 where
398 S: Serializer,
399 {
400 let format = format_description::parse("[year]-[month]-[day]").unwrap();
401 serializer.serialize_str(&self.date.format(&format).unwrap())
402 }
404}
405
406impl<'de> Deserialize<'de> for DateWrapper {
407 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
408 where
409 D: Deserializer<'de>,
410 {
411 use serde::de::Error;
412 let s = String::deserialize(deserializer)?;
413 let format = format_description::parse("[year]-[month]-[day]").unwrap();
414 if let Ok(date) = Date::parse(&s, &format) {
415 return Ok(DateWrapper { date });
416 }
417 let re = regex::Regex::new(r"([0-9]+)-?([0-9]+)?").unwrap();
418 if let Some(caps) = re.captures(&s) {
419 let year = caps.get(1).unwrap();
420 let year = match year.as_str().parse::<i32>() {
421 Ok(year) => year,
422 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
423 };
424 let month = if let Some(month) = caps.get(2) {
425 match month.as_str().parse::<u8>() {
426 Ok(month) => month,
428 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
429 }
430 } else {
431 1
432 };
433 let date = match Date::from_calendar_date(year, Month::try_from(month).unwrap(), 1) {
434 Ok(date) => date,
436 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
437 };
438 Ok(DateWrapper { date })
439 } else {
440 Err(D::Error::custom("Could not parse date"))
441 }
442 }
443
444 fn deserialize_in_place<D>(
445 deserializer: D,
446 place: &mut Self,
447 ) -> Result<(), <D as Deserializer<'de>>::Error>
448 where
449 D: Deserializer<'de>,
450 {
451 use serde::de::Error;
452 let s = String::deserialize(deserializer)?;
453 let format = format_description::parse("[year]-[month]-[day]").unwrap();
454 if let Ok(date) = Date::parse(&s, &format) {
455 place.date = date;
456 return Ok(());
457 };
458 let re = regex::Regex::new(r"([0-9]+)-?([0-9]+)?").unwrap();
459 if let Some(caps) = re.captures(&s) {
460 let year = caps.get(1).unwrap();
461 let year = match year.as_str().parse::<i32>() {
462 Ok(year) => year,
463 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
464 };
465 let month = if let Some(month) = caps.get(2) {
466 match month.as_str().parse::<u8>() {
467 Ok(month) => month,
468 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
469 }
470 } else {
471 1
472 };
473 place.date = match Date::from_calendar_date(year, Month::try_from(month).unwrap(), 1) {
474 Ok(date) => date,
475 Err(e) => return Err(serde::de::Error::custom(e.to_string())),
476 };
477 Ok(())
478 } else {
479 Err(D::Error::custom("Could not parse date"))
480 }
481 }
482}
483
484impl Serialize for DateTimeWrapper {
485 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
486 where
487 S: Serializer,
488 {
489 serializer.serialize_str(&self.datetime.format(&FORMAT).unwrap())
490 }
491}
492
493impl<'de> Deserialize<'de> for DateTimeWrapper {
494 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
495 where
496 D: Deserializer<'de>,
497 {
498 use serde::de::Error;
499 let s = String::deserialize(deserializer)?;
500 match PrimitiveDateTime::parse(&s, &FORMAT) {
501 Ok(datetime) => Ok(DateTimeWrapper { datetime }),
502 Err(e) => Err(D::Error::custom(e.to_string())),
503 }
504 }
505
506 fn deserialize_in_place<D>(
507 deserializer: D,
508 place: &mut Self,
509 ) -> Result<(), <D as Deserializer<'de>>::Error>
510 where
511 D: Deserializer<'de>,
512 {
513 use serde::de::Error;
514 let s = String::deserialize(deserializer)?;
515 match PrimitiveDateTime::parse(&s, &FORMAT) {
516 Ok(datetime) => {
517 place.datetime = datetime;
518 Ok(())
519 }
520 Err(e) => Err(D::Error::custom(e.to_string())),
521 }
522 }
523}