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}