fix: support AB3 (channel handles in search results)
This commit is contained in:
parent
73fa0295bf
commit
aaffc6404d
14 changed files with 5855 additions and 50 deletions
|
|
@ -32,40 +32,72 @@ struct QVideo<'a> {
|
|||
racy_check_ok: bool,
|
||||
}
|
||||
|
||||
pub async fn run_test(ab: ABTest, n: usize, concurrency: usize) -> usize {
|
||||
pub async fn run_test(
|
||||
ab: ABTest,
|
||||
n: usize,
|
||||
concurrency: usize,
|
||||
) -> (usize, Option<String>, Option<String>) {
|
||||
eprintln!("🧪 A/B test #{}: {:?}", ab as u16, ab);
|
||||
|
||||
let rp = RustyPipe::new();
|
||||
let pb = ProgressBar::new(n as u64);
|
||||
let http = reqwest::Client::default();
|
||||
pb.set_style(
|
||||
ProgressStyle::with_template(
|
||||
"{msg} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len}",
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
// let mut count = 0;
|
||||
|
||||
let results = stream::iter(0..n)
|
||||
.map(|_| {
|
||||
let rp = rp.clone();
|
||||
let pb = pb.clone();
|
||||
let http = http.clone();
|
||||
async move {
|
||||
let visitor_data = get_visitor_data(&http).await;
|
||||
let is_present = match ab {
|
||||
ABTest::AttributedTextDescription => attributed_text_description(&rp).await,
|
||||
ABTest::ThreeTabChannelLayout => three_tab_channel_layout(&rp).await,
|
||||
ABTest::AttributedTextDescription => {
|
||||
attributed_text_description(&rp, &visitor_data).await
|
||||
}
|
||||
ABTest::ThreeTabChannelLayout => {
|
||||
three_tab_channel_layout(&rp, &visitor_data).await
|
||||
}
|
||||
}
|
||||
.unwrap();
|
||||
pb.inc(1);
|
||||
is_present
|
||||
(is_present, visitor_data)
|
||||
}
|
||||
})
|
||||
.buffer_unordered(concurrency)
|
||||
.collect::<Vec<_>>()
|
||||
.await;
|
||||
|
||||
let count = results.iter().filter(|x| **x).count();
|
||||
let count = results.iter().filter(|(p, _)| *p).count();
|
||||
let vd_present = results
|
||||
.iter()
|
||||
.find_map(|(p, vd)| if *p { Some(vd.to_owned()) } else { None });
|
||||
let vd_absent = results
|
||||
.iter()
|
||||
.find_map(|(p, vd)| if !*p { Some(vd.to_owned()) } else { None });
|
||||
|
||||
count
|
||||
(count, vd_present, vd_absent)
|
||||
}
|
||||
|
||||
async fn get_visitor_data(http: &reqwest::Client) -> String {
|
||||
let resp = http.get("https://www.youtube.com").send().await.unwrap();
|
||||
resp.headers()
|
||||
.get_all(reqwest::header::SET_COOKIE)
|
||||
.iter()
|
||||
.find_map(|c| {
|
||||
if let Ok(cookie) = c.to_str() {
|
||||
if let Some(after) = cookie.strip_prefix("__Secure-YEC=") {
|
||||
return after.split_once(';').map(|s| s.0.to_owned());
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn run_all_tests(n: usize, concurrency: usize) -> Vec<ABTestRes> {
|
||||
|
|
@ -73,7 +105,7 @@ pub async fn run_all_tests(n: usize, concurrency: usize) -> Vec<ABTestRes> {
|
|||
|
||||
for id in 1..=N_TESTS {
|
||||
let ab = ABTest::try_from(id).unwrap();
|
||||
let occurrences = run_test(ab, n, concurrency).await;
|
||||
let (occurrences, _, _) = run_test(ab, n, concurrency).await;
|
||||
results.push(ABTestRes {
|
||||
id,
|
||||
name: ab,
|
||||
|
|
@ -84,9 +116,11 @@ pub async fn run_all_tests(n: usize, concurrency: usize) -> Vec<ABTestRes> {
|
|||
results
|
||||
}
|
||||
|
||||
pub async fn attributed_text_description(rp: &RustyPipe) -> Result<bool> {
|
||||
pub async fn attributed_text_description(rp: &RustyPipe, visitor_data: &str) -> Result<bool> {
|
||||
let query = rp.query();
|
||||
let context = query.get_context(ClientType::Desktop, true, None).await;
|
||||
let context = query
|
||||
.get_context(ClientType::Desktop, true, Some(visitor_data))
|
||||
.await;
|
||||
let q = QVideo {
|
||||
context,
|
||||
video_id: "ZeerrnuLi5E",
|
||||
|
|
@ -102,9 +136,10 @@ pub async fn attributed_text_description(rp: &RustyPipe) -> Result<bool> {
|
|||
Ok(response_txt.contains("\"attributedDescription\""))
|
||||
}
|
||||
|
||||
pub async fn three_tab_channel_layout(rp: &RustyPipe) -> Result<bool> {
|
||||
pub async fn three_tab_channel_layout(rp: &RustyPipe, visitor_data: &str) -> Result<bool> {
|
||||
let channel = rp
|
||||
.query()
|
||||
.visitor_data(visitor_data)
|
||||
.channel_videos("UCR-DXc1voovS8nhAvccRZhg")
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -73,8 +73,16 @@ async fn main() {
|
|||
match id {
|
||||
Some(id) => {
|
||||
let ab = abtest::ABTest::try_from(id).expect("invalid A/B test id");
|
||||
let res = abtest::run_test(ab, n, cli.concurrency).await;
|
||||
eprintln!("{} occurences", res);
|
||||
let (occurrences, vd_present, vd_absent) =
|
||||
abtest::run_test(ab, n, cli.concurrency).await;
|
||||
eprintln!(
|
||||
"{}/{} occurences ({:.1}%)",
|
||||
occurrences,
|
||||
n,
|
||||
occurrences as f32 / n as f32 * 100.0
|
||||
);
|
||||
eprintln!("visitor_data (present): {:?}", vd_present);
|
||||
eprintln!("visitor_data (absent): {:?}", vd_absent);
|
||||
}
|
||||
None => {
|
||||
let res = abtest::run_all_tests(n, cli.concurrency).await;
|
||||
|
|
|
|||
Reference in a new issue