tmdb_api/watch_provider/
list.rs

1use std::borrow::Cow;
2use std::collections::HashMap;
3
4use crate::client::Executor;
5use crate::common::Results;
6
7use super::WatchProvider;
8
9#[derive(Debug, Default, serde::Serialize)]
10pub struct Params<'a> {
11    /// ISO 3166-1 alpha-2 value to filter the results for one country.
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub watch_region: Option<Cow<'a, str>>,
14    /// ISO 639-1 value to display translated data for the fields that support it.
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub language: Option<Cow<'a, str>>,
17}
18
19impl<'a> Params<'a> {
20    pub fn set_watch_region(&mut self, value: impl Into<Cow<'a, str>>) {
21        self.watch_region = Some(value.into());
22    }
23
24    pub fn with_watch_region(mut self, value: impl Into<Cow<'a, str>>) -> Self {
25        self.set_watch_region(value);
26        self
27    }
28
29    pub fn set_language(&mut self, value: impl Into<Cow<'a, str>>) {
30        self.language = Some(value.into());
31    }
32
33    pub fn with_language(mut self, value: impl Into<Cow<'a, str>>) -> Self {
34        self.set_language(value);
35        self
36    }
37}
38
39#[derive(Clone, Debug, Deserialize, Serialize)]
40pub struct WatchProviderDetail {
41    /// A hash map of display priority by country code
42    pub display_priorities: HashMap<String, u64>,
43    #[serde(flatten)]
44    pub inner: WatchProvider,
45}
46
47impl<E: Executor> crate::Client<E> {
48    /// List watch providers for movies
49    ///
50    /// ```rust
51    /// use tmdb_api::Client;
52    /// use tmdb_api::client::reqwest::Client as ReqwestClient;
53    ///
54    /// #[tokio::main]
55    /// async fn main() {
56    ///     let client = Client::<ReqwestClient>::new("this-is-my-secret-token".into());
57    ///     match client.list_movie_watch_providers(&Default::default()).await {
58    ///         Ok(res) => println!("found: {:#?}", res),
59    ///         Err(err) => eprintln!("error: {:?}", err),
60    ///     };
61    /// }
62    /// ```
63    pub async fn list_movie_watch_providers(
64        &self,
65        params: &Params<'_>,
66    ) -> crate::Result<Results<Vec<WatchProviderDetail>>> {
67        self.execute("/watch/providers/movie", params).await
68    }
69
70    /// List watch providers for tvshows
71    ///
72    /// ```rust
73    /// use tmdb_api::Client;
74    /// use tmdb_api::client::reqwest::Client as ReqwestClient;
75    ///
76    /// #[tokio::main]
77    /// async fn main() {
78    ///     let client = Client::<ReqwestClient>::new("this-is-my-secret-token".into());
79    ///     match client.list_movie_watch_providers(&Default::default()).await {
80    ///         Ok(res) => println!("found: {:#?}", res),
81    ///         Err(err) => eprintln!("error: {:?}", err),
82    ///     };
83    /// }
84    /// ```
85    pub async fn list_tvshow_watch_providers(
86        &self,
87        params: &Params<'_>,
88    ) -> crate::Result<Results<Vec<WatchProviderDetail>>> {
89        self.execute("/watch/providers/tv", params).await
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use mockito::Matcher;
96
97    use crate::client::Client;
98    use crate::client::reqwest::Client as ReqwestClient;
99
100    #[tokio::test]
101    async fn movie_works() {
102        let mut server = mockito::Server::new_async().await;
103        let _m = server
104            .mock("GET", "/watch/providers/movie")
105            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
106            .with_status(200)
107            .with_header("content-type", "application/json")
108            .with_body(include_str!("../../assets/watch-provider-movie-list.json"))
109            .create_async()
110            .await;
111        let client = Client::<ReqwestClient>::builder()
112            .with_api_key("secret".into())
113            .with_base_url(server.url())
114            .build()
115            .unwrap();
116        let result = client
117            .list_movie_watch_providers(&Default::default())
118            .await
119            .unwrap();
120        assert!(!result.results.is_empty());
121    }
122
123    #[tokio::test]
124    async fn tv_works() {
125        let mut server = mockito::Server::new_async().await;
126        let _m = server
127            .mock("GET", "/watch/providers/tv")
128            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
129            .with_status(200)
130            .with_header("content-type", "application/json")
131            .with_body(include_str!("../../assets/watch-provider-tv-list.json"))
132            .create_async()
133            .await;
134
135        let client = Client::<ReqwestClient>::builder()
136            .with_api_key("secret".into())
137            .with_base_url(server.url())
138            .build()
139            .unwrap();
140        let result = client
141            .list_tvshow_watch_providers(&Default::default())
142            .await
143            .unwrap();
144        assert!(!result.results.is_empty());
145    }
146
147    #[tokio::test]
148    async fn invalid_api_key() {
149        let mut server = mockito::Server::new_async().await;
150        let _m = server
151            .mock("GET", "/watch/providers/tv")
152            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
153            .with_status(401)
154            .with_header("content-type", "application/json")
155            .with_body(include_str!("../../assets/invalid-api-key.json"))
156            .create_async()
157            .await;
158
159        let client = Client::<ReqwestClient>::builder()
160            .with_api_key("secret".into())
161            .with_base_url(server.url())
162            .build()
163            .unwrap();
164        let err = client
165            .list_tvshow_watch_providers(&Default::default())
166            .await
167            .unwrap_err();
168        let server_err = err.as_server_error().unwrap();
169        assert_eq!(server_err.status_code, 7);
170    }
171
172    #[tokio::test]
173    async fn resource_not_found() {
174        let mut server = mockito::Server::new_async().await;
175        let _m = server
176            .mock("GET", "/watch/providers/tv")
177            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
178            .with_status(404)
179            .with_header("content-type", "application/json")
180            .with_body(include_str!("../../assets/resource-not-found.json"))
181            .create_async()
182            .await;
183        let client = Client::<ReqwestClient>::builder()
184            .with_api_key("secret".into())
185            .with_base_url(server.url())
186            .build()
187            .unwrap();
188        let err = client
189            .list_tvshow_watch_providers(&Default::default())
190            .await
191            .unwrap_err();
192        let server_err = err.as_server_error().unwrap();
193        assert_eq!(server_err.status_code, 34);
194    }
195}
196
197#[cfg(all(test, feature = "integration"))]
198mod integration_tests {
199    use super::Params;
200    use crate::client::Client;
201    use crate::client::reqwest::Client as ReqwestClient;
202
203    #[tokio::test]
204    async fn execute_tv() {
205        let secret = std::env::var("TMDB_TOKEN_V3").unwrap();
206        let client = Client::<ReqwestClient>::new(secret);
207        let params = Params::default().with_language("en-US");
208        let result = client.list_tvshow_watch_providers(&params).await.unwrap();
209        assert!(!result.results.is_empty());
210    }
211
212    #[tokio::test]
213    async fn execute_movie() {
214        let secret = std::env::var("TMDB_TOKEN_V3").unwrap();
215        let client = Client::<ReqwestClient>::new(secret);
216        let params = Params::default().with_language("en-US");
217        let result = client.list_movie_watch_providers(&params).await.unwrap();
218        assert!(!result.results.is_empty());
219    }
220}