fix: a/b test 10: channel about modal
This commit is contained in:
parent
cced125390
commit
ba06e2c8c8
17 changed files with 1686 additions and 2932 deletions
|
|
@ -2,10 +2,10 @@ use serde::Deserialize;
|
|||
use serde_with::{rust::deserialize_ignore_any, serde_as, DefaultOnError, VecSkipError};
|
||||
|
||||
use super::{
|
||||
video_item::YouTubeListRenderer, Alert, ChannelBadge, ContentsRenderer, ResponseContext,
|
||||
Thumbnails, TwoColumnBrowseResults,
|
||||
video_item::YouTubeListRenderer, Alert, ChannelBadge, ContentsRenderer, ContinuationActionWrap,
|
||||
ResponseContext, Thumbnails, TwoColumnBrowseResults,
|
||||
};
|
||||
use crate::serializer::text::Text;
|
||||
use crate::serializer::text::{AttributedText, Text, TextComponent};
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
@ -145,3 +145,66 @@ pub(crate) struct MicroformatDataRenderer {
|
|||
#[serde(default)]
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ChannelAbout {
|
||||
#[serde_as(as = "VecSkipError<_>")]
|
||||
pub on_response_received_endpoints: Vec<ContinuationActionWrap<AboutChannelRendererWrap>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AboutChannelRendererWrap {
|
||||
pub about_channel_renderer: AboutChannelRenderer,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AboutChannelRenderer {
|
||||
pub metadata: ChannelMetadata,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ChannelMetadata {
|
||||
pub about_channel_view_model: ChannelMetadataView,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ChannelMetadataView {
|
||||
pub channel_id: String,
|
||||
pub canonical_channel_url: String,
|
||||
pub country: Option<String>,
|
||||
#[serde(default)]
|
||||
pub description: String,
|
||||
#[serde_as(as = "Option<Text>")]
|
||||
pub joined_date_text: Option<String>,
|
||||
#[serde_as(as = "Option<Text>")]
|
||||
pub subscriber_count_text: Option<String>,
|
||||
#[serde_as(as = "Option<Text>")]
|
||||
pub video_count_text: Option<String>,
|
||||
#[serde_as(as = "Option<Text>")]
|
||||
pub view_count_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub links: Vec<ExternalLink>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ExternalLink {
|
||||
pub channel_external_link_view_model: ExternalLinkInner,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ExternalLinkInner {
|
||||
#[serde_as(as = "AttributedText")]
|
||||
pub title: TextComponent,
|
||||
#[serde_as(as = "AttributedText")]
|
||||
pub link: TextComponent,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ pub(crate) mod video_details;
|
|||
pub(crate) mod video_item;
|
||||
|
||||
pub(crate) use channel::Channel;
|
||||
pub(crate) use channel::ChannelAbout;
|
||||
pub(crate) use music_artist::MusicArtist;
|
||||
pub(crate) use music_artist::MusicArtistAlbums;
|
||||
pub(crate) use music_charts::MusicCharts;
|
||||
|
|
@ -208,7 +209,7 @@ pub(crate) struct Continuation {
|
|||
alias = "onResponseReceivedEndpoints"
|
||||
)]
|
||||
#[serde_as(as = "Option<VecSkipError<_>>")]
|
||||
pub on_response_received_actions: Option<Vec<ContinuationActionWrap>>,
|
||||
pub on_response_received_actions: Option<Vec<ContinuationActionWrap<YouTubeListItem>>>,
|
||||
/// Used for channel video rich grid renderer
|
||||
///
|
||||
/// A/B test seen on 19.10.2022
|
||||
|
|
@ -217,15 +218,15 @@ pub(crate) struct Continuation {
|
|||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ContinuationActionWrap {
|
||||
pub(crate) struct ContinuationActionWrap<T> {
|
||||
#[serde(alias = "reloadContinuationItemsCommand")]
|
||||
pub append_continuation_items_action: ContinuationAction,
|
||||
pub append_continuation_items_action: ContinuationAction<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ContinuationAction {
|
||||
pub continuation_items: MapResult<Vec<YouTubeListItem>>,
|
||||
pub(crate) struct ContinuationAction<T> {
|
||||
pub continuation_items: MapResult<Vec<T>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use serde::Deserialize;
|
||||
use serde_with::{serde_as, DefaultOnError};
|
||||
|
||||
use crate::{model::UrlTarget, util};
|
||||
use crate::model::UrlTarget;
|
||||
|
||||
/// navigation/resolve_url response model
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
@ -280,14 +280,4 @@ impl NavigationEndpoint {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the sanitized URL from a url endpoint
|
||||
pub(crate) fn url(&self) -> Option<String> {
|
||||
match self {
|
||||
NavigationEndpoint::Url { url_endpoint } => {
|
||||
Some(util::sanitize_yt_url(&url_endpoint.url))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,15 @@ use serde_with::{
|
|||
};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
use super::{url_endpoint::NavigationEndpoint, ChannelBadge, ContinuationEndpoint, Thumbnails};
|
||||
use super::{ChannelBadge, ContinuationEndpoint, Thumbnails};
|
||||
use crate::{
|
||||
model::{
|
||||
Channel, ChannelId, ChannelInfo, ChannelItem, ChannelTag, PlaylistItem, Verification,
|
||||
VideoItem, YouTubeItem,
|
||||
Channel, ChannelId, ChannelItem, ChannelTag, PlaylistItem, Verification, VideoItem,
|
||||
YouTubeItem,
|
||||
},
|
||||
param::Language,
|
||||
serializer::{
|
||||
text::{AccessibilityText, AttributedText, Text, TextComponent},
|
||||
text::{AccessibilityText, Text, TextComponent},
|
||||
MapResult,
|
||||
},
|
||||
util::{self, timeago, TryRemove},
|
||||
|
|
@ -48,9 +48,6 @@ pub(crate) enum YouTubeListItem {
|
|||
corrected_query: String,
|
||||
},
|
||||
|
||||
/// Channel metadata (about tab)
|
||||
ChannelAboutFullMetadataRenderer(ChannelFullMetadata),
|
||||
|
||||
/// Contains video on startpage
|
||||
///
|
||||
/// Seems to be currently A/B tested on the channel page,
|
||||
|
|
@ -358,47 +355,6 @@ pub(crate) struct ReelPlayerHeaderRenderer {
|
|||
pub timestamp_text: String,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ChannelFullMetadata {
|
||||
#[serde_as(as = "Text")]
|
||||
pub joined_date_text: String,
|
||||
#[serde_as(as = "Option<Text>")]
|
||||
pub view_count_text: Option<String>,
|
||||
#[serde(default)]
|
||||
#[serde_as(as = "VecSkipError<_>")]
|
||||
pub primary_links: Vec<PrimaryLink>,
|
||||
#[serde(default)]
|
||||
// #[serde_as(as = "VecSkipError<_>")]
|
||||
pub links: Vec<ExternalLink>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PrimaryLink {
|
||||
#[serde_as(as = "Text")]
|
||||
pub title: String,
|
||||
pub navigation_endpoint: NavigationEndpoint,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ExternalLink {
|
||||
pub channel_external_link_view_model: ExternalLinkInner,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ExternalLinkInner {
|
||||
#[serde_as(as = "AttributedText")]
|
||||
pub title: TextComponent,
|
||||
#[serde_as(as = "AttributedText")]
|
||||
pub link: TextComponent,
|
||||
}
|
||||
|
||||
trait IsLive {
|
||||
fn is_live(&self) -> bool;
|
||||
}
|
||||
|
|
@ -446,7 +402,6 @@ pub(crate) struct YouTubeListMapper<T> {
|
|||
pub warnings: Vec<String>,
|
||||
pub ctoken: Option<String>,
|
||||
pub corrected_query: Option<String>,
|
||||
pub channel_info: Option<ChannelInfo>,
|
||||
}
|
||||
|
||||
impl<T> YouTubeListMapper<T> {
|
||||
|
|
@ -458,7 +413,6 @@ impl<T> YouTubeListMapper<T> {
|
|||
warnings: Vec::new(),
|
||||
ctoken: None,
|
||||
corrected_query: None,
|
||||
channel_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -476,7 +430,6 @@ impl<T> YouTubeListMapper<T> {
|
|||
warnings,
|
||||
ctoken: None,
|
||||
corrected_query: None,
|
||||
channel_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -744,32 +697,6 @@ impl YouTubeListMapper<YouTubeItem> {
|
|||
YouTubeListItem::ShowingResultsForRenderer { corrected_query } => {
|
||||
self.corrected_query = Some(corrected_query);
|
||||
}
|
||||
YouTubeListItem::ChannelAboutFullMetadataRenderer(meta) => {
|
||||
let mut links = meta
|
||||
.primary_links
|
||||
.into_iter()
|
||||
.filter_map(|l| l.navigation_endpoint.url().map(|url| (l.title, url)))
|
||||
.collect::<Vec<_>>();
|
||||
for l in meta.links {
|
||||
let l = l.channel_external_link_view_model;
|
||||
if let TextComponent::Web { url, .. } = l.link {
|
||||
links.push((l.title.into(), util::sanitize_yt_url(&url)));
|
||||
}
|
||||
}
|
||||
|
||||
self.channel_info = Some(ChannelInfo {
|
||||
create_date: timeago::parse_textual_date_or_warn(
|
||||
self.lang,
|
||||
&meta.joined_date_text,
|
||||
&mut self.warnings,
|
||||
)
|
||||
.map(OffsetDateTime::date),
|
||||
view_count: meta
|
||||
.view_count_text
|
||||
.and_then(|txt| util::parse_numeric_or_warn(&txt, &mut self.warnings)),
|
||||
links,
|
||||
});
|
||||
}
|
||||
YouTubeListItem::RichItemRenderer { content } => {
|
||||
self.map_item(*content);
|
||||
}
|
||||
|
|
|
|||
Reference in a new issue