#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(not(any(
feature = "rustls-tls",
feature = "native-tls",
feature = "default-tls"
)))]
compile_error!("One of the TLS features must be enabled for this crate");
use auth::{
browser::BrowserToken, oauth::OAuthDeviceCode, AuthToken, OAuthToken, OAuthTokenGenerator,
};
use continuations::Continuable;
use futures::Stream;
use parse::ParseFrom;
use query::{PostQuery, Query, QueryMethod};
use std::{
borrow::Borrow,
hash::{DefaultHasher, Hash, Hasher},
path::Path,
};
#[doc(inline)]
pub use builder::YtMusicBuilder;
#[doc(inline)]
pub use client::Client;
#[doc(inline)]
pub use error::{Error, Result};
#[doc(inline)]
pub use parse::ProcessedResult;
#[doc(inline)]
pub use process::RawResult;
#[macro_use]
mod utils;
mod nav_consts;
mod process;
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;
#[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().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 })
}
}
impl YtMusic<OAuthToken> {
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 async fn raw_query<'a, Q: Query<A>>(&self, query: &'a Q) -> Result<RawResult<'a, Q, A>> {
Q::Method::call(query, &self.client, &self.token).await
}
pub async fn processed_query<'a, Q: Query<A>>(
&self,
query: &'a Q,
) -> Result<ProcessedResult<'a, Q>> {
self.raw_query(query).await?.process()
}
pub async fn json_query<Q: Query<A>>(&self, query: impl Borrow<Q>) -> Result<String> {
let json = self
.raw_query(query.borrow())
.await?
.process()?
.clone_json();
Ok(json)
}
pub async fn query<Q: Query<A>>(&self, query: impl Borrow<Q>) -> Result<Q::Output> {
Q::Output::parse_from(self.processed_query(query.borrow()).await?)
}
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: Continuable<Q>,
{
continuations::stream(query, &self.client, &self.token)
}
}
pub async fn generate_oauth_code_and_url(client: &Client) -> Result<(OAuthDeviceCode, String)> {
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(client: &Client, code: OAuthDeviceCode) -> Result<OAuthToken> {
let token = OAuthToken::from_code(client, code).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::from_raw(json, query.borrow()).process()?)
}