From dc0eb1d4cc0e630edd87fb9c9883a0ea0bee2b92 Mon Sep 17 00:00:00 2001 From: ThetaDev Date: Mon, 13 Feb 2023 14:42:22 +0100 Subject: [PATCH] fix: use desktop client by default for fetching player --- src/client/player.rs | 28 ++++++++++++++++---------- src/client/response/player.rs | 38 +++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/client/player.rs b/src/client/player.rs index f7bcbdc..f4131a5 100644 --- a/src/client/player.rs +++ b/src/client/player.rs @@ -61,9 +61,9 @@ impl RustyPipeQuery { /// Get YouTube player data (video/audio streams + basic metadata) pub async fn player>(&self, video_id: S) -> Result { let video_id = video_id.as_ref(); - let android_res = self.player_from_client(video_id, ClientType::Android).await; + let desktop_res = self.player_from_client(video_id, ClientType::Desktop).await; - match android_res { + match desktop_res { Ok(res) => Ok(res), Err(Error::Extraction(e)) => { if e.switch_client() { @@ -72,7 +72,7 @@ impl RustyPipeQuery { .await; match tv_res { - // Output android client error if the tv client is unsupported + // Output desktop client error if the tv client is unsupported Err(Error::Extraction(ExtractionError::VideoClientUnsupported(_))) => { Err(Error::Extraction(e)) } @@ -152,25 +152,31 @@ impl MapResponse for response::Player { response::player::PlayabilityStatus::Ok { live_streamability } => { live_streamability.is_some() } - response::player::PlayabilityStatus::Unplayable { reason } => { - for word in reason.split_whitespace() { + response::player::PlayabilityStatus::Unplayable { + reason, + error_screen, + } => { + let mut msg = reason; + if let Some(error_screen) = error_screen { + msg.push_str(" - "); + msg.push_str(&error_screen.player_error_message_renderer.subreason); + } + + for word in msg.split_whitespace() { match word { // reason: "This video requires payment to watch." - "payment" => return Err(ExtractionError::VideoUnavailable("DRM", reason)), + "payment" => return Err(ExtractionError::VideoUnavailable("DRM", msg)), // reason: "The uploader has not made this video available in your country." "country" => return Err(ExtractionError::VideoGeoblocked), // reason (Android): "This video can only be played on newer versions of Android or other supported devices." // reason (TV client): "Playback on other websites has been disabled by the video owner." "Android" | "websites" => { - return Err(ExtractionError::VideoClientUnsupported(reason)) + return Err(ExtractionError::VideoClientUnsupported(msg)) } _ => {} } } - return Err(ExtractionError::VideoUnavailable( - "being unplayable", - reason, - )); + return Err(ExtractionError::VideoUnavailable("being unplayable", msg)); } response::player::PlayabilityStatus::LoginRequired { reason } => { // reason (age restriction): "Sign in to confirm your age" diff --git a/src/client/response/player.rs b/src/client/response/player.rs index 5d4eda0..86c8244 100644 --- a/src/client/response/player.rs +++ b/src/client/response/player.rs @@ -17,6 +17,7 @@ pub(crate) struct Player { pub response_context: ResponseContext, } +#[serde_as] #[derive(Debug, Deserialize)] #[serde(tag = "status", rename_all = "SCREAMING_SNAKE_CASE")] pub(crate) enum PlayabilityStatus { @@ -24,20 +25,49 @@ pub(crate) enum PlayabilityStatus { Ok { live_streamability: Option }, /// Video cant be played because of DRM / Geoblock #[serde(rename_all = "camelCase")] - Unplayable { reason: String }, + Unplayable { + #[serde(default)] + reason: String, + #[serde(default)] + #[serde_as(deserialize_as = "DefaultOnError")] + error_screen: Option, + }, /// Age limit / Private video #[serde(rename_all = "camelCase")] - LoginRequired { reason: String }, + LoginRequired { + #[serde(default)] + reason: String, + }, #[serde(rename_all = "camelCase")] - LiveStreamOffline { reason: String }, + LiveStreamOffline { + #[serde(default)] + reason: String, + }, /// Video was censored / deleted #[serde(rename_all = "camelCase")] - Error { reason: String }, + Error { + #[serde(default)] + reason: String, + }, } #[derive(Debug, Deserialize)] pub(crate) struct Empty {} +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ErrorScreen { + pub player_error_message_renderer: ErrorMessage, +} + +#[serde_as] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ErrorMessage { + #[serde_as(as = "Text")] + pub subreason: String, +} + #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")]