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