use serde::Deserialize; use serde_with::serde_as; use serde_with::{DefaultOnError, VecSkipError}; use super::Thumbnails; use super::{Alert, ChannelBadge}; use super::{ContentRenderer, ContentsRenderer, VideoListItem}; use crate::serializer::ignore_any; use crate::serializer::{text::Text, MapResult, VecLogError}; #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Channel { #[serde(default)] #[serde_as(as = "DefaultOnError")] pub header: Option
, pub contents: Option, pub metadata: Option, pub microformat: Option, #[serde_as(as = "Option")] pub alerts: Option>, } #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ChannelCont { #[serde(default)] #[serde_as(as = "VecSkipError<_>")] pub on_response_received_actions: Vec, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Contents { pub two_column_browse_results_renderer: TabsRenderer, } /// YouTube channel tab view. Contains multiple tabs /// (Home, Videos, Playlists, About...). We can ignore unknown tabs. #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TabsRenderer { #[serde_as(as = "VecSkipError<_>")] pub tabs: Vec, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TabRendererWrap { pub tab_renderer: ContentRenderer, } #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TabContent { #[serde(default)] #[serde_as(as = "DefaultOnError")] pub section_list_renderer: Option, /// Seems to be currently A/B tested, as of 11.10.2022 #[serde(default)] #[serde_as(as = "DefaultOnError")] pub rich_grid_renderer: Option, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SectionListRenderer { pub contents: Vec, /// - **Videos**: browse-feedUC2DjFE7Xf11URZqWBigcVOQvideos (...) /// - **Playlists**: browse-feedUC2DjFE7Xf11URZqWBigcVOQplaylists104 (...) /// - **Info**: None pub target_id: Option, } /// Seems to be currently A/B tested, as of 11.10.2022 #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RichGridRenderer { #[serde_as(as = "VecLogError<_>")] pub contents: MapResult>, /// - **Videos**: browse-feedUC2DjFE7Xf11URZqWBigcVOQvideos (...) /// - **Playlists**: browse-feedUC2DjFE7Xf11URZqWBigcVOQplaylists104 (...) /// - **Info**: None pub target_id: Option, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ItemSectionRendererWrap { pub item_section_renderer: ContentsRenderer, } #[serde_as] #[derive(Default, Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub enum ChannelContent { GridRenderer { #[serde_as(as = "VecLogError<_>")] items: MapResult>, }, ChannelAboutFullMetadataRenderer(ChannelFullMetadata), #[default] #[serde(other, deserialize_with = "ignore_any")] None, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub enum Header { C4TabbedHeaderRenderer(HeaderRenderer), /// Used for special channels like YouTube Music CarouselHeaderRenderer(ContentsRenderer), } #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct HeaderRenderer { /// Approximate subscriber count (e.g. `880K subscribers`), depends on language. /// /// `None` if the subscriber count is hidden. #[serde_as(as = "Option")] pub subscriber_count_text: Option, #[serde(default)] pub avatar: Thumbnails, #[serde_as(as = "Option>")] pub badges: Option>, #[serde(default)] pub banner: Thumbnails, #[serde(default)] pub mobile_banner: Thumbnails, /// Fullscreen (16:9) channel banner #[serde(default)] pub tv_banner: Thumbnails, } #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub enum CarouselHeaderRendererItem { #[serde(rename_all = "camelCase")] TopicChannelDetailsRenderer { #[serde_as(as = "Option")] subscriber_count_text: Option, #[serde(default)] avatar: Thumbnails, }, #[serde(other, deserialize_with = "ignore_any")] None, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Metadata { pub channel_metadata_renderer: ChannelMetadataRenderer, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ChannelMetadataRenderer { pub title: String, /// Channel ID pub external_id: String, pub description: String, pub vanity_channel_url: Option, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Microformat { pub microformat_data_renderer: MicroformatDataRenderer, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct MicroformatDataRenderer { #[serde(default)] pub tags: Vec, } #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ChannelFullMetadata { #[serde_as(as = "Text")] pub joined_date_text: String, #[serde_as(as = "Option")] pub view_count_text: Option, #[serde(default)] #[serde_as(as = "VecSkipError<_>")] pub primary_links: Vec, } #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PrimaryLink { #[serde_as(as = "Text")] pub title: String, pub navigation_endpoint: NavigationEndpoint, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct NavigationEndpoint { pub url_endpoint: UrlEndpoint, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct UrlEndpoint { pub url: String, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct OnResponseReceivedAction { pub append_continuation_items_action: AppendAction, } #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AppendAction { #[serde_as(as = "VecLogError<_>")] pub continuation_items: MapResult>, }