Compare commits
No commits in common. "d9e07b37e688f2bce099ea16fb78a90001704037" and "1d56b9c9a05dee12cfce54169a41acd0dc7191a7" have entirely different histories.
d9e07b37e6
...
1d56b9c9a0
5 changed files with 280 additions and 238 deletions
|
@ -2,7 +2,7 @@
|
||||||
name = "rustypipe"
|
name = "rustypipe"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["ThetaDev <t.testboy@gmail.com>"]
|
authors = ["ThetaDev"]
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
description = "Client for the public YouTube / YouTube Music API (Innertube), inspired by NewPipe"
|
description = "Client for the public YouTube / YouTube Music API (Innertube), inspired by NewPipe"
|
||||||
keywords = ["youtube", "video", "music"]
|
keywords = ["youtube", "video", "music"]
|
||||||
|
@ -23,9 +23,8 @@ rustls-tls-webpki-roots = ["reqwest/rustls-tls-webpki-roots"]
|
||||||
rustls-tls-native-roots = ["reqwest/rustls-tls-native-roots"]
|
rustls-tls-native-roots = ["reqwest/rustls-tls-native-roots"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quick-js-dtp = { version = "0.4.1", default-features = false, features = [
|
# quick-js = "0.4.1"
|
||||||
"patch-dateparser",
|
quick-js = { path = "../quickjs-rs", default-features = false }
|
||||||
] }
|
|
||||||
once_cell = "1.12.0"
|
once_cell = "1.12.0"
|
||||||
regex = "1.6.0"
|
regex = "1.6.0"
|
||||||
fancy-regex = "0.11.0"
|
fancy-regex = "0.11.0"
|
||||||
|
|
|
@ -708,16 +708,15 @@ impl RustyPipe {
|
||||||
/// Instantiate a new deobfuscator from either cached or extracted YouTube JavaScript code.
|
/// Instantiate a new deobfuscator from either cached or extracted YouTube JavaScript code.
|
||||||
async fn get_deobf(&self) -> Result<Deobfuscator, Error> {
|
async fn get_deobf(&self) -> Result<Deobfuscator, Error> {
|
||||||
// Write lock here to prevent concurrent tasks from fetching the same data
|
// Write lock here to prevent concurrent tasks from fetching the same data
|
||||||
let mut deobf_data = self.inner.cache.deobf.write().await;
|
let mut deobf = self.inner.cache.deobf.write().await;
|
||||||
|
|
||||||
match deobf_data.get() {
|
match deobf.get() {
|
||||||
Some(deobf_data) => Ok(Deobfuscator::new(deobf_data.clone())?),
|
Some(deobf) => Ok(Deobfuscator::from(deobf.to_owned())),
|
||||||
None => {
|
None => {
|
||||||
log::debug!("getting deobfuscator");
|
log::debug!("getting deobfuscator");
|
||||||
let data = DeobfData::download(self.inner.http.clone()).await?;
|
let new_deobf = Deobfuscator::new(self.inner.http.clone()).await?;
|
||||||
let new_deobf = Deobfuscator::new(data.clone())?;
|
*deobf = CacheEntry::from(new_deobf.get_data());
|
||||||
*deobf_data = CacheEntry::from(data);
|
drop(deobf);
|
||||||
drop(deobf_data);
|
|
||||||
self.store_cache().await;
|
self.store_cache().await;
|
||||||
Ok(new_deobf)
|
Ok(new_deobf)
|
||||||
}
|
}
|
||||||
|
|
|
@ -612,20 +612,19 @@ mod tests {
|
||||||
use std::{fs::File, io::BufReader};
|
use std::{fs::File, io::BufReader};
|
||||||
|
|
||||||
use path_macro::path;
|
use path_macro::path;
|
||||||
use rstest::{fixture, rstest};
|
use rstest::rstest;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::deobfuscate::DeobfData;
|
use crate::deobfuscate::DeobfData;
|
||||||
|
|
||||||
#[fixture]
|
static DEOBFUSCATOR: Lazy<Deobfuscator> = Lazy::new(|| {
|
||||||
fn deobf() -> Deobfuscator {
|
Deobfuscator::from(DeobfData {
|
||||||
Deobfuscator::new(DeobfData {
|
js_url: "https://www.youtube.com/s/player/c8b8a173/player_ias.vflset/en_US/base.js".to_owned(),
|
||||||
js_url: "https://www.youtube.com/s/player/c8b8a173/player_ias.vflset/en_US/base.js".to_owned(),
|
sig_fn: "var oB={B4:function(a){a.reverse()},xm:function(a,b){a.splice(0,b)},dC:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b%a.length]=c}};var Vva=function(a){a=a.split(\"\");oB.dC(a,42);oB.xm(a,3);oB.dC(a,48);oB.B4(a,68);return a.join(\"\")};function deobfuscate(a){return Vva(a);}".to_owned(),
|
||||||
sig_fn: "var oB={B4:function(a){a.reverse()},xm:function(a,b){a.splice(0,b)},dC:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b%a.length]=c}};var Vva=function(a){a=a.split(\"\");oB.dC(a,42);oB.xm(a,3);oB.dC(a,48);oB.B4(a,68);return a.join(\"\")};var deobf_sig=Vva;".to_owned(),
|
nsig_fn: "Ska=function(a){var b=a.split(\"\"),c=[-1505243983,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(-e).reverse().forEach(function(f){d.unshift(f)})},\n-1692381986,function(d,e){e=(e%d.length+d.length)%d.length;var f=d[0];d[0]=d[e];d[e]=f},\n-262444939,\"unshift\",function(d){for(var e=d.length;e;)d.push(d.splice(--e,1)[0])},\n1201502951,-546377604,-504264123,-1978377336,1042456724,function(d,e){for(e=(e%d.length+d.length)%d.length;e--;)d.unshift(d.pop())},\n711986897,406699922,-1842537993,-1678108293,1803491779,1671716087,12778705,-718839990,null,null,-1617525823,342523552,-1338406651,-399705108,-696713950,b,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])},\nfunction(d,e){e=(e%d.length+d.length)%d.length;d.splice(e,1)},\n-980602034,356396192,null,-1617525823,function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(\"\"))},\n-1029864222,-641353250,-1681901809,-1391247867,1707415199,-1957855835,b,function(){for(var d=64,e=[];++d-e.length-32;)switch(d){case 58:d=96;continue;case 91:d=44;break;case 65:d=47;continue;case 46:d=153;case 123:d-=58;default:e.push(String.fromCharCode(d))}return e},\n-1936558978,-1505243983,function(d){d.reverse()},\n1296889058,-1813915420,-943019300,function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(\"\"))},\n\"join\",b,-2061642263];c[21]=c;c[22]=c;c[33]=c;try{c[3](c[33],c[9]),c[29](c[22],c[25]),c[29](c[22],c[19]),c[29](c[33],c[17]),c[29](c[21],c[2]),c[29](c[42],c[10]),c[1](c[52],c[40]),c[12](c[28],c[8]),c[29](c[21],c[45]),c[1](c[21],c[48]),c[44](c[26]),c[39](c[5],c[2]),c[31](c[53],c[16]),c[30](c[29],c[8]),c[51](c[29],c[6],c[44]()),c[4](c[43],c[1]),c[2](c[23],c[42]),c[2](c[0],c[46]),c[38](c[14],c[52]),c[32](c[5]),c[26](c[29],c[46]),c[26](c[5],c[13]),c[28](c[1],c[37]),c[26](c[31],c[13]),c[26](c[1],c[34]),\nc[46](c[1],c[32],c[40]()),c[26](c[50],c[44]),c[17](c[50],c[51]),c[0](c[3],c[24]),c[32](c[13]),c[43](c[3],c[51]),c[0](c[34],c[17]),c[16](c[45],c[53]),c[29](c[44],c[13]),c[42](c[1],c[50]),c[47](c[22],c[53]),c[37](c[22]),c[13](c[52],c[21]),c[6](c[43],c[34]),c[6](c[31],c[46])}catch(d){return\"enhanced_except_gZYB_un-_w8_\"+a}return b.join(\"\")};function deobfuscate(a){return Ska(a);}".to_owned(),
|
||||||
nsig_fn: "Ska=function(a){var b=a.split(\"\"),c=[-1505243983,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(-e).reverse().forEach(function(f){d.unshift(f)})},\n-1692381986,function(d,e){e=(e%d.length+d.length)%d.length;var f=d[0];d[0]=d[e];d[e]=f},\n-262444939,\"unshift\",function(d){for(var e=d.length;e;)d.push(d.splice(--e,1)[0])},\n1201502951,-546377604,-504264123,-1978377336,1042456724,function(d,e){for(e=(e%d.length+d.length)%d.length;e--;)d.unshift(d.pop())},\n711986897,406699922,-1842537993,-1678108293,1803491779,1671716087,12778705,-718839990,null,null,-1617525823,342523552,-1338406651,-399705108,-696713950,b,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])},\nfunction(d,e){e=(e%d.length+d.length)%d.length;d.splice(e,1)},\n-980602034,356396192,null,-1617525823,function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(\"\"))},\n-1029864222,-641353250,-1681901809,-1391247867,1707415199,-1957855835,b,function(){for(var d=64,e=[];++d-e.length-32;)switch(d){case 58:d=96;continue;case 91:d=44;break;case 65:d=47;continue;case 46:d=153;case 123:d-=58;default:e.push(String.fromCharCode(d))}return e},\n-1936558978,-1505243983,function(d){d.reverse()},\n1296889058,-1813915420,-943019300,function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(\"\"))},\n\"join\",b,-2061642263];c[21]=c;c[22]=c;c[33]=c;try{c[3](c[33],c[9]),c[29](c[22],c[25]),c[29](c[22],c[19]),c[29](c[33],c[17]),c[29](c[21],c[2]),c[29](c[42],c[10]),c[1](c[52],c[40]),c[12](c[28],c[8]),c[29](c[21],c[45]),c[1](c[21],c[48]),c[44](c[26]),c[39](c[5],c[2]),c[31](c[53],c[16]),c[30](c[29],c[8]),c[51](c[29],c[6],c[44]()),c[4](c[43],c[1]),c[2](c[23],c[42]),c[2](c[0],c[46]),c[38](c[14],c[52]),c[32](c[5]),c[26](c[29],c[46]),c[26](c[5],c[13]),c[28](c[1],c[37]),c[26](c[31],c[13]),c[26](c[1],c[34]),\nc[46](c[1],c[32],c[40]()),c[26](c[50],c[44]),c[17](c[50],c[51]),c[0](c[3],c[24]),c[32](c[13]),c[43](c[3],c[51]),c[0](c[34],c[17]),c[16](c[45],c[53]),c[29](c[44],c[13]),c[42](c[1],c[50]),c[47](c[22],c[53]),c[37](c[22]),c[13](c[52],c[21]),c[6](c[43],c[34]),c[6](c[31],c[46])}catch(d){return\"enhanced_except_gZYB_un-_w8_\"+a}return b.join(\"\")};var deobf_nsig=Ska;".to_owned(),
|
sts: "19201".to_owned(),
|
||||||
sts: "19201".to_owned(),
|
})
|
||||||
}).unwrap()
|
});
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::desktop("desktop")]
|
#[case::desktop("desktop")]
|
||||||
|
@ -633,13 +632,13 @@ mod tests {
|
||||||
#[case::tv_html5_embed("tvhtml5embed")]
|
#[case::tv_html5_embed("tvhtml5embed")]
|
||||||
#[case::android("android")]
|
#[case::android("android")]
|
||||||
#[case::ios("ios")]
|
#[case::ios("ios")]
|
||||||
fn map_player_data(#[case] name: &str, deobf: Deobfuscator) {
|
fn map_player_data(#[case] name: &str) {
|
||||||
let json_path = path!("testfiles" / "player" / format!("{name}_video.json"));
|
let json_path = path!("testfiles" / "player" / format!("{name}_video.json"));
|
||||||
let json_file = File::open(json_path).unwrap();
|
let json_file = File::open(json_path).unwrap();
|
||||||
|
|
||||||
let resp: response::Player = serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
let resp: response::Player = serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res = resp
|
let map_res = resp
|
||||||
.map_response("pPvd8UxmSbQ", Language::En, Some(&deobf))
|
.map_response("pPvd8UxmSbQ", Language::En, Some(&DEOBFUSCATOR))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -661,14 +660,14 @@ mod tests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn cipher_to_url(deobf: Deobfuscator) {
|
fn cipher_to_url() {
|
||||||
let signature_cipher = "s=w%3DAe%3DA6aDNQLkViKS7LOm9QtxZJHKwb53riq9qEFw-ecBWJCAiA%3DcEg0tn3dty9jEHszfzh4Ud__bg9CEHVx4ix-7dKsIPAhIQRw8JQ0qOA&sp=sig&url=https://rr5---sn-h0jelnez.googlevideo.com/videoplayback%3Fexpire%3D1659376413%26ei%3Dvb7nYvH5BMK8gAfBj7ToBQ%26ip%3D2003%253Ade%253Aaf06%253A6300%253Ac750%253A1b77%253Ac74a%253A80e3%26id%3Do-AB_BABwrXZJN428ZwDxq5ScPn2AbcGODnRlTVhCQ3mj2%26itag%3D251%26source%3Dyoutube%26requiressl%3Dyes%26mh%3DhH%26mm%3D31%252C26%26mn%3Dsn-h0jelnez%252Csn-4g5ednsl%26ms%3Dau%252Conr%26mv%3Dm%26mvi%3D5%26pl%3D37%26initcwndbps%3D1588750%26spc%3DlT-Khi831z8dTejFIRCvCEwx_6romtM%26vprv%3D1%26mime%3Daudio%252Fwebm%26ns%3Db_Mq_qlTFcSGlG9RpwpM9xQH%26gir%3Dyes%26clen%3D3781277%26dur%3D229.301%26lmt%3D1655510291473933%26mt%3D1659354538%26fvip%3D5%26keepalive%3Dyes%26fexp%3D24001373%252C24007246%26c%3DWEB%26rbqsm%3Dfr%26txp%3D4532434%26n%3Dd2g6G2hVqWIXxedQ%26sparams%3Dexpire%252Cei%252Cip%252Cid%252Citag%252Csource%252Crequiressl%252Cspc%252Cvprv%252Cmime%252Cns%252Cgir%252Cclen%252Cdur%252Clmt%26lsparams%3Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%252Cinitcwndbps%26lsig%3DAG3C_xAwRQIgCKCGJ1iu4wlaGXy3jcJyU3inh9dr1FIfqYOZEG_MdmACIQCbungkQYFk7EhD6K2YvLaHFMjKOFWjw001_tLb0lPDtg%253D%253D";
|
let signature_cipher = "s=w%3DAe%3DA6aDNQLkViKS7LOm9QtxZJHKwb53riq9qEFw-ecBWJCAiA%3DcEg0tn3dty9jEHszfzh4Ud__bg9CEHVx4ix-7dKsIPAhIQRw8JQ0qOA&sp=sig&url=https://rr5---sn-h0jelnez.googlevideo.com/videoplayback%3Fexpire%3D1659376413%26ei%3Dvb7nYvH5BMK8gAfBj7ToBQ%26ip%3D2003%253Ade%253Aaf06%253A6300%253Ac750%253A1b77%253Ac74a%253A80e3%26id%3Do-AB_BABwrXZJN428ZwDxq5ScPn2AbcGODnRlTVhCQ3mj2%26itag%3D251%26source%3Dyoutube%26requiressl%3Dyes%26mh%3DhH%26mm%3D31%252C26%26mn%3Dsn-h0jelnez%252Csn-4g5ednsl%26ms%3Dau%252Conr%26mv%3Dm%26mvi%3D5%26pl%3D37%26initcwndbps%3D1588750%26spc%3DlT-Khi831z8dTejFIRCvCEwx_6romtM%26vprv%3D1%26mime%3Daudio%252Fwebm%26ns%3Db_Mq_qlTFcSGlG9RpwpM9xQH%26gir%3Dyes%26clen%3D3781277%26dur%3D229.301%26lmt%3D1655510291473933%26mt%3D1659354538%26fvip%3D5%26keepalive%3Dyes%26fexp%3D24001373%252C24007246%26c%3DWEB%26rbqsm%3Dfr%26txp%3D4532434%26n%3Dd2g6G2hVqWIXxedQ%26sparams%3Dexpire%252Cei%252Cip%252Cid%252Citag%252Csource%252Crequiressl%252Cspc%252Cvprv%252Cmime%252Cns%252Cgir%252Cclen%252Cdur%252Clmt%26lsparams%3Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%252Cinitcwndbps%26lsig%3DAG3C_xAwRQIgCKCGJ1iu4wlaGXy3jcJyU3inh9dr1FIfqYOZEG_MdmACIQCbungkQYFk7EhD6K2YvLaHFMjKOFWjw001_tLb0lPDtg%253D%253D";
|
||||||
let mut last_nsig: [String; 2] = ["".to_owned(), "".to_owned()];
|
let mut last_nsig: [String; 2] = ["".to_owned(), "".to_owned()];
|
||||||
let map_res = map_url(
|
let map_res = map_url(
|
||||||
&None,
|
&None,
|
||||||
&Some(signature_cipher.to_owned()),
|
&Some(signature_cipher.to_owned()),
|
||||||
&deobf,
|
&DEOBFUSCATOR,
|
||||||
&mut last_nsig,
|
&mut last_nsig,
|
||||||
);
|
);
|
||||||
let (url, throttled) = map_res.c.unwrap();
|
let (url, throttled) = map_res.c.unwrap();
|
||||||
|
|
|
@ -3,6 +3,7 @@ use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::result::Result::Ok;
|
||||||
|
|
||||||
use crate::{error::DeobfError, util};
|
use crate::{error::DeobfError, util};
|
||||||
|
|
||||||
|
@ -10,7 +11,6 @@ type Result<T> = core::result::Result<T, DeobfError>;
|
||||||
|
|
||||||
pub struct Deobfuscator {
|
pub struct Deobfuscator {
|
||||||
data: DeobfData,
|
data: DeobfData,
|
||||||
ctx: quick_js::Context,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
@ -21,8 +21,8 @@ pub struct DeobfData {
|
||||||
pub sts: String,
|
pub sts: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeobfData {
|
impl Deobfuscator {
|
||||||
pub async fn download(http: Client) -> Result<Self> {
|
pub async fn new(http: Client) -> Result<Self> {
|
||||||
let js_url = get_player_js_url(&http).await?;
|
let js_url = get_player_js_url(&http).await?;
|
||||||
let player_js = get_response(&http, &js_url).await?;
|
let player_js = get_response(&http, &js_url).await?;
|
||||||
|
|
||||||
|
@ -33,46 +33,21 @@ impl DeobfData {
|
||||||
let sts = get_sts(&player_js)?;
|
let sts = get_sts(&player_js)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
js_url,
|
data: DeobfData {
|
||||||
sig_fn,
|
js_url,
|
||||||
nsig_fn,
|
nsig_fn,
|
||||||
sts,
|
sig_fn,
|
||||||
|
sts,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Deobfuscator {
|
|
||||||
pub fn new(data: DeobfData) -> Result<Self> {
|
|
||||||
let ctx =
|
|
||||||
quick_js::Context::new().or(Err(DeobfError::Other("could not create QuickJS rt")))?;
|
|
||||||
ctx.eval(&data.sig_fn)?;
|
|
||||||
ctx.eval(&data.nsig_fn)?;
|
|
||||||
|
|
||||||
Ok(Self { data, ctx })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deobfuscate_sig(&self, sig: &str) -> Result<String> {
|
pub fn deobfuscate_sig(&self, sig: &str) -> Result<String> {
|
||||||
let res = self.ctx.call_function(DEOBF_SIG_FUNC_NAME, vec![sig])?;
|
deobfuscate_sig(sig, &self.data.sig_fn)
|
||||||
|
|
||||||
res.as_str().map_or(
|
|
||||||
Err(DeobfError::Other("sig deobfuscation func returned null")),
|
|
||||||
|res| {
|
|
||||||
log::debug!("deobfuscated sig");
|
|
||||||
Ok(res.to_owned())
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deobfuscate_nsig(&self, nsig: &str) -> Result<String> {
|
pub fn deobfuscate_nsig(&self, nsig: &str) -> Result<String> {
|
||||||
let res = self.ctx.call_function(DEOBF_NSIG_FUNC_NAME, vec![nsig])?;
|
deobfuscate_nsig(nsig, &self.data.nsig_fn)
|
||||||
|
|
||||||
res.as_str().map_or(
|
|
||||||
Err(DeobfError::Other("nsig deobfuscation func returned null")),
|
|
||||||
|res| {
|
|
||||||
log::debug!("deobfuscated nsig");
|
|
||||||
Ok(res.to_owned())
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sts(&self) -> String {
|
pub fn get_sts(&self) -> String {
|
||||||
|
@ -84,8 +59,13 @@ impl Deobfuscator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEOBF_SIG_FUNC_NAME: &str = "deobf_sig";
|
impl From<DeobfData> for Deobfuscator {
|
||||||
const DEOBF_NSIG_FUNC_NAME: &str = "deobf_nsig";
|
fn from(data: DeobfData) -> Self {
|
||||||
|
Self { data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEOBFUSCATION_FUNC_NAME: &str = "deobfuscate";
|
||||||
|
|
||||||
fn get_sig_fn_name(player_js: &str) -> Result<String> {
|
fn get_sig_fn_name(player_js: &str) -> Result<String> {
|
||||||
static FUNCTION_REGEXES: Lazy<[FancyRegex; 6]> = Lazy::new(|| {
|
static FUNCTION_REGEXES: Lazy<[FancyRegex; 6]> = Lazy::new(|| {
|
||||||
|
@ -103,8 +83,8 @@ fn get_sig_fn_name(player_js: &str) -> Result<String> {
|
||||||
.ok_or(DeobfError::Extraction("deobf function name"))
|
.ok_or(DeobfError::Extraction("deobf function name"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn caller_function(mapped_name: &str, fn_name: &str) -> String {
|
fn caller_function(fn_name: &str) -> String {
|
||||||
format!("var {mapped_name}={fn_name};")
|
format!("var {DEOBFUSCATION_FUNC_NAME}={fn_name};")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sig_fn(player_js: &str) -> Result<String> {
|
fn get_sig_fn(player_js: &str) -> Result<String> {
|
||||||
|
@ -145,9 +125,19 @@ fn get_sig_fn(player_js: &str) -> Result<String> {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_str();
|
.as_str();
|
||||||
|
|
||||||
Ok(helper_object.to_owned()
|
Ok(helper_object.to_owned() + &deobfuscate_function + &caller_function(&dfunc_name))
|
||||||
+ &deobfuscate_function
|
}
|
||||||
+ &caller_function(DEOBF_SIG_FUNC_NAME, &dfunc_name))
|
|
||||||
|
fn deobfuscate_sig(sig: &str, sig_fn: &str) -> Result<String> {
|
||||||
|
let context =
|
||||||
|
quick_js::Context::new().or(Err(DeobfError::Other("could not create QuickJS rt")))?;
|
||||||
|
context.eval(sig_fn)?;
|
||||||
|
let res = context.call_function(DEOBFUSCATION_FUNC_NAME, vec![sig])?;
|
||||||
|
|
||||||
|
res.as_str().map_or(
|
||||||
|
Err(DeobfError::Other("sig deobfuscation func returned null")),
|
||||||
|
|res| Ok(res.to_owned()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_nsig_fn_name(player_js: &str) -> Result<String> {
|
fn get_nsig_fn_name(player_js: &str) -> Result<String> {
|
||||||
|
@ -250,7 +240,19 @@ fn get_nsig_fn(player_js: &str) -> Result<String> {
|
||||||
let offset = player_js.find(&function_base).unwrap_or_default();
|
let offset = player_js.find(&function_base).unwrap_or_default();
|
||||||
|
|
||||||
extract_js_fn(&player_js[offset..], &function_name)
|
extract_js_fn(&player_js[offset..], &function_name)
|
||||||
.map(|s| s + ";" + &caller_function(DEOBF_NSIG_FUNC_NAME, &function_name))
|
.map(|s| s + ";" + &caller_function(&function_name))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deobfuscate_nsig(sig: &str, nsig_fn: &str) -> Result<String> {
|
||||||
|
let context =
|
||||||
|
quick_js::Context::new().or(Err(DeobfError::Other("could not create QuickJS rt")))?;
|
||||||
|
context.eval(nsig_fn)?;
|
||||||
|
let res = context.call_function(DEOBFUSCATION_FUNC_NAME, vec![sig])?;
|
||||||
|
|
||||||
|
res.as_str().map_or(
|
||||||
|
Err(DeobfError::Other("nsig deobfuscation func returned null")),
|
||||||
|
|res| Ok(res.to_owned()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_player_js_url(http: &Client) -> Result<String> {
|
async fn get_player_js_url(http: &Client) -> Result<String> {
|
||||||
|
@ -298,15 +300,14 @@ fn get_sts(player_js: &str) -> Result<String> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use path_macro::path;
|
use path_macro::path;
|
||||||
use rstest::{fixture, rstest};
|
use test_log::test;
|
||||||
|
|
||||||
static TEST_JS: Lazy<String> = Lazy::new(|| {
|
static TEST_JS: Lazy<String> = Lazy::new(|| {
|
||||||
let js_path = path!("testfiles" / "deobf" / "dummy_player.js");
|
let js_path = path!("testfiles" / "deobf" / "dummy_player.js");
|
||||||
std::fs::read_to_string(js_path).unwrap()
|
std::fs::read_to_string(js_path).unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
const SIG_DEOBF_FUNC: &str = r#"var qB={w8:function(a){a.reverse()},EC:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b%a.length]=c},Np:function(a,b){a.splice(0,b)}};var Rva=function(a){a=a.split("");qB.Np(a,3);qB.w8(a,41);qB.EC(a,55);qB.Np(a,3);qB.w8(a,33);qB.Np(a,3);qB.EC(a,48);qB.EC(a,17);qB.EC(a,43);return a.join("")};var deobf_sig=Rva;"#;
|
const N_DEOBF_FUNC: &str = r#"Vo=function(a){var b=a.split(""),c=[function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(""))},
|
||||||
const NSIG_DEOBF_FUNC: &str = r#"Vo=function(a){var b=a.split(""),c=[function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(""))},
|
|
||||||
928409064,-595856984,1403221911,653089124,-168714481,-1883008765,158931990,1346921902,361518508,1403221911,-362174697,-233641452,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e},
|
928409064,-595856984,1403221911,653089124,-168714481,-1883008765,158931990,1346921902,361518508,1403221911,-362174697,-233641452,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e},
|
||||||
b,158931990,791141857,-907319795,-1776185924,1595027902,-829736173,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])},
|
b,158931990,791141857,-907319795,-1776185924,1595027902,-829736173,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])},
|
||||||
-1274951142,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e},
|
-1274951142,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e},
|
||||||
|
@ -318,18 +319,7 @@ null,497372841,-1912651541,function(d,e){d.push(e)},
|
||||||
function(d,e){e=(e%d.length+d.length)%d.length;d.splice(-e).reverse().forEach(function(f){d.unshift(f)})},
|
function(d,e){e=(e%d.length+d.length)%d.length;d.splice(-e).reverse().forEach(function(f){d.unshift(f)})},
|
||||||
function(d,e){e=(e%d.length+d.length)%d.length;var f=d[0];d[0]=d[e];d[e]=f}];
|
function(d,e){e=(e%d.length+d.length)%d.length;var f=d[0];d[0]=d[e];d[e]=f}];
|
||||||
c[30]=c;c[40]=c;c[46]=c;try{c[43](c[34]),c[45](c[40],c[47]),c[46](c[51],c[33]),c[16](c[47],c[36]),c[38](c[31],c[49]),c[16](c[11],c[39]),c[0](c[11]),c[35](c[0],c[30]),c[35](c[4],c[17]),c[34](c[48],c[7],c[11]()),c[35](c[4],c[23]),c[35](c[4],c[9]),c[5](c[48],c[28]),c[36](c[46],c[16]),c[4](c[41],c[1]),c[4](c[16],c[28]),c[3](c[40],c[17]),c[9](c[8],c[23]),c[45](c[30],c[4]),c[50](c[3],c[28]),c[36](c[51],c[23]),c[14](c[0],c[24]),c[14](c[35],c[1]),c[20](c[51],c[41]),c[15](c[8],c[0]),c[31](c[35]),c[29](c[26]),
|
c[30]=c;c[40]=c;c[46]=c;try{c[43](c[34]),c[45](c[40],c[47]),c[46](c[51],c[33]),c[16](c[47],c[36]),c[38](c[31],c[49]),c[16](c[11],c[39]),c[0](c[11]),c[35](c[0],c[30]),c[35](c[4],c[17]),c[34](c[48],c[7],c[11]()),c[35](c[4],c[23]),c[35](c[4],c[9]),c[5](c[48],c[28]),c[36](c[46],c[16]),c[4](c[41],c[1]),c[4](c[16],c[28]),c[3](c[40],c[17]),c[9](c[8],c[23]),c[45](c[30],c[4]),c[50](c[3],c[28]),c[36](c[51],c[23]),c[14](c[0],c[24]),c[14](c[35],c[1]),c[20](c[51],c[41]),c[15](c[8],c[0]),c[31](c[35]),c[29](c[26]),
|
||||||
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[47],c[49]),c[1](c[44],c[28]),c[39](c[16]),c[32](c[42],c[22]),c[46](c[14],c[48]),c[26](c[29],c[10]),c[46](c[9],c[3]),c[32](c[45])}catch(d){return"enhanced_except_85UBjOr-_w8_"+a}return b.join("")};var deobf_nsig=Vo;"#;
|
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[47],c[49]),c[1](c[44],c[28]),c[39](c[16]),c[32](c[42],c[22]),c[46](c[14],c[48]),c[26](c[29],c[10]),c[46](c[9],c[3]),c[32](c[45])}catch(d){return"enhanced_except_85UBjOr-_w8_"+a}return b.join("")};var deobfuscate=Vo;"#;
|
||||||
|
|
||||||
#[fixture]
|
|
||||||
fn deobf() -> Deobfuscator {
|
|
||||||
Deobfuscator::new(DeobfData {
|
|
||||||
js_url: String::default(),
|
|
||||||
sig_fn: SIG_DEOBF_FUNC.to_owned(),
|
|
||||||
nsig_fn: NSIG_DEOBF_FUNC.to_owned(),
|
|
||||||
sts: String::default(),
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn t_get_sig_fn_name() {
|
fn t_get_sig_fn_name() {
|
||||||
|
@ -340,13 +330,17 @@ 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
|
||||||
#[test]
|
#[test]
|
||||||
fn t_get_sig_fn() {
|
fn t_get_sig_fn() {
|
||||||
let dcode = get_sig_fn(&TEST_JS).unwrap();
|
let dcode = get_sig_fn(&TEST_JS).unwrap();
|
||||||
assert_eq!(dcode, SIG_DEOBF_FUNC);
|
assert_eq!(
|
||||||
|
dcode,
|
||||||
|
r#"var qB={w8:function(a){a.reverse()},EC:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b%a.length]=c},Np:function(a,b){a.splice(0,b)}};var Rva=function(a){a=a.split("");qB.Np(a,3);qB.w8(a,41);qB.EC(a,55);qB.Np(a,3);qB.w8(a,33);qB.Np(a,3);qB.EC(a,48);qB.EC(a,17);qB.EC(a,43);return a.join("")};var deobfuscate=Rva;"#
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn t_deobfuscate_sig(deobf: Deobfuscator) {
|
fn t_deobfuscate_sig() {
|
||||||
let dsig = deobf.deobfuscate_sig("GOqGOqGOq0QJ8wRAIgaryQHfplJ9xJSKFywyaSMHuuwZYsoMTAvRvfm51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5fb5i").unwrap();
|
let dcode = get_sig_fn(&TEST_JS).unwrap();
|
||||||
assert_eq!(dsig, "AOq0QJ8wRAIgaryQHmplJ9xJSKFywyaSMHuuwZYsoMTfvRviG51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5f");
|
let deobf = deobfuscate_sig("GOqGOqGOq0QJ8wRAIgaryQHfplJ9xJSKFywyaSMHuuwZYsoMTAvRvfm51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5fb5i", &dcode).unwrap();
|
||||||
|
assert_eq!(deobf, "AOq0QJ8wRAIgaryQHmplJ9xJSKFywyaSMHuuwZYsoMTfvRviG51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5f");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -367,7 +361,6 @@ 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
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn t_extract_js_fn_eviljs() {
|
fn t_extract_js_fn_eviljs() {
|
||||||
// Evil JavaScript code containing braces within strings and regular expressions
|
|
||||||
let base_js = "Wka = function(d){var x = [/,,/,913,/(,)}/,\"abcdef}\\\"\",];var y = 10/2/1;return x[1][y];}//some={}random-padding+;";
|
let base_js = "Wka = function(d){var x = [/,,/,913,/(,)}/,\"abcdef}\\\"\",];var y = 10/2/1;return x[1][y];}//some={}random-padding+;";
|
||||||
let res = extract_js_fn(base_js, "Wka").unwrap();
|
let res = extract_js_fn(base_js, "Wka").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -379,7 +372,7 @@ 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
|
||||||
#[test]
|
#[test]
|
||||||
fn t_get_nsig_fn() {
|
fn t_get_nsig_fn() {
|
||||||
let res = get_nsig_fn(&TEST_JS).unwrap();
|
let res = get_nsig_fn(&TEST_JS).unwrap();
|
||||||
assert_eq!(res, NSIG_DEOBF_FUNC);
|
assert_eq!(res, N_DEOBF_FUNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -388,9 +381,9 @@ 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, "19187")
|
assert_eq!(res, "19187")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn t_deobfuscate_nsig(deobf: Deobfuscator) {
|
fn t_deobfuscate_nsig() {
|
||||||
let res = deobf.deobfuscate_nsig("BI_n4PxQ22is-KKajKUW").unwrap();
|
let res = deobfuscate_nsig("BI_n4PxQ22is-KKajKUW", N_DEOBF_FUNC).unwrap();
|
||||||
assert_eq!(res, "nrkec0fwgTWolw");
|
assert_eq!(res, "nrkec0fwgTWolw");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,8 +398,7 @@ 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
|
||||||
#[test]
|
#[test]
|
||||||
fn t_update() {
|
fn t_update() {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
let deobf_data = tokio_test::block_on(DeobfData::download(client)).unwrap();
|
let deobf = tokio_test::block_on(Deobfuscator::new(client)).unwrap();
|
||||||
let deobf = Deobfuscator::new(deobf_data).unwrap();
|
|
||||||
|
|
||||||
let deobf_sig = deobf.deobfuscate_sig("GOqGOqGOq0QJ8wRAIgaryQHfplJ9xJSKFywyaSMHuuwZYsoMTAvRvfm51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5fb5i").unwrap();
|
let deobf_sig = deobf.deobfuscate_sig("GOqGOqGOq0QJ8wRAIgaryQHfplJ9xJSKFywyaSMHuuwZYsoMTAvRvfm51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5fb5i").unwrap();
|
||||||
println!("{deobf_sig}");
|
println!("{deobf_sig}");
|
||||||
|
|
335
tests/youtube.rs
335
tests/youtube.rs
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use rstest::{fixture, rstest};
|
use rstest::rstest;
|
||||||
use rustypipe::model::paginator::ContinuationEndpoint;
|
use rustypipe::model::paginator::ContinuationEndpoint;
|
||||||
use rustypipe::validate;
|
use rustypipe::validate;
|
||||||
use time::macros::date;
|
use time::macros::date;
|
||||||
|
@ -28,8 +28,8 @@ use rustypipe::param::{
|
||||||
#[case::tv_html5_embed(ClientType::TvHtml5Embed)]
|
#[case::tv_html5_embed(ClientType::TvHtml5Embed)]
|
||||||
#[case::android(ClientType::Android)]
|
#[case::android(ClientType::Android)]
|
||||||
#[case::ios(ClientType::Ios)]
|
#[case::ios(ClientType::Ios)]
|
||||||
#[test_log::test]
|
fn get_player_from_client(#[case] client_type: ClientType) {
|
||||||
fn get_player_from_client(#[case] client_type: ClientType, rp: RustyPipe) {
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let player_data =
|
let player_data =
|
||||||
tokio_test::block_on(rp.query().player_from_client("n4tK7LYFxI0", client_type)).unwrap();
|
tokio_test::block_on(rp.query().player_from_client("n4tK7LYFxI0", client_type)).unwrap();
|
||||||
|
|
||||||
|
@ -218,8 +218,8 @@ fn get_player(
|
||||||
#[case] views: u64,
|
#[case] views: u64,
|
||||||
#[case] is_live: bool,
|
#[case] is_live: bool,
|
||||||
#[case] is_live_content: bool,
|
#[case] is_live_content: bool,
|
||||||
rp: RustyPipe,
|
|
||||||
) {
|
) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let player_data = tokio_test::block_on(rp.query().player(id)).unwrap();
|
let player_data = tokio_test::block_on(rp.query().player(id)).unwrap();
|
||||||
let details = player_data.details;
|
let details = player_data.details;
|
||||||
|
|
||||||
|
@ -303,7 +303,8 @@ fn get_player(
|
||||||
"extraction error: Video cant be played because of being private. Reason (from YT): "
|
"extraction error: Video cant be played because of being private. Reason (from YT): "
|
||||||
)]
|
)]
|
||||||
#[case::age_restricted("CUO8secmc0g", "extraction error: Video is age restricted")]
|
#[case::age_restricted("CUO8secmc0g", "extraction error: Video is age restricted")]
|
||||||
fn get_player_error(#[case] id: &str, #[case] msg: &str, rp: RustyPipe) {
|
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))
|
let err = tokio_test::block_on(rp.query().player(id))
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
@ -344,8 +345,8 @@ fn get_playlist(
|
||||||
#[case] is_long: bool,
|
#[case] is_long: bool,
|
||||||
#[case] description: Option<String>,
|
#[case] description: Option<String>,
|
||||||
#[case] channel: Option<(&str, &str)>,
|
#[case] channel: Option<(&str, &str)>,
|
||||||
rp: RustyPipe,
|
|
||||||
) {
|
) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let playlist = tokio_test::block_on(rp.query().playlist(id)).unwrap();
|
let playlist = tokio_test::block_on(rp.query().playlist(id)).unwrap();
|
||||||
|
|
||||||
assert_eq!(playlist.id, id);
|
assert_eq!(playlist.id, id);
|
||||||
|
@ -364,8 +365,9 @@ fn get_playlist(
|
||||||
assert!(!playlist.thumbnail.is_empty());
|
assert!(!playlist.thumbnail.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn playlist_cont(rp: RustyPipe) {
|
fn playlist_cont() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let mut playlist =
|
let mut playlist =
|
||||||
tokio_test::block_on(rp.query().playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi")).unwrap();
|
tokio_test::block_on(rp.query().playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi")).unwrap();
|
||||||
|
|
||||||
|
@ -374,8 +376,9 @@ fn playlist_cont(rp: RustyPipe) {
|
||||||
assert!(playlist.videos.count.unwrap() > 100);
|
assert!(playlist.videos.count.unwrap() > 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn playlist_cont2(rp: RustyPipe) {
|
fn playlist_cont2() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let mut playlist =
|
let mut playlist =
|
||||||
tokio_test::block_on(rp.query().playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi")).unwrap();
|
tokio_test::block_on(rp.query().playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi")).unwrap();
|
||||||
|
|
||||||
|
@ -384,8 +387,9 @@ fn playlist_cont2(rp: RustyPipe) {
|
||||||
assert!(playlist.videos.count.unwrap() > 100);
|
assert!(playlist.videos.count.unwrap() > 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn playlist_not_found(rp: RustyPipe) {
|
fn playlist_not_found() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let err = tokio_test::block_on(rp.query().playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qz"))
|
let err = tokio_test::block_on(rp.query().playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qz"))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
|
@ -400,8 +404,9 @@ fn playlist_not_found(rp: RustyPipe) {
|
||||||
|
|
||||||
//#VIDEO DETAILS
|
//#VIDEO DETAILS
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_video_details(rp: RustyPipe) {
|
fn get_video_details() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let details = tokio_test::block_on(rp.query().video_details("ZeerrnuLi5E")).unwrap();
|
let details = tokio_test::block_on(rp.query().video_details("ZeerrnuLi5E")).unwrap();
|
||||||
|
|
||||||
// dbg!(&details);
|
// dbg!(&details);
|
||||||
|
@ -440,8 +445,9 @@ fn get_video_details(rp: RustyPipe) {
|
||||||
assert!(!details.latest_comments.is_exhausted());
|
assert!(!details.latest_comments.is_exhausted());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_video_details_music(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().video_details("XuM2onMGvTI")).unwrap();
|
||||||
|
|
||||||
// dbg!(&details);
|
// dbg!(&details);
|
||||||
|
@ -481,8 +487,9 @@ fn get_video_details_music(rp: RustyPipe) {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_video_details_ccommons(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().video_details("0rb9CfOvojk")).unwrap();
|
||||||
|
|
||||||
// dbg!(&details);
|
// dbg!(&details);
|
||||||
|
@ -524,8 +531,9 @@ fn get_video_details_ccommons(rp: RustyPipe) {
|
||||||
assert!(!details.latest_comments.is_exhausted());
|
assert!(!details.latest_comments.is_exhausted());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_video_details_chapters(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().video_details("nFDBxBUfE74")).unwrap();
|
||||||
|
|
||||||
// dbg!(&details);
|
// dbg!(&details);
|
||||||
|
@ -647,8 +655,9 @@ fn get_video_details_chapters(rp: RustyPipe) {
|
||||||
assert!(!details.latest_comments.is_exhausted());
|
assert!(!details.latest_comments.is_exhausted());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_video_details_live(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().video_details("86YLFOog4GM")).unwrap();
|
||||||
|
|
||||||
// dbg!(&details);
|
// dbg!(&details);
|
||||||
|
@ -692,8 +701,9 @@ fn get_video_details_live(rp: RustyPipe) {
|
||||||
assert!(details.latest_comments.is_empty());
|
assert!(details.latest_comments.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_video_details_agegate(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().video_details("HRKu0cvrr_o")).unwrap();
|
||||||
|
|
||||||
// dbg!(&details);
|
// dbg!(&details);
|
||||||
|
@ -731,8 +741,9 @@ fn get_video_details_agegate(rp: RustyPipe) {
|
||||||
assert!(details.recommended.items.is_empty());
|
assert!(details.recommended.items.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_video_details_not_found(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().video_details("abcdefgLi5X")).unwrap_err();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -744,8 +755,9 @@ fn get_video_details_not_found(rp: RustyPipe) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_video_comments(rp: RustyPipe) {
|
fn get_video_comments() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let details = tokio_test::block_on(rp.query().video_details("ZeerrnuLi5E")).unwrap();
|
let details = tokio_test::block_on(rp.query().video_details("ZeerrnuLi5E")).unwrap();
|
||||||
|
|
||||||
let top_comments = tokio_test::block_on(details.top_comments.next(rp.query()))
|
let top_comments = tokio_test::block_on(details.top_comments.next(rp.query()))
|
||||||
|
@ -768,8 +780,9 @@ fn get_video_comments(rp: RustyPipe) {
|
||||||
|
|
||||||
//#CHANNEL
|
//#CHANNEL
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn channel_videos(rp: RustyPipe) {
|
fn channel_videos() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let channel =
|
let channel =
|
||||||
tokio_test::block_on(rp.query().channel_videos("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap();
|
tokio_test::block_on(rp.query().channel_videos("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap();
|
||||||
|
|
||||||
|
@ -790,8 +803,9 @@ fn channel_videos(rp: RustyPipe) {
|
||||||
assert_next(channel.content, rp.query(), 15, 2);
|
assert_next(channel.content, rp.query(), 15, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn channel_shorts(rp: RustyPipe) {
|
fn channel_shorts() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let channel =
|
let channel =
|
||||||
tokio_test::block_on(rp.query().channel_shorts("UCh8gHdtzO2tXd593_bjErWg")).unwrap();
|
tokio_test::block_on(rp.query().channel_shorts("UCh8gHdtzO2tXd593_bjErWg")).unwrap();
|
||||||
|
|
||||||
|
@ -820,8 +834,9 @@ fn channel_shorts(rp: RustyPipe) {
|
||||||
assert_next(channel.content, rp.query(), 15, 1);
|
assert_next(channel.content, rp.query(), 15, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn channel_livestreams(rp: RustyPipe) {
|
fn channel_livestreams() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let channel =
|
let channel =
|
||||||
tokio_test::block_on(rp.query().channel_livestreams("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap();
|
tokio_test::block_on(rp.query().channel_livestreams("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap();
|
||||||
|
|
||||||
|
@ -836,8 +851,9 @@ fn channel_livestreams(rp: RustyPipe) {
|
||||||
assert_next(channel.content, rp.query(), 5, 1);
|
assert_next(channel.content, rp.query(), 5, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn channel_playlists(rp: RustyPipe) {
|
fn channel_playlists() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let channel =
|
let channel =
|
||||||
tokio_test::block_on(rp.query().channel_playlists("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap();
|
tokio_test::block_on(rp.query().channel_playlists("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap();
|
||||||
|
|
||||||
|
@ -851,8 +867,9 @@ fn channel_playlists(rp: RustyPipe) {
|
||||||
assert_next(channel.content, rp.query(), 15, 1);
|
assert_next(channel.content, rp.query(), 15, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn channel_info(rp: RustyPipe) {
|
fn channel_info() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let channel =
|
let channel =
|
||||||
tokio_test::block_on(rp.query().channel_info("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap();
|
tokio_test::block_on(rp.query().channel_info("UC2DjFE7Xf11URZqWBigcVOQ")).unwrap();
|
||||||
|
|
||||||
|
@ -887,8 +904,9 @@ fn channel_info(rp: RustyPipe) {
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn channel_search(rp: RustyPipe) {
|
fn channel_search() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let channel = tokio_test::block_on(
|
let channel = tokio_test::block_on(
|
||||||
rp.query()
|
rp.query()
|
||||||
.channel_search("UC2DjFE7Xf11URZqWBigcVOQ", "test"),
|
.channel_search("UC2DjFE7Xf11URZqWBigcVOQ", "test"),
|
||||||
|
@ -933,8 +951,9 @@ fn channel_more(
|
||||||
#[case] name: &str,
|
#[case] name: &str,
|
||||||
#[case] has_videos: bool,
|
#[case] has_videos: bool,
|
||||||
#[case] has_playlists: bool,
|
#[case] has_playlists: bool,
|
||||||
rp: RustyPipe,
|
|
||||||
) {
|
) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
|
|
||||||
fn assert_channel<T>(channel: &Channel<T>, id: &str, name: &str) {
|
fn assert_channel<T>(channel: &Channel<T>, id: &str, name: &str) {
|
||||||
assert_eq!(channel.id, id);
|
assert_eq!(channel.id, id);
|
||||||
assert_eq!(channel.name, name);
|
assert_eq!(channel.name, name);
|
||||||
|
@ -965,7 +984,8 @@ fn channel_more(
|
||||||
#[case::movies("UCuJcl0Ju-gPDoksRjK1ya-w")]
|
#[case::movies("UCuJcl0Ju-gPDoksRjK1ya-w")]
|
||||||
#[case::sports("UCEgdi0XIXXZ-qJOFPf4JSKw")]
|
#[case::sports("UCEgdi0XIXXZ-qJOFPf4JSKw")]
|
||||||
#[case::learning("UCtFRv9O2AHqOZjjynzrv-xg")]
|
#[case::learning("UCtFRv9O2AHqOZjjynzrv-xg")]
|
||||||
fn channel_not_found(#[case] id: &str, rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().channel_videos(&id)).unwrap_err();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -984,8 +1004,9 @@ mod channel_rss {
|
||||||
use super::*;
|
use super::*;
|
||||||
use time::macros::datetime;
|
use time::macros::datetime;
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_channel_rss(rp: RustyPipe) {
|
fn get_channel_rss() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let channel =
|
let channel =
|
||||||
tokio_test::block_on(rp.query().channel_rss("UCHnyfMqiRRG1u-2MsSQLbXA")).unwrap();
|
tokio_test::block_on(rp.query().channel_rss("UCHnyfMqiRRG1u-2MsSQLbXA")).unwrap();
|
||||||
|
|
||||||
|
@ -996,8 +1017,9 @@ mod channel_rss {
|
||||||
assert!(!channel.videos.is_empty());
|
assert!(!channel.videos.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn get_channel_rss_not_found(rp: RustyPipe) {
|
fn get_channel_rss_not_found() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let err =
|
let err =
|
||||||
tokio_test::block_on(rp.query().channel_rss("UCHnyfMqiRRG1u-2MsSQLbXZ")).unwrap_err();
|
tokio_test::block_on(rp.query().channel_rss("UCHnyfMqiRRG1u-2MsSQLbXZ")).unwrap_err();
|
||||||
|
|
||||||
|
@ -1014,8 +1036,9 @@ mod channel_rss {
|
||||||
|
|
||||||
//#SEARCH
|
//#SEARCH
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn search(rp: RustyPipe) {
|
fn search() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let result = tokio_test::block_on(rp.query().search("doobydoobap")).unwrap();
|
let result = tokio_test::block_on(rp.query().search("doobydoobap")).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -1032,7 +1055,8 @@ fn search(rp: RustyPipe) {
|
||||||
#[case::video(search_filter::ItemType::Video)]
|
#[case::video(search_filter::ItemType::Video)]
|
||||||
#[case::channel(search_filter::ItemType::Channel)]
|
#[case::channel(search_filter::ItemType::Channel)]
|
||||||
#[case::playlist(search_filter::ItemType::Playlist)]
|
#[case::playlist(search_filter::ItemType::Playlist)]
|
||||||
fn search_filter_item_type(#[case] item_type: search_filter::ItemType, rp: RustyPipe) {
|
fn search_filter_item_type(#[case] item_type: search_filter::ItemType) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let mut result = tokio_test::block_on(
|
let mut result = tokio_test::block_on(
|
||||||
rp.query()
|
rp.query()
|
||||||
.search_filter("with no videos", &SearchFilter::new().item_type(item_type)),
|
.search_filter("with no videos", &SearchFilter::new().item_type(item_type)),
|
||||||
|
@ -1055,8 +1079,9 @@ fn search_filter_item_type(#[case] item_type: search_filter::ItemType, rp: Rusty
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn search_empty(rp: RustyPipe) {
|
fn search_empty() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let result = tokio_test::block_on(
|
let result = tokio_test::block_on(
|
||||||
rp.query().search_filter(
|
rp.query().search_filter(
|
||||||
"test",
|
"test",
|
||||||
|
@ -1070,15 +1095,17 @@ fn search_empty(rp: RustyPipe) {
|
||||||
assert!(result.items.is_empty());
|
assert!(result.items.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn search_suggestion(rp: RustyPipe) {
|
fn search_suggestion() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let result = tokio_test::block_on(rp.query().search_suggestion("hunger ga")).unwrap();
|
let result = tokio_test::block_on(rp.query().search_suggestion("hunger ga")).unwrap();
|
||||||
|
|
||||||
assert!(result.contains(&"hunger games".to_owned()));
|
assert!(result.contains(&"hunger games".to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn search_suggestion_empty(rp: RustyPipe) {
|
fn search_suggestion_empty() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let result =
|
let result =
|
||||||
tokio_test::block_on(rp.query().search_suggestion("fjew327%4ifjelwfvnewg49")).unwrap();
|
tokio_test::block_on(rp.query().search_suggestion("fjew327%4ifjelwfvnewg49")).unwrap();
|
||||||
|
|
||||||
|
@ -1109,7 +1136,8 @@ fn search_suggestion_empty(rp: RustyPipe) {
|
||||||
#[case("https://music.youtube.com/playlist?list=OLAK5uy_k0yFrZlFRgCf3rLPza-lkRmCrtLPbK9pE", UrlTarget::Album {id: "MPREb_GyH43gCvdM5".to_owned()})]
|
#[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/MPREb_GyH43gCvdM5", UrlTarget::Album {id: "MPREb_GyH43gCvdM5".to_owned()})]
|
||||||
#[case("https://music.youtube.com/browse/UC5I2hjZYiW9gZPVkvzM8_Cw", UrlTarget::Channel {id: "UC5I2hjZYiW9gZPVkvzM8_Cw".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, rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().resolve_url(url, true)).unwrap();
|
||||||
assert_eq!(target, expect);
|
assert_eq!(target, expect);
|
||||||
}
|
}
|
||||||
|
@ -1126,13 +1154,15 @@ fn resolve_url(#[case] url: &str, #[case] expect: UrlTarget, rp: RustyPipe) {
|
||||||
#[case("RDCLAK5uy_kFQXdnqMaQCVx2wpUM4ZfbsGCDibZtkJk", UrlTarget::Playlist {id: "RDCLAK5uy_kFQXdnqMaQCVx2wpUM4ZfbsGCDibZtkJk".to_owned()})]
|
#[case("RDCLAK5uy_kFQXdnqMaQCVx2wpUM4ZfbsGCDibZtkJk", UrlTarget::Playlist {id: "RDCLAK5uy_kFQXdnqMaQCVx2wpUM4ZfbsGCDibZtkJk".to_owned()})]
|
||||||
#[case("OLAK5uy_k0yFrZlFRgCf3rLPza-lkRmCrtLPbK9pE", UrlTarget::Album {id: "MPREb_GyH43gCvdM5".to_owned()})]
|
#[case("OLAK5uy_k0yFrZlFRgCf3rLPza-lkRmCrtLPbK9pE", UrlTarget::Album {id: "MPREb_GyH43gCvdM5".to_owned()})]
|
||||||
#[case("MPREb_GyH43gCvdM5", 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, rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().resolve_string(string, true)).unwrap();
|
||||||
assert_eq!(target, expect);
|
assert_eq!(target, expect);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn resolve_channel_not_found(rp: RustyPipe) {
|
fn resolve_channel_not_found() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let err = tokio_test::block_on(
|
let err = tokio_test::block_on(
|
||||||
rp.query()
|
rp.query()
|
||||||
.resolve_url("https://www.youtube.com/feeqegnhq3rkwghjq43ruih43io3", true),
|
.resolve_url("https://www.youtube.com/feeqegnhq3rkwghjq43ruih43io3", true),
|
||||||
|
@ -1147,8 +1177,9 @@ fn resolve_channel_not_found(rp: RustyPipe) {
|
||||||
|
|
||||||
//#TRENDS
|
//#TRENDS
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn startpage(rp: RustyPipe) {
|
fn startpage() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let startpage = tokio_test::block_on(rp.query().startpage()).unwrap();
|
let startpage = tokio_test::block_on(rp.query().startpage()).unwrap();
|
||||||
|
|
||||||
// The startpage requires visitor data to fetch continuations
|
// The startpage requires visitor data to fetch continuations
|
||||||
|
@ -1157,8 +1188,9 @@ fn startpage(rp: RustyPipe) {
|
||||||
assert_next(startpage, rp.query(), 12, 2);
|
assert_next(startpage, rp.query(), 12, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn trending(rp: RustyPipe) {
|
fn trending() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let result = tokio_test::block_on(rp.query().trending()).unwrap();
|
let result = tokio_test::block_on(rp.query().trending()).unwrap();
|
||||||
|
|
||||||
assert_gte(result.len(), 50, "items");
|
assert_gte(result.len(), 50, "items");
|
||||||
|
@ -1198,8 +1230,8 @@ fn music_playlist(
|
||||||
#[case] description: Option<String>,
|
#[case] description: Option<String>,
|
||||||
#[case] channel: Option<(&str, &str)>,
|
#[case] channel: Option<(&str, &str)>,
|
||||||
#[case] from_ytm: bool,
|
#[case] from_ytm: bool,
|
||||||
rp: RustyPipe,
|
|
||||||
) {
|
) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let playlist = tokio_test::block_on(rp.query().music_playlist(id)).unwrap();
|
let playlist = tokio_test::block_on(rp.query().music_playlist(id)).unwrap();
|
||||||
|
|
||||||
assert_eq!(playlist.id, id);
|
assert_eq!(playlist.id, id);
|
||||||
|
@ -1219,8 +1251,9 @@ fn music_playlist(
|
||||||
assert_eq!(playlist.from_ytm, from_ytm);
|
assert_eq!(playlist.from_ytm, from_ytm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_playlist_cont(rp: RustyPipe) {
|
fn music_playlist_cont() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let mut playlist = tokio_test::block_on(
|
let mut playlist = tokio_test::block_on(
|
||||||
rp.query()
|
rp.query()
|
||||||
.music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi"),
|
.music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi"),
|
||||||
|
@ -1233,8 +1266,9 @@ fn music_playlist_cont(rp: RustyPipe) {
|
||||||
assert_gte(playlist.tracks.count.unwrap(), 100, "track count");
|
assert_gte(playlist.tracks.count.unwrap(), 100, "track count");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_playlist_related(rp: RustyPipe) {
|
fn music_playlist_related() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let mut playlist = tokio_test::block_on(
|
let mut playlist = tokio_test::block_on(
|
||||||
rp.query()
|
rp.query()
|
||||||
.music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi"),
|
.music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi"),
|
||||||
|
@ -1250,8 +1284,9 @@ fn music_playlist_related(rp: RustyPipe) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_playlist_not_found(rp: RustyPipe) {
|
fn music_playlist_not_found() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let err = tokio_test::block_on(
|
let err = tokio_test::block_on(
|
||||||
rp.query()
|
rp.query()
|
||||||
.music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qz"),
|
.music_playlist("PLbZIPy20-1pN7mqjckepWF78ndb6ci_qz"),
|
||||||
|
@ -1278,7 +1313,8 @@ fn music_playlist_not_found(rp: RustyPipe) {
|
||||||
#[case::no_year("no_year", "MPREb_F3Af9UZZVxX")]
|
#[case::no_year("no_year", "MPREb_F3Af9UZZVxX")]
|
||||||
#[case::version_no_artist("version_no_artist", "MPREb_h8ltx5oKvyY")]
|
#[case::version_no_artist("version_no_artist", "MPREb_h8ltx5oKvyY")]
|
||||||
#[case::no_artist("no_artist", "MPREb_bqWA6mAZFWS")]
|
#[case::no_artist("no_artist", "MPREb_bqWA6mAZFWS")]
|
||||||
fn music_album(#[case] name: &str, #[case] id: &str, rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_album(id)).unwrap();
|
||||||
|
|
||||||
assert!(!album.cover.is_empty(), "got no cover");
|
assert!(!album.cover.is_empty(), "got no cover");
|
||||||
|
@ -1288,8 +1324,9 @@ fn music_album(#[case] name: &str, #[case] id: &str, rp: RustyPipe) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_album_not_found(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_album("MPREb_nlBWQROfvjoz")).unwrap_err();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -1316,8 +1353,9 @@ fn music_artist(
|
||||||
#[case] all_albums: bool,
|
#[case] all_albums: bool,
|
||||||
#[case] min_tracks: usize,
|
#[case] min_tracks: usize,
|
||||||
#[case] min_playlists: usize,
|
#[case] min_playlists: usize,
|
||||||
rp: RustyPipe,
|
|
||||||
) {
|
) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
|
|
||||||
let mut artist = tokio_test::block_on(rp.query().music_artist(id, all_albums)).unwrap();
|
let mut artist = tokio_test::block_on(rp.query().music_artist(id, all_albums)).unwrap();
|
||||||
|
|
||||||
assert_gte(artist.tracks.len(), min_tracks, "tracks");
|
assert_gte(artist.tracks.len(), min_tracks, "tracks");
|
||||||
|
@ -1362,8 +1400,9 @@ fn music_artist(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_artist_not_found(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_artist("UC7cl4MmM6ZZ2TcFyMk_b4pq", false))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
|
@ -1379,7 +1418,8 @@ fn music_artist_not_found(rp: RustyPipe) {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::default(false)]
|
#[case::default(false)]
|
||||||
#[case::typo(true)]
|
#[case::typo(true)]
|
||||||
fn music_search(#[case] typo: bool, rp: RustyPipe) {
|
fn music_search(#[case] typo: bool) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let res = tokio_test::block_on(rp.query().music_search(match typo {
|
let res = tokio_test::block_on(rp.query().music_search(match typo {
|
||||||
false => "black mamba aespa",
|
false => "black mamba aespa",
|
||||||
true => "blck mamba aespa",
|
true => "blck mamba aespa",
|
||||||
|
@ -1417,8 +1457,9 @@ fn music_search(#[case] typo: bool, rp: RustyPipe) {
|
||||||
assert_eq!(track.track_nr, None);
|
assert_eq!(track.track_nr, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_search_tracks(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_search_tracks("black mamba")).unwrap();
|
||||||
|
|
||||||
let track = &res
|
let track = &res
|
||||||
|
@ -1450,8 +1491,9 @@ fn music_search_tracks(rp: RustyPipe) {
|
||||||
assert_next(res.items, rp.query(), 15, 2);
|
assert_next(res.items, rp.query(), 15, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_search_videos(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_search_videos("black mamba")).unwrap();
|
||||||
|
|
||||||
let track = &res
|
let track = &res
|
||||||
|
@ -1542,8 +1584,8 @@ fn music_search_albums(
|
||||||
#[case] artist_id: &str,
|
#[case] artist_id: &str,
|
||||||
#[case] year: u16,
|
#[case] year: u16,
|
||||||
#[case] album_type: AlbumType,
|
#[case] album_type: AlbumType,
|
||||||
rp: RustyPipe,
|
|
||||||
) {
|
) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let res = tokio_test::block_on(rp.query().music_search_albums(query)).unwrap();
|
let res = tokio_test::block_on(rp.query().music_search_albums(query)).unwrap();
|
||||||
|
|
||||||
let album = &res.items.items.iter().find(|a| a.id == id).unwrap();
|
let album = &res.items.items.iter().find(|a| a.id == id).unwrap();
|
||||||
|
@ -1564,8 +1606,9 @@ fn music_search_albums(
|
||||||
assert_next(res.items, rp.query(), 15, 1);
|
assert_next(res.items, rp.query(), 15, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_search_artists(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_search_artists("namika")).unwrap();
|
||||||
|
|
||||||
let artist = res
|
let artist = res
|
||||||
|
@ -1584,8 +1627,9 @@ fn music_search_artists(rp: RustyPipe) {
|
||||||
assert_eq!(res.corrected_query, None);
|
assert_eq!(res.corrected_query, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_search_artists_cont(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_search_artists("band")).unwrap();
|
||||||
|
|
||||||
assert_eq!(res.corrected_query, None);
|
assert_eq!(res.corrected_query, None);
|
||||||
|
@ -1595,7 +1639,8 @@ fn music_search_artists_cont(rp: RustyPipe) {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::ytm(false)]
|
#[case::ytm(false)]
|
||||||
#[case::default(true)]
|
#[case::default(true)]
|
||||||
fn music_search_playlists(#[case] with_community: bool, rp: RustyPipe) {
|
fn music_search_playlists(#[case] with_community: bool) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let res = if with_community {
|
let res = if with_community {
|
||||||
tokio_test::block_on(rp.query().music_search_playlists("easy pop")).unwrap()
|
tokio_test::block_on(rp.query().music_search_playlists("easy pop")).unwrap()
|
||||||
} else {
|
} else {
|
||||||
|
@ -1617,8 +1662,9 @@ fn music_search_playlists(#[case] with_community: bool, rp: RustyPipe) {
|
||||||
assert!(playlist.from_ytm);
|
assert!(playlist.from_ytm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_search_playlists_community(rp: RustyPipe) {
|
fn music_search_playlists_community() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let res = tokio_test::block_on(
|
let res = tokio_test::block_on(
|
||||||
rp.query()
|
rp.query()
|
||||||
.music_search_playlists_filter("Best Pop Music Videos - Top Pop Hits Playlist", true),
|
.music_search_playlists_filter("Best Pop Music Videos - Top Pop Hits Playlist", true),
|
||||||
|
@ -1647,8 +1693,9 @@ fn music_search_playlists_community(rp: RustyPipe) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The YouTube Music search sometimes shows genre radio items. They should be skipped.
|
/// The YouTube Music search sometimes shows genre radio items. They should be skipped.
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_search_genre_radio(rp: RustyPipe) {
|
fn music_search_genre_radio() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
tokio_test::block_on(rp.query().music_search("pop radio")).unwrap();
|
tokio_test::block_on(rp.query().music_search("pop radio")).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1659,8 +1706,8 @@ fn music_search_suggestion(
|
||||||
#[case] query: &str,
|
#[case] query: &str,
|
||||||
#[case] term: Option<&str>,
|
#[case] term: Option<&str>,
|
||||||
#[case] artist: Option<&str>,
|
#[case] artist: Option<&str>,
|
||||||
rp: RustyPipe,
|
|
||||||
) {
|
) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let suggestion = tokio_test::block_on(rp.query().music_search_suggestion(query)).unwrap();
|
let suggestion = tokio_test::block_on(rp.query().music_search_suggestion(query)).unwrap();
|
||||||
|
|
||||||
match term {
|
match term {
|
||||||
|
@ -1685,7 +1732,8 @@ fn music_search_suggestion(
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::mv("mv", "ZeerrnuLi5E")]
|
#[case::mv("mv", "ZeerrnuLi5E")]
|
||||||
#[case::track("track", "7nigXQS1Xb0")]
|
#[case::track("track", "7nigXQS1Xb0")]
|
||||||
fn music_details(#[case] name: &str, #[case] id: &str, rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_details(id)).unwrap();
|
||||||
|
|
||||||
assert!(!track.track.cover.is_empty(), "got no cover");
|
assert!(!track.track.cover.is_empty(), "got no cover");
|
||||||
|
@ -1703,15 +1751,17 @@ fn music_details(#[case] name: &str, #[case] id: &str, rp: RustyPipe) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_lyrics(rp: RustyPipe) {
|
fn music_lyrics() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let track = tokio_test::block_on(rp.query().music_details("NO8Arj4yeww")).unwrap();
|
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 lyrics = tokio_test::block_on(rp.query().music_lyrics(&track.lyrics_id.unwrap())).unwrap();
|
||||||
insta::assert_ron_snapshot!(lyrics);
|
insta::assert_ron_snapshot!(lyrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_lyrics_not_found(rp: RustyPipe) {
|
fn music_lyrics_not_found() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let track = tokio_test::block_on(rp.query().music_details("ekXI8qrbe1s")).unwrap();
|
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 err = tokio_test::block_on(rp.query().music_lyrics(&track.lyrics_id.unwrap())).unwrap_err();
|
||||||
|
|
||||||
|
@ -1727,7 +1777,8 @@ fn music_lyrics_not_found(rp: RustyPipe) {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::a("7nigXQS1Xb0", true)]
|
#[case::a("7nigXQS1Xb0", true)]
|
||||||
#[case::b("4t3SUDZCBaQ", false)]
|
#[case::b("4t3SUDZCBaQ", false)]
|
||||||
fn music_related(#[case] id: &str, #[case] full: bool, rp: RustyPipe) {
|
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 track = tokio_test::block_on(rp.query().music_details(id)).unwrap();
|
||||||
let related =
|
let related =
|
||||||
tokio_test::block_on(rp.query().music_related(&track.related_id.unwrap())).unwrap();
|
tokio_test::block_on(rp.query().music_related(&track.related_id.unwrap())).unwrap();
|
||||||
|
@ -1824,8 +1875,9 @@ fn music_related(#[case] id: &str, #[case] full: bool, rp: RustyPipe) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_details_not_found(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_details("7nigXQS1XbZ")).unwrap_err();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -1837,14 +1889,16 @@ fn music_details_not_found(rp: RustyPipe) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_radio_track(rp: RustyPipe) {
|
fn music_radio_track() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let tracks = tokio_test::block_on(rp.query().music_radio_track("ZeerrnuLi5E")).unwrap();
|
let tracks = tokio_test::block_on(rp.query().music_radio_track("ZeerrnuLi5E")).unwrap();
|
||||||
assert_next_items(tracks, rp.query(), 20);
|
assert_next_items(tracks, rp.query(), 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_radio_track_not_found(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_radio_track("7nigXQS1XbZ")).unwrap_err();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -1856,8 +1910,9 @@ fn music_radio_track_not_found(rp: RustyPipe) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_radio_playlist(rp: RustyPipe) {
|
fn music_radio_playlist() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let tracks = tokio_test::block_on(
|
let tracks = tokio_test::block_on(
|
||||||
rp.query()
|
rp.query()
|
||||||
.music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlRbE7PiJ"),
|
.music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlRbE7PiJ"),
|
||||||
|
@ -1866,8 +1921,9 @@ fn music_radio_playlist(rp: RustyPipe) {
|
||||||
assert_next_items(tracks, rp.query(), 20);
|
assert_next_items(tracks, rp.query(), 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_radio_playlist_not_found(rp: RustyPipe) {
|
fn music_radio_playlist_not_found() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let res = tokio_test::block_on(
|
let res = tokio_test::block_on(
|
||||||
rp.query()
|
rp.query()
|
||||||
.music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlZZZZZZZ"),
|
.music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlZZZZZZZ"),
|
||||||
|
@ -1884,15 +1940,17 @@ fn music_radio_playlist_not_found(rp: RustyPipe) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_radio_artist(rp: RustyPipe) {
|
fn music_radio_artist() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let tracks =
|
let tracks =
|
||||||
tokio_test::block_on(rp.query().music_radio("RDEM_Ktu-TilkxtLvmc9wX1MLQ")).unwrap();
|
tokio_test::block_on(rp.query().music_radio("RDEM_Ktu-TilkxtLvmc9wX1MLQ")).unwrap();
|
||||||
assert_next_items(tracks, rp.query(), 20);
|
assert_next_items(tracks, rp.query(), 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_radio_not_found(rp: RustyPipe) {
|
fn music_radio_not_found() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let err =
|
let err =
|
||||||
tokio_test::block_on(rp.query().music_radio("RDEM_Ktu-TilkxtLvmc9wXZZZZ")).unwrap_err();
|
tokio_test::block_on(rp.query().music_radio("RDEM_Ktu-TilkxtLvmc9wXZZZZ")).unwrap_err();
|
||||||
|
|
||||||
|
@ -1916,12 +1974,8 @@ fn music_radio_not_found(rp: RustyPipe) {
|
||||||
"PL4fGSI1pDJn69On1f-8NAvX_CYlx7QyZc",
|
"PL4fGSI1pDJn69On1f-8NAvX_CYlx7QyZc",
|
||||||
"PLrEnWoR732-DtKgaDdnPkezM_nDidBU9H"
|
"PLrEnWoR732-DtKgaDdnPkezM_nDidBU9H"
|
||||||
)]
|
)]
|
||||||
fn music_charts(
|
fn music_charts(#[case] country: Country, #[case] plid_top: &str, #[case] plid_trend: &str) {
|
||||||
#[case] country: Country,
|
let rp = RustyPipe::builder().strict().build();
|
||||||
#[case] plid_top: &str,
|
|
||||||
#[case] plid_trend: &str,
|
|
||||||
rp: RustyPipe,
|
|
||||||
) {
|
|
||||||
let charts = tokio_test::block_on(rp.query().music_charts(Some(country))).unwrap();
|
let charts = tokio_test::block_on(rp.query().music_charts(Some(country))).unwrap();
|
||||||
|
|
||||||
assert_eq!(charts.top_playlist_id.unwrap(), plid_top);
|
assert_eq!(charts.top_playlist_id.unwrap(), plid_top);
|
||||||
|
@ -1937,8 +1991,9 @@ fn music_charts(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_new_albums(rp: RustyPipe) {
|
fn music_new_albums() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let albums = tokio_test::block_on(rp.query().music_new_albums()).unwrap();
|
let albums = tokio_test::block_on(rp.query().music_new_albums()).unwrap();
|
||||||
assert_gte(albums.len(), 10, "albums");
|
assert_gte(albums.len(), 10, "albums");
|
||||||
|
|
||||||
|
@ -1949,8 +2004,9 @@ fn music_new_albums(rp: RustyPipe) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_new_videos(rp: RustyPipe) {
|
fn music_new_videos() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let videos = tokio_test::block_on(rp.query().music_new_videos()).unwrap();
|
let videos = tokio_test::block_on(rp.query().music_new_videos()).unwrap();
|
||||||
assert_gte(videos.len(), 5, "videos");
|
assert_gte(videos.len(), 5, "videos");
|
||||||
|
|
||||||
|
@ -1963,8 +2019,9 @@ fn music_new_videos(rp: RustyPipe) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_genres(rp: RustyPipe) {
|
fn music_genres() {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let genres = tokio_test::block_on(rp.query().music_genres()).unwrap();
|
let genres = tokio_test::block_on(rp.query().music_genres()).unwrap();
|
||||||
|
|
||||||
let chill = genres
|
let chill = genres
|
||||||
|
@ -1990,7 +2047,8 @@ fn music_genres(rp: RustyPipe) {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::chill("ggMPOg1uX1JOQWZFeDByc2Jm", "Chill")]
|
#[case::chill("ggMPOg1uX1JOQWZFeDByc2Jm", "Chill")]
|
||||||
#[case::pop("ggMPOg1uX1lMbVZmbzl6NlJ3", "Pop")]
|
#[case::pop("ggMPOg1uX1lMbVZmbzl6NlJ3", "Pop")]
|
||||||
fn music_genre(#[case] id: &str, #[case] name: &str, rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_genre(id)).unwrap();
|
||||||
|
|
||||||
fn check_music_genre(genre: MusicGenre, id: &str, name: &str) -> Vec<(String, String)> {
|
fn check_music_genre(genre: MusicGenre, id: &str, name: &str) -> Vec<(String, String)> {
|
||||||
|
@ -2040,8 +2098,9 @@ fn music_genre(#[case] id: &str, #[case] name: &str, rp: RustyPipe) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn music_genre_not_found(rp: RustyPipe) {
|
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 = tokio_test::block_on(rp.query().music_genre("ggMPOg1uX1JOQWZFeDByc2zz")).unwrap_err();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -2059,7 +2118,10 @@ const VISITOR_DATA_SEARCH_CHANNEL_HANDLES: &str = "CgszYlc1Yk1WZGRCSSjrwOSbBg%3D
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ab3_search_channel_handles() {
|
fn ab3_search_channel_handles() {
|
||||||
let rp = rp_visitor_data(VISITOR_DATA_SEARCH_CHANNEL_HANDLES);
|
let rp = RustyPipe::builder()
|
||||||
|
.strict()
|
||||||
|
.visitor_data(VISITOR_DATA_SEARCH_CHANNEL_HANDLES)
|
||||||
|
.build();
|
||||||
|
|
||||||
tokio_test::block_on(rp.query().search_filter(
|
tokio_test::block_on(rp.query().search_filter(
|
||||||
"test",
|
"test",
|
||||||
|
@ -2073,7 +2135,10 @@ fn ab3_search_channel_handles() {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::desktop(ContinuationEndpoint::Browse)]
|
#[case::desktop(ContinuationEndpoint::Browse)]
|
||||||
#[case::music(ContinuationEndpoint::MusicBrowse)]
|
#[case::music(ContinuationEndpoint::MusicBrowse)]
|
||||||
fn invalid_ctoken(#[case] ep: ContinuationEndpoint, rp: RustyPipe) {
|
#[test]
|
||||||
|
fn invalid_ctoken(#[case] ep: ContinuationEndpoint) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
|
|
||||||
let e = tokio_test::block_on(rp.query().continuation::<YouTubeItem, _>("Abcd", ep, None))
|
let e = tokio_test::block_on(rp.query().continuation::<YouTubeItem, _>("Abcd", ep, None))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
|
@ -2090,17 +2155,6 @@ fn invalid_ctoken(#[case] ep: ContinuationEndpoint, rp: RustyPipe) {
|
||||||
|
|
||||||
//#TESTUTIL
|
//#TESTUTIL
|
||||||
|
|
||||||
/// Get a new RustyPipe instance
|
|
||||||
#[fixture]
|
|
||||||
fn rp() -> RustyPipe {
|
|
||||||
RustyPipe::builder().strict().build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a new RustyPipe instance with pre-set visitor data
|
|
||||||
fn rp_visitor_data(vdata: &str) -> RustyPipe {
|
|
||||||
RustyPipe::builder().strict().visitor_data(vdata).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assert equality within 10% margin
|
/// Assert equality within 10% margin
|
||||||
fn assert_approx(left: f64, right: f64) {
|
fn assert_approx(left: f64, right: f64) {
|
||||||
if left != right {
|
if left != right {
|
||||||
|
@ -2112,7 +2166,6 @@ fn assert_approx(left: f64, right: f64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assert that number A is greater than or equal to number B
|
|
||||||
fn assert_gte<T: PartialOrd + Display>(a: T, b: T, msg: &str) {
|
fn assert_gte<T: PartialOrd + Display>(a: T, b: T, msg: &str) {
|
||||||
assert!(a >= b, "expected {b} {msg}, got {a}");
|
assert!(a >= b, "expected {b} {msg}, got {a}");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue