diff --git a/src/client/pagination.rs b/src/client/pagination.rs index 94b5396..818d3af 100644 --- a/src/client/pagination.rs +++ b/src/client/pagination.rs @@ -53,14 +53,20 @@ impl> MapResponse> for response::Continuati lang: crate::param::Language, _deobf: Option<&crate::deobfuscate::Deobfuscator>, ) -> Result>, ExtractionError> { - let mut actions = self.on_response_received_actions; - let items = actions - .try_swap_remove(0) + let items = self + .on_response_received_actions + .and_then(|mut actions| { + actions + .try_swap_remove(0) + .map(|action| action.append_continuation_items_action.continuation_items) + }) + .or_else(|| { + self.continuation_contents + .map(|contents| contents.rich_grid_continuation.contents) + }) .ok_or(ExtractionError::InvalidData(Cow::Borrowed( - "no item section renderer", - )))? - .append_continuation_items_action - .continuation_items; + "no continuation items", + )))?; let mut mapper = response::YouTubeListMapper::::new(lang); mapper.map_response(items); diff --git a/src/client/response/mod.rs b/src/client/response/mod.rs index 644b998..b0452d7 100644 --- a/src/client/response/mod.rs +++ b/src/client/response/mod.rs @@ -140,6 +140,12 @@ pub(crate) struct AlertRenderer { pub text: String, } +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ResponseContext { + pub visitor_data: Option, +} + // CONTINUATION #[serde_as] @@ -153,8 +159,12 @@ pub(crate) struct Continuation { alias = "onResponseReceivedCommands", alias = "onResponseReceivedEndpoints" )] - #[serde_as(as = "VecSkipError<_>")] - pub on_response_received_actions: Vec, + #[serde_as(as = "Option>")] + pub on_response_received_actions: Option>, + /// Used for channel video rich grid renderer + /// + /// A/B test seen on 19.10.2022 + pub continuation_contents: Option, } #[derive(Debug, Deserialize)] @@ -173,8 +183,16 @@ pub(crate) struct ContinuationAction { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] -pub(crate) struct ResponseContext { - pub visitor_data: Option, +pub(crate) struct RichGridContinuationContents { + pub rich_grid_continuation: RichGridContinuation, +} + +#[serde_as] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct RichGridContinuation { + #[serde_as(as = "VecLogError<_>")] + pub contents: MapResult>, } // YouTube Music diff --git a/src/client/response/video_details.rs b/src/client/response/video_details.rs index 19a0cce..77871e2 100644 --- a/src/client/response/video_details.rs +++ b/src/client/response/video_details.rs @@ -66,8 +66,8 @@ pub(crate) struct VideoResultsWrap { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub(crate) struct VideoResults { - #[serde_as(as = "VecLogError<_>")] - pub contents: MapResult>, + #[serde_as(as = "Option>")] + pub contents: Option>>, } /// Video metadata item diff --git a/src/client/video_details.rs b/src/client/video_details.rs index 132af0f..714875e 100644 --- a/src/client/video_details.rs +++ b/src/client/video_details.rs @@ -102,7 +102,10 @@ impl MapResponse for response::VideoDetails { .two_column_watch_next_results .results .results - .contents; + .contents + .ok_or(ExtractionError::ContentUnavailable(Cow::Borrowed( + "Video not found", + )))?; warnings.append(&mut primary_results.warnings); let mut primary_info = None;