ytmapi_rs/
simplified_queries.rs

1//! This module contains the implementation for more convenient ways to call the
2//! API, in many cases without the need of building Query structs.
3//! This module contains purely additional implementations for YtMusic. To see
4//! the documentation, refer to the [`YtMusic`] documentation itself.
5//! # Optional
6//! To enable this module, feature `simplified-queries` must be enabled (enabled
7//! by default)
8use crate::auth::AuthToken;
9use crate::common::{
10    AlbumID, ApiOutcome, ArtistChannelID, BrowseParams, EpisodeID, LyricsID, MoodCategoryParams,
11    PodcastChannelID, PodcastChannelParams, PodcastID, SetVideoID, SongTrackingUrl, VideoID,
12};
13use crate::common::{
14    FeedbackTokenRemoveFromHistory, PlaylistID, SearchSuggestion, UploadAlbumID, UploadArtistID,
15};
16use crate::common::{LikeStatus, TasteToken};
17use crate::parse::{
18    AddPlaylistItem, ArtistParams, GetAlbum, GetArtistAlbumsAlbum, GetLibraryAlbums,
19    GetLibraryArtistSubscriptions, GetLibraryArtists, GetLibraryPlaylists, GetPlaylist,
20    HistoryPeriod, Lyrics, SearchResultAlbum, SearchResultArtist, SearchResultEpisode,
21    SearchResultFeaturedPlaylist, SearchResultPlaylist, SearchResultPodcast, SearchResultProfile,
22    SearchResultSong, SearchResultVideo, SearchResults, WatchPlaylist,
23};
24use crate::query::song::GetSongTrackingUrlQuery;
25use crate::query::{
26    filteredsearch::{
27        AlbumsFilter, ArtistsFilter, CommunityPlaylistsFilter, EpisodesFilter,
28        FeaturedPlaylistsFilter, FilteredSearch, PlaylistsFilter, PodcastsFilter, ProfilesFilter,
29        SongsFilter, VideosFilter,
30    },
31    lyrics::GetLyricsQuery,
32    rate::{RatePlaylistQuery, RateSongQuery},
33    watch::GetWatchPlaylistQuery,
34    AddPlaylistItemsQuery, BasicSearch, CreatePlaylistQuery, CreatePlaylistType,
35    DeletePlaylistQuery, EditPlaylistQuery, EditSongLibraryStatusQuery, GetAlbumQuery,
36    GetArtistAlbumsQuery, GetArtistQuery, GetHistoryQuery, GetLibraryAlbumsQuery,
37    GetLibraryArtistSubscriptionsQuery, GetLibraryArtistsQuery, GetLibraryPlaylistsQuery,
38    GetLibrarySongsQuery, GetLibraryUploadAlbumQuery, GetLibraryUploadAlbumsQuery,
39    GetLibraryUploadArtistQuery, GetLibraryUploadArtistsQuery, GetLibraryUploadSongsQuery,
40    GetPlaylistQuery, GetSearchSuggestionsQuery, Query, RemoveHistoryItemsQuery,
41    RemovePlaylistItemsQuery, SearchQuery,
42};
43use crate::query::{
44    AddHistoryItemQuery, DuplicateHandlingMode, GetChannelEpisodesQuery, GetChannelQuery,
45    GetEpisodeQuery, GetMoodCategoriesQuery, GetMoodPlaylistsQuery, GetNewEpisodesQuery,
46    GetPodcastQuery, GetTasteProfileQuery, SetTasteProfileQuery,
47};
48use crate::{common::UploadEntityID, query::DeleteUploadEntityQuery};
49use crate::{Result, YtMusic};
50
51impl<A: AuthToken> YtMusic<A> {
52    /// API Search Query that returns results for each category if available.
53    /// # Usage
54    /// ```no_run
55    /// # async {
56    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
57    /// yt.search("Beatles").await
58    /// # };
59    pub async fn search<'a, Q: Into<SearchQuery<'a, BasicSearch>>>(
60        &self,
61        query: Q,
62    ) -> Result<SearchResults> {
63        let query = query.into();
64        self.query(query).await
65    }
66    /// API Search Query for Artists only.
67    /// ```no_run
68    /// # async {
69    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
70    /// yt.search_artists("Beatles").await
71    /// # };
72    pub async fn search_artists<'a, Q: Into<SearchQuery<'a, FilteredSearch<ArtistsFilter>>>>(
73        &self,
74        query: Q,
75    ) -> Result<Vec<SearchResultArtist>> {
76        let query = query.into();
77        self.query(query).await
78    }
79    /// API Search Query for Albums only.
80    /// ```no_run
81    /// # async {
82    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
83    /// yt.search_albums("Beatles").await
84    /// # };
85    pub async fn search_albums<'a, Q: Into<SearchQuery<'a, FilteredSearch<AlbumsFilter>>>>(
86        &self,
87        query: Q,
88    ) -> Result<Vec<SearchResultAlbum>> {
89        let query = query.into();
90        self.query(query).await
91    }
92    /// API Search Query for Songs only.
93    /// ```no_run
94    /// # async {
95    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
96    /// yt.search_songs("Beatles").await
97    /// # };
98    pub async fn search_songs<'a, Q: Into<SearchQuery<'a, FilteredSearch<SongsFilter>>>>(
99        &self,
100        query: Q,
101    ) -> Result<Vec<SearchResultSong>> {
102        let query = query.into();
103        self.query(query).await
104    }
105    /// API Search Query for Playlists only.
106    /// ```no_run
107    /// # async {
108    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
109    /// yt.search_playlists("Beatles").await
110    /// # };
111    pub async fn search_playlists<'a, Q: Into<SearchQuery<'a, FilteredSearch<PlaylistsFilter>>>>(
112        &self,
113        query: Q,
114    ) -> Result<Vec<SearchResultPlaylist>> {
115        let query = query.into();
116        self.query(query).await
117    }
118    /// API Search Query for Community Playlists only.
119    /// ```no_run
120    /// # async {
121    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
122    /// yt.search_community_playlists("Beatles").await
123    /// # };
124    pub async fn search_community_playlists<
125        'a,
126        Q: Into<SearchQuery<'a, FilteredSearch<CommunityPlaylistsFilter>>>,
127    >(
128        &self,
129        query: Q,
130    ) -> Result<Vec<SearchResultPlaylist>> {
131        let query = query.into();
132        self.query(query).await
133    }
134    /// API Search Query for Featured Playlists only.
135    /// ```no_run
136    /// # async {
137    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
138    /// yt.search_featured_playlists("Beatles").await
139    /// # };
140    pub async fn search_featured_playlists<
141        'a,
142        Q: Into<SearchQuery<'a, FilteredSearch<FeaturedPlaylistsFilter>>>,
143    >(
144        &self,
145        query: Q,
146    ) -> Result<Vec<SearchResultFeaturedPlaylist>> {
147        let query = query.into();
148        self.query(query).await
149    }
150    /// API Search Query for Episodes only.
151    /// ```no_run
152    /// # async {
153    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
154    /// yt.search_episodes("Beatles").await
155    /// # };
156    pub async fn search_episodes<'a, Q: Into<SearchQuery<'a, FilteredSearch<EpisodesFilter>>>>(
157        &self,
158        query: Q,
159    ) -> Result<Vec<SearchResultEpisode>> {
160        let query = query.into();
161        self.query(query).await
162    }
163    /// API Search Query for Podcasts only.
164    /// ```no_run
165    /// # async {
166    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
167    /// yt.search_podcasts("Beatles").await
168    /// # };
169    pub async fn search_podcasts<'a, Q: Into<SearchQuery<'a, FilteredSearch<PodcastsFilter>>>>(
170        &self,
171        query: Q,
172    ) -> Result<Vec<SearchResultPodcast>> {
173        let query = query.into();
174        self.query(query).await
175    }
176    /// API Search Query for Videos only.
177    /// ```no_run
178    /// # async {
179    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
180    /// yt.search_videos("Beatles").await
181    /// # };
182    pub async fn search_videos<'a, Q: Into<SearchQuery<'a, FilteredSearch<VideosFilter>>>>(
183        &self,
184        query: Q,
185    ) -> Result<Vec<SearchResultVideo>> {
186        let query = query.into();
187        self.query(query).await
188    }
189    /// API Search Query for Profiles only.
190    /// ```no_run
191    /// # async {
192    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
193    /// yt.search_profiles("Beatles").await
194    /// # };
195    pub async fn search_profiles<'a, Q: Into<SearchQuery<'a, FilteredSearch<ProfilesFilter>>>>(
196        &self,
197        query: Q,
198    ) -> Result<Vec<SearchResultProfile>> {
199        let query = query.into();
200        self.query(query).await
201    }
202    /// Gets information about an artist and their top releases.
203    /// ```no_run
204    /// # async {
205    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
206    /// let results = yt.search_artists("Beatles").await.unwrap();
207    /// yt.get_artist(&results[0].browse_id).await
208    /// # };
209    pub async fn get_artist<'a>(
210        &self,
211        query: impl Into<GetArtistQuery<'a>>,
212    ) -> Result<ArtistParams> {
213        self.query(query.into()).await
214    }
215    /// Gets a full list albums for an artist.
216    /// ```no_run
217    /// # async {
218    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
219    /// let results = yt.search_artists("Beatles").await.unwrap();
220    /// let artist_top_albums = yt.get_artist(&results[0].browse_id).await.unwrap().top_releases.albums.unwrap();
221    /// yt.get_artist_albums(
222    ///     artist_top_albums.browse_id.unwrap(),
223    ///     artist_top_albums.params.unwrap(),
224    /// ).await
225    /// # };
226    pub async fn get_artist_albums<'a, T: Into<ArtistChannelID<'a>>, U: Into<BrowseParams<'a>>>(
227        &self,
228        channel_id: T,
229        browse_params: U,
230    ) -> Result<Vec<GetArtistAlbumsAlbum>> {
231        let query = GetArtistAlbumsQuery::new(channel_id.into(), browse_params.into());
232        self.query(query).await
233    }
234    /// Gets information about an album and its tracks.
235    /// ```no_run
236    /// # async {
237    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
238    /// let results = yt.search_albums("Dark Side Of The Moon").await.unwrap();
239    /// yt.get_album(&results[0].album_id).await
240    /// # };
241    pub async fn get_album<'a, T: Into<AlbumID<'a>>>(&self, album_id: T) -> Result<GetAlbum> {
242        let query = GetAlbumQuery::new(album_id);
243        self.query(query).await
244    }
245    /// Gets the information that's available when playing a song or playlist;
246    /// upcoming tracks and lyrics.
247    /// # Partially implemented
248    /// Tracks are not implemented - empty vector always returned.
249    /// See [`GetWatchPlaylistQuery`] and [`YtMusic.query()`]
250    /// for more ways to construct and run
251    /// a GetWatchPlaylistQuery.
252    ///
253    /// [`YtMusic.query()`]: crate::YtMusic::query
254    /// [GetWatchPlaylistQuery]: crate::query::watch::GetWatchPlaylistQuery
255    ///
256    /// ```no_run
257    /// # async {
258    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
259    /// let results = yt.search_songs("While My Guitar Gently Weeps").await.unwrap();
260    /// yt.get_watch_playlist_from_video_id(&results[0].video_id).await
261    /// # };
262    // NOTE: Could be generic across PlaylistID or VideoID using
263    // Into<GetWatchPlaylistQuery>
264    pub async fn get_watch_playlist_from_video_id<'a, S: Into<VideoID<'a>>>(
265        &self,
266        video_id: S,
267    ) -> Result<WatchPlaylist> {
268        let query = GetWatchPlaylistQuery::new_from_video_id(video_id.into());
269        self.query(query).await
270    }
271    /// Gets song lyrics and the source.
272    /// ```no_run
273    /// # async {
274    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
275    /// let results = yt.search_songs("While My Guitar Gently Weeps").await.unwrap();
276    /// let watch_playlist = yt.get_watch_playlist_from_video_id(&results[0].video_id).await.unwrap();
277    /// yt.get_lyrics(watch_playlist.lyrics_id).await
278    /// # };
279    pub async fn get_lyrics<'a, T: Into<LyricsID<'a>>>(&self, lyrics_id: T) -> Result<Lyrics> {
280        let query = GetLyricsQuery::new(lyrics_id.into());
281        self.query(query).await
282    }
283    /// Gets information about a playlist and its tracks.
284    /// ```no_run
285    /// # async {
286    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
287    /// let results = yt.search_featured_playlists("Heavy metal").await.unwrap();
288    /// yt.get_playlist(&results[0].playlist_id).await
289    /// # };
290    pub async fn get_playlist<'a, T: Into<PlaylistID<'a>>>(
291        &self,
292        playlist_id: T,
293    ) -> Result<GetPlaylist> {
294        let query = GetPlaylistQuery::new(playlist_id.into());
295        self.query(query).await
296    }
297    /// Gets search suggestions
298    /// ```no_run
299    /// # async {
300    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
301    /// yt.get_search_suggestions("The Beat").await;
302    /// # };
303    pub async fn get_search_suggestions<'a, S: Into<GetSearchSuggestionsQuery<'a>>>(
304        &self,
305        query: S,
306    ) -> Result<Vec<SearchSuggestion>> {
307        let query = query.into();
308        self.query(query).await
309    }
310    /// Gets a list of all playlists in your Library.
311    /// ```no_run
312    /// # async {
313    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
314    /// yt.get_library_playlists().await;
315    /// # };
316    pub async fn get_library_playlists(&self) -> Result<GetLibraryPlaylists> {
317        let query = GetLibraryPlaylistsQuery;
318        self.query(query).await
319    }
320    /// Gets a list of all artists in your Library.
321    /// # Additional functionality
322    /// See [`GetLibraryArtistsQuery`] and [`YtMusic.query()`]
323    /// for more ways to construct and run.
324    ///
325    /// [`YtMusic.query()`]: crate::YtMusic::query
326    /// [GetLibraryArtistsQuery]: crate::query::GetLibraryArtistsQuery
327    ///
328    /// ```no_run
329    /// # async {
330    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
331    /// let results = yt.get_library_artists().await;
332    /// # };
333    pub async fn get_library_artists(&self) -> Result<GetLibraryArtists> {
334        let query = GetLibraryArtistsQuery::default();
335        self.query(query).await
336    }
337    /// Gets a list of all songs in your Library.
338    /// # Additional functionality
339    /// See [`GetLibrarySongsQuery`] and [`YtMusic.query()`]
340    /// for more ways to construct and run.
341    ///
342    /// [`YtMusic.query()`]: crate::YtMusic::query
343    /// [GetLibrarySongsQuery]: crate::query::GetLibrarySongsQuery
344    ///
345    /// ```no_run
346    /// # async {
347    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
348    /// let results = yt.get_library_songs().await;
349    /// # };
350    pub async fn get_library_songs(&self) -> Result<<GetLibrarySongsQuery as Query<A>>::Output> {
351        let query = GetLibrarySongsQuery::default();
352        self.query(query).await
353    }
354    /// Gets a list of all albums in your Library.
355    /// # Additional functionality
356    /// See [`GetLibraryAlbumsQuery`] and [`YtMusic.query()`]
357    /// for more ways to construct and run.
358    ///
359    /// [`YtMusic.query()`]: crate::YtMusic::query
360    /// [GetLibraryAlbumsQuery]: crate::query::GetLibraryAlbumsQuery
361    ///
362    /// ```no_run
363    /// # async {
364    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
365    /// let results = yt.get_library_albums().await;
366    /// # };
367    pub async fn get_library_albums(&self) -> Result<GetLibraryAlbums> {
368        let query = GetLibraryAlbumsQuery::default();
369        self.query(query).await
370    }
371    /// Gets a list of all artist subscriptions in your Library.
372    /// # Additional functionality
373    /// See [`GetLibraryArtistSubscriptionsQuery`] and [`YtMusic.query()`]
374    /// for more ways to construct and run.
375    ///
376    /// [`YtMusic.query()`]: crate::YtMusic::query
377    /// [GetLibraryArtistSubscriptionsQuery]: crate::query::GetLibraryArtistSubscriptionsQuery
378    ///
379    /// ```no_run
380    /// # async {
381    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
382    /// let results = yt.get_library_artist_subscriptions().await;
383    /// # };
384    pub async fn get_library_artist_subscriptions(&self) -> Result<GetLibraryArtistSubscriptions> {
385        let query = GetLibraryArtistSubscriptionsQuery::default();
386        self.query(query).await
387    }
388    /// Gets your recently played history.
389    /// ```no_run
390    /// # async {
391    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
392    /// let results = yt.get_history().await;
393    /// # };
394    pub async fn get_history(&self) -> Result<Vec<HistoryPeriod>> {
395        let query = GetHistoryQuery;
396        self.query(query).await
397    }
398    /// Removes a list of items from your recently played history.
399    /// ```no_run
400    /// # async {
401    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
402    /// let history = yt.get_history().await.unwrap();
403    /// let first_history_token = match history.first().unwrap().items.first().unwrap() {
404    ///     ytmapi_rs::parse::HistoryItem::Song(i) => &i.feedback_token_remove,
405    ///     ytmapi_rs::parse::HistoryItem::Video(i) => &i.feedback_token_remove,
406    ///     ytmapi_rs::parse::HistoryItem::Episode(i) => &i.feedback_token_remove,
407    ///     ytmapi_rs::parse::HistoryItem::UploadSong(i) => &i.feedback_token_remove,
408    /// }.into();
409    /// yt.remove_history_items(vec![first_history_token]).await
410    /// # };
411    pub async fn remove_history_items(
412        &self,
413        feedback_tokens: Vec<FeedbackTokenRemoveFromHistory<'_>>,
414    ) -> Result<Vec<ApiOutcome>> {
415        let query = RemoveHistoryItemsQuery::new(feedback_tokens);
416        self.query(query).await
417    }
418    // TODO: Docs / alternative constructors.
419    pub async fn edit_song_library_status(
420        &self,
421        query: EditSongLibraryStatusQuery<'_>,
422    ) -> Result<Vec<ApiOutcome>> {
423        self.query(query).await
424    }
425    /// Sets the like status for a song.
426    /// ```no_run
427    /// # async {
428    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
429    /// let results = yt.search_songs("While My Guitar Gently Weeps").await.unwrap();
430    /// yt.rate_song(&results[0].video_id, ytmapi_rs::common::LikeStatus::Liked).await
431    /// # };
432    pub async fn rate_song<'a, T: Into<VideoID<'a>>>(
433        &self,
434        video_id: T,
435        rating: LikeStatus,
436    ) -> Result<()> {
437        let query = RateSongQuery::new(video_id.into(), rating);
438        self.query(query).await
439    }
440    /// Sets the like status for a playlist.
441    /// A 'Liked' playlist will be added to your library, an 'Indifferent' will
442    /// be removed, and a 'Disliked' will reduce the chance of it appearing in
443    /// your recommendations.
444    ///  ```no_run
445    /// # async {
446    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
447    /// let results = yt.search_featured_playlists("Heavy metal")
448    ///     .await
449    ///     .unwrap();
450    /// yt.rate_playlist(
451    ///     &results[0].playlist_id,
452    ///     ytmapi_rs::common::LikeStatus::Liked,
453    /// ).await
454    /// # };
455    pub async fn rate_playlist<'a, T: Into<PlaylistID<'a>>>(
456        &self,
457        playlist_id: T,
458        rating: LikeStatus,
459    ) -> Result<()> {
460        let query = RatePlaylistQuery::new(playlist_id.into(), rating);
461        self.query(query).await
462    }
463    /// Deletes a playlist you own.
464    ///  ```no_run
465    /// # async {
466    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
467    /// let results = yt.get_library_playlists().await.unwrap();
468    /// yt.delete_playlist(&results.playlists[0].playlist_id).await
469    /// # };
470    pub async fn delete_playlist<'a, T: Into<PlaylistID<'a>>>(&self, playlist_id: T) -> Result<()> {
471        let query = DeletePlaylistQuery::new(playlist_id.into());
472        self.query(query).await
473    }
474    /// Creates a new playlist.
475    ///  ```no_run
476    /// # async {
477    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
478    /// let playlists = yt.search_featured_playlists("Heavy metal")
479    ///     .await
480    ///     .unwrap();
481    /// let query = ytmapi_rs::query::CreatePlaylistQuery::new(
482    ///     "My heavy metal playlist",
483    ///     None,
484    ///     ytmapi_rs::query::PrivacyStatus::Public,
485    /// )
486    ///     .with_source(&playlists[0].playlist_id);
487    /// yt.create_playlist(query).await
488    /// # };
489    pub async fn create_playlist<T: CreatePlaylistType>(
490        &self,
491        query: CreatePlaylistQuery<'_, T>,
492    ) -> Result<PlaylistID<'static>> {
493        self.query(query).await
494    }
495    /// Adds video items to a playlist you own.
496    ///  ```no_run
497    /// # async {
498    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
499    /// let ytmapi_rs::parse::LibraryPlaylist { playlist_id, .. } =
500    ///     yt.get_library_playlists().await.unwrap().playlists.pop().unwrap();
501    /// let songs = yt.search_songs("Master of puppets").await.unwrap();
502    /// yt.add_video_items_to_playlist(
503    ///     playlist_id,
504    ///     songs.iter().map(|s| (&s.video_id).into()).collect()
505    /// ).await
506    /// # };
507    pub async fn add_video_items_to_playlist<'a, T: Into<PlaylistID<'a>>>(
508        &self,
509        playlist_id: T,
510        video_ids: Vec<VideoID<'a>>,
511    ) -> Result<Vec<AddPlaylistItem>> {
512        let query = AddPlaylistItemsQuery::new_from_videos(
513            playlist_id.into(),
514            video_ids,
515            DuplicateHandlingMode::default(),
516        );
517        self.query(query).await
518    }
519    /// Appends another playlist to a playlist you own.
520    ///  ```no_run
521    /// # async {
522    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
523    /// let ytmapi_rs::parse::LibraryPlaylist { playlist_id, .. } =
524    ///     yt.get_library_playlists().await.unwrap().playlists.pop().unwrap();
525    /// let source_playlist = yt.search_featured_playlists("Heavy metal")
526    ///     .await
527    ///     .unwrap();
528    /// yt.add_playlist_to_playlist(
529    ///     playlist_id,
530    ///     &source_playlist[0].playlist_id
531    /// ).await
532    /// # };
533    pub async fn add_playlist_to_playlist<'a, T: Into<PlaylistID<'a>>, U: Into<PlaylistID<'a>>>(
534        &self,
535        destination_playlist: T,
536        source_playlist: U,
537    ) -> Result<Vec<AddPlaylistItem>> {
538        let query = AddPlaylistItemsQuery::new_from_playlist(
539            destination_playlist.into(),
540            source_playlist.into(),
541        );
542        self.query(query).await
543    }
544    /// Removes items from a playlist you own.
545    ///  ```no_run
546    /// # async {
547    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
548    /// let ytmapi_rs::parse::LibraryPlaylist { playlist_id, .. } =
549    ///     yt.get_library_playlists().await.unwrap().playlists.pop().unwrap();
550    /// let source_playlist = yt.search_featured_playlists("Heavy metal")
551    ///     .await
552    ///     .unwrap();
553    /// let outcome = yt.add_playlist_to_playlist(
554    ///     &playlist_id,
555    ///     &source_playlist[0].playlist_id
556    /// ).await.unwrap();
557    /// yt.remove_playlist_items(
558    ///     playlist_id,
559    ///     outcome.iter().map(|o| (&o.set_video_id).into()).collect(),
560    /// ).await
561    /// # };
562    pub async fn remove_playlist_items<'a, T: Into<PlaylistID<'a>>>(
563        &self,
564        playlist_id: T,
565        video_items: Vec<SetVideoID<'a>>,
566    ) -> Result<()> {
567        let query = RemovePlaylistItemsQuery::new(playlist_id.into(), video_items);
568        self.query(query).await
569    }
570    /// Makes changes to a playlist.
571    ///  ```no_run
572    /// # async {
573    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
574    /// let playlists = yt.get_library_playlists()
575    ///     .await
576    ///     .unwrap()
577    ///     .playlists;
578    /// let query = ytmapi_rs::query::EditPlaylistQuery::new_title(
579    ///     &playlists[0].playlist_id,
580    ///     "Better playlist title",
581    /// )
582    ///     .with_new_description("Edited description");
583    /// yt.edit_playlist(query).await
584    /// # };
585    pub async fn edit_playlist(&self, query: EditPlaylistQuery<'_>) -> Result<ApiOutcome> {
586        self.query(query).await
587    }
588    /// Gets a list of all uploaded songs in your Library.
589    /// # Additional functionality
590    /// See [`GetLibraryUploadSongsQuery`] and [`YtMusic.query()`]
591    /// for more ways to construct and run.
592    ///
593    /// [`YtMusic.query()`]: crate::YtMusic::query
594    /// [GetLibraryUploadSongsQuery]: crate::query::GetLibraryUploadSongsQuery
595    ///
596    /// ```no_run
597    /// # async {
598    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
599    /// yt.get_library_upload_songs().await
600    /// # };
601    pub async fn get_library_upload_songs(
602        &self,
603    ) -> Result<<GetLibraryUploadSongsQuery as Query<A>>::Output> {
604        let query = GetLibraryUploadSongsQuery::default();
605        self.query(query).await
606    }
607    /// Gets a list of all uploaded artists in your Library.
608    /// # Additional functionality
609    /// See [`GetLibraryUploadArtistsQuery`] and [`YtMusic.query()`]
610    /// for more ways to construct and run.
611    ///
612    /// [`YtMusic.query()`]: crate::YtMusic::query
613    /// [GetLibraryUploadArtistsQuery]: crate::query::GetLibraryUploadArtistsQuery
614    ///
615    /// ```no_run
616    /// # async {
617    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
618    /// yt.get_library_upload_artists().await
619    /// # };
620    pub async fn get_library_upload_artists(
621        &self,
622    ) -> Result<<GetLibraryUploadArtistsQuery as Query<A>>::Output> {
623        let query = GetLibraryUploadArtistsQuery::default();
624        self.query(query).await
625    }
626    /// Gets a list of all uploaded albums in your Library.
627    /// # Additional functionality
628    /// See [`GetLibraryUploadAlbumsQuery`] and [`YtMusic.query()`]
629    /// for more ways to construct and run.
630    ///
631    /// [`YtMusic.query()`]: crate::YtMusic::query
632    /// [GetLibraryUploadAlbumsQuery]: crate::query::GetLibraryUploadAlbumsQuery
633    ///
634    /// ```no_run
635    /// # async {
636    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
637    /// yt.get_library_upload_albums().await
638    /// # };
639    pub async fn get_library_upload_albums(
640        &self,
641    ) -> Result<<GetLibraryUploadAlbumsQuery as Query<A>>::Output> {
642        let query = GetLibraryUploadAlbumsQuery::default();
643        self.query(query).await
644    }
645    /// Gets information and tracks for an uploaded album in your Library.
646    /// ```no_run
647    /// # async {
648    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
649    /// let albums = yt.get_library_upload_albums().await.unwrap();
650    /// yt.get_library_upload_album(&albums[0].album_id).await
651    /// # };
652    pub async fn get_library_upload_album<'a, T: Into<UploadAlbumID<'a>>>(
653        &self,
654        upload_album_id: T,
655    ) -> Result<<GetLibraryUploadAlbumQuery as Query<A>>::Output> {
656        let query = GetLibraryUploadAlbumQuery::new(upload_album_id.into());
657        self.query(query).await
658    }
659    /// Gets all tracks for an uploaded artist in your Library.
660    /// ```no_run
661    /// # async {
662    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
663    /// let artists = yt.get_library_upload_artists().await.unwrap();
664    /// yt.get_library_upload_artist(&artists[0].artist_id).await
665    /// # };
666    pub async fn get_library_upload_artist<'a, T: Into<UploadArtistID<'a>>>(
667        &self,
668        upload_artist_id: T,
669    ) -> Result<<GetLibraryUploadArtistQuery as Query<A>>::Output> {
670        let query = GetLibraryUploadArtistQuery::new(upload_artist_id.into());
671        self.query(query).await
672    }
673    /// Deletes an upload entity from your library - this is either a song or an
674    /// album.
675    /// ```no_run
676    /// # async {
677    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
678    /// let albums = yt.get_library_upload_albums().await.unwrap();
679    /// yt.delete_upload_entity(&albums[0].entity_id).await
680    /// # };
681    pub async fn delete_upload_entity<'a, T: Into<UploadEntityID<'a>>>(
682        &self,
683        upload_entity_id: T,
684    ) -> Result<<DeleteUploadEntityQuery as Query<A>>::Output> {
685        let query = DeleteUploadEntityQuery::new(upload_entity_id.into());
686        self.query(query).await
687    }
688    /// Fetches suggested artists from taste profile
689    /// <https://music.youtube.com/tasteprofile>.
690    /// Tasteprofile allows users to pick artists to update their
691    /// recommendations.
692    /// ```no_run
693    /// # async {
694    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
695    /// yt.get_taste_profile().await
696    /// # };
697    pub async fn get_taste_profile(&self) -> Result<<GetTasteProfileQuery as Query<A>>::Output> {
698        self.query(GetTasteProfileQuery).await
699    }
700    /// Sets artists as favourites to influence your recommendations.
701    /// ```no_run
702    /// # async {
703    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
704    /// let results = yt.get_taste_profile().await.unwrap();
705    /// yt.set_taste_profile(results.into_iter()
706    ///     .take(5)
707    ///     .map(|r| r.taste_tokens))
708    ///     .await
709    /// # };
710    pub async fn set_taste_profile<'a, I, II>(
711        &self,
712        taste_tokens: II,
713    ) -> Result<<SetTasteProfileQuery<'a, I> as Query<A>>::Output>
714    where
715        I: Iterator<Item = TasteToken<'a>> + Clone,
716        II: IntoIterator<IntoIter = I>,
717    {
718        self.query(SetTasteProfileQuery::new(taste_tokens)).await
719    }
720    /// Fetches 'Moods & Genres' categories.
721    /// ```no_run
722    /// # async {
723    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
724    /// yt.get_mood_categories().await
725    /// # };
726    pub async fn get_mood_categories(
727        &self,
728    ) -> Result<<GetMoodCategoriesQuery as Query<A>>::Output> {
729        self.query(GetMoodCategoriesQuery).await
730    }
731    /// Returns a list of playlists for a given mood category.
732    /// ```no_run
733    /// # async {
734    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
735    /// let results = yt.get_mood_categories().await.unwrap();
736    /// yt.get_mood_playlists(&results[0].mood_categories[0].params).await
737    /// # };
738    pub async fn get_mood_playlists<'a, T: Into<MoodCategoryParams<'a>>>(
739        &self,
740        mood_params: T,
741    ) -> Result<<GetMoodPlaylistsQuery as Query<A>>::Output> {
742        self.query(GetMoodPlaylistsQuery::new(mood_params.into()))
743            .await
744    }
745    /// Get the 'SongTrackingUrl' for a song. This is used to add items to
746    /// history using `add_history_item()`.
747    /// ```no_run
748    /// # async {
749    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
750    /// let song = yt.search_songs("While My Guitar Gently Weeps")
751    ///     .await
752    ///     .unwrap()
753    ///     .into_iter()
754    ///     .next()
755    ///     .unwrap();
756    /// yt.get_song_tracking_url(song.video_id).await
757    /// # };
758    pub async fn get_song_tracking_url<'a, T: Into<VideoID<'a>>>(
759        &self,
760        video_id: T,
761    ) -> Result<SongTrackingUrl<'static>> {
762        let query = GetSongTrackingUrlQuery::new(video_id.into())?;
763        self.query(query).await
764    }
765    /// Adds an item to the accounts history.
766    /// ```no_run
767    /// # async {
768    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
769    /// let song = yt.search_songs("While My Guitar Gently Weeps")
770    ///     .await
771    ///     .unwrap()
772    ///     .into_iter()
773    ///     .next()
774    ///     .unwrap();
775    /// let url = yt.get_song_tracking_url(song.video_id).await.unwrap();
776    /// yt.add_history_item(url).await
777    /// # };
778    pub async fn add_history_item<'a, T: Into<SongTrackingUrl<'a>>>(
779        &self,
780        song_url: T,
781    ) -> Result<<AddHistoryItemQuery<'a> as Query<A>>::Output> {
782        self.query(AddHistoryItemQuery::new(song_url.into())).await
783    }
784    /// Gets information about a Channel of Podcasts.
785    /// ```no_run
786    /// # async {
787    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
788    /// let podcasts = yt.search_podcasts("Rustacean").await.unwrap();
789    /// let podcast = yt.get_podcast(&podcasts[0].podcast_id).await.unwrap();
790    /// yt.get_channel(podcast.channels[0].id.as_ref().unwrap()).await
791    /// # };
792    pub async fn get_channel(
793        &self,
794        channel_id: impl Into<PodcastChannelID<'_>>,
795    ) -> Result<<GetChannelQuery as Query<A>>::Output> {
796        self.query(GetChannelQuery::new(channel_id)).await
797    }
798    /// Gets a list of all Episodes for a Channel. Note, if GetPodcastChannel
799    /// doesn't contain `episode_params`, you can be sure that all episodes are
800    /// already included at `episodes` key.
801    /// ```no_run
802    /// # async {
803    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
804    /// let podcasts = yt.search_podcasts("Rustacean").await.unwrap();
805    /// let podcast = yt.get_podcast(&podcasts[0].podcast_id).await.unwrap();
806    /// let channel_id = podcast.channels[0].id.as_ref().unwrap();
807    /// let channel = yt.get_channel(channel_id).await.unwrap();
808    /// match channel.episode_params {
809    ///     Some(p) => yt.get_channel_episodes(channel_id, p).await,
810    ///     None => Ok(channel.episodes),
811    /// }
812    /// # };
813    pub async fn get_channel_episodes<'a>(
814        &self,
815        channel_id: impl Into<PodcastChannelID<'a>>,
816        podcast_channel_params: impl Into<PodcastChannelParams<'a>>,
817    ) -> Result<<GetChannelEpisodesQuery as Query<A>>::Output> {
818        self.query(GetChannelEpisodesQuery::new(
819            channel_id,
820            podcast_channel_params,
821        ))
822        .await
823    }
824    /// Gets information about a Podcast, including Episodes.
825    /// ```no_run
826    /// # async {
827    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
828    /// let podcasts = yt.search_podcasts("Rustacean").await.unwrap();
829    /// yt.get_podcast(&podcasts[0].podcast_id).await
830    /// # };
831    pub async fn get_podcast(
832        &self,
833        podcast_id: impl Into<PodcastID<'_>>,
834    ) -> Result<<GetPodcastQuery as Query<A>>::Output> {
835        self.query(GetPodcastQuery::new(podcast_id)).await
836    }
837    /// ```no_run
838    /// # async {
839    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
840    /// let episodes = yt.search_episodes("Ratatui").await.unwrap();
841    /// yt.get_episode(&episodes[0].episode_id).await
842    /// # };
843    pub async fn get_episode(
844        &self,
845        episode_id: impl Into<EpisodeID<'_>>,
846    ) -> Result<<GetEpisodeQuery as Query<A>>::Output> {
847        self.query(GetEpisodeQuery::new(episode_id)).await
848    }
849    /// Gets the special 'New Episodes' playlist.
850    /// ```no_run
851    /// # async {
852    /// let yt = ytmapi_rs::YtMusic::from_cookie("FAKE COOKIE").await.unwrap();
853    /// yt.get_new_episodes().await
854    /// # };
855    pub async fn get_new_episodes(&self) -> Result<<GetNewEpisodesQuery as Query<A>>::Output> {
856        self.query(GetNewEpisodesQuery).await
857    }
858}