1use model::{FindResult, Movie, SearchMovie, SearchResult, TV};
2use reqwest;
3
4const BASE_URL: &str = "https://api.themoviedb.org/3";
5pub 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}