1use super::{
2 AuthToken, PostMethod, PostQuery, Query, SEARCH_QUERY_PATH,
3 SPECIALIZED_PLAYLIST_EXACT_MATCH_PARAMS, SPECIALIZED_PLAYLIST_PREFIX_PARAMS,
4 SPECIALIZED_PLAYLIST_WITH_SUGGESTIONS_PARAMS, SearchQuery, SearchType, SpellingMode,
5 search_query_header,
6};
7use crate::parse::{
8 SearchResultAlbum, SearchResultArtist, SearchResultEpisode, SearchResultFeaturedPlaylist,
9 SearchResultPlaylist, SearchResultPodcast, SearchResultProfile, SearchResultSong,
10 SearchResultVideo,
11};
12use std::borrow::Cow;
13
14pub trait FilteredSearchType: Default {
19 fn filtered_param_bits(&self) -> Cow<'_, str>;
20 fn filtered_spelling_param(&self, spelling_mode: &SpellingMode) -> Cow<'_, str> {
23 match spelling_mode {
24 SpellingMode::ExactMatch => "AWoMEA4QChADEAQQCRAF".into(),
25 SpellingMode::WithSuggestions => "AUICCAFqDBAOEAoQAxAEEAkQBQ%3D%3D".into(),
26 }
27 }
28 fn filtered_prefix_param(&self) -> Cow<'_, str> {
31 "EgWKAQ".into()
32 }
33}
34#[derive(Default, Debug, Clone, PartialEq)]
36pub struct FilteredSearch<F: FilteredSearchType> {
37 pub(crate) filter: F,
38}
39#[derive(Default, PartialEq, Debug, Clone)]
41pub struct SongsFilter;
42#[derive(Default, PartialEq, Debug, Clone)]
44pub struct VideosFilter;
45#[derive(Default, PartialEq, Debug, Clone)]
47pub struct AlbumsFilter;
48#[derive(Default, PartialEq, Debug, Clone)]
50pub struct ArtistsFilter;
51#[derive(Default, PartialEq, Debug, Clone)]
53pub struct PlaylistsFilter;
54#[derive(Default, PartialEq, Debug, Clone)]
56pub struct CommunityPlaylistsFilter;
57#[derive(Default, PartialEq, Debug, Clone)]
59pub struct FeaturedPlaylistsFilter;
60#[derive(Default, PartialEq, Debug, Clone)]
62pub struct EpisodesFilter;
63#[derive(Default, PartialEq, Debug, Clone)]
65pub struct PodcastsFilter;
66#[derive(Default, PartialEq, Debug, Clone)]
68pub struct ProfilesFilter;
69
70impl<F: FilteredSearchType> SearchType for FilteredSearch<F> {
71 fn specialised_params(&self, spelling_mode: &SpellingMode) -> Option<Cow<'_, str>> {
72 Some(
73 format!(
74 "{}{}{}",
75 self.filter.filtered_prefix_param(),
76 self.filter.filtered_param_bits(),
77 self.filter.filtered_spelling_param(spelling_mode),
78 )
79 .into(),
80 )
81 }
82}
83
84impl FilteredSearchType for SongsFilter {
86 fn filtered_param_bits(&self) -> Cow<'_, str> {
87 "II".into()
88 }
89}
90impl FilteredSearchType for VideosFilter {
91 fn filtered_param_bits(&self) -> Cow<'_, str> {
92 "IQ".into()
93 }
94}
95impl FilteredSearchType for AlbumsFilter {
96 fn filtered_param_bits(&self) -> Cow<'_, str> {
97 "IY".into()
98 }
99}
100impl FilteredSearchType for ArtistsFilter {
101 fn filtered_param_bits(&self) -> Cow<'_, str> {
102 "Ig".into()
103 }
104}
105impl FilteredSearchType for PlaylistsFilter {
106 fn filtered_param_bits(&self) -> Cow<'_, str> {
107 "".into()
109 }
110 fn filtered_spelling_param(&self, spelling_mode: &SpellingMode) -> Cow<'_, str> {
111 match spelling_mode {
112 SpellingMode::ExactMatch => "MABCAggBagoQBBADEAkQBRAK",
113 SpellingMode::WithSuggestions => "MABqChAEEAMQCRAFEAo%3D",
114 }
115 .into()
116 }
117 fn filtered_prefix_param(&self) -> Cow<'_, str> {
118 "Eg-KAQwIABAAGAAgACgB".into()
119 }
120}
121impl FilteredSearchType for CommunityPlaylistsFilter {
122 fn filtered_param_bits(&self) -> Cow<'_, str> {
123 "EA".into()
124 }
125 fn filtered_spelling_param(&self, spelling_mode: &SpellingMode) -> Cow<'_, str> {
126 match spelling_mode {
127 SpellingMode::ExactMatch => SPECIALIZED_PLAYLIST_EXACT_MATCH_PARAMS,
128 SpellingMode::WithSuggestions => SPECIALIZED_PLAYLIST_WITH_SUGGESTIONS_PARAMS,
129 }
130 .into()
131 }
132 fn filtered_prefix_param(&self) -> Cow<'_, str> {
133 SPECIALIZED_PLAYLIST_PREFIX_PARAMS.into()
134 }
135}
136impl FilteredSearchType for FeaturedPlaylistsFilter {
137 fn filtered_param_bits(&self) -> Cow<'_, str> {
138 "Dg".into()
139 }
140 fn filtered_spelling_param(&self, spelling_mode: &SpellingMode) -> Cow<'_, str> {
141 match spelling_mode {
142 SpellingMode::ExactMatch => SPECIALIZED_PLAYLIST_EXACT_MATCH_PARAMS,
143 SpellingMode::WithSuggestions => SPECIALIZED_PLAYLIST_WITH_SUGGESTIONS_PARAMS,
144 }
145 .into()
146 }
147 fn filtered_prefix_param(&self) -> Cow<'_, str> {
148 SPECIALIZED_PLAYLIST_PREFIX_PARAMS.into()
149 }
150}
151impl FilteredSearchType for EpisodesFilter {
152 fn filtered_param_bits(&self) -> Cow<'_, str> {
153 "JI".into()
154 }
155}
156impl FilteredSearchType for PodcastsFilter {
157 fn filtered_param_bits(&self) -> Cow<'_, str> {
158 "JQ".into()
159 }
160}
161impl FilteredSearchType for ProfilesFilter {
162 fn filtered_param_bits(&self) -> Cow<'_, str> {
163 "JY".into()
164 }
165}
166impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<SongsFilter>> {
168 type Output = Vec<SearchResultSong>;
169 type Method = PostMethod;
170}
171impl PostQuery for SearchQuery<'_, FilteredSearch<SongsFilter>> {
172 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
173 search_query_header(self)
174 }
175 fn path(&self) -> &str {
176 SEARCH_QUERY_PATH
177 }
178 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
179 vec![]
180 }
181}
182impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<PlaylistsFilter>> {
183 type Output = Vec<SearchResultPlaylist>;
184 type Method = PostMethod;
185}
186impl PostQuery for SearchQuery<'_, FilteredSearch<PlaylistsFilter>> {
187 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
188 search_query_header(self)
189 }
190 fn path(&self) -> &str {
191 SEARCH_QUERY_PATH
192 }
193 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
194 vec![]
195 }
196}
197impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<CommunityPlaylistsFilter>> {
198 type Output = Vec<SearchResultPlaylist>;
199 type Method = PostMethod;
200}
201impl PostQuery for SearchQuery<'_, FilteredSearch<CommunityPlaylistsFilter>> {
202 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
203 search_query_header(self)
204 }
205 fn path(&self) -> &str {
206 SEARCH_QUERY_PATH
207 }
208 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
209 vec![]
210 }
211}
212impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<AlbumsFilter>> {
213 type Output = Vec<SearchResultAlbum>;
214 type Method = PostMethod;
215}
216impl PostQuery for SearchQuery<'_, FilteredSearch<AlbumsFilter>> {
217 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
218 search_query_header(self)
219 }
220 fn path(&self) -> &str {
221 SEARCH_QUERY_PATH
222 }
223 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
224 vec![]
225 }
226}
227impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<ArtistsFilter>> {
228 type Output = Vec<SearchResultArtist>;
229 type Method = PostMethod;
230}
231impl PostQuery for SearchQuery<'_, FilteredSearch<ArtistsFilter>> {
232 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
233 search_query_header(self)
234 }
235 fn path(&self) -> &str {
236 SEARCH_QUERY_PATH
237 }
238 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
239 vec![]
240 }
241}
242impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<FeaturedPlaylistsFilter>> {
243 type Output = Vec<SearchResultFeaturedPlaylist>;
244 type Method = PostMethod;
245}
246impl PostQuery for SearchQuery<'_, FilteredSearch<FeaturedPlaylistsFilter>> {
247 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
248 search_query_header(self)
249 }
250 fn path(&self) -> &str {
251 SEARCH_QUERY_PATH
252 }
253 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
254 vec![]
255 }
256}
257impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<EpisodesFilter>> {
258 type Output = Vec<SearchResultEpisode>;
259 type Method = PostMethod;
260}
261impl PostQuery for SearchQuery<'_, FilteredSearch<EpisodesFilter>> {
262 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
263 search_query_header(self)
264 }
265 fn path(&self) -> &str {
266 SEARCH_QUERY_PATH
267 }
268 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
269 vec![]
270 }
271}
272impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<PodcastsFilter>> {
273 type Output = Vec<SearchResultPodcast>;
274 type Method = PostMethod;
275}
276impl PostQuery for SearchQuery<'_, FilteredSearch<PodcastsFilter>> {
277 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
278 search_query_header(self)
279 }
280 fn path(&self) -> &str {
281 SEARCH_QUERY_PATH
282 }
283 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
284 vec![]
285 }
286}
287impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<VideosFilter>> {
288 type Output = Vec<SearchResultVideo>;
289 type Method = PostMethod;
290}
291impl PostQuery for SearchQuery<'_, FilteredSearch<VideosFilter>> {
292 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
293 search_query_header(self)
294 }
295 fn path(&self) -> &str {
296 SEARCH_QUERY_PATH
297 }
298 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
299 vec![]
300 }
301}
302impl<A: AuthToken> Query<A> for SearchQuery<'_, FilteredSearch<ProfilesFilter>> {
303 type Output = Vec<SearchResultProfile>;
304 type Method = PostMethod;
305}
306impl PostQuery for SearchQuery<'_, FilteredSearch<ProfilesFilter>> {
307 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
308 search_query_header(self)
309 }
310 fn path(&self) -> &str {
311 SEARCH_QUERY_PATH
312 }
313 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
314 vec![]
315 }
316}