#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(not(any(feature = "rustls", feature = "native-tls", feature = "default-tls")))]
compile_error!("One of the TLS features must be enabled for this crate");
use auth::browser::BrowserToken;
use auth::noauth::NoAuthToken;
use auth::oauth::OAuthDeviceCode;
use auth::{AuthToken, OAuthToken, OAuthTokenGenerator, RawResult};
#[doc(inline)]
pub use builder::YtMusicBuilder;
#[doc(inline)]
pub use client::Client;
use common::ApiOutcome;
use continuations::ParseFromContinuable;
#[doc(inline)]
pub use error::{Error, Result};
use futures::Stream;
use json::Json;
use parse::ParseFrom;
#[doc(inline)]
pub use parse::ProcessedResult;
use query::{PostQuery, Query, QueryMethod};
use std::borrow::Borrow;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::path::Path;
#[macro_use]
mod utils;
mod nav_consts;
mod upload_song;
mod youtube_enums;
pub mod auth;
pub mod builder;
pub mod client;
pub mod common;
pub mod continuations;
pub mod error;
pub mod json;
pub mod parse;
pub mod query;
#[cfg(feature = "simplified-queries")]
#[cfg_attr(docsrs, doc(cfg(feature = "simplified-queries")))]
pub mod simplified_queries;
#[derive(Debug, Clone)]
pub struct YtMusic<A: AuthToken> {
client: Client,
token: A,
}
impl YtMusic<NoAuthToken> {
pub async fn new_unauthenticated() -> Result<Self> {
let client = Client::new().expect("Expected Client build to succeed");
let token = NoAuthToken::new(&client).await?;
Ok(YtMusic { client, token })
}
}
impl YtMusic<BrowserToken> {
#[deprecated = "Use generic `from_auth_token` instead"]
pub fn from_browser_token(token: BrowserToken) -> YtMusic<BrowserToken> {
let client = Client::new().expect("Expected Client build to succeed");
YtMusic { client, token }
}
pub async fn from_cookie_file<P: AsRef<Path>>(path: P) -> Result<Self> {
let client = Client::new().expect("Expected Client build to succeed");
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().expect("Expected Client build to succeed");
let token = BrowserToken::from_str(cookie.as_ref(), &client).await?;
Ok(Self { client, token })
}
pub async fn upload_song(&self, file_path: impl AsRef<Path>) -> Result<ApiOutcome> {
upload_song::upload_song(file_path, &self.token, &self.client).await
}
}
impl YtMusic<OAuthToken> {
#[deprecated = "Use generic `from_auth_token` instead"]
pub fn from_oauth_token(token: OAuthToken) -> YtMusic<OAuthToken> {
let client = Client::new().expect("Expected Client build to succeed");
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)
}
pub fn get_token_hash(&self) -> u64 {
let mut h = DefaultHasher::new();
self.token.hash(&mut h);
h.finish()
}
}
impl<A: AuthToken> YtMusic<A> {
pub fn from_auth_token(token: A) -> YtMusic<A> {
let client = Client::new().expect("Expected Client build to succeed");
YtMusic { client, token }
}
pub async fn raw_json_query<Q: Query<A>>(&self, query: impl Borrow<Q>) -> Result<String> {
Q::Method::call(query.borrow(), &self.client, &self.token)
.await
.map(|raw| raw.json)
}
pub async fn json_query<Q: Query<A>>(&self, query: impl Borrow<Q>) -> Result<Json> {
Q::Method::call(query.borrow(), &self.client, &self.token)
.await?
.process()
.map(|processed| processed.json)
}
pub async fn query<Q: Query<A>>(&self, query: impl Borrow<Q>) -> Result<Q::Output> {
Q::Output::parse_from(
Q::Method::call(query.borrow(), &self.client, &self.token)
.await?
.process()?,
)
}
pub fn stream<'a, Q>(&'a self, query: &'a Q) -> impl Stream<Item = Result<Q::Output>> + 'a
where
Q: Query<A>,
Q: PostQuery,
Q::Output: ParseFromContinuable<Q>,
{
continuations::stream(query, &self.client, &self.token)
}
pub fn raw_json_stream<'a, Q>(&'a self, query: &'a Q) -> impl Stream<Item = Result<String>> + 'a
where
Q: Query<A>,
Q: PostQuery,
Q::Output: ParseFromContinuable<Q>,
{
continuations::raw_json_stream(query, &self.client, &self.token)
}
}
pub async fn generate_oauth_code_and_url(
client: &Client,
client_id: impl Into<String>,
) -> Result<(OAuthDeviceCode, String)> {
let code = OAuthTokenGenerator::new(client, client_id).await?;
let url = format!("{}?user_code={}", code.verification_url, code.user_code);
Ok((code.device_code, url))
}
pub async fn generate_oauth_token(
client: &Client,
code: OAuthDeviceCode,
client_id: impl Into<String>,
client_secret: impl Into<String>,
) -> Result<OAuthToken> {
let token = OAuthToken::from_code(client, code, client_id, client_secret).await?;
Ok(token)
}
pub async fn generate_browser_token<S: AsRef<str>>(
client: &Client,
cookie: S,
) -> Result<BrowserToken> {
let token = BrowserToken::from_str(cookie.as_ref(), client).await?;
Ok(token)
}
pub fn process_json<Q: Query<A>, A: AuthToken>(
json: String,
query: impl Borrow<Q>,
) -> Result<Q::Output> {
Q::Output::parse_from(RawResult::<Q, A>::from_raw(json, query.borrow()).process()?)
}