Compare commits
No commits in common. "4d124c6d981ca3bd68a78361cf728ec41d637400" and "452f765ffd4e4d9a5ad95829fff57d0bced9b280" have entirely different histories.
4d124c6d98
...
452f765ffd
6 changed files with 8 additions and 112 deletions
|
@ -27,7 +27,6 @@ pub enum ABTest {
|
||||||
TrackViewcount = 8,
|
TrackViewcount = 8,
|
||||||
PlaylistsForShorts = 9,
|
PlaylistsForShorts = 9,
|
||||||
ChannelAboutModal = 10,
|
ChannelAboutModal = 10,
|
||||||
LikeButtonViewmodel = 11,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TESTS_TO_RUN: [ABTest; 3] = [
|
const TESTS_TO_RUN: [ABTest; 3] = [
|
||||||
|
@ -101,7 +100,6 @@ pub async fn run_test(
|
||||||
ABTest::PlaylistsForShorts => playlists_for_shorts(&query).await,
|
ABTest::PlaylistsForShorts => playlists_for_shorts(&query).await,
|
||||||
ABTest::TrackViewcount => track_viewcount(&query).await,
|
ABTest::TrackViewcount => track_viewcount(&query).await,
|
||||||
ABTest::ChannelAboutModal => channel_about_modal(&query).await,
|
ABTest::ChannelAboutModal => channel_about_modal(&query).await,
|
||||||
ABTest::LikeButtonViewmodel => like_button_viewmodel(&query).await,
|
|
||||||
}
|
}
|
||||||
.unwrap();
|
.unwrap();
|
||||||
pb.inc(1);
|
pb.inc(1);
|
||||||
|
@ -303,19 +301,3 @@ pub async fn channel_about_modal(rp: &RustyPipeQuery) -> Result<bool> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(!res.contains("\"EgVhYm91dPIGBAoCEgA%3D\""))
|
Ok(!res.contains("\"EgVhYm91dPIGBAoCEgA%3D\""))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn like_button_viewmodel(rp: &RustyPipeQuery) -> Result<bool> {
|
|
||||||
let res = rp
|
|
||||||
.raw(
|
|
||||||
ClientType::Desktop,
|
|
||||||
"next",
|
|
||||||
&QVideo {
|
|
||||||
context: rp.get_context(ClientType::Desktop, true, None).await,
|
|
||||||
video_id: "ZeerrnuLi5E",
|
|
||||||
content_check_ok: true,
|
|
||||||
racy_check_ok: true,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(res.contains("\"segmentedLikeDislikeButtonViewModel\""))
|
|
||||||
}
|
|
||||||
|
|
|
@ -432,35 +432,3 @@ channel metadata has to be fetched.
|
||||||
The new modal uses a continuation request with a token which can be easily generated.
|
The new modal uses a continuation request with a token which can be easily generated.
|
||||||
Attempts to fetch the old about tab with the A/B test enabled will lead to a redirect to
|
Attempts to fetch the old about tab with the A/B test enabled will lead to a redirect to
|
||||||
the main tab.
|
the main tab.
|
||||||
|
|
||||||
## [11] Like-Button viewmodel
|
|
||||||
|
|
||||||
- **Encountered on:** 03.11.2023
|
|
||||||
- **Impact:** 🟢 Low
|
|
||||||
- **Endpoint:** next
|
|
||||||
|
|
||||||
YouTube introduced an updated date model for the like/dislike buttons. The new model
|
|
||||||
looks needlessly complex but contains the same parsing-relevant data as the old model
|
|
||||||
(accessibility text to get like count).
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"segmentedLikeDislikeButtonViewModel": {
|
|
||||||
"likeButtonViewModel": {
|
|
||||||
"likeButtonViewModel": {
|
|
||||||
"toggleButtonViewModel": {
|
|
||||||
"toggleButtonViewModel": {
|
|
||||||
"defaultButtonViewModel": {
|
|
||||||
"buttonViewModel": {
|
|
||||||
"iconName": "LIKE",
|
|
||||||
"title": "4.2M",
|
|
||||||
"accessibilityText": "like this video along with 4,209,059 other people"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
|
@ -291,14 +291,10 @@ impl MapResponse<ChannelInfo> for response::ChannelAbout {
|
||||||
fn map_response(
|
fn map_response(
|
||||||
self,
|
self,
|
||||||
_id: &str,
|
_id: &str,
|
||||||
_lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
_visitor_data: Option<&str>,
|
_visitor_data: Option<&str>,
|
||||||
) -> Result<MapResult<ChannelInfo>, ExtractionError> {
|
) -> Result<MapResult<ChannelInfo>, ExtractionError> {
|
||||||
// Channel info is always fetched in English. There is no localized data there
|
|
||||||
// and it allows parsing the country name.
|
|
||||||
let lang = Language::En;
|
|
||||||
|
|
||||||
let ep = self
|
let ep = self
|
||||||
.on_response_received_endpoints
|
.on_response_received_endpoints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -147,46 +147,6 @@ pub(crate) enum TopLevelButton {
|
||||||
SegmentedLikeDislikeButtonRenderer {
|
SegmentedLikeDislikeButtonRenderer {
|
||||||
like_button: ToggleButtonWrap,
|
like_button: ToggleButtonWrap,
|
||||||
},
|
},
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
SegmentedLikeDislikeButtonViewModel {
|
|
||||||
like_button_view_model: LikeButtonViewModelWrap,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct LikeButtonViewModelWrap {
|
|
||||||
pub like_button_view_model: LikeButtonViewModel,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct LikeButtonViewModel {
|
|
||||||
pub toggle_button_view_model: ToggleButtonViewModelWrap,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct ToggleButtonViewModelWrap {
|
|
||||||
pub toggle_button_view_model: ToggleButtonViewModel,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct ToggleButtonViewModel {
|
|
||||||
pub default_button_view_model: ButtonViewModelWrap,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct ButtonViewModelWrap {
|
|
||||||
pub button_view_model: ButtonViewModel,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct ButtonViewModel {
|
|
||||||
pub accessibility_text: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like/Dislike button
|
/// Like/Dislike button
|
||||||
|
|
|
@ -159,20 +159,17 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
|
||||||
video_actions,
|
video_actions,
|
||||||
date_text,
|
date_text,
|
||||||
}) => {
|
}) => {
|
||||||
let like_text = video_actions
|
let like_btn = video_actions
|
||||||
.menu_renderer
|
.menu_renderer
|
||||||
.top_level_buttons
|
.top_level_buttons
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find_map(|button| {
|
.find_map(|button| {
|
||||||
let (icon, text) = match button {
|
let btn = match button {
|
||||||
response::video_details::TopLevelButton::ToggleButtonRenderer(btn) => (btn.default_icon.icon_type, btn.accessibility_data),
|
response::video_details::TopLevelButton::ToggleButtonRenderer(btn) => btn,
|
||||||
response::video_details::TopLevelButton::SegmentedLikeDislikeButtonRenderer { like_button } => (like_button.toggle_button_renderer.default_icon.icon_type, like_button.toggle_button_renderer.accessibility_data),
|
response::video_details::TopLevelButton::SegmentedLikeDislikeButtonRenderer { like_button } => like_button.toggle_button_renderer,
|
||||||
response::video_details::TopLevelButton::SegmentedLikeDislikeButtonViewModel { like_button_view_model } => {
|
|
||||||
(IconType::Like, like_button_view_model.like_button_view_model.toggle_button_view_model.toggle_button_view_model.default_button_view_model.button_view_model.accessibility_text)
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
match icon {
|
match btn.default_icon.icon_type {
|
||||||
IconType::Like => Some(text),
|
IconType::Like => Some(btn),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -187,7 +184,7 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
// accessibility_data contains no digits if the like count is hidden,
|
// accessibility_data contains no digits if the like count is hidden,
|
||||||
// so we ignore parse errors here for now
|
// so we ignore parse errors here for now
|
||||||
like_text.and_then(|txt| util::parse_numeric(&txt).ok()),
|
like_btn.and_then(|btn| util::parse_numeric(&btn.accessibility_data).ok()),
|
||||||
date_text.as_deref().and_then(|txt| {
|
date_text.as_deref().and_then(|txt| {
|
||||||
timeago::parse_textual_date_or_warn(lang, txt, &mut warnings)
|
timeago::parse_textual_date_or_warn(lang, txt, &mut warnings)
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -362,7 +362,6 @@ where
|
||||||
let mut filtered = String::new();
|
let mut filtered = String::new();
|
||||||
let mut exp = 0;
|
let mut exp = 0;
|
||||||
let mut after_point = false;
|
let mut after_point = false;
|
||||||
let mut last_number = false;
|
|
||||||
|
|
||||||
for c in string.chars() {
|
for c in string.chars() {
|
||||||
if c.is_ascii_digit() {
|
if c.is_ascii_digit() {
|
||||||
|
@ -371,10 +370,6 @@ where
|
||||||
if after_point {
|
if after_point {
|
||||||
exp -= 1;
|
exp -= 1;
|
||||||
}
|
}
|
||||||
if !last_number {
|
|
||||||
filtered.push(' ');
|
|
||||||
last_number = true;
|
|
||||||
}
|
|
||||||
} else if c == decimal_point && !digits.is_empty() {
|
} else if c == decimal_point && !digits.is_empty() {
|
||||||
after_point = true;
|
after_point = true;
|
||||||
} else if !matches!(
|
} else if !matches!(
|
||||||
|
@ -382,7 +377,6 @@ where
|
||||||
'\u{200b}' | '\u{202b}' | '\u{202c}' | '\u{202e}' | '\u{200e}' | '\u{200f}' | '.' | ','
|
'\u{200b}' | '\u{202b}' | '\u{202c}' | '\u{202e}' | '\u{200e}' | '\u{200f}' | '.' | ','
|
||||||
) {
|
) {
|
||||||
c.to_lowercase().for_each(|c| filtered.push(c));
|
c.to_lowercase().for_each(|c| filtered.push(c));
|
||||||
last_number = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,7 +636,6 @@ pub(crate) mod tests {
|
||||||
)]
|
)]
|
||||||
#[case(Language::As, "১ জন গ্ৰাহক", 1)]
|
#[case(Language::As, "১ জন গ্ৰাহক", 1)]
|
||||||
#[case(Language::Ru, "Зрителей, ожидающих начала трансляции: 6", 6)]
|
#[case(Language::Ru, "Зрителей, ожидающих начала трансляции: 6", 6)]
|
||||||
#[case(Language::Si, "වාදන මි4.6ක්", 4_600_000)]
|
|
||||||
fn t_parse_large_numstr(#[case] lang: Language, #[case] string: &str, #[case] expect: u64) {
|
fn t_parse_large_numstr(#[case] lang: Language, #[case] string: &str, #[case] expect: u64) {
|
||||||
let res = parse_large_numstr::<u64>(string, lang).unwrap();
|
let res = parse_large_numstr::<u64>(string, lang).unwrap();
|
||||||
assert_eq!(res, expect);
|
assert_eq!(res, expect);
|
||||||
|
|
Loading…
Reference in a new issue