kodik_api/
translations.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    error::Error,
5    types::{
6        AllStatus, AnimeKind, AnimeStatus, DramaStatus, MaterialDataField, MppaRating, ReleaseType,
7        TranslationType,
8    },
9    util::serialize_into_query_parts,
10    Client,
11};
12
13#[derive(Serialize, Deserialize, Debug, Clone)]
14pub struct TranslationResult {
15    pub id: i32,
16
17    /// Name of the translation team
18    pub title: String,
19
20    /// The number of materials with this voice acting
21    pub count: i32,
22}
23
24/// A struct containing translations results and other information about the translations
25#[derive(Deserialize, Debug, Clone)]
26pub struct TranslationResponse {
27    pub time: String,
28    pub total: i32,
29    pub prev_page: Option<String>,
30    pub next_page: Option<String>,
31    pub results: Vec<TranslationResult>,
32}
33
34/// A struct containing search results and other information about the search
35#[derive(Deserialize, Debug, Clone)]
36#[serde(untagged)]
37enum TranslationResponseUnion {
38    Result(TranslationResponse),
39    Error { error: String },
40}
41
42#[derive(Serialize, Deserialize, Debug, Clone)]
43pub enum TranslationSort {
44    #[serde(rename = "title")]
45    Title,
46    #[serde(rename = "count")]
47    Count,
48}
49
50#[derive(Debug, Serialize, Clone)]
51pub struct TranslationQuery<'a> {
52    /// What field to sort materials by
53    #[serde(skip_serializing_if = "Option::is_none")]
54    sort: Option<TranslationSort>,
55
56    /// Maximum number of outputs
57    #[serde(skip_serializing_if = "Option::is_none")]
58    types: Option<&'a [ReleaseType]>,
59
60    ///Filter materials by year If you set this parameter, only materials of the corresponding year will be displayed
61    #[serde(skip_serializing_if = "Option::is_none")]
62    year: Option<&'a [u32]>,
63
64    /// Filter content by translation type. Allows you to output only voice translation or only subtitles
65    #[serde(skip_serializing_if = "Option::is_none")]
66    translation_type: Option<&'a [TranslationType]>,
67
68    /// 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
69    #[serde(skip_serializing_if = "Option::is_none")]
70    has_field: Option<&'a [MaterialDataField]>,
71    /// Filtering materials based on the presence of a specific field. Materials that have all the listed fields are shown
72    #[serde(skip_serializing_if = "Option::is_none")]
73    has_field_and: Option<&'a [MaterialDataField]>,
74
75    /// 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
76    #[serde(skip_serializing_if = "Option::is_none")]
77    countries: Option<&'a [&'a str]>,
78
79    /// 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
80    #[serde(skip_serializing_if = "Option::is_none")]
81    genres: Option<&'a [&'a str]>,
82    /// 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
83    #[serde(skip_serializing_if = "Option::is_none")]
84    anime_genres: Option<&'a [&'a str]>,
85    /// 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
86    #[serde(skip_serializing_if = "Option::is_none")]
87    drama_genres: Option<&'a [&'a str]>,
88    /// 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
89    #[serde(skip_serializing_if = "Option::is_none")]
90    all_genres: Option<&'a [&'a str]>,
91
92    /// Filtering by duration (in minutes). You can specify either a single value to search for the exact duration, or an interval.
93    #[serde(skip_serializing_if = "Option::is_none")]
94    duration: Option<&'a [&'a str]>,
95
96    /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
97    #[serde(skip_serializing_if = "Option::is_none")]
98    kinopoisk_rating: Option<&'a [&'a str]>,
99    /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
100    #[serde(skip_serializing_if = "Option::is_none")]
101    imdb_rating: Option<&'a [&'a str]>,
102    /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
103    #[serde(skip_serializing_if = "Option::is_none")]
104    shikimori_rating: Option<&'a [&'a str]>,
105    /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
106    #[serde(skip_serializing_if = "Option::is_none")]
107    mydramalist_rating: Option<&'a [&'a str]>,
108
109    /// 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
110    #[serde(skip_serializing_if = "Option::is_none")]
111    actors: Option<&'a [&'a str]>,
112    /// 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
113    #[serde(skip_serializing_if = "Option::is_none")]
114    directors: Option<&'a [&'a str]>,
115    /// 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
116    #[serde(skip_serializing_if = "Option::is_none")]
117    producers: Option<&'a [&'a str]>,
118    /// 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
119    #[serde(skip_serializing_if = "Option::is_none")]
120    writers: Option<&'a [&'a str]>,
121    /// 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
122    #[serde(skip_serializing_if = "Option::is_none")]
123    composers: Option<&'a [&'a str]>,
124    /// 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
125    #[serde(skip_serializing_if = "Option::is_none")]
126    editors: Option<&'a [&'a str]>,
127    /// 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
128    #[serde(skip_serializing_if = "Option::is_none")]
129    designers: Option<&'a [&'a str]>,
130    /// 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
131    #[serde(skip_serializing_if = "Option::is_none")]
132    operators: Option<&'a [&'a str]>,
133
134    /// Filtering materials by age rating. You can specify a single value or multiple values, separated by commas. The parameter is case-insensitive
135    #[serde(skip_serializing_if = "Option::is_none")]
136    rating_mpaa: Option<&'a [MppaRating]>,
137
138    /// Filter content by the minimum age from which it can be viewed. You can specify either a single value or a range of values
139    #[serde(skip_serializing_if = "Option::is_none")]
140    minimal_age: Option<&'a [&'a str]>,
141
142    /// 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)
143    #[serde(skip_serializing_if = "Option::is_none")]
144    anime_kind: Option<&'a [AnimeKind]>,
145
146    /// 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)
147    #[serde(skip_serializing_if = "Option::is_none")]
148    mydramalist_tags: Option<&'a [&'a str]>,
149
150    /// 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)
151    #[serde(skip_serializing_if = "Option::is_none")]
152    anime_status: Option<&'a [AnimeStatus]>,
153    /// 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)
154    #[serde(skip_serializing_if = "Option::is_none")]
155    drama_status: Option<&'a [DramaStatus]>,
156    /// 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)
157    #[serde(skip_serializing_if = "Option::is_none")]
158    all_status: Option<&'a [AllStatus]>,
159
160    /// 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)
161    #[serde(skip_serializing_if = "Option::is_none")]
162    anime_studios: Option<&'a [&'a str]>,
163    /// 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)
164    #[serde(skip_serializing_if = "Option::is_none")]
165    anime_licensed_by: Option<&'a [&'a str]>,
166}
167
168impl<'a> TranslationQuery<'a> {
169    pub fn new() -> TranslationQuery<'a> {
170        TranslationQuery {
171            sort: None,
172            types: None,
173            year: None,
174            translation_type: None,
175            has_field: None,
176            has_field_and: None,
177            countries: None,
178            genres: None,
179            anime_genres: None,
180            drama_genres: None,
181            all_genres: None,
182            duration: None,
183            kinopoisk_rating: None,
184            imdb_rating: None,
185            shikimori_rating: None,
186            mydramalist_rating: None,
187            actors: None,
188            directors: None,
189            producers: None,
190            writers: None,
191            composers: None,
192            editors: None,
193            designers: None,
194            operators: None,
195            rating_mpaa: None,
196            minimal_age: None,
197            anime_kind: None,
198            mydramalist_tags: None,
199            anime_status: None,
200            drama_status: None,
201            all_status: None,
202            anime_studios: None,
203            anime_licensed_by: None,
204        }
205    }
206
207    /// Maximum number of outputs
208    pub fn with_types<'b>(&'b mut self, types: &'a [ReleaseType]) -> &'b mut TranslationQuery<'a> {
209        self.types = Some(types);
210        self
211    }
212
213    ///Filter materials by year If you set this parameter, only materials of the corresponding year will be displayed
214
215    pub fn with_year<'b>(&'b mut self, year: &'a [u32]) -> &'b mut TranslationQuery<'a> {
216        self.year = Some(year);
217        self
218    }
219
220    /// Filter content by translation type. Allows you to output only voice translation or only subtitles
221    pub fn with_translation_type<'b>(
222        &'b mut self,
223        translation_type: &'a [TranslationType],
224    ) -> &'b mut TranslationQuery<'a> {
225        self.translation_type = Some(translation_type);
226        self
227    }
228
229    /// 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
230    pub fn with_has_field<'b>(
231        &'b mut self,
232        has_field: &'a [MaterialDataField],
233    ) -> &'b mut TranslationQuery<'a> {
234        self.has_field = Some(has_field);
235        self
236    }
237    /// Filtering materials based on the presence of a specific field. Materials that have all the listed fields are shown
238    pub fn with_has_field_and<'b>(
239        &'b mut self,
240        has_field: &'a [MaterialDataField],
241    ) -> &'b mut TranslationQuery<'a> {
242        self.has_field_and = Some(has_field);
243        self
244    }
245
246    /// 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
247    pub fn with_countries<'b>(
248        &'b mut self,
249        countries: &'a [&'a str],
250    ) -> &'b mut TranslationQuery<'a> {
251        self.countries = Some(countries);
252        self
253    }
254
255    /// 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
256    pub fn with_genres<'b>(&'b mut self, genres: &'a [&'a str]) -> &'b mut TranslationQuery<'a> {
257        self.genres = Some(genres);
258        self
259    }
260    /// 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
261    pub fn with_anime_genres<'b>(
262        &'b mut self,
263        anime_genres: &'a [&'a str],
264    ) -> &'b mut TranslationQuery<'a> {
265        self.anime_genres = Some(anime_genres);
266        self
267    }
268    /// 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
269    pub fn with_drama_genres<'b>(
270        &'b mut self,
271        drama_genres: &'a [&'a str],
272    ) -> &'b mut TranslationQuery<'a> {
273        self.drama_genres = Some(drama_genres);
274        self
275    }
276    /// 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
277    pub fn with_all_genres<'b>(
278        &'b mut self,
279        all_genres: &'a [&'a str],
280    ) -> &'b mut TranslationQuery<'a> {
281        self.all_genres = Some(all_genres);
282        self
283    }
284
285    /// Filtering by duration (in minutes). You can specify either a single value to search for the exact duration, or an interval.
286    pub fn with_duration<'b>(
287        &'b mut self,
288        duration: &'a [&'a str],
289    ) -> &'b mut TranslationQuery<'a> {
290        self.duration = Some(duration);
291        self
292    }
293
294    /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
295    pub fn with_kinopoisk_rating<'b>(
296        &'b mut self,
297        kinopoisk_rating: &'a [&'a str],
298    ) -> &'b mut TranslationQuery<'a> {
299        self.kinopoisk_rating = Some(kinopoisk_rating);
300        self
301    }
302    /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
303    pub fn with_imdb_rating<'b>(
304        &'b mut self,
305        imdb_rating: &'a [&'a str],
306    ) -> &'b mut TranslationQuery<'a> {
307        self.imdb_rating = Some(imdb_rating);
308        self
309    }
310    /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
311    pub fn with_shikimori_rating<'b>(
312        &'b mut self,
313        shikimori_rating: &'a [&'a str],
314    ) -> &'b mut TranslationQuery<'a> {
315        self.shikimori_rating = Some(shikimori_rating);
316        self
317    }
318    /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
319    pub fn with_mydramalist_rating<'b>(
320        &'b mut self,
321        mydramalist_rating: &'a [&'a str],
322    ) -> &'b mut TranslationQuery<'a> {
323        self.mydramalist_rating = Some(mydramalist_rating);
324        self
325    }
326
327    /// 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
328    pub fn with_actors<'b>(&'b mut self, actors: &'a [&'a str]) -> &'b mut TranslationQuery<'a> {
329        self.actors = Some(actors);
330        self
331    }
332    /// 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
333    pub fn with_directors<'b>(
334        &'b mut self,
335        directors: &'a [&'a str],
336    ) -> &'b mut TranslationQuery<'a> {
337        self.directors = Some(directors);
338        self
339    }
340    /// 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
341    pub fn with_producers<'b>(
342        &'b mut self,
343        producers: &'a [&'a str],
344    ) -> &'b mut TranslationQuery<'a> {
345        self.producers = Some(producers);
346        self
347    }
348    /// 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
349    pub fn with_writers<'b>(&'b mut self, writers: &'a [&'a str]) -> &'b mut TranslationQuery<'a> {
350        self.writers = Some(writers);
351        self
352    }
353    /// 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
354    pub fn with_composers<'b>(
355        &'b mut self,
356        composers: &'a [&'a str],
357    ) -> &'b mut TranslationQuery<'a> {
358        self.composers = Some(composers);
359        self
360    }
361    /// 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
362    pub fn with_editors<'b>(&'b mut self, editors: &'a [&'a str]) -> &'b mut TranslationQuery<'a> {
363        self.editors = Some(editors);
364        self
365    }
366    /// 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
367    pub fn with_designers<'b>(
368        &'b mut self,
369        designers: &'a [&'a str],
370    ) -> &'b mut TranslationQuery<'a> {
371        self.designers = Some(designers);
372        self
373    }
374    /// 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
375    pub fn with_operators<'b>(
376        &'b mut self,
377        operators: &'a [&'a str],
378    ) -> &'b mut TranslationQuery<'a> {
379        self.operators = Some(operators);
380        self
381    }
382
383    /// Filtering materials by age rating. You can specify a single value or multiple values, separated by commas. The parameter is case-insensitive
384    pub fn with_rating_mpaa<'b>(
385        &'b mut self,
386        rating_mpaa: &'a [MppaRating],
387    ) -> &'b mut TranslationQuery<'a> {
388        self.rating_mpaa = Some(rating_mpaa);
389        self
390    }
391
392    /// Filter content by the minimum age from which it can be viewed. You can specify either a single value or a range of values
393    pub fn with_minimal_age<'b>(
394        &'b mut self,
395        minimal_age: &'a [&'a str],
396    ) -> &'b mut TranslationQuery<'a> {
397        self.minimal_age = Some(minimal_age);
398        self
399    }
400
401    /// 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)
402    pub fn with_anime_kind<'b>(
403        &'b mut self,
404        anime_kind: &'a [AnimeKind],
405    ) -> &'b mut TranslationQuery<'a> {
406        self.anime_kind = Some(anime_kind);
407        self
408    }
409
410    /// 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)
411    pub fn with_mydramalist_tags<'b>(
412        &'b mut self,
413        mydramalist_tags: &'a [&'a str],
414    ) -> &'b mut TranslationQuery<'a> {
415        self.mydramalist_tags = Some(mydramalist_tags);
416        self
417    }
418
419    /// 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)
420    pub fn with_anime_status<'b>(
421        &'b mut self,
422        anime_status: &'a [AnimeStatus],
423    ) -> &'b mut TranslationQuery<'a> {
424        self.anime_status = Some(anime_status);
425        self
426    }
427    /// 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)
428    pub fn with_drama_status<'b>(
429        &'b mut self,
430        drama_status: &'a [DramaStatus],
431    ) -> &'b mut TranslationQuery<'a> {
432        self.drama_status = Some(drama_status);
433        self
434    }
435    /// 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)
436    pub fn with_all_status<'b>(
437        &'b mut self,
438        all_status: &'a [AllStatus],
439    ) -> &'b mut TranslationQuery<'a> {
440        self.all_status = Some(all_status);
441        self
442    }
443
444    /// 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)
445    pub fn with_anime_studios<'b>(
446        &'b mut self,
447        anime_studios: &'a [&'a str],
448    ) -> &'b mut TranslationQuery<'a> {
449        self.anime_studios = Some(anime_studios);
450        self
451    }
452    /// 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)
453    pub fn with_anime_licensed_by<'b>(
454        &'b mut self,
455        anime_licensed_by: &'a [&'a str],
456    ) -> &'b mut TranslationQuery<'a> {
457        self.anime_licensed_by = Some(anime_licensed_by);
458        self
459    }
460
461    /// Execute the query and fetch the results.
462    pub async fn execute<'b>(&'a self, client: &'b Client) -> Result<TranslationResponse, Error> {
463        let payload = serialize_into_query_parts(self)?;
464
465        let response = client
466            .init_post_request("/translations/v2")
467            .query(&payload)
468            .send()
469            .await
470            .map_err(Error::HttpError)?;
471
472        let result = response
473            .json::<TranslationResponseUnion>()
474            .await
475            .map_err(Error::HttpError)?;
476
477        match result {
478            TranslationResponseUnion::Result(result) => Ok(result),
479            TranslationResponseUnion::Error { error } => Err(Error::KodikError(error)),
480        }
481    }
482}
483
484impl<'a> Default for TranslationQuery<'a> {
485    fn default() -> Self {
486        Self::new()
487    }
488}