Compare commits

..

3 commits

Author SHA1 Message Date
127596687b chore: update quick-xml
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2023-09-22 03:25:39 +02:00
1d1dcd622f feat: add tracing 2023-09-22 03:22:38 +02:00
ab599206c5 tests: expect album for artist top tracks 2023-09-22 02:50:44 +02:00
24 changed files with 156 additions and 73 deletions

View file

@ -35,7 +35,6 @@ regex = "1.6.0"
fancy-regex = "0.11.0"
thiserror = "1.0.36"
url = "2.2.2"
log = "0.4.17"
reqwest = { version = "0.11.11", default-features = false, features = [
"json",
"gzip",
@ -60,11 +59,10 @@ ress = "0.11.4"
phf = "0.11.1"
base64 = "0.21.0"
urlencoding = "2.1.2"
quick-xml = { version = "0.29.0", features = ["serialize"], optional = true }
quick-xml = { version = "0.30.0", features = ["serialize"], optional = true }
tracing = { version = "0.1.37", features = ["log"] }
[dev-dependencies]
env_logger = "0.10.0"
test-log = "0.2.11"
rstest = "0.18.1"
tokio-test = "0.4.2"
insta = { version = "1.17.1", features = ["ron", "redactions"] }

View file

@ -47,7 +47,7 @@ indicatif = "0.17.0"
futures = "0.3.21"
anyhow = "1.0"
clap = { version = "4.0.29", features = ["derive"] }
env_logger = "0.10.0"
tracing-subscriber = "0.3.17"
serde = "1.0"
serde_json = "1.0.82"
serde_yaml = "0.9.19"

View file

@ -390,7 +390,8 @@ async fn download_videos(
#[tokio::main]
async fn main() {
env_logger::builder().format_timestamp_micros().init();
// env_logger::builder().format_timestamp_micros().init();
tracing_subscriber::fmt::init();
let cli = Cli::parse();

View file

@ -20,7 +20,7 @@ use std::{
path::{Path, PathBuf},
};
use log::error;
use tracing::error;
pub(crate) const DEFAULT_CACHE_FILE: &str = "rustypipe_cache.json";

View file

@ -1,3 +1,5 @@
use std::fmt::Debug;
use serde::Serialize;
use url::Url;
@ -78,7 +80,8 @@ impl RustyPipeQuery {
}
/// Get the videos from a YouTube channel
pub async fn channel_videos<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn channel_videos<S: AsRef<str> + Debug>(
&self,
channel_id: S,
) -> Result<Channel<Paginator<VideoItem>>, Error> {
@ -89,7 +92,8 @@ impl RustyPipeQuery {
/// Get a ordered list of videos from a YouTube channel
///
/// This function does not return channel metadata.
pub async fn channel_videos_order<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn channel_videos_order<S: AsRef<str> + Debug>(
&self,
channel_id: S,
order: ChannelOrder,
@ -99,7 +103,8 @@ impl RustyPipeQuery {
}
/// Get the videos of the given tab (Shorts, Livestreams) from a YouTube channel
pub async fn channel_videos_tab<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn channel_videos_tab<S: AsRef<str> + Debug>(
&self,
channel_id: S,
tab: ChannelVideoTab,
@ -111,7 +116,8 @@ impl RustyPipeQuery {
/// Get a ordered list of videos from the given tab (Shorts, Livestreams) of a YouTube channel
///
/// This function does not return channel metadata.
pub async fn channel_videos_tab_order<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn channel_videos_tab_order<S: AsRef<str> + Debug>(
&self,
channel_id: S,
tab: ChannelVideoTab,
@ -128,7 +134,8 @@ impl RustyPipeQuery {
}
/// Search the videos of a channel
pub async fn channel_search<S: AsRef<str>, S2: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn channel_search<S: AsRef<str> + Debug, S2: AsRef<str> + Debug>(
&self,
channel_id: S,
query: S2,
@ -143,7 +150,8 @@ impl RustyPipeQuery {
}
/// Get the playlists of a channel
pub async fn channel_playlists<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn channel_playlists<S: AsRef<str> + Debug>(
&self,
channel_id: S,
) -> Result<Channel<Paginator<PlaylistItem>>, Error> {
@ -167,7 +175,8 @@ impl RustyPipeQuery {
}
/// Get additional metadata from the *About* tab of a channel
pub async fn channel_info<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn channel_info<S: AsRef<str> + Debug>(
&self,
channel_id: S,
) -> Result<Channel<ChannelInfo>, Error> {

View file

@ -1,3 +1,5 @@
use std::fmt::Debug;
use crate::{
error::{Error, ExtractionError},
model::ChannelRss,
@ -15,7 +17,11 @@ impl RustyPipeQuery {
/// for checking a lot of channels or implementing a subscription feed.
///
/// The downside of using the RSS feed is that it does not provide video durations.
pub async fn channel_rss<S: AsRef<str>>(&self, channel_id: S) -> Result<ChannelRss, Error> {
#[tracing::instrument(skip(self))]
pub async fn channel_rss<S: AsRef<str> + Debug>(
&self,
channel_id: S,
) -> Result<ChannelRss, Error> {
let channel_id = channel_id.as_ref();
let url = format!("https://www.youtube.com/feeds/videos.xml?channel_id={channel_id}");
let xml = self

View file

@ -489,7 +489,7 @@ impl RustyPipeBuilder {
.and_then(|data| match serde_json::from_str::<CacheData>(&data) {
Ok(data) => Some(data),
Err(e) => {
log::error!("Could not deserialize cache. Error: {}", e);
tracing::error!("Could not deserialize cache. Error: {}", e);
None
}
})
@ -745,7 +745,7 @@ impl RustyPipe {
// Retry in case of a recoverable status code (server err, too many requests)
if n != self.inner.n_http_retries {
let ms = util::retry_delay(n, 1000, 60000, 3);
log::warn!(
tracing::warn!(
"Retry attempt #{}. Error: {}. Waiting {} ms",
n + 1,
status,
@ -866,7 +866,7 @@ impl RustyPipe {
match desktop_client.get() {
Some(cdata) => cdata.version.clone(),
None => {
log::debug!("getting desktop client version");
tracing::debug!("getting desktop client version");
match self.extract_desktop_client_version().await {
Ok(version) => {
*desktop_client = CacheEntry::from(ClientData {
@ -877,7 +877,7 @@ impl RustyPipe {
version
}
Err(e) => {
log::warn!("{}, falling back to hardcoded desktop client version", e);
tracing::warn!("{}, falling back to hardcoded desktop client version", e);
DESKTOP_CLIENT_VERSION.to_owned()
}
}
@ -898,7 +898,7 @@ impl RustyPipe {
match music_client.get() {
Some(cdata) => cdata.version.clone(),
None => {
log::debug!("getting music client version");
tracing::debug!("getting music client version");
match self.extract_music_client_version().await {
Ok(version) => {
*music_client = CacheEntry::from(ClientData {
@ -909,7 +909,7 @@ impl RustyPipe {
version
}
Err(e) => {
log::warn!("{}, falling back to hardcoded music client version", e);
tracing::warn!("{}, falling back to hardcoded music client version", e);
DESKTOP_MUSIC_CLIENT_VERSION.to_owned()
}
}
@ -925,7 +925,7 @@ impl RustyPipe {
match deobf_data.get() {
Some(deobf_data) => Ok(deobf_data.clone()),
None => {
log::debug!("getting deobf data");
tracing::debug!("getting deobf data");
match DeobfData::extract(self.inner.http.clone(), self.inner.reporter.as_deref())
.await
@ -941,7 +941,7 @@ impl RustyPipe {
// Try to fall back to expired cache data if available, otherwise return error
match deobf_data.get_expired() {
Some(d) => {
log::warn!("could not get new deobf data ({e}), falling back to expired cache");
tracing::warn!("could not get new deobf data ({e}), falling back to expired cache");
Ok(d.clone())
}
None => Err(e),
@ -963,7 +963,7 @@ impl RustyPipe {
match serde_json::to_string(&cdata) {
Ok(data) => storage.write(&data),
Err(e) => log::error!("Could not serialize cache. Error: {}", e),
Err(e) => tracing::error!("Could not serialize cache. Error: {}", e),
}
}
}
@ -976,7 +976,7 @@ impl RustyPipe {
/// Sometimes YouTube does not set the `__Secure-YEC` cookie. In this case, the
/// visitor data is extracted from the html page.
async fn get_visitor_data(&self) -> Result<String, Error> {
log::debug!("getting YT visitor data");
tracing::debug!("getting YT visitor data");
let resp = self.inner.http.get(YOUTUBE_MUSIC_HOME_URL).send().await?;
let vdata = resp
@ -1284,6 +1284,7 @@ impl RustyPipeQuery {
let status = response.status();
let body = response.text().await?;
tracing::debug!("fetched {} bytes from YT", body.len());
let res = if status.is_client_error() || status.is_server_error() {
let error_msg = serde_json::from_str::<response::ErrorResponse>(&body)
@ -1314,9 +1315,11 @@ impl RustyPipeQuery {
}
};
tracing::debug!("mapped response");
Ok(RequestResult { res, status, body })
}
#[tracing::instrument(skip_all)]
async fn yt_request<R: DeserializeOwned + MapResponse<M> + Debug, M>(
&self,
request: &Request,
@ -1339,7 +1342,7 @@ impl RustyPipeQuery {
if n != self.client.inner.n_http_retries {
let ms = util::retry_delay(n, 1000, 60000, 3);
log::warn!(
tracing::warn!(
"Retry attempt #{}. Error: {}. Waiting {} ms",
n + 1,
err,
@ -1380,7 +1383,7 @@ impl RustyPipeQuery {
body: &B,
deobf: Option<&DeobfData>,
) -> Result<M, Error> {
log::debug!("getting {}({})", operation, id);
tracing::debug!("getting {}({})", operation, id);
let request = self
.request_builder(ctype, endpoint)
@ -1528,7 +1531,7 @@ trait MapResponse<T> {
fn validate_country(country: Country) -> Country {
if country == Country::Zz {
log::warn!("Country:Zz (Global) can only be used for fetching music charts, falling back to Country:Us");
tracing::warn!("Country:Zz (Global) can only be used for fetching music charts, falling back to Country:Us");
Country::Us
} else {
country

View file

@ -2,6 +2,7 @@ use std::borrow::Cow;
use once_cell::sync::Lazy;
use regex::Regex;
use tracing::debug;
use crate::{
client::response::url_endpoint::NavigationEndpoint,
@ -29,7 +30,7 @@ impl RustyPipeQuery {
let res = self._music_artist(artist_id, all_albums).await;
if let Err(Error::Extraction(ExtractionError::Redirect(id))) = res {
log::debug!("music artist {} redirects to {}", artist_id, &id);
debug!("music artist {} redirects to {}", artist_id, &id);
self._music_artist(&id, all_albums).await
} else {
res

View file

@ -32,6 +32,7 @@ struct FormData {
impl RustyPipeQuery {
/// Get the YouTube Music charts for a given country
#[tracing::instrument(skip(self))]
pub async fn music_charts(&self, country: Option<Country>) -> Result<MusicCharts, Error> {
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QCharts {

View file

@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::{borrow::Cow, fmt::Debug};
use serde::Serialize;
@ -38,7 +38,11 @@ struct QRadio<'a> {
impl RustyPipeQuery {
/// Get the metadata of a YouTube music track
pub async fn music_details<S: AsRef<str>>(&self, video_id: S) -> Result<TrackDetails, Error> {
#[tracing::instrument(skip(self))]
pub async fn music_details<S: AsRef<str> + Debug>(
&self,
video_id: S,
) -> Result<TrackDetails, Error> {
let video_id = video_id.as_ref();
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QMusicDetails {
@ -62,7 +66,8 @@ impl RustyPipeQuery {
/// Get the lyrics of a YouTube music track
///
/// The `lyrics_id` has to be obtained using [`RustyPipeQuery::music_details`].
pub async fn music_lyrics<S: AsRef<str>>(&self, lyrics_id: S) -> Result<Lyrics, Error> {
#[tracing::instrument(skip(self))]
pub async fn music_lyrics<S: AsRef<str> + Debug>(&self, lyrics_id: S) -> Result<Lyrics, Error> {
let lyrics_id = lyrics_id.as_ref();
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QBrowse {
@ -83,7 +88,11 @@ impl RustyPipeQuery {
/// Get related items (tracks, playlists, artists) to a YouTube Music track
///
/// The `related_id` has to be obtained using [`RustyPipeQuery::music_details`].
pub async fn music_related<S: AsRef<str>>(&self, related_id: S) -> Result<MusicRelated, Error> {
#[tracing::instrument(skip(self))]
pub async fn music_related<S: AsRef<str> + Debug>(
&self,
related_id: S,
) -> Result<MusicRelated, Error> {
let related_id = related_id.as_ref();
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QBrowse {
@ -104,7 +113,8 @@ impl RustyPipeQuery {
/// Get a YouTube Music radio (a dynamically generated playlist)
///
/// The `radio_id` can be obtained using [`RustyPipeQuery::music_artist`] to get an artist's radio.
pub async fn music_radio<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn music_radio<S: AsRef<str> + Debug>(
&self,
radio_id: S,
) -> Result<Paginator<TrackItem>, Error> {
@ -133,7 +143,8 @@ impl RustyPipeQuery {
}
/// Get a YouTube Music radio (a dynamically generated playlist) for a track
pub async fn music_radio_track<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn music_radio_track<S: AsRef<str> + Debug>(
&self,
video_id: S,
) -> Result<Paginator<TrackItem>, Error> {
@ -142,7 +153,8 @@ impl RustyPipeQuery {
}
/// Get a YouTube Music radio (a dynamically generated playlist) for a playlist
pub async fn music_radio_playlist<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn music_radio_playlist<S: AsRef<str> + Debug>(
&self,
playlist_id: S,
) -> Result<Paginator<TrackItem>, Error> {

View file

@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::{borrow::Cow, fmt::Debug};
use crate::{
error::{Error, ExtractionError},
@ -13,6 +13,7 @@ use super::{
impl RustyPipeQuery {
/// Get a list of moods and genres from YouTube Music
#[tracing::instrument(skip(self))]
pub async fn music_genres(&self) -> Result<Vec<MusicGenreItem>, Error> {
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QBrowse {
@ -31,7 +32,11 @@ impl RustyPipeQuery {
}
/// Get the playlists from a YouTube Music genre
pub async fn music_genre<S: AsRef<str>>(&self, genre_id: S) -> Result<MusicGenre, Error> {
#[tracing::instrument(skip(self))]
pub async fn music_genre<S: AsRef<str> + Debug>(
&self,
genre_id: S,
) -> Result<MusicGenre, Error> {
let genre_id = genre_id.as_ref();
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QBrowseParams {

View file

@ -10,6 +10,7 @@ use super::{response, ClientType, MapResponse, QBrowse, RustyPipeQuery};
impl RustyPipeQuery {
/// Get the new albums that were released on YouTube Music
#[tracing::instrument(skip(self))]
pub async fn music_new_albums(&self) -> Result<Vec<AlbumItem>, Error> {
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QBrowse {
@ -28,6 +29,7 @@ impl RustyPipeQuery {
}
/// Get the new music videos that were released on YouTube Music
#[tracing::instrument(skip(self))]
pub async fn music_new_videos(&self) -> Result<Vec<TrackItem>, Error> {
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QBrowse {

View file

@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::{borrow::Cow, fmt::Debug};
use crate::{
error::{Error, ExtractionError},
@ -17,7 +17,8 @@ use super::{
impl RustyPipeQuery {
/// Get a playlist from YouTube Music
pub async fn music_playlist<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn music_playlist<S: AsRef<str> + Debug>(
&self,
playlist_id: S,
) -> Result<MusicPlaylist, Error> {
@ -39,7 +40,11 @@ impl RustyPipeQuery {
}
/// Get an album from YouTube Music
pub async fn music_album<S: AsRef<str>>(&self, album_id: S) -> Result<MusicAlbum, Error> {
#[tracing::instrument(skip(self))]
pub async fn music_album<S: AsRef<str> + Debug>(
&self,
album_id: S,
) -> Result<MusicAlbum, Error> {
let album_id = album_id.as_ref();
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QBrowse {

View file

@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::{borrow::Cow, fmt::Debug};
use serde::Serialize;
@ -48,7 +48,11 @@ enum Params {
impl RustyPipeQuery {
/// Search YouTube Music. Returns items from any type.
pub async fn music_search<S: AsRef<str>>(&self, query: S) -> Result<MusicSearchResult, Error> {
#[tracing::instrument(skip(self))]
pub async fn music_search<S: AsRef<str> + Debug>(
&self,
query: S,
) -> Result<MusicSearchResult, Error> {
let query = query.as_ref();
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QSearch {
@ -68,7 +72,8 @@ impl RustyPipeQuery {
}
/// Search YouTube Music tracks
pub async fn music_search_tracks<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn music_search_tracks<S: AsRef<str> + Debug>(
&self,
query: S,
) -> Result<MusicSearchFiltered<TrackItem>, Error> {
@ -76,7 +81,8 @@ impl RustyPipeQuery {
}
/// Search YouTube Music videos
pub async fn music_search_videos<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn music_search_videos<S: AsRef<str> + Debug>(
&self,
query: S,
) -> Result<MusicSearchFiltered<TrackItem>, Error> {
@ -107,7 +113,8 @@ impl RustyPipeQuery {
}
/// Search YouTube Music albums
pub async fn music_search_albums<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn music_search_albums<S: AsRef<str> + Debug>(
&self,
query: S,
) -> Result<MusicSearchFiltered<AlbumItem>, Error> {
@ -130,10 +137,12 @@ impl RustyPipeQuery {
}
/// Search YouTube Music artists
pub async fn music_search_artists(
#[tracing::instrument(skip(self))]
pub async fn music_search_artists<S: AsRef<str> + Debug>(
&self,
query: &str,
query: S,
) -> Result<MusicSearchFiltered<ArtistItem>, Error> {
let query = query.as_ref();
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QSearch {
context,
@ -154,7 +163,8 @@ impl RustyPipeQuery {
///
/// Playlists are filtered whether they are created by users
/// (`community=true`) or by YouTube Music (`community=false`)
pub async fn music_search_playlists<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn music_search_playlists<S: AsRef<str> + Debug>(
&self,
query: S,
community: bool,
@ -182,7 +192,8 @@ impl RustyPipeQuery {
}
/// Get YouTube Music search suggestions
pub async fn music_search_suggestion<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn music_search_suggestion<S: AsRef<str> + Debug>(
&self,
query: S,
) -> Result<MusicSearchSuggestion, Error> {

View file

@ -1,3 +1,5 @@
use std::fmt::Debug;
use crate::error::{Error, ExtractionError};
use crate::model::{
paginator::{ContinuationEndpoint, Paginator},
@ -11,7 +13,8 @@ use super::{response, ClientType, MapResponse, QContinuation, RustyPipeQuery};
impl RustyPipeQuery {
/// Get more YouTube items from the given continuation token and endpoint
pub async fn continuation<T: FromYtItem, S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn continuation<T: FromYtItem, S: AsRef<str> + Debug>(
&self,
ctoken: S,
endpoint: ContinuationEndpoint,

View file

@ -1,6 +1,7 @@
use std::{
borrow::Cow,
collections::{BTreeMap, HashMap},
fmt::Debug,
};
use once_cell::sync::Lazy;
@ -61,7 +62,8 @@ struct QContentPlaybackContext<'a> {
impl RustyPipeQuery {
/// Get YouTube player data (video/audio streams + basic metadata)
pub async fn player<S: AsRef<str>>(&self, video_id: S) -> Result<VideoPlayer, Error> {
#[tracing::instrument(skip(self))]
pub async fn player<S: AsRef<str> + Debug>(&self, video_id: S) -> Result<VideoPlayer, Error> {
let video_id = video_id.as_ref();
let desktop_res = self.player_from_client(video_id, ClientType::Desktop).await;
@ -90,7 +92,8 @@ impl RustyPipeQuery {
}
/// Get YouTube player data (video/audio streams + basic metadata) using the specified client
pub async fn player_from_client<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn player_from_client<S: AsRef<str> + Debug>(
&self,
video_id: S,
client_type: ClientType,

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, convert::TryFrom};
use std::{borrow::Cow, convert::TryFrom, fmt::Debug};
use time::OffsetDateTime;
@ -12,7 +12,8 @@ use super::{response, ClientType, MapResponse, MapResult, QBrowse, RustyPipeQuer
impl RustyPipeQuery {
/// Get a YouTube playlist
pub async fn playlist<S: AsRef<str>>(&self, playlist_id: S) -> Result<Playlist, Error> {
#[tracing::instrument(skip(self))]
pub async fn playlist<S: AsRef<str> + Debug>(&self, playlist_id: S) -> Result<Playlist, Error> {
let playlist_id = playlist_id.as_ref();
let context = self.get_context(ClientType::Desktop, true, None).await;
let request_body = QBrowse {

View file

@ -1,3 +1,5 @@
use std::fmt::Debug;
use serde::Serialize;
use crate::{
@ -19,7 +21,8 @@ struct QSearch<'a> {
impl RustyPipeQuery {
/// Search YouTube
pub async fn search<S: AsRef<str>>(&self, query: S) -> Result<SearchResult, Error> {
#[tracing::instrument(skip(self))]
pub async fn search<S: AsRef<str> + Debug>(&self, query: S) -> Result<SearchResult, Error> {
let query = query.as_ref();
let context = self.get_context(ClientType::Desktop, true, None).await;
let request_body = QSearch {
@ -39,7 +42,8 @@ impl RustyPipeQuery {
}
/// Search YouTube using the given [`SearchFilter`]
pub async fn search_filter<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn search_filter<S: AsRef<str> + Debug>(
&self,
query: S,
filter: &SearchFilter,
@ -63,7 +67,11 @@ impl RustyPipeQuery {
}
/// Get YouTube search suggestions
pub async fn search_suggestion<S: AsRef<str>>(&self, query: S) -> Result<Vec<String>, Error> {
#[tracing::instrument(skip(self))]
pub async fn search_suggestion<S: AsRef<str> + Debug>(
&self,
query: S,
) -> Result<Vec<String>, Error> {
let url = url::Url::parse_with_params(
"https://suggestqueries-clients6.youtube.com/complete/search?client=youtube&xhr=t",
&[

View file

@ -11,6 +11,7 @@ use super::{response, ClientType, MapResponse, QBrowse, QBrowseParams, RustyPipe
impl RustyPipeQuery {
/// Get the videos from the YouTube startpage
#[tracing::instrument(skip(self))]
pub async fn startpage(&self) -> Result<Paginator<VideoItem>, Error> {
let context = self.get_context(ClientType::Desktop, true, None).await;
let request_body = QBrowse {
@ -29,6 +30,7 @@ impl RustyPipeQuery {
}
/// Get the videos from the YouTube trending page
#[tracing::instrument(skip(self))]
pub async fn trending(&self) -> Result<Vec<VideoItem>, Error> {
let context = self.get_context(ClientType::Desktop, true, None).await;
let request_body = QBrowseParams {

View file

@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::{borrow::Cow, fmt::Debug};
use serde::Serialize;
@ -59,7 +59,8 @@ impl RustyPipeQuery {
/// );
/// # });
/// ```
pub async fn resolve_url<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn resolve_url<S: AsRef<str> + Debug>(
self,
url: S,
resolve_albums: bool,
@ -236,7 +237,8 @@ impl RustyPipeQuery {
/// );
/// # });
/// ```
pub async fn resolve_string<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn resolve_string<S: AsRef<str> + Debug>(
self,
s: S,
resolve_albums: bool,

View file

@ -1,3 +1,5 @@
use std::fmt::Debug;
use serde::Serialize;
use crate::{
@ -26,7 +28,11 @@ struct QVideo<'a> {
impl RustyPipeQuery {
/// Get the metadata for a video
pub async fn video_details<S: AsRef<str>>(&self, video_id: S) -> Result<VideoDetails, Error> {
#[tracing::instrument(skip(self))]
pub async fn video_details<S: AsRef<str> + Debug>(
&self,
video_id: S,
) -> Result<VideoDetails, Error> {
let video_id = video_id.as_ref();
let context = self.get_context(ClientType::Desktop, true, None).await;
let request_body = QVideo {
@ -47,7 +53,8 @@ impl RustyPipeQuery {
}
/// Get the comments for a video using the continuation token obtained from `rusty_pipe_query.video_details()`
pub async fn video_comments<S: AsRef<str>>(
#[tracing::instrument(skip(self))]
pub async fn video_comments<S: AsRef<str> + Debug>(
&self,
ctoken: S,
visitor_data: Option<&str>,

View file

@ -29,7 +29,7 @@ impl DeobfData {
pub async fn extract(http: Client, reporter: Option<&dyn Reporter>) -> Result<Self, Error> {
let js_url = get_player_js_url(&http).await?;
let player_js = get_response(&http, &js_url).await?;
log::debug!("downloaded player.js from {}", js_url);
tracing::debug!("downloaded player.js from {}", js_url);
let res = Self::extract_fns(&js_url, &player_js);
@ -89,7 +89,7 @@ impl Deobfuscator {
res.as_str().map_or(
Err(DeobfError::Other("sig deobfuscation func returned null")),
|res| {
log::debug!("deobfuscated sig");
tracing::debug!("deobfuscated sig");
Ok(res.to_owned())
},
)
@ -102,7 +102,7 @@ impl Deobfuscator {
res.as_str().map_or(
Err(DeobfError::Other("nsig deobfuscation func returned null")),
|res| {
log::debug!("deobfuscated nsig");
tracing::debug!("deobfuscated nsig");
Ok(res.to_owned())
},
)

View file

@ -23,9 +23,9 @@ use std::{
path::{Path, PathBuf},
};
use log::error;
use serde::{Deserialize, Serialize};
use time::{macros::format_description, OffsetDateTime};
use tracing::error;
use crate::{deobfuscate::DeobfData, util};

View file

@ -32,7 +32,6 @@ use rustypipe::param::{
#[case::tv_html5_embed(ClientType::TvHtml5Embed)]
#[case::android(ClientType::Android)]
#[case::ios(ClientType::Ios)]
#[test_log::test]
fn get_player_from_client(#[case] client_type: ClientType, rp: RustyPipe) {
let player_data =
tokio_test::block_on(rp.query().player_from_client("n4tK7LYFxI0", client_type)).unwrap();
@ -1469,7 +1468,6 @@ fn music_album_not_found(rp: RustyPipe) {
#[case::no_artist("no_artist", "UCh8gHdtzO2tXd593_bjErWg", false, 0, 2)]
// querying Trailerpark's secondary YouTube channel should result in the YTM channel being fetched
#[case::secondary_channel("no_more_albums", "UCC9192yGQD25eBZgFZ84MPw", true, 15, 0)]
#[test_log::test]
fn music_artist(
#[case] name: &str,
#[case] id: &str,
@ -1491,12 +1489,17 @@ fn music_artist(
assert_gte(artist.subscriber_count.unwrap(), 30000, "subscribers");
}
artist.tracks.iter().for_each(|t| {
assert!(!t.cover.is_empty());
if t.is_video {
assert!(t.view_count.is_some());
} else {
assert!(t.album.is_some());
}
});
// Check images
assert!(!artist.header_image.is_empty(), "got no header image");
artist
.tracks
.iter()
.for_each(|t| assert!(!t.cover.is_empty()));
artist
.albums
.iter()