1use super::{PostMethod, PostQuery, Query};
2use crate::auth::LoggedIn;
3use crate::common::{
4 ApiOutcome, FeedbackTokenAddToLibrary, FeedbackTokenRemoveFromLibrary, YoutubeID,
5};
6use crate::parse::{
7 LibraryArtist, LibraryArtistSubscription, LibraryChannel, LibraryPlaylist, LibraryPodcast,
8 SearchResultAlbum, TableListSong,
9};
10use serde_json::json;
11use std::borrow::Cow;
12
13#[derive(Default, Clone)]
18pub enum GetLibrarySortOrder {
19 NameAsc,
20 NameDesc,
21 RecentlySaved,
22 #[default]
23 Default,
24}
25
26pub struct GetLibraryPlaylistsQuery;
27#[derive(Default)]
28pub struct GetLibrarySongsQuery {
29 sort_order: GetLibrarySortOrder,
30}
31#[derive(Default)]
32pub struct GetLibraryAlbumsQuery {
33 sort_order: GetLibrarySortOrder,
34}
35#[derive(Default)]
36pub struct GetLibraryArtistSubscriptionsQuery {
37 sort_order: GetLibrarySortOrder,
38}
39#[derive(Default)]
40pub struct GetLibraryArtistsQuery {
41 sort_order: GetLibrarySortOrder,
42}
43#[derive(Default)]
44pub struct GetLibraryPodcastsQuery {
45 sort_order: GetLibrarySortOrder,
46}
47#[derive(Default)]
48pub struct GetLibraryChannelsQuery {
49 sort_order: GetLibrarySortOrder,
50}
51pub struct EditSongLibraryStatusQuery<'a> {
52 add_to_library_feedback_tokens: Vec<FeedbackTokenAddToLibrary<'a>>,
53 remove_from_library_feedback_tokens: Vec<FeedbackTokenRemoveFromLibrary<'a>>,
54}
55
56impl GetLibrarySongsQuery {
57 pub fn new(sort_order: GetLibrarySortOrder) -> Self {
58 Self { sort_order }
59 }
60}
61impl GetLibraryAlbumsQuery {
62 pub fn new(sort_order: GetLibrarySortOrder) -> Self {
63 Self { sort_order }
64 }
65}
66impl GetLibraryArtistSubscriptionsQuery {
67 pub fn new(sort_order: GetLibrarySortOrder) -> Self {
68 Self { sort_order }
69 }
70}
71impl GetLibraryArtistsQuery {
72 pub fn new(sort_order: GetLibrarySortOrder) -> Self {
73 Self { sort_order }
74 }
75}
76impl GetLibraryPodcastsQuery {
77 pub fn new(sort_order: GetLibrarySortOrder) -> Self {
78 Self { sort_order }
79 }
80}
81impl GetLibraryChannelsQuery {
82 pub fn new(sort_order: GetLibrarySortOrder) -> Self {
83 Self { sort_order }
84 }
85}
86impl<'a> EditSongLibraryStatusQuery<'a> {
87 pub fn new_from_add_to_library_feedback_tokens(
88 add_to_library_feedback_tokens: impl IntoIterator<Item = FeedbackTokenAddToLibrary<'a>>,
89 ) -> Self {
90 Self {
91 add_to_library_feedback_tokens: add_to_library_feedback_tokens.into_iter().collect(),
92 remove_from_library_feedback_tokens: vec![],
93 }
94 }
95 pub fn new_from_remove_from_library_feedback_tokens(
96 remove_from_library_feedback_tokens: impl IntoIterator<
97 Item = FeedbackTokenRemoveFromLibrary<'a>,
98 >,
99 ) -> Self {
100 Self {
101 add_to_library_feedback_tokens: vec![],
102 remove_from_library_feedback_tokens: remove_from_library_feedback_tokens
103 .into_iter()
104 .collect(),
105 }
106 }
107 pub fn with_add_to_library_feedback_tokens(
108 mut self,
109 add_to_library_feedback_tokens: impl IntoIterator<Item = FeedbackTokenAddToLibrary<'a>>,
110 ) -> Self {
111 self.add_to_library_feedback_tokens = add_to_library_feedback_tokens.into_iter().collect();
112 self
113 }
114 pub fn with_remove_from_library_feedback_tokens(
115 mut self,
116 remove_from_library_feedback_tokens: impl IntoIterator<
117 Item = FeedbackTokenRemoveFromLibrary<'a>,
118 >,
119 ) -> Self {
120 self.remove_from_library_feedback_tokens =
121 remove_from_library_feedback_tokens.into_iter().collect();
122 self
123 }
124}
125
126impl<A: LoggedIn> Query<A> for GetLibraryPlaylistsQuery {
127 type Output = Vec<LibraryPlaylist>;
128 type Method = PostMethod;
129}
130impl PostQuery for GetLibraryPlaylistsQuery {
131 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
132 FromIterator::from_iter([("browseId".to_string(), json!("FEmusic_liked_playlists"))])
133 }
134 fn path(&self) -> &str {
135 "browse"
136 }
137 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
138 vec![]
139 }
140}
141impl<A: LoggedIn> Query<A> for GetLibraryArtistsQuery {
142 type Output = Vec<LibraryArtist>;
143 type Method = PostMethod;
144}
145impl PostQuery for GetLibraryArtistsQuery {
146 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
147 if let Some(params) = get_sort_order_params(&self.sort_order) {
148 FromIterator::from_iter([
149 (
150 "browseId".to_string(),
151 json!("FEmusic_library_corpus_track_artists"),
152 ),
153 ("params".to_string(), json!(params)),
154 ])
155 } else {
156 FromIterator::from_iter([(
157 "browseId".to_string(),
158 json!("FEmusic_library_corpus_track_artists"),
159 )])
160 }
161 }
162 fn path(&self) -> &str {
163 "browse"
164 }
165 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
166 vec![]
167 }
168}
169
170impl<A: LoggedIn> Query<A> for GetLibrarySongsQuery {
171 type Output = Vec<TableListSong>;
172 type Method = PostMethod;
173}
174impl PostQuery for GetLibrarySongsQuery {
175 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
176 if let Some(params) = get_sort_order_params(&self.sort_order) {
177 serde_json::Map::from_iter([
178 ("browseId".to_string(), json!("FEmusic_liked_videos")),
179 ("params".to_string(), json!(params)),
180 ])
181 } else {
182 serde_json::Map::from_iter([("browseId".to_string(), json!("FEmusic_liked_videos"))])
183 }
184 }
185 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
186 vec![]
187 }
188 fn path(&self) -> &str {
189 "browse"
190 }
191}
192impl<A: LoggedIn> Query<A> for GetLibraryAlbumsQuery {
193 type Output = Vec<SearchResultAlbum>;
194 type Method = PostMethod;
195}
196impl PostQuery for GetLibraryAlbumsQuery {
197 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
198 if let Some(params) = get_sort_order_params(&self.sort_order) {
199 serde_json::Map::from_iter([
200 ("browseId".to_string(), json!("FEmusic_liked_albums")),
201 ("params".to_string(), json!(params)),
202 ])
203 } else {
204 serde_json::Map::from_iter([("browseId".to_string(), json!("FEmusic_liked_albums"))])
205 }
206 }
207 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
208 vec![]
209 }
210 fn path(&self) -> &str {
211 "browse"
212 }
213}
214impl<A: LoggedIn> Query<A> for GetLibraryArtistSubscriptionsQuery {
215 type Output = Vec<LibraryArtistSubscription>;
216 type Method = PostMethod;
217}
218impl PostQuery for GetLibraryArtistSubscriptionsQuery {
219 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
220 if let Some(params) = get_sort_order_params(&self.sort_order) {
221 serde_json::Map::from_iter([
222 (
223 "browseId".to_string(),
224 json!("FEmusic_library_corpus_artists"),
225 ),
226 ("params".to_string(), json!(params)),
227 ])
228 } else {
229 serde_json::Map::from_iter([(
230 "browseId".to_string(),
231 json!("FEmusic_library_corpus_artists"),
232 )])
233 }
234 }
235 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
236 vec![]
237 }
238 fn path(&self) -> &str {
239 "browse"
240 }
241}
242impl<A: LoggedIn> Query<A> for EditSongLibraryStatusQuery<'_> {
244 type Output = Vec<ApiOutcome>;
245 type Method = PostMethod;
246}
247impl PostQuery for EditSongLibraryStatusQuery<'_> {
248 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
249 let add_feedback_tokens_raw = self
250 .add_to_library_feedback_tokens
251 .iter()
252 .map(|t| t.get_raw());
253 let feedback_tokens = self
254 .remove_from_library_feedback_tokens
255 .iter()
256 .map(|t| t.get_raw())
257 .chain(add_feedback_tokens_raw)
258 .collect::<Vec<_>>();
259 serde_json::Map::from_iter([("feedbackTokens".to_string(), json!(feedback_tokens))])
260 }
261 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
262 vec![]
263 }
264 fn path(&self) -> &str {
265 "feedback"
266 }
267}
268impl<A: LoggedIn> Query<A> for GetLibraryPodcastsQuery {
269 type Output = Vec<LibraryPodcast>;
270 type Method = PostMethod;
271}
272impl PostQuery for GetLibraryPodcastsQuery {
273 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
274 if let Some(params) = get_sort_order_params(&self.sort_order) {
275 serde_json::Map::from_iter([
276 (
277 "browseId".to_string(),
278 json!("FEmusic_library_non_music_audio_list"),
279 ),
280 ("params".to_string(), json!(params)),
281 ])
282 } else {
283 serde_json::Map::from_iter([(
284 "browseId".to_string(),
285 json!("FEmusic_library_non_music_audio_list"),
286 )])
287 }
288 }
289 fn path(&self) -> &str {
290 "browse"
291 }
292 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
293 vec![]
294 }
295}
296impl<A: LoggedIn> Query<A> for GetLibraryChannelsQuery {
297 type Output = Vec<LibraryChannel>;
298 type Method = PostMethod;
299}
300impl PostQuery for GetLibraryChannelsQuery {
301 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
302 if let Some(params) = get_sort_order_params(&self.sort_order) {
303 serde_json::Map::from_iter([
304 (
305 "browseId".to_string(),
306 json!("FEmusic_library_non_music_audio_channels_list"),
307 ),
308 ("params".to_string(), json!(params)),
309 ])
310 } else {
311 serde_json::Map::from_iter([(
312 "browseId".to_string(),
313 json!("FEmusic_library_non_music_audio_channels_list"),
314 )])
315 }
316 }
317 fn path(&self) -> &str {
318 "browse"
319 }
320 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
321 vec![]
322 }
323}
324
325pub(crate) fn get_sort_order_params(o: &GetLibrarySortOrder) -> Option<&'static str> {
326 match o {
327 GetLibrarySortOrder::NameAsc => Some("ggMGKgQIARAA"),
328 GetLibrarySortOrder::NameDesc => Some("ggMGKgQIARAB"),
329 GetLibrarySortOrder::RecentlySaved => Some("ggMGKgQIABAB"),
330 GetLibrarySortOrder::Default => None,
331 }
332}