kodik_api/list.rs
1use async_fn_stream::try_fn_stream;
2use futures_util::{Stream, StreamExt, pin_mut};
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 Client,
7 error::Error,
8 types::{
9 AllStatus, AnimeKind, AnimeStatus, DramaStatus, MaterialDataField, MppaRating, Release,
10 ReleaseType, TranslationType,
11 },
12 util::serialize_into_query_parts,
13};
14
15/// A struct containing releases results and other information about the releases
16#[derive(Deserialize, Debug, Clone)]
17pub struct ListResponse {
18 pub time: String,
19 pub total: i32,
20 pub prev_page: Option<String>,
21 pub next_page: Option<String>,
22 pub results: Vec<Release>,
23}
24
25#[derive(Deserialize, Debug, Clone)]
26#[serde(untagged)]
27enum ListResponseUnion {
28 Result(ListResponse),
29 Error { error: String },
30}
31
32#[derive(Serialize, Deserialize, Debug, Clone)]
33pub enum ListSort {
34 #[serde(rename = "year")]
35 Year,
36 #[serde(rename = "created_at")]
37 CreatedAt,
38 #[serde(rename = "updated_at")]
39 UpdatedAt,
40 #[serde(rename = "kinopoisk_rating")]
41 KinopoiskRating,
42 #[serde(rename = "imdb_rating")]
43 ImdbRating,
44 #[serde(rename = "shikimori_rating")]
45 ShikimoriRating,
46}
47
48#[derive(Serialize, Deserialize, Debug, Clone)]
49pub enum ListOrder {
50 #[serde(rename = "asc")]
51 Asc,
52 #[serde(rename = "desc")]
53 Desc,
54}
55
56#[derive(Debug, Serialize, Clone)]
57pub struct ListQuery<'a> {
58 /// Maximum number of outputs
59 #[serde(skip_serializing_if = "Option::is_none")]
60 limit: Option<u32>,
61
62 /// What field to sort materials by
63 #[serde(skip_serializing_if = "Option::is_none")]
64 sort: Option<ListSort>,
65
66 /// Sorting direction
67 #[serde(skip_serializing_if = "Option::is_none")]
68 order: Option<ListOrder>,
69
70 /// Maximum number of outputs
71 #[serde(skip_serializing_if = "Option::is_none")]
72 types: Option<&'a [ReleaseType]>,
73
74 ///Filter materials by year If you set this parameter, only materials of the corresponding year will be displayed
75 #[serde(skip_serializing_if = "Option::is_none")]
76 year: Option<&'a [u32]>,
77
78 /// Filtering materials by translation ID
79 #[serde(skip_serializing_if = "Option::is_none")]
80 translation_id: Option<&'a [u32]>,
81 /// Filter content by translation type. Allows you to output only voice translation or only subtitles
82 #[serde(skip_serializing_if = "Option::is_none")]
83 translation_type: Option<&'a [TranslationType]>,
84
85 /// Filtering materials based on the presence of a specific field. Materials that have at least one of the listed fields are shown. In order to show only materials that have all the listed fields
86 #[serde(skip_serializing_if = "Option::is_none")]
87 has_field: Option<&'a [MaterialDataField]>,
88 /// Filtering materials based on the presence of a specific field. Materials that have all the listed fields are shown
89 #[serde(skip_serializing_if = "Option::is_none")]
90 has_field_and: Option<&'a [MaterialDataField]>,
91
92 /// Filtering materials by camrip parameter. If you specify false, only materials with a quality picture will be output. If you don't specify this parameter, all materials will be displayed
93 #[serde(skip_serializing_if = "Option::is_none")]
94 camrip: Option<bool>,
95 /// Filters materials by the lgbt parameter. If you specify false, only materials that do not contain LGBT scenes will be output. If you don't specify this parameter, all materials will be displayed
96 #[serde(skip_serializing_if = "Option::is_none")]
97 lgbt: Option<bool>,
98
99 /// If you specify true, the seasons of the series will also be listed in the seasons field. This and the following parameter are made to avoid overloading the output with a huge amount of information about seasons and episodes, if this information is not needed for parsing
100 #[serde(skip_serializing_if = "Option::is_none")]
101 with_seasons: Option<bool>,
102
103 /// With this option you can specify which season you are interested in. This way, only shows that have that season will appear in the search results. Passing this parameter also automatically enables the with_seasons parameter
104 #[serde(skip_serializing_if = "Option::is_none")]
105 season: Option<&'a [u32]>,
106
107 /// If you specify true, the seasons field will be added to each series (even if with_seasons is not specified or specified as false) and the episodes field with the episodes of that season will be added to each season. If the with_episodes parameter is used, the series numbers will correspond to the normal series references. If you use the with_episodes_data parameter, episode objects will be assigned to the episode numbers, where the link will be available via the link parameter, the episode name (if any) via the title parameter, and the frames via screenshots
108 #[serde(skip_serializing_if = "Option::is_none")]
109 with_episodes: Option<bool>,
110 /// If you specify true, the seasons field will be added to each series (even if with_seasons is not specified or specified as false) and the episodes field with the episodes of that season will be added to each season. If the with_episodes parameter is used, the series numbers will correspond to the normal series references. If you use the with_episodes_data parameter, episode objects will be assigned to the episode numbers, where the link will be available via the link parameter, the episode name (if any) via the title parameter, and the frames via screenshots
111 #[serde(skip_serializing_if = "Option::is_none")]
112 with_episodes_data: Option<bool>,
113
114 /// If you specify true, all links to players will be replaced by special links to pages with players (suitable for cases when you don't have your own site). You can customize appearance of these pages in settings in the base. If parameter with_seasons or with_episodes / with_episodes_data is specified together with this parameter, links in seasons and episodes will also be replaced
115 #[serde(skip_serializing_if = "Option::is_none")]
116 with_page_links: Option<bool>,
117
118 /// Filters materials by country in which they should not be blocked. The country codes are specified separated by commas
119 #[serde(skip_serializing_if = "Option::is_none")]
120 not_blocked_in: Option<&'a [&'a str]>,
121 /// A simpler analog of the previous parameter. Our server itself checks which country the current request comes from and doesn't display those materials that are blocked for that country. This parameter can be useful if the API is called on your site
122 #[serde(skip_serializing_if = "Option::is_none")]
123 not_blocked_for_me: Option<&'a [&'a str]>,
124
125 /// If you specify true, the material_data field will be added to each movie/series with information from Kinopoisk and Shikimori
126 #[serde(skip_serializing_if = "Option::is_none")]
127 with_material_data: Option<bool>,
128
129 /// Filtering materials by country. You can specify a single value or multiple values, separated by commas (then materials with at least one of the listed countries will be displayed). The parameter is case sensitive
130 #[serde(skip_serializing_if = "Option::is_none")]
131 countries: Option<&'a [&'a str]>,
132
133 /// Filtering by genre. You can specify either one value or several values separated by commas (then materials that have at least one of the specified genres will be displayed). You can search by Kinopoisk, Shikimori, MyDramaList or by all genres at once. The parameter is not case sensitive
134 #[serde(skip_serializing_if = "Option::is_none")]
135 genres: Option<&'a [&'a str]>,
136 /// Filtering by genre. You can specify either one value or several values separated by commas (then materials that have at least one of the specified genres will be displayed). You can search by Kinopoisk, Shikimori, MyDramaList or by all genres at once. The parameter is not case sensitive
137 #[serde(skip_serializing_if = "Option::is_none")]
138 anime_genres: Option<&'a [&'a str]>,
139 /// Filtering by genre. You can specify either one value or several values separated by commas (then materials that have at least one of the specified genres will be displayed). You can search by Kinopoisk, Shikimori, MyDramaList or by all genres at once. The parameter is not case sensitive
140 #[serde(skip_serializing_if = "Option::is_none")]
141 drama_genres: Option<&'a [&'a str]>,
142 /// Filtering by genre. You can specify either one value or several values separated by commas (then materials that have at least one of the specified genres will be displayed). You can search by Kinopoisk, Shikimori, MyDramaList or by all genres at once. The parameter is not case sensitive
143 #[serde(skip_serializing_if = "Option::is_none")]
144 all_genres: Option<&'a [&'a str]>,
145
146 /// Filtering by duration (in minutes). You can specify either a single value to search for the exact duration, or an interval.
147 #[serde(skip_serializing_if = "Option::is_none")]
148 duration: Option<&'a [&'a str]>,
149
150 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
151 #[serde(skip_serializing_if = "Option::is_none")]
152 kinopoisk_rating: Option<&'a [&'a str]>,
153 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
154 #[serde(skip_serializing_if = "Option::is_none")]
155 imdb_rating: Option<&'a [&'a str]>,
156 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
157 #[serde(skip_serializing_if = "Option::is_none")]
158 shikimori_rating: Option<&'a [&'a str]>,
159 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
160 #[serde(skip_serializing_if = "Option::is_none")]
161 mydramalist_rating: Option<&'a [&'a str]>,
162
163 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
164 #[serde(skip_serializing_if = "Option::is_none")]
165 actors: Option<&'a [&'a str]>,
166 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
167 #[serde(skip_serializing_if = "Option::is_none")]
168 directors: Option<&'a [&'a str]>,
169 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
170 #[serde(skip_serializing_if = "Option::is_none")]
171 producers: Option<&'a [&'a str]>,
172 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
173 #[serde(skip_serializing_if = "Option::is_none")]
174 writers: Option<&'a [&'a str]>,
175 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
176 #[serde(skip_serializing_if = "Option::is_none")]
177 composers: Option<&'a [&'a str]>,
178 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
179 #[serde(skip_serializing_if = "Option::is_none")]
180 editors: Option<&'a [&'a str]>,
181 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
182 #[serde(skip_serializing_if = "Option::is_none")]
183 designers: Option<&'a [&'a str]>,
184 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
185 #[serde(skip_serializing_if = "Option::is_none")]
186 operators: Option<&'a [&'a str]>,
187
188 /// Filtering materials by age rating. You can specify a single value or multiple values, separated by commas. The parameter is case-insensitive
189 #[serde(skip_serializing_if = "Option::is_none")]
190 rating_mpaa: Option<&'a [MppaRating]>,
191
192 /// Filter content by the minimum age from which it can be viewed. You can specify either a single value or a range of values
193 #[serde(skip_serializing_if = "Option::is_none")]
194 minimal_age: Option<&'a [&'a str]>,
195
196 /// Filtering materials by anime type. You can specify one value or several values separated by commas (then materials with at least one of these types will be displayed)
197 #[serde(skip_serializing_if = "Option::is_none")]
198 anime_kind: Option<&'a [AnimeKind]>,
199
200 /// Filters materials by MyDramaList tags. You can specify one value or several values separated by commas (then materials with at least one of these types will be displayed)
201 #[serde(skip_serializing_if = "Option::is_none")]
202 mydramalist_tags: Option<&'a [&'a str]>,
203
204 /// Filter materials by Shikimori status, MyDramaList, or by all statuses. You can specify a single value or several values separated by commas (then materials that have at least one of the listed statuses will be displayed)
205 #[serde(skip_serializing_if = "Option::is_none")]
206 anime_status: Option<&'a [AnimeStatus]>,
207 /// Filter materials by Shikimori status, MyDramaList, or by all statuses. You can specify a single value or several values separated by commas (then materials that have at least one of the listed statuses will be displayed)
208 #[serde(skip_serializing_if = "Option::is_none")]
209 drama_status: Option<&'a [DramaStatus]>,
210 /// Filter materials by Shikimori status, MyDramaList, or by all statuses. You can specify a single value or several values separated by commas (then materials that have at least one of the listed statuses will be displayed)
211 #[serde(skip_serializing_if = "Option::is_none")]
212 all_status: Option<&'a [AllStatus]>,
213
214 /// Filtering materials by anime studio. You can specify either one value or several values separated by commas (then materials with at least one of the listed studios will be displayed)
215 #[serde(skip_serializing_if = "Option::is_none")]
216 anime_studios: Option<&'a [&'a str]>,
217 /// Filtering materials by license owner. You can specify a single value or several values separated by commas (then materials that have at least one of the listed owners will be displayed)
218 #[serde(skip_serializing_if = "Option::is_none")]
219 anime_licensed_by: Option<&'a [&'a str]>,
220}
221
222impl<'a> ListQuery<'a> {
223 pub fn new() -> ListQuery<'a> {
224 ListQuery {
225 limit: None,
226 sort: None,
227 order: None,
228 types: None,
229 year: None,
230 translation_id: None,
231 translation_type: None,
232 has_field: None,
233 has_field_and: None,
234 camrip: None,
235 lgbt: None,
236 with_seasons: None,
237 season: None,
238 with_episodes: None,
239 with_episodes_data: None,
240 with_page_links: None,
241 not_blocked_in: None,
242 not_blocked_for_me: None,
243 with_material_data: None,
244 countries: None,
245 genres: None,
246 anime_genres: None,
247 drama_genres: None,
248 all_genres: None,
249 duration: None,
250 kinopoisk_rating: None,
251 imdb_rating: None,
252 shikimori_rating: None,
253 mydramalist_rating: None,
254 actors: None,
255 directors: None,
256 producers: None,
257 writers: None,
258 composers: None,
259 editors: None,
260 designers: None,
261 operators: None,
262 rating_mpaa: None,
263 minimal_age: None,
264 anime_kind: None,
265 mydramalist_tags: None,
266 anime_status: None,
267 drama_status: None,
268 all_status: None,
269 anime_studios: None,
270 anime_licensed_by: None,
271 }
272 }
273
274 /// Maximum number of outputs
275 pub fn with_limit<'b>(&'b mut self, limit: u32) -> &'b mut ListQuery<'a> {
276 self.limit = Some(limit);
277 self
278 }
279
280 /// What field to sort materials by
281 pub fn with_sort<'b>(&'b mut self, sort: ListSort) -> &'b mut ListQuery<'a> {
282 self.sort = Some(sort);
283 self
284 }
285
286 /// Sorting direction
287 pub fn with_order<'b>(&'b mut self, order: ListOrder) -> &'b mut ListQuery<'a> {
288 self.order = Some(order);
289 self
290 }
291
292 /// Maximum number of outputs
293 pub fn with_types<'b>(&'b mut self, types: &'a [ReleaseType]) -> &'b mut ListQuery<'a> {
294 self.types = Some(types);
295 self
296 }
297
298 ///Filter materials by year If you set this parameter, only materials of the corresponding year will be displayed
299 pub fn with_year<'b>(&'b mut self, year: &'a [u32]) -> &'b mut ListQuery<'a> {
300 self.year = Some(year);
301 self
302 }
303
304 /// Filtering materials by translation ID
305 pub fn with_translation_id<'b>(
306 &'b mut self,
307 translation_id: &'a [u32],
308 ) -> &'b mut ListQuery<'a> {
309 self.translation_id = Some(translation_id);
310 self
311 }
312 /// Filter content by translation type. Allows you to output only voice translation or only subtitles
313 pub fn with_translation_type<'b>(
314 &'b mut self,
315 translation_type: &'a [TranslationType],
316 ) -> &'b mut ListQuery<'a> {
317 self.translation_type = Some(translation_type);
318 self
319 }
320
321 /// Filtering materials based on the presence of a specific field. Materials that have at least one of the listed fields are shown. In order to show only materials that have all the listed fields
322 pub fn with_has_field<'b>(
323 &'b mut self,
324 has_field: &'a [MaterialDataField],
325 ) -> &'b mut ListQuery<'a> {
326 self.has_field = Some(has_field);
327 self
328 }
329 /// Filtering materials based on the presence of a specific field. Materials that have all the listed fields are shown
330 pub fn with_has_field_and<'b>(
331 &'b mut self,
332 has_field: &'a [MaterialDataField],
333 ) -> &'b mut ListQuery<'a> {
334 self.has_field_and = Some(has_field);
335 self
336 }
337
338 /// Filtering materials by camrip parameter. If you specify false, only materials with a quality picture will be output. If you don't specify this parameter, all materials will be displayed
339 pub fn with_camrip<'b>(&'b mut self, camrip: bool) -> &'b mut ListQuery<'a> {
340 self.camrip = Some(camrip);
341 self
342 }
343 /// Filters materials by the lgbt parameter. If you specify false, only materials that do not contain LGBT scenes will be output. If you don't specify this parameter, all materials will be displayed
344 pub fn with_lgbt<'b>(&'b mut self, lgbt: bool) -> &'b mut ListQuery<'a> {
345 self.lgbt = Some(lgbt);
346 self
347 }
348
349 /// If you specify true, the seasons of the series will also be listed in the seasons field. This and the following parameter are made to avoid overloading the output with a huge amount of information about seasons and episodes, if this information is not needed for parsing
350 pub fn with_seasons<'b>(&'b mut self, with_seasons: bool) -> &'b mut ListQuery<'a> {
351 self.with_seasons = Some(with_seasons);
352 self
353 }
354
355 /// With this option you can specify which season you are interested in. This way, only shows that have that season will appear in the search results. Passing this parameter also automatically enables the with_seasons parameter
356 pub fn with_season<'b>(&'b mut self, season: &'a [u32]) -> &'b mut ListQuery<'a> {
357 self.season = Some(season);
358 self
359 }
360
361 /// If you specify true, the seasons field will be added to each series (even if with_seasons is not specified or specified as false) and the episodes field with the episodes of that season will be added to each season. If the with_episodes parameter is used, the series numbers will correspond to the normal series references. If you use the with_episodes_data parameter, episode objects will be assigned to the episode numbers, where the link will be available via the link parameter, the episode name (if any) via the title parameter, and the frames via screenshots
362 pub fn with_episodes<'b>(&'b mut self, with_episodes: bool) -> &'b mut ListQuery<'a> {
363 self.with_episodes = Some(with_episodes);
364 self
365 }
366 /// If you specify true, the seasons field will be added to each series (even if with_seasons is not specified or specified as false) and the episodes field with the episodes of that season will be added to each season. If the with_episodes parameter is used, the series numbers will correspond to the normal series references. If you use the with_episodes_data parameter, episode objects will be assigned to the episode numbers, where the link will be available via the link parameter, the episode name (if any) via the title parameter, and the frames via screenshots
367 pub fn with_episodes_data<'b>(&'b mut self, with_episodes_data: bool) -> &'b mut ListQuery<'a> {
368 self.with_episodes_data = Some(with_episodes_data);
369 self
370 }
371
372 /// If you specify true, all links to players will be replaced by special links to pages with players (suitable for cases when you don't have your own site). You can customize appearance of these pages in settings in the base. If parameter with_seasons or with_episodes / with_episodes_data is specified together with this parameter, links in seasons and episodes will also be replaced
373 pub fn with_page_links<'b>(&'b mut self, with_page_links: bool) -> &'b mut ListQuery<'a> {
374 self.with_page_links = Some(with_page_links);
375 self
376 }
377
378 /// Filters materials by country in which they should not be blocked. The country codes are specified separated by commas
379 pub fn with_not_blocked_in<'b>(
380 &'b mut self,
381 not_blocked_in: &'a [&'a str],
382 ) -> &'b mut ListQuery<'a> {
383 self.not_blocked_in = Some(not_blocked_in);
384 self
385 }
386 /// A simpler analog of the previous parameter. Our server itself checks which country the current request comes from and doesn't display those materials that are blocked for that country. This parameter can be useful if the API is called on your site
387 pub fn with_not_blocked_for_me<'b>(
388 &'b mut self,
389 not_blocked_for_me: &'a [&'a str],
390 ) -> &'b mut ListQuery<'a> {
391 self.not_blocked_for_me = Some(not_blocked_for_me);
392 self
393 }
394 /// If you specify true, the material_data field will be added to each movie/series with information from Kinopoisk and Shikimori
395 pub fn with_material_data<'b>(&'b mut self, with_material_data: bool) -> &'b mut ListQuery<'a> {
396 self.with_material_data = Some(with_material_data);
397 self
398 }
399
400 /// Filtering materials by country. You can specify a single value or multiple values, separated by commas (then materials with at least one of the listed countries will be displayed). The parameter is case sensitive
401 pub fn with_countries<'b>(&'b mut self, countries: &'a [&'a str]) -> &'b mut ListQuery<'a> {
402 self.countries = Some(countries);
403 self
404 }
405
406 /// Filtering by genre. You can specify either one value or several values separated by commas (then materials that have at least one of the specified genres will be displayed). You can search by Kinopoisk, Shikimori, MyDramaList or by all genres at once. The parameter is not case sensitive
407 pub fn with_genres<'b>(&'b mut self, genres: &'a [&'a str]) -> &'b mut ListQuery<'a> {
408 self.genres = Some(genres);
409 self
410 }
411 /// Filtering by genre. You can specify either one value or several values separated by commas (then materials that have at least one of the specified genres will be displayed). You can search by Kinopoisk, Shikimori, MyDramaList or by all genres at once. The parameter is not case sensitive
412 pub fn with_anime_genres<'b>(
413 &'b mut self,
414 anime_genres: &'a [&'a str],
415 ) -> &'b mut ListQuery<'a> {
416 self.anime_genres = Some(anime_genres);
417 self
418 }
419 /// Filtering by genre. You can specify either one value or several values separated by commas (then materials that have at least one of the specified genres will be displayed). You can search by Kinopoisk, Shikimori, MyDramaList or by all genres at once. The parameter is not case sensitive
420 pub fn with_drama_genres<'b>(
421 &'b mut self,
422 drama_genres: &'a [&'a str],
423 ) -> &'b mut ListQuery<'a> {
424 self.drama_genres = Some(drama_genres);
425 self
426 }
427 /// Filtering by genre. You can specify either one value or several values separated by commas (then materials that have at least one of the specified genres will be displayed). You can search by Kinopoisk, Shikimori, MyDramaList or by all genres at once. The parameter is not case sensitive
428 pub fn with_all_genres<'b>(&'b mut self, all_genres: &'a [&'a str]) -> &'b mut ListQuery<'a> {
429 self.all_genres = Some(all_genres);
430 self
431 }
432
433 /// Filtering by duration (in minutes). You can specify either a single value to search for the exact duration, or an interval.
434 pub fn with_duration<'b>(&'b mut self, duration: &'a [&'a str]) -> &'b mut ListQuery<'a> {
435 self.duration = Some(duration);
436 self
437 }
438
439 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
440 pub fn with_kinopoisk_rating<'b>(
441 &'b mut self,
442 kinopoisk_rating: &'a [&'a str],
443 ) -> &'b mut ListQuery<'a> {
444 self.kinopoisk_rating = Some(kinopoisk_rating);
445 self
446 }
447 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
448 pub fn with_imdb_rating<'b>(&'b mut self, imdb_rating: &'a [&'a str]) -> &'b mut ListQuery<'a> {
449 self.imdb_rating = Some(imdb_rating);
450 self
451 }
452 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
453 pub fn with_shikimori_rating<'b>(
454 &'b mut self,
455 shikimori_rating: &'a [&'a str],
456 ) -> &'b mut ListQuery<'a> {
457 self.shikimori_rating = Some(shikimori_rating);
458 self
459 }
460 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
461 pub fn with_mydramalist_rating<'b>(
462 &'b mut self,
463 mydramalist_rating: &'a [&'a str],
464 ) -> &'b mut ListQuery<'a> {
465 self.mydramalist_rating = Some(mydramalist_rating);
466 self
467 }
468
469 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
470 pub fn with_actors<'b>(&'b mut self, actors: &'a [&'a str]) -> &'b mut ListQuery<'a> {
471 self.actors = Some(actors);
472 self
473 }
474 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
475 pub fn with_directors<'b>(&'b mut self, directors: &'a [&'a str]) -> &'b mut ListQuery<'a> {
476 self.directors = Some(directors);
477 self
478 }
479 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
480 pub fn with_producers<'b>(&'b mut self, producers: &'a [&'a str]) -> &'b mut ListQuery<'a> {
481 self.producers = Some(producers);
482 self
483 }
484 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
485 pub fn with_writers<'b>(&'b mut self, writers: &'a [&'a str]) -> &'b mut ListQuery<'a> {
486 self.writers = Some(writers);
487 self
488 }
489 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
490 pub fn with_composers<'b>(&'b mut self, composers: &'a [&'a str]) -> &'b mut ListQuery<'a> {
491 self.composers = Some(composers);
492 self
493 }
494 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
495 pub fn with_editors<'b>(&'b mut self, editors: &'a [&'a str]) -> &'b mut ListQuery<'a> {
496 self.editors = Some(editors);
497 self
498 }
499 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
500 pub fn with_designers<'b>(&'b mut self, designers: &'a [&'a str]) -> &'b mut ListQuery<'a> {
501 self.designers = Some(designers);
502 self
503 }
504 /// Filtering materials by personas. You can specify a single value or multiple values, separated by commas (then materials that have at least one of the specified personas will be displayed). This parameter is case-independent. You can specify filters for several professions at once
505 pub fn with_operators<'b>(&'b mut self, operators: &'a [&'a str]) -> &'b mut ListQuery<'a> {
506 self.operators = Some(operators);
507 self
508 }
509
510 /// Filtering materials by age rating. You can specify a single value or multiple values, separated by commas. The parameter is case-insensitive
511 pub fn with_rating_mpaa<'b>(
512 &'b mut self,
513 rating_mpaa: &'a [MppaRating],
514 ) -> &'b mut ListQuery<'a> {
515 self.rating_mpaa = Some(rating_mpaa);
516 self
517 }
518
519 /// Filter content by the minimum age from which it can be viewed. You can specify either a single value or a range of values
520 pub fn with_minimal_age<'b>(&'b mut self, minimal_age: &'a [&'a str]) -> &'b mut ListQuery<'a> {
521 self.minimal_age = Some(minimal_age);
522 self
523 }
524
525 /// Filtering materials by anime type. You can specify one value or several values separated by commas (then materials with at least one of these types will be displayed)
526 pub fn with_anime_kind<'b>(&'b mut self, anime_kind: &'a [AnimeKind]) -> &'b mut ListQuery<'a> {
527 self.anime_kind = Some(anime_kind);
528 self
529 }
530
531 /// Filters materials by MyDramaList tags. You can specify one value or several values separated by commas (then materials with at least one of these types will be displayed)
532 pub fn with_mydramalist_tags<'b>(
533 &'b mut self,
534 mydramalist_tags: &'a [&'a str],
535 ) -> &'b mut ListQuery<'a> {
536 self.mydramalist_tags = Some(mydramalist_tags);
537 self
538 }
539
540 /// Filter materials by Shikimori status, MyDramaList, or by all statuses. You can specify a single value or several values separated by commas (then materials that have at least one of the listed statuses will be displayed)
541 pub fn with_anime_status<'b>(
542 &'b mut self,
543 anime_status: &'a [AnimeStatus],
544 ) -> &'b mut ListQuery<'a> {
545 self.anime_status = Some(anime_status);
546 self
547 }
548 /// Filter materials by Shikimori status, MyDramaList, or by all statuses. You can specify a single value or several values separated by commas (then materials that have at least one of the listed statuses will be displayed)
549 pub fn with_drama_status<'b>(
550 &'b mut self,
551 drama_status: &'a [DramaStatus],
552 ) -> &'b mut ListQuery<'a> {
553 self.drama_status = Some(drama_status);
554 self
555 }
556 /// Filter materials by Shikimori status, MyDramaList, or by all statuses. You can specify a single value or several values separated by commas (then materials that have at least one of the listed statuses will be displayed)
557 pub fn with_all_status<'b>(&'b mut self, all_status: &'a [AllStatus]) -> &'b mut ListQuery<'a> {
558 self.all_status = Some(all_status);
559 self
560 }
561
562 /// Filtering materials by anime studio. You can specify either one value or several values separated by commas (then materials with at least one of the listed studios will be displayed)
563 pub fn with_anime_studios<'b>(
564 &'b mut self,
565 anime_studios: &'a [&'a str],
566 ) -> &'b mut ListQuery<'a> {
567 self.anime_studios = Some(anime_studios);
568 self
569 }
570 /// Filtering materials by license owner. You can specify a single value or several values separated by commas (then materials that have at least one of the listed owners will be displayed)
571 pub fn with_anime_licensed_by<'b>(
572 &'b mut self,
573 anime_licensed_by: &'a [&'a str],
574 ) -> &'b mut ListQuery<'a> {
575 self.anime_licensed_by = Some(anime_licensed_by);
576 self
577 }
578
579 /// Execute the query and fetch the results.
580 pub async fn execute<'b>(&'a self, client: &'b Client) -> Result<ListResponse, Error> {
581 let stream = self.stream(client);
582
583 pin_mut!(stream);
584
585 stream
586 .next()
587 .await
588 .ok_or_else(|| Error::KodikError("Empty response".to_owned()))?
589 }
590
591 /// Stream the query
592 pub fn stream(
593 &self,
594 client: &Client,
595 ) -> impl Stream<Item = Result<ListResponse, Error>> + use<> {
596 let client = client.clone();
597 let payload = serialize_into_query_parts(self);
598
599 try_fn_stream(|emitter| async move {
600 let mut next_page: Option<String> = None;
601 let payload = payload?;
602
603 loop {
604 let request_builder = if let Some(url) = &next_page {
605 client.init_post_request(url)
606 } else {
607 client.init_post_request("/list").query(&payload)
608 };
609
610 let response = request_builder.send().await.map_err(Error::HttpError);
611
612 let result = match response {
613 Ok(response) => response
614 .json::<ListResponseUnion>()
615 .await
616 .map_err(Error::HttpError),
617 Err(error) => {
618 emitter.emit_err(error).await;
619
620 continue;
621 }
622 };
623
624 match result {
625 Ok(ListResponseUnion::Result(result)) => {
626 next_page.clone_from(&result.next_page);
627
628 emitter.emit(result).await;
629 }
630 Ok(ListResponseUnion::Error { error }) => {
631 emitter.emit_err(Error::KodikError(error)).await;
632
633 continue;
634 }
635 Err(err) => {
636 emitter.emit_err(err).await;
637
638 continue;
639 }
640 };
641
642 if next_page.is_none() {
643 break;
644 }
645 }
646
647 Ok(())
648 })
649 }
650}
651
652impl<'a> Default for ListQuery<'a> {
653 fn default() -> Self {
654 Self::new()
655 }
656}