kodik_api/translations.rs
1use serde::{Deserialize, Serialize};
2
3use crate::{
4 Client,
5 error::Error,
6 types::{
7 AllStatus, AnimeKind, AnimeStatus, DramaStatus, MaterialDataField, MppaRating, ReleaseType,
8 TranslationType,
9 },
10 util::serialize_into_query_parts,
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 pub fn with_year<'b>(&'b mut self, year: &'a [u32]) -> &'b mut TranslationQuery<'a> {
215 self.year = Some(year);
216 self
217 }
218
219 /// Filter content by translation type. Allows you to output only voice translation or only subtitles
220 pub fn with_translation_type<'b>(
221 &'b mut self,
222 translation_type: &'a [TranslationType],
223 ) -> &'b mut TranslationQuery<'a> {
224 self.translation_type = Some(translation_type);
225 self
226 }
227
228 /// 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
229 pub fn with_has_field<'b>(
230 &'b mut self,
231 has_field: &'a [MaterialDataField],
232 ) -> &'b mut TranslationQuery<'a> {
233 self.has_field = Some(has_field);
234 self
235 }
236 /// Filtering materials based on the presence of a specific field. Materials that have all the listed fields are shown
237 pub fn with_has_field_and<'b>(
238 &'b mut self,
239 has_field: &'a [MaterialDataField],
240 ) -> &'b mut TranslationQuery<'a> {
241 self.has_field_and = Some(has_field);
242 self
243 }
244
245 /// 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
246 pub fn with_countries<'b>(
247 &'b mut self,
248 countries: &'a [&'a str],
249 ) -> &'b mut TranslationQuery<'a> {
250 self.countries = Some(countries);
251 self
252 }
253
254 /// 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
255 pub fn with_genres<'b>(&'b mut self, genres: &'a [&'a str]) -> &'b mut TranslationQuery<'a> {
256 self.genres = Some(genres);
257 self
258 }
259 /// 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
260 pub fn with_anime_genres<'b>(
261 &'b mut self,
262 anime_genres: &'a [&'a str],
263 ) -> &'b mut TranslationQuery<'a> {
264 self.anime_genres = Some(anime_genres);
265 self
266 }
267 /// 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
268 pub fn with_drama_genres<'b>(
269 &'b mut self,
270 drama_genres: &'a [&'a str],
271 ) -> &'b mut TranslationQuery<'a> {
272 self.drama_genres = Some(drama_genres);
273 self
274 }
275 /// 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
276 pub fn with_all_genres<'b>(
277 &'b mut self,
278 all_genres: &'a [&'a str],
279 ) -> &'b mut TranslationQuery<'a> {
280 self.all_genres = Some(all_genres);
281 self
282 }
283
284 /// Filtering by duration (in minutes). You can specify either a single value to search for the exact duration, or an interval.
285 pub fn with_duration<'b>(
286 &'b mut self,
287 duration: &'a [&'a str],
288 ) -> &'b mut TranslationQuery<'a> {
289 self.duration = Some(duration);
290 self
291 }
292
293 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
294 pub fn with_kinopoisk_rating<'b>(
295 &'b mut self,
296 kinopoisk_rating: &'a [&'a str],
297 ) -> &'b mut TranslationQuery<'a> {
298 self.kinopoisk_rating = Some(kinopoisk_rating);
299 self
300 }
301 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
302 pub fn with_imdb_rating<'b>(
303 &'b mut self,
304 imdb_rating: &'a [&'a str],
305 ) -> &'b mut TranslationQuery<'a> {
306 self.imdb_rating = Some(imdb_rating);
307 self
308 }
309 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
310 pub fn with_shikimori_rating<'b>(
311 &'b mut self,
312 shikimori_rating: &'a [&'a str],
313 ) -> &'b mut TranslationQuery<'a> {
314 self.shikimori_rating = Some(shikimori_rating);
315 self
316 }
317 /// Filtering by Kinopoisk, IMDb, Shikimori, or MyDramaList ratings. You can specify either a single value to search for the exact rating, or an interval
318 pub fn with_mydramalist_rating<'b>(
319 &'b mut self,
320 mydramalist_rating: &'a [&'a str],
321 ) -> &'b mut TranslationQuery<'a> {
322 self.mydramalist_rating = Some(mydramalist_rating);
323 self
324 }
325
326 /// 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
327 pub fn with_actors<'b>(&'b mut self, actors: &'a [&'a str]) -> &'b mut TranslationQuery<'a> {
328 self.actors = Some(actors);
329 self
330 }
331 /// 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
332 pub fn with_directors<'b>(
333 &'b mut self,
334 directors: &'a [&'a str],
335 ) -> &'b mut TranslationQuery<'a> {
336 self.directors = Some(directors);
337 self
338 }
339 /// 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
340 pub fn with_producers<'b>(
341 &'b mut self,
342 producers: &'a [&'a str],
343 ) -> &'b mut TranslationQuery<'a> {
344 self.producers = Some(producers);
345 self
346 }
347 /// 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
348 pub fn with_writers<'b>(&'b mut self, writers: &'a [&'a str]) -> &'b mut TranslationQuery<'a> {
349 self.writers = Some(writers);
350 self
351 }
352 /// 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
353 pub fn with_composers<'b>(
354 &'b mut self,
355 composers: &'a [&'a str],
356 ) -> &'b mut TranslationQuery<'a> {
357 self.composers = Some(composers);
358 self
359 }
360 /// 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
361 pub fn with_editors<'b>(&'b mut self, editors: &'a [&'a str]) -> &'b mut TranslationQuery<'a> {
362 self.editors = Some(editors);
363 self
364 }
365 /// 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
366 pub fn with_designers<'b>(
367 &'b mut self,
368 designers: &'a [&'a str],
369 ) -> &'b mut TranslationQuery<'a> {
370 self.designers = Some(designers);
371 self
372 }
373 /// 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
374 pub fn with_operators<'b>(
375 &'b mut self,
376 operators: &'a [&'a str],
377 ) -> &'b mut TranslationQuery<'a> {
378 self.operators = Some(operators);
379 self
380 }
381
382 /// Filtering materials by age rating. You can specify a single value or multiple values, separated by commas. The parameter is case-insensitive
383 pub fn with_rating_mpaa<'b>(
384 &'b mut self,
385 rating_mpaa: &'a [MppaRating],
386 ) -> &'b mut TranslationQuery<'a> {
387 self.rating_mpaa = Some(rating_mpaa);
388 self
389 }
390
391 /// Filter content by the minimum age from which it can be viewed. You can specify either a single value or a range of values
392 pub fn with_minimal_age<'b>(
393 &'b mut self,
394 minimal_age: &'a [&'a str],
395 ) -> &'b mut TranslationQuery<'a> {
396 self.minimal_age = Some(minimal_age);
397 self
398 }
399
400 /// 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)
401 pub fn with_anime_kind<'b>(
402 &'b mut self,
403 anime_kind: &'a [AnimeKind],
404 ) -> &'b mut TranslationQuery<'a> {
405 self.anime_kind = Some(anime_kind);
406 self
407 }
408
409 /// 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)
410 pub fn with_mydramalist_tags<'b>(
411 &'b mut self,
412 mydramalist_tags: &'a [&'a str],
413 ) -> &'b mut TranslationQuery<'a> {
414 self.mydramalist_tags = Some(mydramalist_tags);
415 self
416 }
417
418 /// 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)
419 pub fn with_anime_status<'b>(
420 &'b mut self,
421 anime_status: &'a [AnimeStatus],
422 ) -> &'b mut TranslationQuery<'a> {
423 self.anime_status = Some(anime_status);
424 self
425 }
426 /// 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)
427 pub fn with_drama_status<'b>(
428 &'b mut self,
429 drama_status: &'a [DramaStatus],
430 ) -> &'b mut TranslationQuery<'a> {
431 self.drama_status = Some(drama_status);
432 self
433 }
434 /// 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)
435 pub fn with_all_status<'b>(
436 &'b mut self,
437 all_status: &'a [AllStatus],
438 ) -> &'b mut TranslationQuery<'a> {
439 self.all_status = Some(all_status);
440 self
441 }
442
443 /// 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)
444 pub fn with_anime_studios<'b>(
445 &'b mut self,
446 anime_studios: &'a [&'a str],
447 ) -> &'b mut TranslationQuery<'a> {
448 self.anime_studios = Some(anime_studios);
449 self
450 }
451 /// 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)
452 pub fn with_anime_licensed_by<'b>(
453 &'b mut self,
454 anime_licensed_by: &'a [&'a str],
455 ) -> &'b mut TranslationQuery<'a> {
456 self.anime_licensed_by = Some(anime_licensed_by);
457 self
458 }
459
460 /// Execute the query and fetch the results.
461 pub async fn execute<'b>(&'a self, client: &'b Client) -> Result<TranslationResponse, Error> {
462 let payload = serialize_into_query_parts(self)?;
463
464 let response = client
465 .init_post_request("/translations/v2")
466 .query(&payload)
467 .send()
468 .await
469 .map_err(Error::HttpError)?;
470
471 let result = response
472 .json::<TranslationResponseUnion>()
473 .await
474 .map_err(Error::HttpError)?;
475
476 match result {
477 TranslationResponseUnion::Result(result) => Ok(result),
478 TranslationResponseUnion::Error { error } => Err(Error::KodikError(error)),
479 }
480 }
481}
482
483impl<'a> Default for TranslationQuery<'a> {
484 fn default() -> Self {
485 Self::new()
486 }
487}