1pub mod favorited {
6 use serde::Deserialize;
11 use trakt_core::{Pagination, PaginationResponse};
12
13 use crate::smo::{Movie, Period};
14
15 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
16 #[trakt(
17 response = Response,
18 endpoint = "/movies/favorited/{period}",
19 )]
20 pub struct Request {
21 pub period: Period,
22 #[serde(flatten)]
23 pub pagination: Pagination,
24 }
25
26 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Response)]
27 pub struct Response {
28 #[trakt(pagination)]
29 pub items: PaginationResponse<ResponseItem>,
30 }
31
32 #[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
33 pub struct ResponseItem {
34 pub user_count: usize,
35 pub movie: Movie,
36 }
37}
38
39pub mod popular {
40 use trakt_core::PaginationResponse;
44
45 use crate::smo::Movie;
46
47 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default, trakt_macros::Request)]
48 #[trakt(
49 response = Response,
50 endpoint = "/movies/popular",
51 )]
52 pub struct Request {
53 #[serde(flatten)]
54 pub pagination: trakt_core::Pagination,
55 }
56
57 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Response)]
58 pub struct Response {
59 #[trakt(pagination)]
60 pub items: PaginationResponse<Movie>,
61 }
62}
63
64pub mod trending {
65 use http::StatusCode;
69 use serde::Deserialize;
70 use trakt_core::{
71 error::FromHttpError, handle_response_body, parse_from_header, Pagination,
72 PaginationResponse,
73 };
74
75 use crate::smo::Movie;
76
77 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default, trakt_macros::Request)]
78 #[trakt(
79 response = Response,
80 endpoint = "/movies/trending",
81 )]
82 pub struct Request {
83 #[serde(flatten)]
84 pub pagination: Pagination,
85 }
86
87 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Paginated)]
88 pub struct Response {
89 #[trakt(pagination)]
90 pub items: PaginationResponse<ResponseItem>,
91 pub trending_user_count: usize,
92 }
93
94 #[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
95 pub struct ResponseItem {
96 pub watchers: usize,
97 pub movie: Movie,
98 }
99
100 impl trakt_core::Response for Response {
101 fn try_from_http_response<T: AsRef<[u8]>>(
102 response: http::Response<T>,
103 ) -> Result<Self, FromHttpError> {
104 let body: Vec<ResponseItem> = handle_response_body(&response, StatusCode::OK)?;
105
106 let items = PaginationResponse::from_headers(body, response.headers())?;
107
108 Ok(Self {
109 items,
110 trending_user_count: parse_from_header(
111 response.headers(),
112 "X-Trending-User-Count",
113 )?,
114 })
115 }
116 }
117}
118
119pub mod played {
120 use trakt_core::{Pagination, PaginationResponse};
124
125 use crate::smo::{Movie, Period};
126
127 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
128 #[trakt(
129 response = Response,
130 endpoint = "/movies/played/{period}",
131 )]
132 pub struct Request {
133 pub period: Period,
134 #[serde(flatten)]
135 pub pagination: Pagination,
136 }
137
138 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Response)]
139 pub struct Response {
140 #[trakt(pagination)]
141 pub items: PaginationResponse<ResponseItem>,
142 }
143
144 #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize)]
145 pub struct ResponseItem {
146 pub watcher_count: usize,
147 pub play_count: usize,
148 pub collected_count: usize,
149 pub movie: Movie,
150 }
151}
152
153pub mod watched {
154 use trakt_core::{Pagination, PaginationResponse};
158
159 use crate::smo::{Movie, Period};
160
161 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
162 #[trakt(
163 response = Response,
164 endpoint = "/movies/watched/{period}",
165 )]
166 pub struct Request {
167 pub period: Period,
168 #[serde(flatten)]
169 pub pagination: Pagination,
170 }
171
172 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Response)]
173 pub struct Response {
174 #[trakt(pagination)]
175 pub items: PaginationResponse<ResponseItem>,
176 }
177
178 #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize)]
179 pub struct ResponseItem {
180 pub watcher_count: usize,
181 pub play_count: usize,
182 pub collected_count: usize,
183 pub movie: Movie,
184 }
185}
186
187pub mod collected {
188 use trakt_core::{Pagination, PaginationResponse};
192
193 use crate::smo::{Movie, Period};
194
195 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
196 #[trakt(
197 response = Response,
198 endpoint = "/movies/collected/{period}",
199 )]
200 pub struct Request {
201 pub period: Period,
202 #[serde(flatten)]
203 pub pagination: Pagination,
204 }
205
206 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Response)]
207 pub struct Response {
208 #[trakt(pagination)]
209 pub items: PaginationResponse<ResponseItem>,
210 }
211
212 #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize)]
213 pub struct ResponseItem {
214 pub watcher_count: usize,
215 pub play_count: usize,
216 pub collected_count: usize,
217 pub movie: Movie,
218 }
219}
220
221pub mod anticipated {
222 use trakt_core::{Pagination, PaginationResponse};
226
227 use crate::smo::Movie;
228
229 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
230 #[trakt(
231 response = Response,
232 endpoint = "/movies/anticipated",
233 )]
234 pub struct Request {
235 #[serde(flatten)]
236 pub pagination: Pagination,
237 }
238
239 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Response)]
240 pub struct Response {
241 #[trakt(pagination)]
242 pub items: PaginationResponse<ResponseItem>,
243 }
244
245 #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize)]
246 pub struct ResponseItem {
247 pub list_count: usize,
248 pub movie: Movie,
249 }
250}
251
252pub mod boxoffice {
253 use crate::smo::Movie;
258
259 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default, trakt_macros::Request)]
260 #[trakt(
261 response = Response,
262 endpoint = "/movies/boxoffice",
263 )]
264 pub struct Request;
265
266 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Response)]
267 pub struct Response(pub Vec<ResponseItem>);
268
269 #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize)]
270 pub struct ResponseItem {
271 pub revenue: usize,
272 pub movie: Movie,
273 }
274}
275
276pub mod updates {
277 use time::OffsetDateTime;
281 use trakt_core::{Pagination, PaginationResponse};
282
283 use crate::smo::Movie;
284
285 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
286 #[trakt(
287 response = Response,
288 endpoint = "/movies/updates/{start_date}",
289 )]
290 pub struct Request {
291 #[serde(with = "time::serde::iso8601")]
292 pub start_date: OffsetDateTime,
293 #[serde(flatten)]
294 pub pagination: Pagination,
295 }
296
297 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Response)]
298 #[trakt(expected = OK)]
299 pub struct Response {
300 #[trakt(pagination)]
301 pub items: PaginationResponse<Movie>,
302 }
303}
304
305pub mod updates_id {
306 use time::OffsetDateTime;
311 use trakt_core::{Pagination, PaginationResponse};
312
313 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
314 #[trakt(
315 response = Response,
316 endpoint = "/movies/updates/id/{start_date}",
317 )]
318 pub struct Request {
319 #[serde(with = "time::serde::iso8601")]
320 pub start_date: OffsetDateTime,
321 #[serde(flatten)]
322 pub pagination: Pagination,
323 }
324
325 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Response)]
326 #[trakt(expected = OK)]
327 pub struct Response {
328 #[trakt(pagination)]
329 pub items: PaginationResponse<u32>,
330 }
331}
332
333pub mod summary {
334 use crate::smo::{Id, Movie};
339
340 #[derive(Debug, Clone, Eq, PartialEq, trakt_macros::Request)]
341 #[trakt(response = Response, endpoint = "/movies/{id}")]
342 pub struct Request {
343 pub id: Id,
344 }
345
346 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Response)]
347 pub struct Response(pub Movie);
348}
349
350pub mod aliases {
351 use serde::Deserialize;
356
357 use crate::smo::Id;
358
359 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
360 #[trakt(
361 response = Response,
362 endpoint = "/movies/{id}/aliases",
363 )]
364 pub struct Request {
365 pub id: Id,
366 }
367
368 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Response)]
369 pub struct Response(pub Vec<ResponseItem>);
370
371 #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
372 pub struct ResponseItem {
373 pub title: String,
374 pub country: String,
375 }
376}
377
378pub mod releases {
379 use serde::Deserialize;
384
385 use crate::smo::{Country, Id};
386
387 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
388 #[trakt(
389 response = Response,
390 endpoint = "/movies/{id}/releases/{country}",
391 )]
392 pub struct Request {
393 pub id: Id,
394 pub country: Country,
395 }
396
397 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Response)]
398 pub struct Response(pub Vec<ResponseItem>);
399
400 #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
401 pub struct ResponseItem {
402 pub country: Country,
403 pub certification: String,
404 pub release_date: String,
405 pub release_type: ReleaseType,
406 pub note: Option<String>,
407 }
408
409 #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
410 #[serde(rename_all = "lowercase")]
411 pub enum ReleaseType {
412 Unknown,
413 Premiere,
414 Limited,
415 Theatrical,
416 Digital,
417 Physical,
418 TV,
419 }
420}
421
422pub mod translations {
423 use serde::Deserialize;
428
429 use crate::smo::{Country, Id, Language};
430
431 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
432 #[trakt(
433 response = Response,
434 endpoint = "/movies/{id}/translations/{language}",
435 )]
436 pub struct Request {
437 pub id: Id,
438 pub language: Language,
439 }
440
441 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Response)]
442 pub struct Response(pub Vec<ResponseItem>);
443
444 #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
445 pub struct ResponseItem {
446 pub title: String,
447 pub overview: String,
448 pub tagline: String,
449 pub language: Language,
450 pub country: Country,
451 }
452}
453
454pub mod comments {
455 use trakt_core::{Pagination, PaginationResponse};
461
462 use crate::smo::{Comment, Sort};
463
464 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
465 #[trakt(
466 response = Response,
467 endpoint = "/movies/{id}/comments/{sort}",
468 auth = Optional,
469 )]
470 pub struct Request {
471 pub id: String,
472 pub sort: Sort,
473 #[serde(flatten)]
474 pub pagination: Pagination,
475 }
476
477 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Response)]
478 #[trakt(expected = OK)]
479 pub struct Response {
480 #[trakt(pagination)]
481 pub items: PaginationResponse<Comment>,
482 }
483}
484
485pub mod lists {
486 }
524
525pub mod people {
526 use serde::Deserialize;
531
532 use crate::smo::{Id, Person};
533
534 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
535 #[trakt(
536 response = Response,
537 endpoint = "/movies/{id}/people",
538 )]
539 pub struct Request {
540 pub id: Id,
541 }
542
543 #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, trakt_macros::Response)]
544 pub struct Response {
545 pub cast: Vec<Character>,
546 pub crew: Crew,
547 }
548
549 #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
550 pub struct Character {
551 pub characters: Vec<String>,
552 pub person: Person,
553 }
554
555 #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
556 pub struct Crew {
557 pub production: Vec<CrewMember>,
558 pub art: Vec<CrewMember>,
559 pub crew: Vec<CrewMember>,
560 #[serde(rename = "costume & make-up")]
561 pub costume_and_make_up: Vec<CrewMember>,
562 pub directing: Vec<CrewMember>,
563 pub writing: Vec<CrewMember>,
564 pub sound: Vec<CrewMember>,
565 pub camera: Vec<CrewMember>,
566 #[serde(rename = "visual effects")]
567 pub visual_effects: Vec<CrewMember>,
568 pub lighting: Vec<CrewMember>,
569 pub editing: Vec<CrewMember>,
570 }
571
572 #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
573 pub struct CrewMember {
574 pub jobs: Vec<String>,
575 pub person: Person,
576 }
577}
578
579pub mod ratings {
580 use serde::Deserialize;
585
586 use crate::smo::{Id, Ratings};
587
588 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
589 #[trakt(
590 response = Response,
591 endpoint = "/movies/{id}/ratings",
592 )]
593 pub struct Request {
594 pub id: Id,
595 }
596
597 #[derive(Debug, Clone, PartialEq, Deserialize, trakt_macros::Response)]
598 pub struct Response(pub Ratings);
599}
600
601pub mod related {
602 use trakt_core::PaginationResponse;
607
608 use crate::smo::{Id, Movie};
609
610 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
611 #[trakt(
612 response = Response,
613 endpoint = "/movies/{id}/related",
614 )]
615 pub struct Request {
616 pub id: Id,
617 }
618
619 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Response)]
620 #[trakt(expected = OK)]
621 pub struct Response {
622 #[trakt(pagination)]
623 pub items: PaginationResponse<Movie>,
624 }
625}
626
627pub mod stats {
628 use crate::smo::Id;
632
633 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
634 #[trakt(
635 response = Response,
636 endpoint = "/movies/{id}/stats",
637 )]
638 pub struct Request {
639 pub id: Id,
640 }
641
642 #[derive(Debug, Clone, Eq, PartialEq, Hash, serde::Deserialize, trakt_macros::Response)]
643 pub struct Response {
644 pub watchers: u32,
645 pub plays: u32,
646 pub collectors: u32,
647 pub comments: u32,
648 pub lists: u32,
649 pub votes: u32,
650 pub favorited: u32,
651 }
652}
653
654pub mod studio {
655 use crate::smo::{Id, Studio};
660
661 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
662 #[trakt(
663 response = Response,
664 endpoint = "/movies/{id}/studios",
665 )]
666 pub struct Request {
667 pub id: Id,
668 }
669
670 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Response)]
671 pub struct Response(pub Vec<Studio>);
672}
673
674pub mod watching {
675 use crate::smo::{Id, User};
679
680 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Request)]
681 #[trakt(
682 response = Response,
683 endpoint = "/movies/{id}/watching",
684 )]
685 pub struct Request {
686 pub id: Id,
687 }
688
689 #[derive(Debug, Clone, Eq, PartialEq, Hash, trakt_macros::Response)]
690 pub struct Response(pub Vec<User>);
691}
692
693#[cfg(test)]
694mod tests {
695 use httpmock::prelude::*;
696 use serde_json::json;
697 use trakt_core::{Context, PaginatedResponse, Request};
698
699 use super::*;
700
701 #[test]
702 pub fn test_popular() {
703 let server = MockServer::start();
704
705 let popular_mock = server.mock(|when, then| {
706 when.method(GET)
707 .path("/movies/popular")
708 .header("Content-Type", "application/json")
709 .header("trakt-api-key", "abc")
710 .header("trakt-api-version", "2")
711 .query_param("page", "1")
712 .query_param("limit", "10");
713 then.status(200)
714 .header("Content-Type", "application/json")
715 .header("X-Pagination-Page", "1")
716 .header("X-Pagination-Limit", "10")
717 .header("X-Pagination-Page-Count", "1")
718 .header("X-Pagination-Item-Count", "2")
719 .json_body(json!([
720 {
721 "title": "The Dark Knight",
722 "year": 2008,
723 "ids": {
724 "trakt": 16,
725 "slug": "the-dark-knight-2008",
726 "imdb": "tt0468569",
727 "tmdb": 155
728 }
729 },
730 {
731 "title": "Fight Club",
732 "year": 1999,
733 "ids": {
734 "trakt": 727,
735 "slug": "fight-club-1999",
736 "imdb": "tt0137523",
737 "tmdb": 550
738 }
739 }
740 ]));
741 });
742
743 let ctx = Context {
744 base_url: &server.base_url(),
745 client_id: "abc",
746 oauth_token: None,
747 };
748
749 let request = popular::Request::default();
750 let http_req: http::Request<Vec<u8>> = request.try_into_http_request(ctx).unwrap();
751
752 assert_eq!(
753 http_req.uri(),
754 &*format!("{}/movies/popular?page=1&limit=10", server.base_url())
755 );
756 assert_eq!(http_req.method(), http::Method::GET);
757 assert_eq!(
758 http_req.headers().get("Content-Type").unwrap(),
759 "application/json"
760 );
761 assert_eq!(http_req.headers().get("trakt-api-key").unwrap(), "abc");
762 assert_eq!(http_req.headers().get("trakt-api-version").unwrap(), "2");
763 assert_eq!(http_req.headers().get("Authorization"), None);
764 assert!(http_req.body().is_empty());
765
766 let response = crate::test::execute(ctx, request).unwrap();
767
768 assert_eq!(response.items().len(), 2);
769 assert_eq!(response.items()[0].title, "The Dark Knight");
770 assert_eq!(response.items()[0].year, 2008);
771 assert_eq!(response.items()[0].ids.trakt, Some(16));
772 assert_eq!(response.items()[1].title, "Fight Club");
773 assert_eq!(response.items()[1].year, 1999);
774 assert_eq!(response.items()[1].ids.trakt, Some(727));
775
776 assert_eq!(response.next_page(), None);
777
778 popular_mock.assert();
779 }
780}