kodik_api/list.rs
1use async_fn_stream::try_fn_stream;
2use futures_util::{pin_mut, Stream, StreamExt};
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 error::Error,
7 types::{
8 AllStatus, AnimeKind, AnimeStatus, DramaStatus, MaterialDataField, MppaRating, Release,
9 ReleaseType, TranslationType,
10 },
11 util::serialize_into_query_parts,
12 Client,
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
300 pub fn with_year<'b>(&'b mut self, year: &'a [u32]) -> &'b mut ListQuery<'a> {
301 self.year = Some(year);
302 self
303 }
304
305 /// Filtering materials by translation ID
306 pub fn with_translation_id<'b>(
307 &'b mut self,
308 translation_id: &'a [u32],
309 ) -> &'b mut ListQuery<'a> {
310 self.translation_id = Some(translation_id);
311 self
312 }
313 /// Filter content by translation type. Allows you to output only voice translation or only subtitles
314 pub fn with_translation_type<'b>(
315 &'b mut self,
316 translation_type: &'a [TranslationType],
317 ) -> &'b mut ListQuery<'a> {
318 self.translation_type = Some(translation_type);
319 self
320 }
321
322 /// 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
323 pub fn with_has_field<'b>(
324 &'b mut self,
325 has_field: &'a [MaterialDataField],
326 ) -> &'b mut ListQuery<'a> {
327 self.has_field = Some(has_field);
328 self
329 }
330 /// Filtering materials based on the presence of a specific field. Materials that have all the listed fields are shown
331 pub fn with_has_field_and<'b>(
332 &'b mut self,
333 has_field: &'a [MaterialDataField],
334 ) -> &'b mut ListQuery<'a> {
335 self.has_field_and = Some(has_field);
336 self
337 }
338
339 /// 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
340 pub fn with_camrip<'b>(&'b mut self, camrip: bool) -> &'b mut ListQuery<'a> {
341 self.camrip = Some(camrip);
342 self
343 }
344 /// 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
345 pub fn with_lgbt<'b>(&'b mut self, lgbt: bool) -> &'b mut ListQuery<'a> {
346 self.lgbt = Some(lgbt);
347 self
348 }
349
350 /// 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
351 pub fn with_seasons<'b>(&'b mut self, with_seasons: bool) -> &'b mut ListQuery<'a> {
352 self.with_seasons = Some(with_seasons);
353 self
354 }
355
356 /// 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
357 pub fn with_season<'b>(&'b mut self, season: &'a [u32]) -> &'b mut ListQuery<'a> {
358 self.season = Some(season);
359 self
360 }
361
362 /// 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
363 pub fn with_episodes<'b>(&'b mut self, with_episodes: bool) -> &'b mut ListQuery<'a> {
364 self.with_episodes = Some(with_episodes);
365 self
366 }
367 /// 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
368 pub fn with_episodes_data<'b>(&'b mut self, with_episodes_data: bool) -> &'b mut ListQuery<'a> {
369 self.with_episodes_data = Some(with_episodes_data);
370 self
371 }
372
373 /// 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
374 pub fn with_page_links<'b>(&'b mut self, with_page_links: bool) -> &'b mut ListQuery<'a> {
375 self.with_page_links = Some(with_page_links);
376 self
377 }
378
379 /// Filters materials by country in which they should not be blocked. The country codes are specified separated by commas
380 pub fn with_not_blocked_in<'b>(
381 &'b mut self,
382 not_blocked_in: &'a [&'a str],
383 ) -> &'b mut ListQuery<'a> {
384 self.not_blocked_in = Some(not_blocked_in);
385 self
386 }
387 /// 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
388 pub fn with_not_blocked_for_me<'b>(
389 &'b mut self,
390 not_blocked_for_me: &'a [&'a str],
391 ) -> &'b mut ListQuery<'a> {
392 self.not_blocked_for_me = Some(not_blocked_for_me);
393 self
394 }
395 /// If you specify true, the material_data field will be added to each movie/series with information from Kinopoisk and Shikimori
396 pub fn with_material_data<'b>(&'b mut self, with_material_data: bool) -> &'b mut ListQuery<'a> {
397 self.with_material_data = Some(with_material_data);
398 self
399 }
400
401 /// 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
402 pub fn with_countries<'b>(&'b mut self, countries: &'a [&'a str]) -> &'b mut ListQuery<'a> {
403 self.countries = Some(countries);
404 self
405 }
406
407 /// 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
408 pub fn with_genres<'b>(&'b mut self, genres: &'a [&'a str]) -> &'b mut ListQuery<'a> {
409 self.genres = Some(genres);
410 self
411 }
412 /// 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
413 pub fn with_anime_genres<'b>(
414 &'b mut self,
415 anime_genres: &'a [&'a str],
416 ) -> &'b mut ListQuery<'a> {
417 self.anime_genres = Some(anime_genres);
418 self
419 }
420 /// 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
421 pub fn with_drama_genres<'b>(
422 &'b mut self,
423 drama_genres: &'a [&'a str],
424 ) -> &'b mut ListQuery<'a> {
425 self.drama_genres = Some(drama_genres);
426 self
427 }
428 /// 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
429 pub fn with_all_genres<'b>(&'b mut self, all_genres: &'a [&'a str]) -> &'b mut ListQuery<'a> {
430 self.all_genres = Some(all_genres);
431 self
432 }
433
434 /// Filtering by duration (in minutes). You can specify either a single value to search for the exact duration, or an interval.
435 pub fn with_duration<'b>(&'b mut self, duration: &'a [&'a str]) -> &'b mut ListQuery<'a> {
436 self.duration = Some(duration);
437 self
438 }
439
440 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
441 pub fn with_kinopoisk_rating<'b>(
442 &'b mut self,
443 kinopoisk_rating: &'a [&'a str],
444 ) -> &'b mut ListQuery<'a> {
445 self.kinopoisk_rating = Some(kinopoisk_rating);
446 self
447 }
448 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
449 pub fn with_imdb_rating<'b>(&'b mut self, imdb_rating: &'a [&'a str]) -> &'b mut ListQuery<'a> {
450 self.imdb_rating = Some(imdb_rating);
451 self
452 }
453 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
454 pub fn with_shikimori_rating<'b>(
455 &'b mut self,
456 shikimori_rating: &'a [&'a str],
457 ) -> &'b mut ListQuery<'a> {
458 self.shikimori_rating = Some(shikimori_rating);
459 self
460 }
461 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
462 pub fn with_mydramalist_rating<'b>(
463 &'b mut self,
464 mydramalist_rating: &'a [&'a str],
465 ) -> &'b mut ListQuery<'a> {
466 self.mydramalist_rating = Some(mydramalist_rating);
467 self
468 }
469
470 /// 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
471 pub fn with_actors<'b>(&'b mut self, actors: &'a [&'a str]) -> &'b mut ListQuery<'a> {
472 self.actors = Some(actors);
473 self
474 }
475 /// 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
476 pub fn with_directors<'b>(&'b mut self, directors: &'a [&'a str]) -> &'b mut ListQuery<'a> {
477 self.directors = Some(directors);
478 self
479 }
480 /// 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
481 pub fn with_producers<'b>(&'b mut self, producers: &'a [&'a str]) -> &'b mut ListQuery<'a> {
482 self.producers = Some(producers);
483 self
484 }
485 /// 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
486 pub fn with_writers<'b>(&'b mut self, writers: &'a [&'a str]) -> &'b mut ListQuery<'a> {
487 self.writers = Some(writers);
488 self
489 }
490 /// 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
491 pub fn with_composers<'b>(&'b mut self, composers: &'a [&'a str]) -> &'b mut ListQuery<'a> {
492 self.composers = Some(composers);
493 self
494 }
495 /// 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
496 pub fn with_editors<'b>(&'b mut self, editors: &'a [&'a str]) -> &'b mut ListQuery<'a> {
497 self.editors = Some(editors);
498 self
499 }
500 /// 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
501 pub fn with_designers<'b>(&'b mut self, designers: &'a [&'a str]) -> &'b mut ListQuery<'a> {
502 self.designers = Some(designers);
503 self
504 }
505 /// 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
506 pub fn with_operators<'b>(&'b mut self, operators: &'a [&'a str]) -> &'b mut ListQuery<'a> {
507 self.operators = Some(operators);
508 self
509 }
510
511 /// Filtering materials by age rating. You can specify a single value or multiple values, separated by commas. The parameter is case-insensitive
512 pub fn with_rating_mpaa<'b>(
513 &'b mut self,
514 rating_mpaa: &'a [MppaRating],
515 ) -> &'b mut ListQuery<'a> {
516 self.rating_mpaa = Some(rating_mpaa);
517 self
518 }
519
520 /// Filter content by the minimum age from which it can be viewed. You can specify either a single value or a range of values
521 pub fn with_minimal_age<'b>(&'b mut self, minimal_age: &'a [&'a str]) -> &'b mut ListQuery<'a> {
522 self.minimal_age = Some(minimal_age);
523 self
524 }
525
526 /// 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)
527 pub fn with_anime_kind<'b>(&'b mut self, anime_kind: &'a [AnimeKind]) -> &'b mut ListQuery<'a> {
528 self.anime_kind = Some(anime_kind);
529 self
530 }
531
532 /// 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)
533 pub fn with_mydramalist_tags<'b>(
534 &'b mut self,
535 mydramalist_tags: &'a [&'a str],
536 ) -> &'b mut ListQuery<'a> {
537 self.mydramalist_tags = Some(mydramalist_tags);
538 self
539 }
540
541 /// 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)
542 pub fn with_anime_status<'b>(
543 &'b mut self,
544 anime_status: &'a [AnimeStatus],
545 ) -> &'b mut ListQuery<'a> {
546 self.anime_status = Some(anime_status);
547 self
548 }
549 /// 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)
550 pub fn with_drama_status<'b>(
551 &'b mut self,
552 drama_status: &'a [DramaStatus],
553 ) -> &'b mut ListQuery<'a> {
554 self.drama_status = Some(drama_status);
555 self
556 }
557 /// 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)
558 pub fn with_all_status<'b>(&'b mut self, all_status: &'a [AllStatus]) -> &'b mut ListQuery<'a> {
559 self.all_status = Some(all_status);
560 self
561 }
562
563 /// 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)
564 pub fn with_anime_studios<'b>(
565 &'b mut self,
566 anime_studios: &'a [&'a str],
567 ) -> &'b mut ListQuery<'a> {
568 self.anime_studios = Some(anime_studios);
569 self
570 }
571 /// 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)
572 pub fn with_anime_licensed_by<'b>(
573 &'b mut self,
574 anime_licensed_by: &'a [&'a str],
575 ) -> &'b mut ListQuery<'a> {
576 self.anime_licensed_by = Some(anime_licensed_by);
577 self
578 }
579
580 /// Execute the query and fetch the results.
581 pub async fn execute<'b>(&'a self, client: &'b Client) -> Result<ListResponse, Error> {
582 let stream = self.stream(client);
583
584 pin_mut!(stream);
585
586 stream
587 .next()
588 .await
589 .ok_or_else(|| Error::KodikError("Empty response".to_owned()))?
590 }
591
592 /// Stream the query
593 pub fn stream(&self, client: &Client) -> impl Stream<Item = Result<ListResponse, Error>> {
594 let client = client.clone();
595 let payload = serialize_into_query_parts(self);
596
597 try_fn_stream(|emitter| async move {
598 let mut next_page: Option<String> = None;
599 let payload = payload?;
600
601 loop {
602 let request_builder = if let Some(url) = &next_page {
603 client.init_post_request(url)
604 } else {
605 client.init_post_request("/list").query(&payload)
606 };
607
608 let response = request_builder.send().await.map_err(Error::HttpError);
609
610 let result = match response {
611 Ok(response) => response
612 .json::<ListResponseUnion>()
613 .await
614 .map_err(Error::HttpError),
615 Err(error) => {
616 emitter.emit_err(error).await;
617
618 continue;
619 }
620 };
621
622 match result {
623 Ok(ListResponseUnion::Result(result)) => {
624 next_page.clone_from(&result.next_page);
625
626 emitter.emit(result).await;
627 }
628 Ok(ListResponseUnion::Error { error }) => {
629 emitter.emit_err(Error::KodikError(error)).await;
630
631 continue;
632 }
633 Err(err) => {
634 emitter.emit_err(err).await;
635
636 continue;
637 }
638 };
639
640 if next_page.is_none() {
641 break;
642 }
643 }
644
645 Ok(())
646 })
647 }
648}
649
650impl<'a> Default for ListQuery<'a> {
651 fn default() -> Self {
652 Self::new()
653 }
654}