diff --git a/src/client/mod.rs b/src/client/mod.rs index 9150b09..b454b8e 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -25,6 +25,7 @@ mod channel_rss; use std::sync::Arc; use std::{borrow::Cow, fmt::Debug}; +use log::{debug, error, warn}; use once_cell::sync::Lazy; use rand::Rng; use regex::Regex; @@ -167,13 +168,13 @@ const YOUTUBE_MUSIC_HOME_URL: &str = "https://music.youtube.com/"; const DISABLE_PRETTY_PRINT_PARAMETER: &str = "&prettyPrint=false"; -const DESKTOP_CLIENT_VERSION: &str = "2.20230126.00.00"; +const DESKTOP_CLIENT_VERSION: &str = "2.20221011.00.00"; const DESKTOP_API_KEY: &str = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8"; const TVHTML5_CLIENT_VERSION: &str = "2.0"; const DESKTOP_MUSIC_API_KEY: &str = "AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30"; -const DESKTOP_MUSIC_CLIENT_VERSION: &str = "1.20230123.01.01"; +const DESKTOP_MUSIC_CLIENT_VERSION: &str = "1.20221005.01.00"; -const MOBILE_CLIENT_VERSION: &str = "18.03.33"; +const MOBILE_CLIENT_VERSION: &str = "17.39.35"; const ANDROID_API_KEY: &str = "AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w"; const IOS_API_KEY: &str = "AIzaSyB-63vPrdThhKuerbB2N_l7Kwwcxj6yUAc"; const IOS_DEVICE_MODEL: &str = "iPhone14,5"; @@ -322,7 +323,6 @@ impl RustyPipeBuilder { .user_agent(self.user_agent) .gzip(true) .brotli(true) - .redirect(reqwest::redirect::Policy::none()) .build() .unwrap(); @@ -331,7 +331,7 @@ impl RustyPipeBuilder { match serde_json::from_str::(&data) { Ok(data) => data, Err(e) => { - log::error!("Could not deserialize cache. Error: {}", e); + error!("Could not deserialize cache. Error: {}", e); CacheData::default() } } @@ -523,7 +523,7 @@ impl RustyPipe { }; let ms = util::retry_delay(n, 1000, 60000, 3); - log::warn!("Retry attempt #{}. Error: {}. Waiting {} ms", n, emsg, ms); + warn!("Retry attempt #{}. Error: {}. Waiting {} ms", n, emsg, ms); tokio::time::sleep(std::time::Duration::from_millis(ms.into())).await; last_res = Some(res); @@ -656,7 +656,7 @@ impl RustyPipe { match desktop_client.get() { Some(cdata) => cdata.version.to_owned(), None => { - log::debug!("getting desktop client version"); + debug!("getting desktop client version"); match self.extract_desktop_client_version().await { Ok(version) => { *desktop_client = CacheEntry::from(ClientData { @@ -667,7 +667,7 @@ impl RustyPipe { version } Err(e) => { - log::warn!("{}, falling back to hardcoded version", e); + warn!("{}, falling back to hardcoded version", e); DESKTOP_CLIENT_VERSION.to_owned() } } @@ -688,7 +688,7 @@ impl RustyPipe { match music_client.get() { Some(cdata) => cdata.version.to_owned(), None => { - log::debug!("getting music client version"); + debug!("getting music client version"); match self.extract_music_client_version().await { Ok(version) => { *music_client = CacheEntry::from(ClientData { @@ -699,7 +699,7 @@ impl RustyPipe { version } Err(e) => { - log::warn!("{}, falling back to hardcoded version", e); + warn!("{}, falling back to hardcoded version", e); DESKTOP_MUSIC_CLIENT_VERSION.to_owned() } } @@ -715,7 +715,7 @@ impl RustyPipe { match deobf.get() { Some(deobf) => Ok(Deobfuscator::from(deobf.to_owned())), None => { - log::debug!("getting deobfuscator"); + debug!("getting deobfuscator"); let new_deobf = Deobfuscator::new(self.inner.http.clone()).await?; *deobf = CacheEntry::from(new_deobf.get_data()); drop(deobf); @@ -736,13 +736,12 @@ 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) => error!("Could not serialize cache. Error: {}", e), } } } async fn get_ytm_visitor_data(&self) -> Result { - log::debug!("getting YTM visitor data"); let resp = self.inner.http.get(YOUTUBE_MUSIC_HOME_URL).send().await?; resp.headers() @@ -1041,8 +1040,6 @@ impl RustyPipeQuery { body: &B, deobf: Option<&Deobfuscator>, ) -> Result { - log::debug!("getting {}({})", operation, id); - let request = self .request_builder(ctype, endpoint) .await @@ -1215,7 +1212,7 @@ trait MapResponse { 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"); + warn!("Country:Zz (Global) can only be used for fetching music charts, falling back to Country:Us"); Country::Us } else { country @@ -1226,11 +1223,10 @@ fn validate_country(country: Country) -> Country { mod tests { use super::*; - #[test] - fn t_get_ytm_visitor_data() { + #[tokio::test] + async fn t_get_ytm_visitor_data() { let rp = RustyPipe::new(); - let visitor_data = tokio_test::block_on(rp.get_ytm_visitor_data()).unwrap(); - dbg!(&visitor_data); + let visitor_data = rp.get_ytm_visitor_data().await.unwrap(); assert!(visitor_data.ends_with("%3D")); assert_eq!(visitor_data.len(), 32) } diff --git a/src/client/music_artist.rs b/src/client/music_artist.rs index 3319316..12e79d4 100644 --- a/src/client/music_artist.rs +++ b/src/client/music_artist.rs @@ -34,83 +34,77 @@ impl RustyPipeQuery { artist_id: S, all_albums: bool, ) -> Result { - let artist_id = artist_id.as_ref(); - let visitor_data = match all_albums { - true => Some(self.get_ytm_visitor_data().await?), - false => None, - }; - - let res = self._music_artist(artist_id, visitor_data.as_deref()).await; + 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); - self._music_artist(&id, visitor_data.as_deref()).await + self._music_artist(&id, all_albums).await.map(|x| *x) } else { - res + res.map(|x| *x) } } - async fn _music_artist( + async fn _music_artist>( &self, - artist_id: &str, - all_albums_vdata: Option<&str>, - ) -> Result { - match all_albums_vdata { - Some(visitor_data) => { - let context = self - .get_context(ClientType::DesktopMusic, true, Some(visitor_data)) - .await; - let request_body = QBrowse { - context, - browse_id: artist_id, - }; + artist_id: S, + all_albums: bool, + ) -> Result, Error> { + let artist_id = artist_id.as_ref(); - let (mut artist, album_page_params) = self - .execute_request::( - ClientType::DesktopMusic, - "music_artist", - artist_id, - "browse", - &request_body, - ) - .await?; + if all_albums { + let visitor_data = self.get_ytm_visitor_data().await?; + let context = self + .get_context(ClientType::DesktopMusic, true, Some(&visitor_data)) + .await; + let request_body = QBrowse { + context, + browse_id: artist_id, + }; - let visitor_data = Rc::new(visitor_data); - let album_page_results = stream::iter(album_page_params) - .map(|params| { - let visitor_data = visitor_data.clone(); - async move { - self.music_artist_album_page(artist_id, ¶ms, &visitor_data) - .await - } - }) - .buffer_unordered(2) - .collect::>() - .await; - - for res in album_page_results { - let mut res = res?; - artist.albums.append(&mut res); - } - - Ok(artist) - } - None => { - let context = self.get_context(ClientType::DesktopMusic, true, None).await; - let request_body = QBrowse { - context, - browse_id: artist_id, - }; - - self.execute_request::( + let (mut artist, album_page_params) = self + .execute_request::( ClientType::DesktopMusic, "music_artist", artist_id, "browse", &request_body, ) - .await + .await?; + + let visitor_data = Rc::new(visitor_data); + let album_page_results = stream::iter(album_page_params) + .map(|params| { + let visitor_data = visitor_data.clone(); + async move { + self.music_artist_album_page(artist_id, ¶ms, &visitor_data) + .await + } + }) + .buffer_unordered(2) + .collect::>() + .await; + + for res in album_page_results { + let mut res = res?; + artist.albums.append(&mut res); } + + Ok(artist.into()) + } else { + let context = self.get_context(ClientType::DesktopMusic, true, None).await; + let request_body = QBrowse { + context, + browse_id: artist_id, + }; + + self.execute_request::( + ClientType::DesktopMusic, + "music_artist", + artist_id, + "browse", + &request_body, + ) + .await + .map(|x: MusicArtist| x.into()) } } @@ -243,24 +237,14 @@ fn map_artist_page( { if let Some(cfg) = bep.browse_endpoint_context_supported_configs { match cfg.browse_endpoint_context_music_config.page_type { - // Music videos PageType::Playlist => { if videos_playlist_id.is_none() { videos_playlist_id = Some(bep.browse_id); } } - // Albums or playlists PageType::Artist => { - // Peek at the first item to determine type - if let Some(response::music_item::MusicResponseItem::MusicTwoRowItemRenderer(item)) = shelf.contents.c.first() { - if let Some(PageType::Album) = item.navigation_endpoint.browse_endpoint.as_ref().and_then(|be| { - be.browse_endpoint_context_supported_configs.as_ref().map(|config| { - config.browse_endpoint_context_music_config.page_type - })}) { - album_page_params.push(bep.params); - extendable_albums = true; - } - } + album_page_params.push(bep.params); + extendable_albums = true; } _ => {} } diff --git a/src/client/player.rs b/src/client/player.rs index 05061cb..c646b31 100644 --- a/src/client/player.rs +++ b/src/client/player.rs @@ -676,7 +676,7 @@ mod tests { let (url, throttled) = map_res.c.unwrap(); assert_eq!(url, "https://rr5---sn-h0jelnez.googlevideo.com/videoplayback?c=WEB&clen=3781277&dur=229.301&ei=vb7nYvH5BMK8gAfBj7ToBQ&expire=1659376413&fexp=24001373%2C24007246&fvip=5&gir=yes&id=o-AB_BABwrXZJN428ZwDxq5ScPn2AbcGODnRlTVhCQ3mj2&initcwndbps=1588750&ip=2003%3Ade%3Aaf06%3A6300%3Ac750%3A1b77%3Ac74a%3A80e3&itag=251&keepalive=yes&lmt=1655510291473933&lsig=AG3C_xAwRQIgCKCGJ1iu4wlaGXy3jcJyU3inh9dr1FIfqYOZEG_MdmACIQCbungkQYFk7EhD6K2YvLaHFMjKOFWjw001_tLb0lPDtg%3D%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&mh=hH&mime=audio%2Fwebm&mm=31%2C26&mn=sn-h0jelnez%2Csn-4g5ednsl&ms=au%2Conr&mt=1659354538&mv=m&mvi=5&n=XzXGSfGusw6OCQ&ns=b_Mq_qlTFcSGlG9RpwpM9xQH&pl=37&rbqsm=fr&requiressl=yes&sig=AOq0QJ8wRQIhAPIsKd7-xi4xVHEC9gb__dU4hzfzsHEj9ytd3nt0gEceAiACJWBcw-wFEq9qir35bwKHJZxtQ9mOL7SKiVkLQNDa6A%3D%3D&source=youtube&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cspc%2Cvprv%2Cmime%2Cns%2Cgir%2Cclen%2Cdur%2Clmt&spc=lT-Khi831z8dTejFIRCvCEwx_6romtM&txp=4532434&vprv=1"); - assert!(!throttled); + assert_eq!(throttled, false); assert!( map_res.warnings.is_empty(), "deserialization/mapping warnings: {:?}", diff --git a/src/client/response/url_endpoint.rs b/src/client/response/url_endpoint.rs index 0c1493d..03d9043 100644 --- a/src/client/response/url_endpoint.rs +++ b/src/client/response/url_endpoint.rs @@ -195,37 +195,38 @@ impl From for MusicPageType { impl NavigationEndpoint { pub(crate) fn music_page(self) -> Option<(MusicPageType, String)> { - self.browse_endpoint - .and_then(|be| { - be.browse_endpoint_context_supported_configs.map(|config| { + match self.browse_endpoint { + Some(browse) => match browse.browse_endpoint_context_supported_configs { + Some(config) => Some(( + config.browse_endpoint_context_music_config.page_type.into(), + browse.browse_id, + )), + None => None, + }, + None => None, + } + .or_else(|| { + self.watch_endpoint.map(|watch| { + if watch + .playlist_id + .map(|plid| plid.starts_with("RDQM")) + .unwrap_or_default() + { + // Genre radios (e.g. "pop radio") will be skipped + (MusicPageType::None, watch.video_id) + } else { ( - config.browse_endpoint_context_music_config.page_type.into(), - be.browse_id, + MusicPageType::Track { + is_video: watch + .watch_endpoint_music_supported_configs + .watch_endpoint_music_config + .music_video_type + == MusicVideoType::Video, + }, + watch.video_id, ) - }) - }) - .or_else(|| { - self.watch_endpoint.map(|watch| { - if watch - .playlist_id - .map(|plid| plid.starts_with("RDQM")) - .unwrap_or_default() - { - // Genre radios (e.g. "pop radio") will be skipped - (MusicPageType::None, watch.video_id) - } else { - ( - MusicPageType::Track { - is_video: watch - .watch_endpoint_music_supported_configs - .watch_endpoint_music_config - .music_video_type - == MusicVideoType::Video, - }, - watch.video_id, - ) - } - }) + } }) + }) } } diff --git a/src/deobfuscate.rs b/src/deobfuscate.rs index 036e19d..9753e95 100644 --- a/src/deobfuscate.rs +++ b/src/deobfuscate.rs @@ -1,4 +1,5 @@ use fancy_regex::Regex as FancyRegex; +use log::debug; use once_cell::sync::Lazy; use regex::Regex; use reqwest::Client; @@ -26,7 +27,7 @@ impl Deobfuscator { 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); + debug!("Downloaded player.js from {}", js_url); let sig_fn = get_sig_fn(&player_js)?; let nsig_fn = get_nsig_fn(&player_js)?; @@ -388,18 +389,18 @@ c[36](c[8],c[32]),c[20](c[25],c[10]),c[2](c[22],c[8]),c[32](c[20],c[16]),c[32](c assert_eq!(res, "nrkec0fwgTWolw"); } - #[test] - fn t_get_player_js_url() { + #[test(tokio::test)] + async fn t_get_player_js_url() { let client = Client::new(); - let url = tokio_test::block_on(get_player_js_url(&client)).unwrap(); + let url = get_player_js_url(&client).await.unwrap(); assert!(url.starts_with("https://www.youtube.com/s/player")); assert_eq!(url.len(), 73); } - #[test] - fn t_update() { + #[test(tokio::test)] + async fn t_update() { let client = Client::new(); - let deobf = tokio_test::block_on(Deobfuscator::new(client)).unwrap(); + let deobf = Deobfuscator::new(client).await.unwrap(); let deobf_sig = deobf.deobfuscate_sig("GOqGOqGOq0QJ8wRAIgaryQHfplJ9xJSKFywyaSMHuuwZYsoMTAvRvfm51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5fb5i").unwrap(); println!("{}", deobf_sig); diff --git a/src/serializer/text.rs b/src/serializer/text.rs index c682946..192d790 100644 --- a/src/serializer/text.rs +++ b/src/serializer/text.rs @@ -538,8 +538,8 @@ mod tests { txt: Vec, } - let res_str = serde_json::from_str::(test_json).unwrap(); - let res_vec = serde_json::from_str::(test_json).unwrap(); + let res_str = serde_json::from_str::(&test_json).unwrap(); + let res_vec = serde_json::from_str::(&test_json).unwrap(); assert_eq!(res_str.txt, exp.join("")); assert_eq!(res_vec.txt, exp); @@ -582,7 +582,7 @@ mod tests { } }"#; - let res = serde_json::from_str::(test_json).unwrap(); + let res = serde_json::from_str::(&test_json).unwrap(); insta::assert_debug_snapshot!(res, @r###" SLink { ln: Video { @@ -617,7 +617,7 @@ mod tests { } }"#; - let res = serde_json::from_str::(test_json).unwrap(); + let res = serde_json::from_str::(&test_json).unwrap(); insta::assert_debug_snapshot!(res, @r###" SLink { ln: Browse { @@ -651,7 +651,7 @@ mod tests { } }"#; - let res = serde_json::from_str::(test_json).unwrap(); + let res = serde_json::from_str::(&test_json).unwrap(); insta::assert_debug_snapshot!(res, @r###" SLink { ln: Browse { @@ -675,7 +675,7 @@ mod tests { } }"#; - let res = serde_json::from_str::(test_json).unwrap(); + let res = serde_json::from_str::(&test_json).unwrap(); insta::assert_debug_snapshot!(res, @r###" SLink { ln: Text { @@ -710,7 +710,7 @@ mod tests { } }"#; - let res = serde_json::from_str::(test_json).unwrap(); + let res = serde_json::from_str::(&test_json).unwrap(); insta::assert_debug_snapshot!(res, @r###" SLink { ln: Web { @@ -759,7 +759,7 @@ mod tests { } }"#; - let res = serde_json::from_str::(test_json).unwrap(); + let res = serde_json::from_str::(&test_json).unwrap(); insta::assert_debug_snapshot!(res, @r###" SLinks { ln: TextComponents( @@ -787,7 +787,7 @@ mod tests { fn t_links_empty() { let test_json = r#"{"ln": {}}"#; - let res = serde_json::from_str::(test_json).unwrap(); + let res = serde_json::from_str::(&test_json).unwrap(); assert!(res.ln.0.is_empty()) } diff --git a/tests/youtube.rs b/tests/youtube.rs index 9a7b101..d621194 100644 --- a/tests/youtube.rs +++ b/tests/youtube.rs @@ -28,10 +28,14 @@ use rustypipe::param::{ #[case::tv_html5_embed(ClientType::TvHtml5Embed)] #[case::android(ClientType::Android)] #[case::ios(ClientType::Ios)] -fn get_player_from_client(#[case] client_type: ClientType) { +#[tokio::test] +async fn get_player_from_client(#[case] client_type: ClientType) { let rp = RustyPipe::builder().strict().build(); - let player_data = - tokio_test::block_on(rp.query().player_from_client("n4tK7LYFxI0", client_type)).unwrap(); + let player_data = rp + .query() + .player_from_client("n4tK7LYFxI0", client_type) + .await + .unwrap(); // dbg!(&player_data); @@ -84,8 +88,8 @@ fn get_player_from_client(#[case] client_type: ClientType) { assert_eq!(audio.format, AudioFormat::M4a); assert_eq!(audio.codec, AudioCodec::Mp4a); - check_video_stream(video); - check_video_stream(audio); + check_video_stream(video).await; + check_video_stream(audio).await; } else { let video = player_data .video_only_streams @@ -119,18 +123,21 @@ fn get_player_from_client(#[case] client_type: ClientType) { assert_eq!(audio.codec, AudioCodec::Opus); assert_eq!(audio.throttled, false); - check_video_stream(video); - check_video_stream(audio); + check_video_stream(video).await; + check_video_stream(audio).await; } assert!(player_data.expires_in_seconds > 10000); } /// Request the given stream to check if it returns a valid response -fn check_video_stream(s: impl YtStream) { +async fn check_video_stream(s: impl YtStream) { let http = reqwest::Client::new(); - let resp = tokio_test::block_on(http.get(s.url()).send()) + let resp = http + .get(s.url()) + .send() + .await .unwrap() .error_for_status() .unwrap(); @@ -207,8 +214,8 @@ fn check_video_stream(s: impl YtStream) { false, false )] -#[allow(clippy::too_many_arguments)] -fn get_player( +#[tokio::test] +async fn get_player( #[case] id: &str, #[case] name: &str, #[case] description: &str, @@ -220,7 +227,7 @@ fn get_player( #[case] is_live_content: bool, ) { let rp = RustyPipe::builder().strict().build(); - let player_data = tokio_test::block_on(rp.query().player(id)).unwrap(); + let player_data = rp.query().player(id).await.unwrap(); let details = player_data.details; assert_eq!(details.id, id); @@ -303,11 +310,10 @@ fn get_player( "extraction error: Video cant be played because of being private. Reason (from YT): " )] #[case::age_restricted("CUO8secmc0g", "extraction error: Video is age restricted")] -fn get_player_error(#[case] id: &str, #[case] msg: &str) { +#[tokio::test] +async fn get_player_error(#[case] id: &str, #[case] msg: &str) { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on(rp.query().player(id)) - .unwrap_err() - .to_string(); + let err = rp.query().player(id).await.unwrap_err().to_string(); assert!( err.starts_with(msg), @@ -341,7 +347,8 @@ fn get_player_error(#[case] id: &str, #[case] msg: &str) { Some("SHINE - Survival Hardcore in New Environment: Auf einem Server machen sich tapfere Spieler auf, mystische Welten zu erkunden, magische Technologien zu erforschen und vorallem zu überleben...".to_owned()), Some(("UCQM0bS4_04-Y4JuYrgmnpZQ", "Chaosflo44")), )] -fn get_playlist( +#[tokio::test] +async fn get_playlist( #[case] id: &str, #[case] name: &str, #[case] is_long: bool, @@ -349,7 +356,7 @@ fn get_playlist( #[case] channel: Option<(&str, &str)>, ) { let rp = RustyPipe::builder().strict().build(); - let playlist = tokio_test::block_on(rp.query().playlist(id)).unwrap(); + let playlist = rp.query().playlist(id).await.unwrap(); assert_eq!(playlist.id, id); assert_eq!(playlist.name, name); @@ -367,32 +374,45 @@ fn get_playlist( assert!(!playlist.thumbnail.is_empty()); } -#[test] -fn playlist_cont() { +#[tokio::test] +async fn playlist_cont() { let rp = RustyPipe::builder().strict().build(); - let mut playlist = - tokio_test::block_on(rp.query().playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi")).unwrap(); + let mut playlist = rp + .query() + .playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi") + .await + .unwrap(); - tokio_test::block_on(playlist.videos.extend_pages(rp.query(), usize::MAX)).unwrap(); + playlist + .videos + .extend_pages(rp.query(), usize::MAX) + .await + .unwrap(); assert!(playlist.videos.items.len() > 100); assert!(playlist.videos.count.unwrap() > 100); } -#[test] -fn playlist_cont2() { +#[tokio::test] +async fn playlist_cont2() { let rp = RustyPipe::builder().strict().build(); - let mut playlist = - tokio_test::block_on(rp.query().playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi")).unwrap(); + let mut playlist = rp + .query() + .playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi") + .await + .unwrap(); - tokio_test::block_on(playlist.videos.extend_limit(rp.query(), 101)).unwrap(); + playlist.videos.extend_limit(rp.query(), 101).await.unwrap(); assert!(playlist.videos.items.len() > 100); assert!(playlist.videos.count.unwrap() > 100); } -#[test] -fn playlist_not_found() { +#[tokio::test] +async fn playlist_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on(rp.query().playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qz")) + let err = rp + .query() + .playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qz") + .await .unwrap_err(); assert!( @@ -407,10 +427,10 @@ fn playlist_not_found() { //#VIDEO DETAILS -#[test] -fn get_video_details() { +#[tokio::test] +async fn get_video_details() { let rp = RustyPipe::builder().strict().build(); - let details = tokio_test::block_on(rp.query().video_details("ZeerrnuLi5E")).unwrap(); + let details = rp.query().video_details("ZeerrnuLi5E").await.unwrap(); // dbg!(&details); @@ -442,17 +462,17 @@ fn get_video_details() { assert!(!details.is_ccommons); assert!(details.recommended.visitor_data.is_some()); - assert_next(details.recommended, rp.query(), 10, 2); + assert_next(details.recommended, rp.query(), 10, 2).await; assert_gte(details.top_comments.count.unwrap(), 700_000, "comments"); assert!(!details.top_comments.is_exhausted()); assert!(!details.latest_comments.is_exhausted()); } -#[test] -fn get_video_details_music() { +#[tokio::test] +async fn get_video_details_music() { let rp = RustyPipe::builder().strict().build(); - let details = tokio_test::block_on(rp.query().video_details("XuM2onMGvTI")).unwrap(); + let details = rp.query().video_details("XuM2onMGvTI").await.unwrap(); // dbg!(&details); @@ -480,7 +500,7 @@ fn get_video_details_music() { assert!(!details.is_ccommons); assert!(details.recommended.visitor_data.is_some()); - assert_next(details.recommended, rp.query(), 10, 2); + assert_next(details.recommended, rp.query(), 10, 2).await; // Update(01.11.2022): comments are sometimes enabled /* @@ -491,10 +511,10 @@ fn get_video_details_music() { */ } -#[test] -fn get_video_details_ccommons() { +#[tokio::test] +async fn get_video_details_ccommons() { let rp = RustyPipe::builder().strict().build(); - let details = tokio_test::block_on(rp.query().video_details("0rb9CfOvojk")).unwrap(); + let details = rp.query().video_details("0rb9CfOvojk").await.unwrap(); // dbg!(&details); @@ -529,17 +549,17 @@ fn get_video_details_ccommons() { assert!(details.is_ccommons); assert!(details.recommended.visitor_data.is_some()); - assert_next(details.recommended, rp.query(), 10, 2); + assert_next(details.recommended, rp.query(), 10, 2).await; assert_gte(details.top_comments.count.unwrap(), 2199, "comments"); assert!(!details.top_comments.is_exhausted()); assert!(!details.latest_comments.is_exhausted()); } -#[test] -fn get_video_details_chapters() { +#[tokio::test] +async fn get_video_details_chapters() { let rp = RustyPipe::builder().strict().build(); - let details = tokio_test::block_on(rp.query().video_details("nFDBxBUfE74")).unwrap(); + let details = rp.query().video_details("nFDBxBUfE74").await.unwrap(); // dbg!(&details); @@ -654,17 +674,17 @@ fn get_video_details_chapters() { } assert!(details.recommended.visitor_data.is_some()); - assert_next(details.recommended, rp.query(), 10, 2); + assert_next(details.recommended, rp.query(), 10, 2).await; assert_gte(details.top_comments.count.unwrap(), 3200, "comments"); assert!(!details.top_comments.is_exhausted()); assert!(!details.latest_comments.is_exhausted()); } -#[test] -fn get_video_details_live() { +#[tokio::test] +async fn get_video_details_live() { let rp = RustyPipe::builder().strict().build(); - let details = tokio_test::block_on(rp.query().video_details("86YLFOog4GM")).unwrap(); + let details = rp.query().video_details("86YLFOog4GM").await.unwrap(); // dbg!(&details); @@ -699,7 +719,7 @@ fn get_video_details_live() { assert!(!details.is_ccommons); assert!(details.recommended.visitor_data.is_some()); - assert_next(details.recommended, rp.query(), 10, 2); + assert_next(details.recommended, rp.query(), 10, 2).await; // No comments because livestream assert_eq!(details.top_comments.count, Some(0)); @@ -708,10 +728,10 @@ fn get_video_details_live() { assert!(details.latest_comments.is_empty()); } -#[test] -fn get_video_details_agegate() { +#[tokio::test] +async fn get_video_details_agegate() { let rp = RustyPipe::builder().strict().build(); - let details = tokio_test::block_on(rp.query().video_details("HRKu0cvrr_o")).unwrap(); + let details = rp.query().video_details("HRKu0cvrr_o").await.unwrap(); // dbg!(&details); @@ -748,10 +768,10 @@ fn get_video_details_agegate() { assert!(details.recommended.items.is_empty()); } -#[test] -fn get_video_details_not_found() { +#[tokio::test] +async fn get_video_details_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on(rp.query().video_details("abcdefgLi5X")).unwrap_err(); + let err = rp.query().video_details("abcdefgLi5X").await.unwrap_err(); assert!( matches!( @@ -763,12 +783,15 @@ fn get_video_details_not_found() { ) } -#[test] -fn get_video_comments() { +#[tokio::test] +async fn get_video_comments() { let rp = RustyPipe::builder().strict().build(); - let details = tokio_test::block_on(rp.query().video_details("ZeerrnuLi5E")).unwrap(); + let details = rp.query().video_details("ZeerrnuLi5E").await.unwrap(); - let top_comments = tokio_test::block_on(details.top_comments.next(rp.query())) + let top_comments = details + .top_comments + .next(rp.query()) + .await .unwrap() .unwrap(); assert_gte(top_comments.items.len(), 10, "comments"); @@ -778,7 +801,10 @@ fn get_video_comments() { let n_comments = top_comments.count.unwrap(); assert_gte(n_comments, 700_000, "comments"); - let latest_comments = tokio_test::block_on(details.latest_comments.next(rp.query())) + let latest_comments = details + .latest_comments + .next(rp.query()) + .await .unwrap() .unwrap(); assert_gte(latest_comments.items.len(), 10, "next comments"); @@ -788,11 +814,14 @@ fn get_video_comments() { //#CHANNEL -#[test] -fn channel_videos() { +#[tokio::test] +async fn channel_videos() { let rp = RustyPipe::builder().strict().build(); - let channel = - tokio_test::block_on(rp.query().channel_videos("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap(); + let channel = rp + .query() + .channel_videos("UC2DjFE7Xf11URZqWBigcVOQ") + .await + .unwrap(); // dbg!(&channel); assert_channel_eevblog(&channel); @@ -808,14 +837,17 @@ fn channel_videos() { assert!(age_days < 60, "latest video older than 60 days"); - assert_next(channel.content, rp.query(), 15, 2); + assert_next(channel.content, rp.query(), 15, 2).await; } -#[test] -fn channel_shorts() { +#[tokio::test] +async fn channel_shorts() { let rp = RustyPipe::builder().strict().build(); - let channel = - tokio_test::block_on(rp.query().channel_shorts("UCh8gHdtzO2tXd593_bjErWg")).unwrap(); + let channel = rp + .query() + .channel_shorts("UCh8gHdtzO2tXd593_bjErWg") + .await + .unwrap(); // dbg!(&channel); assert_eq!(channel.id, "UCh8gHdtzO2tXd593_bjErWg"); @@ -839,14 +871,17 @@ fn channel_shorts() { "got no shorts" ); - assert_next(channel.content, rp.query(), 15, 1); + assert_next(channel.content, rp.query(), 15, 1).await; } -#[test] -fn channel_livestreams() { +#[tokio::test] +async fn channel_livestreams() { let rp = RustyPipe::builder().strict().build(); - let channel = - tokio_test::block_on(rp.query().channel_livestreams("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap(); + let channel = rp + .query() + .channel_livestreams("UC2DjFE7Xf11URZqWBigcVOQ") + .await + .unwrap(); // dbg!(&channel); assert_channel_eevblog(&channel); @@ -856,14 +891,17 @@ fn channel_livestreams() { "got no streams" ); - assert_next(channel.content, rp.query(), 5, 1); + assert_next(channel.content, rp.query(), 5, 1).await; } -#[test] -fn channel_playlists() { +#[tokio::test] +async fn channel_playlists() { let rp = RustyPipe::builder().strict().build(); - let channel = - tokio_test::block_on(rp.query().channel_playlists("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap(); + let channel = rp + .query() + .channel_playlists("UC2DjFE7Xf11URZqWBigcVOQ") + .await + .unwrap(); assert_channel_eevblog(&channel); @@ -872,14 +910,17 @@ fn channel_playlists() { "got no playlists" ); - assert_next(channel.content, rp.query(), 15, 1); + assert_next(channel.content, rp.query(), 15, 1).await; } -#[test] -fn channel_info() { +#[tokio::test] +async fn channel_info() { let rp = RustyPipe::builder().strict().build(); - let channel = - tokio_test::block_on(rp.query().channel_info("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap(); + let channel = rp + .query() + .channel_info("UC2DjFE7Xf11URZqWBigcVOQ") + .await + .unwrap(); // dbg!(&channel); assert_channel_eevblog(&channel); @@ -912,17 +953,17 @@ fn channel_info() { "###); } -#[test] -fn channel_search() { +#[tokio::test] +async fn channel_search() { let rp = RustyPipe::builder().strict().build(); - let channel = tokio_test::block_on( - rp.query() - .channel_search("UC2DjFE7Xf11URZqWBigcVOQ", "test"), - ) - .unwrap(); + let channel = rp + .query() + .channel_search("UC2DjFE7Xf11URZqWBigcVOQ", "test") + .await + .unwrap(); assert_channel_eevblog(&channel); - assert_next(channel.content, rp.query(), 20, 2); + assert_next(channel.content, rp.query(), 20, 2).await; } fn assert_channel_eevblog(channel: &Channel) { @@ -954,7 +995,8 @@ fn assert_channel_eevblog(channel: &Channel) { #[case::music("UC-9-kyTW8ZkZNDHQJ6FgpwQ", "Music", false, false)] #[case::live("UC4R8DWoMoI7CAwX8_LjQHig", "Live", false, false)] #[case::news("UCYfdidRxbB8Qhf0Nx7ioOYw", "News", false, false)] -fn channel_more( +#[tokio::test] +async fn channel_more( #[case] id: &str, #[case] name: &str, #[case] has_videos: bool, @@ -967,13 +1009,13 @@ fn channel_more( assert_eq!(channel.name, name); } - let channel_videos = tokio_test::block_on(rp.query().channel_videos(&id)).unwrap(); + let channel_videos = rp.query().channel_videos(&id).await.unwrap(); assert_channel(&channel_videos, id, name); if has_videos { assert!(!channel_videos.content.items.is_empty(), "got no videos"); } - let channel_playlists = tokio_test::block_on(rp.query().channel_playlists(&id)).unwrap(); + let channel_playlists = rp.query().channel_playlists(&id).await.unwrap(); assert_channel(&channel_playlists, id, name); if has_playlists { assert!( @@ -982,7 +1024,7 @@ fn channel_more( ); } - let channel_info = tokio_test::block_on(rp.query().channel_info(&id)).unwrap(); + let channel_info = rp.query().channel_info(&id).await.unwrap(); assert_channel(&channel_info, id, name); } @@ -992,9 +1034,10 @@ fn channel_more( #[case::movies("UCuJcl0Ju-gPDoksRjK1ya-w")] #[case::sports("UCEgdi0XIXXZ-qJOFPf4JSKw")] #[case::learning("UCtFRv9O2AHqOZjjynzrv-xg")] -fn channel_not_found(#[case] id: &str) { +#[tokio::test] +async fn channel_not_found(#[case] id: &str) { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on(rp.query().channel_videos(&id)).unwrap_err(); + let err = rp.query().channel_videos(&id).await.unwrap_err(); assert!( matches!( @@ -1013,11 +1056,14 @@ mod channel_rss { use super::*; use time::macros::datetime; - #[test] - fn get_channel_rss() { + #[tokio::test] + async fn get_channel_rss() { let rp = RustyPipe::builder().strict().build(); - let channel = - tokio_test::block_on(rp.query().channel_rss("UCHnyfMqiRRG1u-2MsSQLbXA")).unwrap(); + let channel = rp + .query() + .channel_rss("UCHnyfMqiRRG1u-2MsSQLbXA") + .await + .unwrap(); assert_eq!(channel.id, "UCHnyfMqiRRG1u-2MsSQLbXA"); assert_eq!(channel.name, "Veritasium"); @@ -1026,11 +1072,14 @@ mod channel_rss { assert!(!channel.videos.is_empty()); } - #[test] - fn get_channel_rss_not_found() { + #[tokio::test] + async fn get_channel_rss_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = - tokio_test::block_on(rp.query().channel_rss("UCHnyfMqiRRG1u-2MsSQLbXZ")).unwrap_err(); + let err = rp + .query() + .channel_rss("UCHnyfMqiRRG1u-2MsSQLbXZ") + .await + .unwrap_err(); assert!( matches!( @@ -1045,10 +1094,10 @@ mod channel_rss { //#SEARCH -#[test] -fn search() { +#[tokio::test] +async fn search() { let rp = RustyPipe::builder().strict().build(); - let result = tokio_test::block_on(rp.query().search("doobydoobap")).unwrap(); + let result = rp.query().search("doobydoobap").await.unwrap(); assert!( result.items.count.unwrap() > 7000, @@ -1057,22 +1106,23 @@ fn search() { ); assert_eq!(result.corrected_query.unwrap(), "doobydobap"); - assert_next(result.items, rp.query(), 10, 2); + assert_next(result.items, rp.query(), 10, 2).await; } #[rstest] #[case::video(search_filter::ItemType::Video)] #[case::channel(search_filter::ItemType::Channel)] #[case::playlist(search_filter::ItemType::Playlist)] -fn search_filter_item_type(#[case] item_type: search_filter::ItemType) { +#[tokio::test] +async fn search_filter_item_type(#[case] item_type: search_filter::ItemType) { let rp = RustyPipe::builder().strict().build(); - let mut result = tokio_test::block_on( - rp.query() - .search_filter("with no videos", &SearchFilter::new().item_type(item_type)), - ) - .unwrap(); + let mut result = rp + .query() + .search_filter("with no videos", &SearchFilter::new().item_type(item_type)) + .await + .unwrap(); - tokio_test::block_on(result.items.extend(rp.query())).unwrap(); + result.items.extend(rp.query()).await.unwrap(); assert_gte(result.items.items.len(), 20, "items"); result.items.items.iter().for_each(|item| match item { @@ -1088,35 +1138,39 @@ fn search_filter_item_type(#[case] item_type: search_filter::ItemType) { }); } -#[test] -fn search_empty() { +#[tokio::test] +async fn search_empty() { let rp = RustyPipe::builder().strict().build(); - let result = tokio_test::block_on( - rp.query().search_filter( + let result = rp + .query() + .search_filter( "test", &search_filter::SearchFilter::new() .feature(search_filter::Feature::IsLive) .feature(search_filter::Feature::Is3d), - ), - ) - .unwrap(); + ) + .await + .unwrap(); assert!(result.items.is_empty()); } -#[test] -fn search_suggestion() { +#[tokio::test] +async fn search_suggestion() { let rp = RustyPipe::builder().strict().build(); - let result = tokio_test::block_on(rp.query().search_suggestion("hunger ga")).unwrap(); + let result = rp.query().search_suggestion("hunger ga").await.unwrap(); assert!(result.contains(&"hunger games".to_owned())); } -#[test] -fn search_suggestion_empty() { +#[tokio::test] +async fn search_suggestion_empty() { let rp = RustyPipe::builder().strict().build(); - let result = - tokio_test::block_on(rp.query().search_suggestion("fjew327%4ifjelwfvnewg49")).unwrap(); + let result = rp + .query() + .search_suggestion("fjew327%4ifjelwfvnewg49") + .await + .unwrap(); assert!(result.is_empty()); } @@ -1145,9 +1199,10 @@ fn search_suggestion_empty() { #[case("https://music.youtube.com/playlist?list=OLAK5uy_k0yFrZlFRgCf3rLPza-lkRmCrtLPbK9pE", UrlTarget::Album {id: "MPREb_GyH43gCvdM5".to_owned()})] #[case("https://music.youtube.com/browse/MPREb_GyH43gCvdM5", UrlTarget::Album {id: "MPREb_GyH43gCvdM5".to_owned()})] #[case("https://music.youtube.com/browse/UC5I2hjZYiW9gZPVkvzM8_Cw", UrlTarget::Channel {id: "UC5I2hjZYiW9gZPVkvzM8_Cw".to_owned()})] -fn resolve_url(#[case] url: &str, #[case] expect: UrlTarget) { +#[tokio::test] +async fn resolve_url(#[case] url: &str, #[case] expect: UrlTarget) { let rp = RustyPipe::builder().strict().build(); - let target = tokio_test::block_on(rp.query().resolve_url(url, true)).unwrap(); + let target = rp.query().resolve_url(url, true).await.unwrap(); assert_eq!(target, expect); } @@ -1163,20 +1218,21 @@ fn resolve_url(#[case] url: &str, #[case] expect: UrlTarget) { #[case("RDCLAK5uy_kFQXdnqMaQCVx2wpUM4ZfbsGCDibZtkJk", UrlTarget::Playlist {id: "RDCLAK5uy_kFQXdnqMaQCVx2wpUM4ZfbsGCDibZtkJk".to_owned()})] #[case("OLAK5uy_k0yFrZlFRgCf3rLPza-lkRmCrtLPbK9pE", UrlTarget::Album {id: "MPREb_GyH43gCvdM5".to_owned()})] #[case("MPREb_GyH43gCvdM5", UrlTarget::Album {id: "MPREb_GyH43gCvdM5".to_owned()})] -fn resolve_string(#[case] string: &str, #[case] expect: UrlTarget) { +#[tokio::test] +async fn resolve_string(#[case] string: &str, #[case] expect: UrlTarget) { let rp = RustyPipe::builder().strict().build(); - let target = tokio_test::block_on(rp.query().resolve_string(string, true)).unwrap(); + let target = rp.query().resolve_string(string, true).await.unwrap(); assert_eq!(target, expect); } -#[test] -fn resolve_channel_not_found() { +#[tokio::test] +async fn resolve_channel_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on( - rp.query() - .resolve_url("https://www.youtube.com/feeqegnhq3rkwghjq43ruih43io3", true), - ) - .unwrap_err(); + let err = rp + .query() + .resolve_url("https://www.youtube.com/feeqegnhq3rkwghjq43ruih43io3", true) + .await + .unwrap_err(); assert!(matches!( err, @@ -1186,21 +1242,21 @@ fn resolve_channel_not_found() { //#TRENDS -#[test] -fn startpage() { +#[tokio::test] +async fn startpage() { let rp = RustyPipe::builder().strict().build(); - let startpage = tokio_test::block_on(rp.query().startpage()).unwrap(); + let startpage = rp.query().startpage().await.unwrap(); // The startpage requires visitor data to fetch continuations assert!(startpage.visitor_data.is_some()); - assert_next(startpage, rp.query(), 12, 2); + assert_next(startpage, rp.query(), 12, 2).await; } -#[test] -fn trending() { +#[tokio::test] +async fn trending() { let rp = RustyPipe::builder().strict().build(); - let result = tokio_test::block_on(rp.query().trending()).unwrap(); + let result = rp.query().trending().await.unwrap(); assert_gte(result.len(), 50, "items"); } @@ -1232,7 +1288,8 @@ fn trending() { Some(("UCQM0bS4_04-Y4JuYrgmnpZQ", "Chaosflo44")), false, )] -fn music_playlist( +#[tokio::test] +async fn music_playlist( #[case] id: &str, #[case] name: &str, #[case] is_long: bool, @@ -1241,7 +1298,7 @@ fn music_playlist( #[case] from_ytm: bool, ) { let rp = RustyPipe::builder().strict().build(); - let playlist = tokio_test::block_on(rp.query().music_playlist(id)).unwrap(); + let playlist = rp.query().music_playlist(id).await.unwrap(); assert_eq!(playlist.id, id); assert_eq!(playlist.name, name); @@ -1260,31 +1317,35 @@ fn music_playlist( assert_eq!(playlist.from_ytm, from_ytm); } -#[test] -fn music_playlist_cont() { +#[tokio::test] +async fn music_playlist_cont() { let rp = RustyPipe::builder().strict().build(); - let mut playlist = tokio_test::block_on( - rp.query() - .music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi"), - ) - .unwrap(); + let mut playlist = rp + .query() + .music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi") + .await + .unwrap(); - tokio_test::block_on(playlist.tracks.extend_pages(rp.query(), usize::MAX)).unwrap(); + playlist + .tracks + .extend_pages(rp.query(), usize::MAX) + .await + .unwrap(); assert_gte(playlist.tracks.items.len(), 100, "tracks"); assert_gte(playlist.tracks.count.unwrap(), 100, "track count"); } -#[test] -fn music_playlist_related() { +#[tokio::test] +async fn music_playlist_related() { let rp = RustyPipe::builder().strict().build(); - let mut playlist = tokio_test::block_on( - rp.query() - .music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi"), - ) - .unwrap(); + let mut playlist = rp + .query() + .music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi") + .await + .unwrap(); - tokio_test::block_on(playlist.related_playlists.extend(rp.query())).unwrap(); + playlist.related_playlists.extend(rp.query()).await.unwrap(); assert_gte( playlist.related_playlists.items.len(), @@ -1293,14 +1354,14 @@ fn music_playlist_related() { ); } -#[test] -fn music_playlist_not_found() { +#[tokio::test] +async fn music_playlist_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on( - rp.query() - .music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qz"), - ) - .unwrap_err(); + let err = rp + .query() + .music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qz") + .await + .unwrap_err(); assert!( matches!( @@ -1323,9 +1384,10 @@ fn music_playlist_not_found() { #[case::no_year("no_year", "MPREb_F3Af9UZZVxX")] #[case::version_no_artist("version_no_artist", "MPREb_h8ltx5oKvyY")] #[case::no_artist("no_artist", "MPREb_bqWA6mAZFWS")] -fn music_album(#[case] name: &str, #[case] id: &str) { +#[tokio::test] +async fn music_album(#[case] name: &str, #[case] id: &str) { let rp = RustyPipe::builder().strict().build(); - let album = tokio_test::block_on(rp.query().music_album(id)).unwrap(); + let album = rp.query().music_album(id).await.unwrap(); assert!(!album.cover.is_empty(), "got no cover"); @@ -1334,10 +1396,14 @@ fn music_album(#[case] name: &str, #[case] id: &str) { ); } -#[test] -fn music_album_not_found() { +#[tokio::test] +async fn music_album_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on(rp.query().music_album("MPREb_nlBWQROfvjoz")).unwrap_err(); + let err = rp + .query() + .music_album("MPREb_nlBWQROfvjoz") + .await + .unwrap_err(); assert!( matches!( @@ -1357,8 +1423,8 @@ fn music_album_not_found() { #[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( +#[tokio::test] +async fn music_artist( #[case] name: &str, #[case] id: &str, #[case] all_albums: bool, @@ -1366,8 +1432,7 @@ fn music_artist( #[case] min_playlists: usize, ) { let rp = RustyPipe::builder().strict().build(); - - let mut artist = tokio_test::block_on(rp.query().music_artist(id, all_albums)).unwrap(); + let mut artist = rp.query().music_artist(id, all_albums).await.unwrap(); assert_gte(artist.tracks.len(), min_tracks, "tracks"); assert_gte(artist.playlists.len(), min_playlists, "playlists"); @@ -1411,10 +1476,13 @@ fn music_artist( }); } -#[test] -fn music_artist_not_found() { +#[tokio::test] +async fn music_artist_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on(rp.query().music_artist("UC7cl4MmM6ZZ2TcFyMk_b4pq", false)) + let err = rp + .query() + .music_artist("UC7cl4MmM6ZZ2TcFyMk_b4pq", false) + .await .unwrap_err(); assert!( @@ -1430,13 +1498,17 @@ fn music_artist_not_found() { #[rstest] #[case::default(false)] #[case::typo(true)] -fn music_search(#[case] typo: bool) { +#[tokio::test] +async fn music_search(#[case] typo: bool) { let rp = RustyPipe::builder().strict().build(); - let res = tokio_test::block_on(rp.query().music_search(match typo { - false => "black mamba", - true => "blck mamba", - })) - .unwrap(); + let res = rp + .query() + .music_search(match typo { + false => "black mamba", + true => "blck mamba", + }) + .await + .unwrap(); assert!(!res.tracks.is_empty(), "no tracks"); assert!(!res.albums.is_empty(), "no albums"); @@ -1469,10 +1541,10 @@ fn music_search(#[case] typo: bool) { assert_eq!(track.track_nr, None); } -#[test] -fn music_search_tracks() { +#[tokio::test] +async fn music_search_tracks() { let rp = RustyPipe::builder().strict().build(); - let res = tokio_test::block_on(rp.query().music_search_tracks("black mamba")).unwrap(); + let res = rp.query().music_search_tracks("black mamba").await.unwrap(); let track = &res .items @@ -1500,13 +1572,13 @@ fn music_search_tracks() { assert_eq!(album.id, "MPREb_OpHWHwyNOuY"); assert_eq!(album.name, "Black Mamba"); - assert_next(res.items, rp.query(), 15, 2); + assert_next(res.items, rp.query(), 15, 2).await; } -#[test] -fn music_search_videos() { +#[tokio::test] +async fn music_search_videos() { let rp = RustyPipe::builder().strict().build(); - let res = tokio_test::block_on(rp.query().music_search_videos("black mamba")).unwrap(); + let res = rp.query().music_search_videos("black mamba").await.unwrap(); let track = &res .items @@ -1532,7 +1604,7 @@ fn music_search_videos() { assert_eq!(track.album, None); assert_gte(track.view_count.unwrap(), 230_000_000, "views"); - assert_next(res.items, rp.query(), 15, 2); + assert_next(res.items, rp.query(), 15, 2).await; } // This podcast was removed from YouTube Music and I could not find another one @@ -1588,7 +1660,8 @@ async fn music_search_episode() { 2016, AlbumType::Album )] -fn music_search_albums( +#[tokio::test] +async fn music_search_albums( #[case] query: &str, #[case] name: &str, #[case] id: &str, @@ -1598,7 +1671,7 @@ fn music_search_albums( #[case] album_type: AlbumType, ) { let rp = RustyPipe::builder().strict().build(); - let res = tokio_test::block_on(rp.query().music_search_albums(query)).unwrap(); + let res = rp.query().music_search_albums(query).await.unwrap(); let album = &res.items.items.iter().find(|a| a.id == id).unwrap(); assert_eq!(album.name, name); @@ -1615,13 +1688,13 @@ fn music_search_albums( assert_eq!(res.corrected_query, None); - assert_next(res.items, rp.query(), 15, 1); + assert_next(res.items, rp.query(), 15, 1).await; } -#[test] -fn music_search_artists() { +#[tokio::test] +async fn music_search_artists() { let rp = RustyPipe::builder().strict().build(); - let res = tokio_test::block_on(rp.query().music_search_artists("namika")).unwrap(); + let res = rp.query().music_search_artists("namika").await.unwrap(); let artist = res .items @@ -1639,24 +1712,28 @@ fn music_search_artists() { assert_eq!(res.corrected_query, None); } -#[test] -fn music_search_artists_cont() { +#[tokio::test] +async fn music_search_artists_cont() { let rp = RustyPipe::builder().strict().build(); - let res = tokio_test::block_on(rp.query().music_search_artists("band")).unwrap(); + let res = rp.query().music_search_artists("band").await.unwrap(); assert_eq!(res.corrected_query, None); - assert_next(res.items, rp.query(), 15, 2); + assert_next(res.items, rp.query(), 15, 2).await; } #[rstest] #[case::ytm(false)] #[case::default(true)] -fn music_search_playlists(#[case] with_community: bool) { +#[tokio::test] +async fn music_search_playlists(#[case] with_community: bool) { let rp = RustyPipe::builder().strict().build(); let res = if with_community { - tokio_test::block_on(rp.query().music_search_playlists("easy pop")).unwrap() + rp.query().music_search_playlists("easy pop").await.unwrap() } else { - tokio_test::block_on(rp.query().music_search_playlists_filter("easy pop", false)).unwrap() + rp.query() + .music_search_playlists_filter("easy pop", false) + .await + .unwrap() }; assert_eq!(res.corrected_query, None); @@ -1674,14 +1751,14 @@ fn music_search_playlists(#[case] with_community: bool) { assert!(playlist.from_ytm); } -#[test] -fn music_search_playlists_community() { +#[tokio::test] +async fn music_search_playlists_community() { let rp = RustyPipe::builder().strict().build(); - let res = tokio_test::block_on( - rp.query() - .music_search_playlists_filter("Best Pop Music Videos - Top Pop Hits Playlist", true), - ) - .unwrap(); + let res = rp + .query() + .music_search_playlists_filter("Best Pop Music Videos - Top Pop Hits Playlist", true) + .await + .unwrap(); assert_eq!(res.corrected_query, None); let playlist = res @@ -1705,18 +1782,19 @@ fn music_search_playlists_community() { } /// The YouTube Music search sometimes shows genre radio items. They should be skipped. -#[test] -fn music_search_genre_radio() { +#[tokio::test] +async fn music_search_genre_radio() { let rp = RustyPipe::builder().strict().build(); - tokio_test::block_on(rp.query().music_search("pop radio")).unwrap(); + rp.query().music_search("pop radio").await.unwrap(); } #[rstest] #[case::default("ed sheer", Some("ed sheeran"))] #[case::empty("reujbhevmfndxnjrze", None)] -fn music_search_suggestion(#[case] query: &str, #[case] expect: Option<&str>) { +#[tokio::test] +async fn music_search_suggestion(#[case] query: &str, #[case] expect: Option<&str>) { let rp = RustyPipe::builder().strict().build(); - let suggestion = tokio_test::block_on(rp.query().music_search_suggestion(query)).unwrap(); + let suggestion = rp.query().music_search_suggestion(query).await.unwrap(); match expect { Some(expect) => assert!( @@ -1736,9 +1814,10 @@ fn music_search_suggestion(#[case] query: &str, #[case] expect: Option<&str>) { #[rstest] #[case::mv("mv", "ZeerrnuLi5E")] #[case::track("track", "7nigXQS1Xb0")] -fn music_details(#[case] name: &str, #[case] id: &str) { +#[tokio::test] +async fn music_details(#[case] name: &str, #[case] id: &str) { let rp = RustyPipe::builder().strict().build(); - let track = tokio_test::block_on(rp.query().music_details(id)).unwrap(); + let track = rp.query().music_details(id).await.unwrap(); assert!(!track.track.cover.is_empty(), "got no cover"); if name == "mv" { @@ -1755,19 +1834,27 @@ fn music_details(#[case] name: &str, #[case] id: &str) { ); } -#[test] -fn music_lyrics() { +#[tokio::test] +async fn music_lyrics() { let rp = RustyPipe::builder().strict().build(); - let track = tokio_test::block_on(rp.query().music_details("NO8Arj4yeww")).unwrap(); - let lyrics = tokio_test::block_on(rp.query().music_lyrics(&track.lyrics_id.unwrap())).unwrap(); + let track = rp.query().music_details("NO8Arj4yeww").await.unwrap(); + let lyrics = rp + .query() + .music_lyrics(&track.lyrics_id.unwrap()) + .await + .unwrap(); insta::assert_ron_snapshot!(lyrics); } -#[test] -fn music_lyrics_not_found() { +#[tokio::test] +async fn music_lyrics_not_found() { let rp = RustyPipe::builder().strict().build(); - let track = tokio_test::block_on(rp.query().music_details("ekXI8qrbe1s")).unwrap(); - let err = tokio_test::block_on(rp.query().music_lyrics(&track.lyrics_id.unwrap())).unwrap_err(); + let track = rp.query().music_details("ekXI8qrbe1s").await.unwrap(); + let err = rp + .query() + .music_lyrics(&track.lyrics_id.unwrap()) + .await + .unwrap_err(); assert!( matches!( @@ -1782,11 +1869,15 @@ fn music_lyrics_not_found() { #[rstest] #[case::a("7nigXQS1Xb0", true)] #[case::b("4t3SUDZCBaQ", false)] -fn music_related(#[case] id: &str, #[case] full: bool) { +#[tokio::test] +async fn music_related(#[case] id: &str, #[case] full: bool) { let rp = RustyPipe::builder().strict().build(); - let track = tokio_test::block_on(rp.query().music_details(id)).unwrap(); - let related = - tokio_test::block_on(rp.query().music_related(&track.related_id.unwrap())).unwrap(); + let track = rp.query().music_details(id).await.unwrap(); + let related = rp + .query() + .music_related(&track.related_id.unwrap()) + .await + .unwrap(); let n_tracks = related.tracks.len(); let mut track_artists = 0; @@ -1880,10 +1971,10 @@ fn music_related(#[case] id: &str, #[case] full: bool) { } } -#[test] -fn music_details_not_found() { +#[tokio::test] +async fn music_details_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on(rp.query().music_details("7nigXQS1XbZ")).unwrap_err(); + let err = rp.query().music_details("7nigXQS1XbZ").await.unwrap_err(); assert!( matches!( @@ -1895,17 +1986,21 @@ fn music_details_not_found() { ); } -#[test] -fn music_radio_track() { +#[tokio::test] +async fn music_radio_track() { let rp = RustyPipe::builder().strict().build(); - let tracks = tokio_test::block_on(rp.query().music_radio_track("ZeerrnuLi5E")).unwrap(); - assert_next_items(tracks, rp.query(), 20); + let tracks = rp.query().music_radio_track("ZeerrnuLi5E").await.unwrap(); + assert_next_items(tracks, rp.query(), 20).await; } -#[test] -fn music_radio_track_not_found() { +#[tokio::test] +async fn music_radio_track_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on(rp.query().music_radio_track("7nigXQS1XbZ")).unwrap_err(); + let err = rp + .query() + .music_radio_track("7nigXQS1XbZ") + .await + .unwrap_err(); assert!( matches!( @@ -1917,24 +2012,24 @@ fn music_radio_track_not_found() { ); } -#[test] -fn music_radio_playlist() { +#[tokio::test] +async fn music_radio_playlist() { let rp = RustyPipe::builder().strict().build(); - let tracks = tokio_test::block_on( - rp.query() - .music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlRbE7PiJ"), - ) - .unwrap(); - assert_next_items(tracks, rp.query(), 20); + let tracks = rp + .query() + .music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlRbE7PiJ") + .await + .unwrap(); + assert_next_items(tracks, rp.query(), 20).await; } -#[test] -fn music_radio_playlist_not_found() { +#[tokio::test] +async fn music_radio_playlist_not_found() { let rp = RustyPipe::builder().strict().build(); - let res = tokio_test::block_on( - rp.query() - .music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlZZZZZZZ"), - ); + let res = rp + .query() + .music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlZZZZZZZ") + .await; if let Err(err) = res { assert!( @@ -1948,28 +2043,32 @@ fn music_radio_playlist_not_found() { } } -#[test] -fn music_radio_artist() { +#[tokio::test] +async fn music_radio_artist() { let rp = RustyPipe::builder().strict().build(); - let tracks = - tokio_test::block_on(rp.query().music_radio("RDEM_Ktu-TilkxtLvmc9wX1MLQ")).unwrap(); - assert_next_items(tracks, rp.query(), 20); + let tracks = rp + .query() + .music_radio("RDEM_Ktu-TilkxtLvmc9wX1MLQ") + .await + .unwrap(); + assert_next_items(tracks, rp.query(), 20).await; } -#[test] -fn music_radio_not_found() { +#[tokio::test] +async fn music_radio_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = - tokio_test::block_on(rp.query().music_radio("RDEM_Ktu-TilkxtLvmc9wXZZZZ")).unwrap_err(); + let res = rp.query().music_radio("RDEM_Ktu-TilkxtLvmc9wXZZZZ").await; - assert!( - matches!( - err, - Error::Extraction(ExtractionError::ContentUnavailable(_)) - ), - "got: {}", - err - ); + if let Err(err) = res { + assert!( + matches!( + err, + Error::Extraction(ExtractionError::ContentUnavailable(_)) + ), + "got: {}", + err + ); + } } #[rstest] @@ -1983,9 +2082,10 @@ fn music_radio_not_found() { "PL4fGSI1pDJn69On1f-8NAvX_CYlx7QyZc", "PLrEnWoR732-DtKgaDdnPkezM_nDidBU9H" )] -fn music_charts(#[case] country: Country, #[case] plid_top: &str, #[case] plid_trend: &str) { +#[tokio::test] +async fn music_charts(#[case] country: Country, #[case] plid_top: &str, #[case] plid_trend: &str) { let rp = RustyPipe::builder().strict().build(); - let charts = tokio_test::block_on(rp.query().music_charts(Some(country))).unwrap(); + let charts = rp.query().music_charts(Some(country)).await.unwrap(); assert_eq!(charts.top_playlist_id.unwrap(), plid_top); assert_eq!(charts.trending_playlist_id.unwrap(), plid_trend); @@ -2000,10 +2100,10 @@ fn music_charts(#[case] country: Country, #[case] plid_top: &str, #[case] plid_t } } -#[test] -fn music_new_albums() { +#[tokio::test] +async fn music_new_albums() { let rp = RustyPipe::builder().strict().build(); - let albums = tokio_test::block_on(rp.query().music_new_albums()).unwrap(); + let albums = rp.query().music_new_albums().await.unwrap(); assert_gte(albums.len(), 10, "albums"); for album in albums { @@ -2013,10 +2113,10 @@ fn music_new_albums() { } } -#[test] -fn music_new_videos() { +#[tokio::test] +async fn music_new_videos() { let rp = RustyPipe::builder().strict().build(); - let videos = tokio_test::block_on(rp.query().music_new_videos()).unwrap(); + let videos = rp.query().music_new_videos().await.unwrap(); assert_gte(videos.len(), 5, "videos"); for video in videos { @@ -2028,10 +2128,10 @@ fn music_new_videos() { } } -#[test] -fn music_genres() { +#[tokio::test] +async fn music_genres() { let rp = RustyPipe::builder().strict().build(); - let genres = tokio_test::block_on(rp.query().music_genres()).unwrap(); + let genres = rp.query().music_genres().await.unwrap(); let chill = genres .iter() @@ -2056,9 +2156,10 @@ fn music_genres() { #[rstest] #[case::chill("ggMPOg1uX1JOQWZFeDByc2Jm", "Chill")] #[case::pop("ggMPOg1uX1lMbVZmbzl6NlJ3", "Pop")] -fn music_genre(#[case] id: &str, #[case] name: &str) { +#[tokio::test] +async fn music_genre(#[case] id: &str, #[case] name: &str) { let rp = RustyPipe::builder().strict().build(); - let genre = tokio_test::block_on(rp.query().music_genre(id)).unwrap(); + let genre = rp.query().music_genre(id).await.unwrap(); fn check_music_genre(genre: MusicGenre, id: &str, name: &str) -> Vec<(String, String)> { assert_eq!(genre.id, id); @@ -2102,15 +2203,19 @@ fn music_genre(#[case] id: &str, #[case] name: &str) { } for (id, name) in subgenres { - let genre = tokio_test::block_on(rp.query().music_genre(&id)).unwrap(); + let genre = rp.query().music_genre(&id).await.unwrap(); check_music_genre(genre, &id, &name); } } -#[test] -fn music_genre_not_found() { +#[tokio::test] +async fn music_genre_not_found() { let rp = RustyPipe::builder().strict().build(); - let err = tokio_test::block_on(rp.query().music_genre("ggMPOg1uX1JOQWZFeDByc2zz")).unwrap_err(); + let err = rp + .query() + .music_genre("ggMPOg1uX1JOQWZFeDByc2zz") + .await + .unwrap_err(); assert!( matches!( @@ -2126,18 +2231,20 @@ fn music_genre_not_found() { const VISITOR_DATA_SEARCH_CHANNEL_HANDLES: &str = "CgszYlc1Yk1WZGRCSSjrwOSbBg%3D%3D"; -#[test] -fn ab3_search_channel_handles() { +#[tokio::test] +async fn ab3_search_channel_handles() { let rp = RustyPipe::builder() .strict() .visitor_data(VISITOR_DATA_SEARCH_CHANNEL_HANDLES) .build(); - tokio_test::block_on(rp.query().search_filter( - "test", - &SearchFilter::new().item_type(search_filter::ItemType::Channel), - )) - .unwrap(); + rp.query() + .search_filter( + "test", + &SearchFilter::new().item_type(search_filter::ItemType::Channel), + ) + .await + .unwrap(); } //#MISCELLANEOUS @@ -2145,11 +2252,14 @@ fn ab3_search_channel_handles() { #[rstest] #[case::desktop(ContinuationEndpoint::Browse)] #[case::music(ContinuationEndpoint::MusicBrowse)] -#[test] -fn invalid_ctoken(#[case] ep: ContinuationEndpoint) { +#[tokio::test] +async fn invalid_ctoken(#[case] ep: ContinuationEndpoint) { let rp = RustyPipe::builder().strict().build(); - let e = tokio_test::block_on(rp.query().continuation::("Abcd", ep, None)) + let e = rp + .query() + .continuation::("Abcd", ep, None) + .await .unwrap_err(); match e { @@ -2182,8 +2292,7 @@ fn assert_gte(a: T, b: T, msg: &str) { assert!(a >= b, "expected {} {}, got {}", b, msg, a); } -/// Assert that the paginator produces at least n pages -fn assert_next>( +async fn assert_next>( paginator: Paginator, query: Q, min_items: usize, @@ -2194,9 +2303,7 @@ fn assert_next>( assert_gte(p.items.len(), min_items, "items on page 0"); for i in 0..n_pages { - p = tokio_test::block_on(p.next(query)) - .unwrap() - .expect("paginator exhausted"); + p = p.next(query).await.unwrap().expect("paginator exhausted"); assert_gte( p.items.len(), min_items, @@ -2205,15 +2312,14 @@ fn assert_next>( } } -/// Assert that the paginator produces at least n items -fn assert_next_items>( +async fn assert_next_items>( paginator: Paginator, query: Q, n_items: usize, ) { let mut p = paginator; let query = query.as_ref(); - tokio_test::block_on(p.extend_limit(query, n_items)).unwrap(); + p.extend_limit(query, n_items).await.unwrap(); assert_gte(p.items.len(), n_items, "items"); }