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}