1use super::model::*;
2use super::Error;
3use super::{get, handle_response, API_URL};
4use crate::auth::OAuth;
5use serde::Serialize;
6
7#[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 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}