tmdb/
themoviedb.rs

1use model::{FindResult, Movie, SearchMovie, SearchResult, TV};
2use reqwest;
3
4const BASE_URL: &str = "https://api.themoviedb.org/3";
5// const BASE_IMG_URL: &'static str = "https://image.tmdb.org/t/p/w500";
6// "https://image.tmdb.org/t/p/w700_and_h392_bestv2/gq4Z1pfOWHn3FKFNutlDCySps9C.jpg"
7
8pub trait Executable<T> {
9    fn execute(&self) -> Result<T, reqwest::Error>;
10}
11
12pub trait Search<'a> {
13    fn title(&mut self, title: &'a str) -> &mut SearchData<'a>;
14    fn year(&mut self, year: u64) -> &mut SearchData<'a>;
15}
16
17#[derive(Debug)]
18pub struct SearchData<'a> {
19    pub tmdb: TMDb,
20    pub title: Option<&'a str>,
21    pub year: Option<u64>,
22}
23
24impl<'a> Search<'a> for SearchData<'a> {
25    fn title(&mut self, title: &'a str) -> &mut SearchData<'a> {
26        self.title = Some(title);
27        self
28    }
29
30    fn year(&mut self, year: u64) -> &mut SearchData<'a> {
31        self.year = Some(year);
32        self
33    }
34}
35
36impl<'a> Executable<SearchResult> for SearchData<'a> {
37    fn execute(&self) -> Result<SearchResult, reqwest::Error> {
38        let url: String = match self.year {
39            None => format!(
40                "{}/search/movie?api_key={}&language={}&query={}&append_to_response=images",
41                BASE_URL,
42                self.tmdb.api_key,
43                self.tmdb.language,
44                self.title.unwrap()
45            ),
46            Some(year) => format!(
47                "{}/search/movie?api_key={}&language={}&query={}&year={}&append_to_response=images",
48                BASE_URL,
49                self.tmdb.api_key,
50                self.tmdb.language,
51                self.title.unwrap(),
52                year
53            ),
54        };
55
56        reqwest::get(&url)?.json()
57    }
58}
59
60pub enum Appendable {
61    Videos,
62    Credits,
63}
64
65pub trait Fetch {
66    fn id(&mut self, id: u64) -> &mut FetchData;
67    fn append_videos(&mut self) -> &mut FetchData;
68    fn append_credits(&mut self) -> &mut FetchData;
69}
70
71pub struct FetchData {
72    pub tmdb: TMDb,
73    pub id: Option<u64>,
74    pub append_to_response: Vec<Appendable>,
75}
76
77impl Fetch for FetchData {
78    fn id(&mut self, id: u64) -> &mut FetchData {
79        self.id = Some(id);
80        self
81    }
82
83    fn append_videos(&mut self) -> &mut FetchData {
84        self.append_to_response.push(Appendable::Videos);
85        self
86    }
87
88    fn append_credits(&mut self) -> &mut FetchData {
89        self.append_to_response.push(Appendable::Credits);
90        self
91    }
92}
93
94impl Executable<Movie> for FetchData {
95    fn execute(&self) -> Result<Movie, reqwest::Error> {
96        let mut url: String = format!(
97            "{}/movie/{}?api_key={}&language={}",
98            BASE_URL,
99            self.id.unwrap(),
100            self.tmdb.api_key,
101            self.tmdb.language
102        );
103
104        if !self.append_to_response.is_empty() {
105            url.push_str("&append_to_response=");
106            for appendable in &self.append_to_response {
107                match appendable {
108                    Appendable::Videos => url.push_str("videos,"),
109                    Appendable::Credits => url.push_str("credits,"),
110                }
111            }
112        }
113
114        reqwest::get(&url)?.json()
115    }
116}
117
118impl Executable<TV> for FetchData {
119    fn execute(&self) -> Result<TV, reqwest::Error> {
120        let mut url: String = format!(
121            "{}/tv/{}?api_key={}&language={}",
122            BASE_URL,
123            self.id.unwrap(),
124            self.tmdb.api_key,
125            self.tmdb.language
126        );
127
128        if !self.append_to_response.is_empty() {
129            url.push_str("&append_to_response=");
130            for appendable in &self.append_to_response {
131                match appendable {
132                    Appendable::Videos => url.push_str("videos,"),
133                    Appendable::Credits => url.push_str("credits,"),
134                }
135            }
136        }
137
138        reqwest::get(&url)?.json()
139    }
140}
141
142pub trait Find<'a> {
143    fn imdb_id(&mut self, imdb_id: &'a str) -> &mut FindData<'a>;
144}
145
146pub struct FindData<'a> {
147    pub tmdb: TMDb,
148    pub imdb_id: Option<&'a str>,
149}
150
151impl<'a> Find<'a> for FindData<'a> {
152    fn imdb_id(&mut self, imdb_id: &'a str) -> &mut FindData<'a> {
153        self.imdb_id = Some(imdb_id);
154        self
155    }
156}
157
158impl<'a> Executable<FindResult> for FindData<'a> {
159    fn execute(&self) -> Result<FindResult, reqwest::Error> {
160        let url = format!(
161            "{}/find/{}?api_key={}&external_source=imdb_id&language={}&append_to_response=images",
162            BASE_URL,
163            self.imdb_id.unwrap(),
164            self.tmdb.api_key,
165            self.tmdb.language
166        );
167        reqwest::get(&url)?.json()
168    }
169}
170
171pub trait TMDbApi {
172    fn search(&self) -> SearchData;
173    fn fetch(&self) -> FetchData;
174    fn find(&self) -> FindData;
175}
176
177#[derive(Debug, Clone)]
178pub struct TMDb {
179    pub api_key: &'static str,
180    pub language: &'static str,
181}
182
183impl TMDbApi for TMDb {
184    fn search(&self) -> SearchData {
185        let tmdb = self.clone();
186        SearchData {
187            tmdb,
188            title: None,
189            year: None,
190        }
191    }
192
193    fn fetch(&self) -> FetchData {
194        let tmdb = self.clone();
195        FetchData {
196            tmdb,
197            id: None,
198            append_to_response: vec![],
199        }
200    }
201
202    fn find(&self) -> FindData {
203        let tmdb = self.clone();
204        FindData {
205            tmdb,
206            imdb_id: None,
207        }
208    }
209}
210
211pub trait Fetchable {
212    fn fetch(&self, tmdb: &TMDb) -> Result<Movie, reqwest::Error>;
213}
214
215impl Fetchable for SearchMovie {
216    fn fetch(&self, tmdb: &TMDb) -> Result<Movie, reqwest::Error> {
217        tmdb.fetch().id(self.id).execute()
218    }
219}