use auth::{
browser::BrowserToken, oauth::OAuthDeviceCode, AuthToken, OAuthToken, OAuthTokenGenerator,
};
use common::{
browsing::Lyrics,
library::{LibraryArtist, Playlist},
watch::WatchPlaylist,
SearchSuggestion,
};
pub use common::{Album, BrowseID, ChannelID, Thumbnail, VideoID};
pub use error::{Error, Result};
use parse::{
AlbumParams, ArtistParams, Parse, SearchResultAlbum, SearchResultArtist, SearchResultEpisode,
SearchResultFeaturedPlaylist, SearchResultPlaylist, SearchResultPodcast, SearchResultProfile,
SearchResultSong, SearchResultVideo, SearchResults,
};
use process::RawResult;
use query::{
lyrics::GetLyricsQuery, watch::GetWatchPlaylistQuery, AlbumsFilter, ArtistsFilter, BasicSearch,
CommunityPlaylistsFilter, EpisodesFilter, FeaturedPlaylistsFilter, FilteredSearch,
GetAlbumQuery, GetArtistAlbumsQuery, GetArtistQuery, GetLibraryArtistsQuery,
GetLibraryPlaylistsQuery, GetSearchSuggestionsQuery, PlaylistsFilter, PodcastsFilter,
ProfilesFilter, Query, SearchQuery, SongsFilter, VideosFilter,
};
use reqwest::Client;
use std::path::Path;
pub mod auth;
mod utils;
mod locales {}
mod nav_consts;
pub mod common;
mod crawler;
mod error;
pub mod parse;
mod process;
pub mod query;
#[cfg(test)]
mod tests;
#[derive(Debug, Clone)]
pub struct YtMusic<A: AuthToken> {
client: Client,
token: A,
}
impl YtMusic<BrowserToken> {
pub fn from_browser_token(token: BrowserToken) -> YtMusic<BrowserToken> {
let client = Client::new();
YtMusic { client, token }
}
pub async fn from_cookie_file<P: AsRef<Path>>(path: P) -> Result<Self> {
let client = Client::new();
let token = BrowserToken::from_cookie_file(path, &client).await?;
Ok(Self { client, token })
}
pub async fn from_cookie<S: AsRef<str>>(cookie: S) -> Result<Self> {
let client = Client::new();
let token = BrowserToken::from_str(cookie.as_ref(), &client).await?;
Ok(Self { client, token })
}
}
impl YtMusic<OAuthToken> {
pub fn from_oauth_token(token: OAuthToken) -> YtMusic<OAuthToken> {
let client = Client::new();
YtMusic { client, token }
}
pub async fn refresh_token(&mut self) -> Result<OAuthToken> {
let refreshed_token = self.token.refresh(&self.client).await?;
self.token = refreshed_token.clone();
Ok(refreshed_token)
}
}
impl<A: AuthToken> YtMusic<A> {
async fn raw_query<Q: Query>(&self, query: Q) -> Result<RawResult<Q, A>> {
self.token.raw_query(&self.client, query).await
}
pub async fn json_query<Q: Query>(&self, query: Q) -> Result<String> {
let json = self.raw_query(query).await?.process()?.clone_json();
Ok(json)
}
pub async fn search<'a, Q: Into<SearchQuery<'a, BasicSearch>>>(
&self,
query: Q,
) -> Result<SearchResults> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_artists<'a, Q: Into<SearchQuery<'a, FilteredSearch<ArtistsFilter>>>>(
&self,
query: Q,
) -> Result<Vec<SearchResultArtist>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_albums<'a, Q: Into<SearchQuery<'a, FilteredSearch<AlbumsFilter>>>>(
&self,
query: Q,
) -> Result<Vec<SearchResultAlbum>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_songs<'a, Q: Into<SearchQuery<'a, FilteredSearch<SongsFilter>>>>(
&self,
query: Q,
) -> Result<Vec<SearchResultSong>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_playlists<'a, Q: Into<SearchQuery<'a, FilteredSearch<PlaylistsFilter>>>>(
&self,
query: Q,
) -> Result<Vec<SearchResultPlaylist>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_community_playlists<
'a,
Q: Into<SearchQuery<'a, FilteredSearch<CommunityPlaylistsFilter>>>,
>(
&self,
query: Q,
) -> Result<Vec<SearchResultPlaylist>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_featured_playlists<
'a,
Q: Into<SearchQuery<'a, FilteredSearch<FeaturedPlaylistsFilter>>>,
>(
&self,
query: Q,
) -> Result<Vec<SearchResultFeaturedPlaylist>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_episodes<'a, Q: Into<SearchQuery<'a, FilteredSearch<EpisodesFilter>>>>(
&self,
query: Q,
) -> Result<Vec<SearchResultEpisode>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_podcasts<'a, Q: Into<SearchQuery<'a, FilteredSearch<PodcastsFilter>>>>(
&self,
query: Q,
) -> Result<Vec<SearchResultPodcast>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_videos<'a, Q: Into<SearchQuery<'a, FilteredSearch<VideosFilter>>>>(
&self,
query: Q,
) -> Result<Vec<SearchResultVideo>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn search_profiles<'a, Q: Into<SearchQuery<'a, FilteredSearch<ProfilesFilter>>>>(
&self,
query: Q,
) -> Result<Vec<SearchResultProfile>> {
let query = query.into();
self.raw_query(query).await?.process()?.parse()
}
pub async fn get_artist(&self, query: GetArtistQuery<'_>) -> Result<ArtistParams> {
self.raw_query(query).await?.process()?.parse()
}
pub async fn get_artist_albums(&self, query: GetArtistAlbumsQuery<'_>) -> Result<Vec<Album>> {
self.raw_query(query).await?.process()?.parse()
}
pub async fn get_album(&self, query: GetAlbumQuery<'_>) -> Result<AlbumParams> {
self.raw_query(query).await?.process()?.parse()
}
pub async fn get_lyrics(&self, query: GetLyricsQuery<'_>) -> Result<Lyrics> {
self.raw_query(query).await?.process()?.parse()
}
pub async fn get_watch_playlist<'a, S: Into<GetWatchPlaylistQuery<VideoID<'a>>>>(
&self,
query: S,
) -> Result<WatchPlaylist> {
self.raw_query(query.into()).await?.process()?.parse()
}
pub async fn get_search_suggestions<'a, S: Into<GetSearchSuggestionsQuery<'a>>>(
&self,
query: S,
) -> Result<Vec<SearchSuggestion>> {
self.raw_query(query.into()).await?.process()?.parse()
}
pub async fn get_library_playlists(&self) -> Result<Vec<Playlist>> {
self.raw_query(GetLibraryPlaylistsQuery)
.await?
.process()?
.parse()
}
pub async fn get_library_artists(
&self,
query: GetLibraryArtistsQuery,
) -> Result<Vec<LibraryArtist>> {
self.raw_query(query).await?.process()?.parse()
}
}
pub async fn generate_oauth_code_and_url() -> Result<(OAuthDeviceCode, String)> {
let client = Client::new();
let code = OAuthTokenGenerator::new(&client).await?;
let url = format!("{}?user_code={}", code.verification_url, code.user_code);
Ok((code.device_code, url))
}
pub async fn generate_oauth_token(code: OAuthDeviceCode) -> Result<OAuthToken> {
let client = Client::new();
OAuthToken::from_code(&client, code).await
}
pub async fn generate_browser_token<S: AsRef<str>>(cookie: S) -> Result<BrowserToken> {
let client = Client::new();
BrowserToken::from_str(cookie.as_ref(), &client).await
}