mal/api/
anime.rs

1use super::model::*;
2use super::Error;
3use super::{get, handle_response, API_URL};
4use crate::auth::OAuth;
5use serde::Serialize;
6
7/// Get Anime List Request
8#[derive(Clone, Debug, Serialize)]
9pub struct GetAnimeListQuery {
10    pub q: String,
11    pub limit: u64,
12    pub offset: u64,
13    pub nsfw: bool,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub fields: Option<String>,
16}
17
18pub async fn get_anime_list(query: &GetAnimeListQuery, auth: &OAuth) -> Result<Page<Anime>, Error> {
19    let response = get(
20        &format!("{}/anime?{}", API_URL, serde_urlencoded::to_string(query)?),
21        auth,
22    )
23    .await?;
24    handle_response(&response)
25}
26
27#[derive(Clone, Debug, Serialize)]
28pub struct GetAnimeDetailQuery {
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub fields: Option<String>,
31    pub nsfw: bool,
32}
33
34pub async fn get_anime_details(
35    anime_id: u64,
36    query: &GetAnimeDetailQuery,
37    auth: &OAuth,
38) -> Result<Anime, Error> {
39    let response = get(
40        &format!(
41            "{}/anime/{}?{}",
42            API_URL,
43            anime_id,
44            serde_urlencoded::to_string(query)?
45        ),
46        auth,
47    )
48    .await?;
49    handle_response(&response)
50}
51
52#[derive(Clone, Debug, Serialize)]
53pub struct GetAnimeRankingQuery {
54    pub ranking_type: AnimeRankingType,
55    pub limit: u64,
56    pub offset: u64,
57    pub nsfw: bool,
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub fields: Option<String>,
60}
61
62pub async fn get_anime_ranking(
63    query: &GetAnimeRankingQuery,
64    auth: &OAuth,
65) -> Result<Ranking<RankingAnimePair>, Error> {
66    let response = get(
67        &format!(
68            "{}/anime/ranking?{}",
69            API_URL,
70            serde_urlencoded::to_string(query)?
71        ),
72        auth,
73    )
74    .await?;
75    handle_response(&response)
76}
77
78#[derive(Clone, Debug, Serialize)]
79pub struct GetSeasonalAnimeQuery {
80    pub sort: Option<SortStyle>,
81    pub limit: u64,
82    pub offset: u64,
83    pub nsfw: bool,
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub fields: Option<String>,
86}
87
88pub async fn get_seasonal_anime(
89    season: &AnimeSeason,
90    query: &GetSeasonalAnimeQuery,
91    auth: &OAuth,
92) -> Result<Page<Anime>, Error> {
93    let season_name: &'static str = season.season.clone().into();
94    let response = get(
95        &format!(
96            "{}/anime/season/{}/{}?{}",
97            API_URL,
98            season.year,
99            season_name,
100            serde_urlencoded::to_string(query)?
101        ),
102        auth,
103    )
104    .await?;
105    handle_response(&response)
106}
107
108#[derive(Clone, Debug, Serialize)]
109pub struct GetSuggestedAnimeQuery {
110    pub limit: u64,
111    pub offset: u64,
112    pub nsfw: bool,
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub fields: Option<String>,
115}
116
117pub async fn get_suggested_anime(
118    query: &GetSuggestedAnimeQuery,
119    auth: &OAuth,
120) -> Result<Page<Anime>, Error> {
121    let response = get(
122        &format!(
123            "{}/anime/suggestions?{}",
124            API_URL,
125            serde_urlencoded::to_string(query)?
126        ),
127        auth,
128    )
129    .await?;
130    handle_response(&response)
131}
132
133#[cfg(test)]
134pub mod tests {
135
136    use super::*;
137
138    pub async fn get_anime<T: ToString>(q: T, auth: &OAuth) -> Result<Anime, Error> {
139        let anime_query = GetAnimeListQuery {
140            q: q.to_string(),
141            limit: 4,
142            offset: 0,
143            nsfw: false,
144            fields: Some(ALL_ANIME_AND_MANGA_FIELDS.to_string()),
145        };
146        let anime_list = get_anime_list(&anime_query, auth).await.unwrap();
147        let anime = anime_list.data.first().unwrap().node.clone();
148        Ok(anime)
149    }
150
151    #[tokio::test]
152    async fn test_get_anime_list() {
153        let mut auth = crate::auth::tests::get_auth();
154        auth.refresh().unwrap();
155        // let oauth = crate::auth::OAuth::get_auth(app_config::AppConfig::Load())
156        let query = GetAnimeListQuery {
157            q: "Code Geass".to_string(),
158            limit: 4,
159            offset: 0,
160            nsfw: false,
161            fields: Some(ALL_ANIME_AND_MANGA_FIELDS.to_string()),
162        };
163        let result = get_anime_list(&query, &auth).await.unwrap();
164        println!("{:#?}", result);
165        assert!(!result.data.is_empty());
166    }
167
168    #[tokio::test]
169    async fn test_get_anime_details() {
170        let auth = crate::auth::tests::get_auth();
171        let query = GetAnimeDetailQuery {
172            fields: Some(ALL_ANIME_AND_MANGA_FIELDS.to_string()),
173            nsfw: false,
174        };
175
176        let anime = get_anime("Cowboy Bebop", &auth).await.unwrap();
177        let result = get_anime_details(anime.id, &query, &auth).await.unwrap();
178        println!("{:#?}", result);
179        assert_eq!(result.title, anime.title);
180    }
181
182    #[tokio::test]
183    async fn test_get_anime_ranking() {
184        let auth = crate::auth::tests::get_auth();
185        let query = GetAnimeRankingQuery {
186            ranking_type: AnimeRankingType::All,
187            limit: 4,
188            offset: 0,
189            nsfw: false,
190            fields: Some(ALL_ANIME_AND_MANGA_FIELDS.to_string()),
191        };
192        let result = get_anime_ranking(&query, &auth).await.unwrap();
193        println!("{:#?}", result);
194        assert!(!result.data.is_empty());
195    }
196    #[tokio::test]
197    async fn test_get_seasonal_anime() {
198        let auth = crate::auth::tests::get_auth();
199        let query = GetSeasonalAnimeQuery {
200            sort: None,
201            limit: 4,
202            offset: 0,
203            nsfw: false,
204            fields: Some(ALL_ANIME_AND_MANGA_FIELDS.to_string()),
205        };
206        let season = AnimeSeason {
207            year: 2020,
208            season: Season::Summer,
209        };
210        let result = get_seasonal_anime(&season, &query, &auth).await.unwrap();
211        println!("{:#?}", result);
212        assert!(!result.data.is_empty());
213    }
214    #[tokio::test]
215    async fn test_get_suggested_anime() {
216        let auth = crate::auth::tests::get_auth();
217        let query = GetSuggestedAnimeQuery {
218            limit: 4,
219            offset: 0,
220            nsfw: false,
221            fields: Some(ALL_ANIME_AND_MANGA_FIELDS.to_string()),
222        };
223        let result = get_suggested_anime(&query, &auth).await.unwrap();
224        println!("{:#?}", result);
225        assert!(!result.data.is_empty());
226    }
227}