Compare commits

..

2 commits

Author SHA1 Message Date
53bdd5f0d2 feat: add artist radio 2023-01-25 01:02:46 +01:00
fe76b2ac66 feat: add error message to HttpStatus error
dont create reports on http status errors
2023-01-24 23:06:17 +01:00
19 changed files with 70 additions and 27 deletions

View file

@ -25,9 +25,9 @@ impl RustyPipeQuery {
.http_request_txt(self.client.inner.http.get(&url).build()?) .http_request_txt(self.client.inner.http.get(&url).build()?)
.await .await
.map_err(|e| match e { .map_err(|e| match e {
Error::HttpStatus(404) => Error::Extraction(ExtractionError::ContentUnavailable( Error::HttpStatus(404, _) => Error::Extraction(
"Channel not found".into(), ExtractionError::ContentUnavailable("Channel not found".into()),
)), ),
_ => e, _ => e,
})?; })?;

View file

@ -538,7 +538,7 @@ impl RustyPipe {
let status = res.status(); let status = res.status();
if status.is_client_error() || status.is_server_error() { if status.is_client_error() || status.is_server_error() {
Err(Error::HttpStatus(status.into())) Err(Error::HttpStatus(status.into(), "none".into()))
} else { } else {
Ok(res) Ok(res)
} }
@ -1086,26 +1086,18 @@ impl RustyPipeQuery {
}; };
if status.is_client_error() || status.is_server_error() { if status.is_client_error() || status.is_server_error() {
let status_code = status.as_u16(); let error_msg = serde_json::from_str::<response::ErrorResponse>(&resp_str)
.map(|r| r.error.message)
.unwrap_or_default();
return match status { return match status {
StatusCode::NOT_FOUND => Err(Error::Extraction( StatusCode::NOT_FOUND => Err(Error::Extraction(
ExtractionError::ContentUnavailable("404 Not found".into()), ExtractionError::ContentUnavailable(error_msg.into()),
)), )),
StatusCode::BAD_REQUEST => { StatusCode::BAD_REQUEST => Err(Error::Extraction(ExtractionError::BadRequest(
let error_res = serde_json::from_str::<response::ErrorResponse>(&resp_str); error_msg.into(),
Err(Error::Extraction(ExtractionError::BadRequest( ))),
error_res _ => Err(Error::HttpStatus(status.as_u16(), error_msg.into())),
.map(|r| r.error.message)
.unwrap_or_default()
.into(),
)))
}
_ => {
let e = Error::HttpStatus(status_code);
create_report(Level::ERR, Some(e.to_string()), vec![]);
Err(e)
}
}; };
} }

View file

@ -166,7 +166,7 @@ fn map_artist_page(
lang: crate::param::Language, lang: crate::param::Language,
skip_extendables: bool, skip_extendables: bool,
) -> Result<MapResult<(MusicArtist, Vec<String>)>, ExtractionError> { ) -> Result<MapResult<(MusicArtist, Vec<String>)>, ExtractionError> {
// dbg!(&self); // dbg!(&res);
let header = res.header.music_immersive_header_renderer; let header = res.header.music_immersive_header_renderer;
@ -272,6 +272,13 @@ fn map_artist_page(
.map(|m| m.as_str().to_owned()) .map(|m| m.as_str().to_owned())
}); });
let radio_id = header.start_radio_button.and_then(|b| {
b.button_renderer
.navigation_endpoint
.watch_endpoint
.and_then(|w| w.playlist_id)
});
Ok(MapResult { Ok(MapResult {
c: ( c: (
MusicArtist { MusicArtist {
@ -292,6 +299,7 @@ fn map_artist_page(
similar_artists: mapped.c.artists, similar_artists: mapped.c.artists,
tracks_playlist_id, tracks_playlist_id,
videos_playlist_id, videos_playlist_id,
radio_id,
}, },
album_page_params, album_page_params,
), ),

View file

@ -5,7 +5,7 @@ use crate::serializer::text::Text;
use super::{ use super::{
music_item::{ music_item::{
Grid, ItemSection, MusicThumbnailRenderer, SimpleHeader, SingleColumnBrowseResult, Button, Grid, ItemSection, MusicThumbnailRenderer, SimpleHeader, SingleColumnBrowseResult,
}, },
SectionList, Tab, SectionList, Tab,
}; };
@ -41,6 +41,9 @@ pub(crate) struct MusicHeaderRenderer {
#[serde(default)] #[serde(default)]
#[serde_as(as = "DefaultOnError")] #[serde_as(as = "DefaultOnError")]
pub share_endpoint: Option<ShareEndpoint>, pub share_endpoint: Option<ShareEndpoint>,
#[serde(default)]
#[serde_as(as = "DefaultOnError")]
pub start_radio_button: Option<Button>,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]

View file

@ -320,14 +320,14 @@ pub(crate) struct MusicCarouselShelfHeader {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct MusicCarouselShelfHeaderRenderer { pub(crate) struct MusicCarouselShelfHeaderRenderer {
pub more_content_button: Option<MoreContentButton>, pub more_content_button: Option<Button>,
#[serde(default)] #[serde(default)]
pub title: TextComponents, pub title: TextComponents,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct MoreContentButton { pub(crate) struct Button {
pub button_renderer: ButtonRenderer, pub button_renderer: ButtonRenderer,
} }

View file

@ -3649,4 +3649,5 @@ MusicArtist(
], ],
tracks_playlist_id: Some("OLAK5uy_mHzt_lZ0Vdnv3NAqvCLQw5CiYe0q96iBs"), tracks_playlist_id: Some("OLAK5uy_mHzt_lZ0Vdnv3NAqvCLQw5CiYe0q96iBs"),
videos_playlist_id: Some("OLAK5uy_k9FAxC8Xb8T0KqP5wFbn8KsP3VkUjb334"), videos_playlist_id: Some("OLAK5uy_k9FAxC8Xb8T0KqP5wFbn8KsP3VkUjb334"),
radio_id: Some("RDEM_Ktu-TilkxtLvmc9wX1MLQ"),
) )

View file

@ -152,4 +152,5 @@ MusicArtist(
similar_artists: [], similar_artists: [],
tracks_playlist_id: None, tracks_playlist_id: None,
videos_playlist_id: None, videos_playlist_id: None,
radio_id: None,
) )

View file

@ -1387,4 +1387,5 @@ MusicArtist(
], ],
tracks_playlist_id: Some("OLAK5uy_mHzt_lZ0Vdnv3NAqvCLQw5CiYe0q96iBs"), tracks_playlist_id: Some("OLAK5uy_mHzt_lZ0Vdnv3NAqvCLQw5CiYe0q96iBs"),
videos_playlist_id: Some("OLAK5uy_k9FAxC8Xb8T0KqP5wFbn8KsP3VkUjb334"), videos_playlist_id: Some("OLAK5uy_k9FAxC8Xb8T0KqP5wFbn8KsP3VkUjb334"),
radio_id: Some("RDEM_Ktu-TilkxtLvmc9wX1MLQ"),
) )

View file

@ -966,4 +966,5 @@ MusicArtist(
], ],
tracks_playlist_id: Some("OLAK5uy_m6843aeUO05cz_t1seql2dQ9eUgwyuOXI"), tracks_playlist_id: Some("OLAK5uy_m6843aeUO05cz_t1seql2dQ9eUgwyuOXI"),
videos_playlist_id: None, videos_playlist_id: None,
radio_id: Some("RDEMd8PZIv9CPsvvEDbo_pUD4w"),
) )

View file

@ -1885,4 +1885,5 @@ MusicArtist(
], ],
tracks_playlist_id: Some("OLAK5uy_nGjQIyWU6PsJZdJst7WOJHVZ7N7DupP04"), tracks_playlist_id: Some("OLAK5uy_nGjQIyWU6PsJZdJst7WOJHVZ7N7DupP04"),
videos_playlist_id: Some("OLAK5uy_mulXOv4f1FNKi1-0zgY3YouLDTXX2wLu4"), videos_playlist_id: Some("OLAK5uy_mulXOv4f1FNKi1-0zgY3YouLDTXX2wLu4"),
radio_id: Some("RDEMzMxPuaGyofN40xcgHuZAbw"),
) )

View file

@ -626,4 +626,5 @@ MusicArtist(
], ],
tracks_playlist_id: None, tracks_playlist_id: None,
videos_playlist_id: Some("OLAK5uy_lmH3iVq6lqjsnLkBWzpvRTh0DidLzbU-I"), videos_playlist_id: Some("OLAK5uy_lmH3iVq6lqjsnLkBWzpvRTh0DidLzbU-I"),
radio_id: Some("RDEMYsk_DTFHAng1G7n5toi_oA"),
) )

View file

@ -19,8 +19,8 @@ pub enum Error {
#[error("http error: {0}")] #[error("http error: {0}")]
Http(#[from] reqwest::Error), Http(#[from] reqwest::Error),
/// Erroneous HTTP status code received /// Erroneous HTTP status code received
#[error("http status code: {0}")] #[error("http status code: {0} message: {1}")]
HttpStatus(u16), HttpStatus(u16, Cow<'static, str>),
/// Unspecified error /// Unspecified error
#[error("error: {0}")] #[error("error: {0}")]
Other(Cow<'static, str>), Other(Cow<'static, str>),

View file

@ -1111,6 +1111,8 @@ pub struct MusicArtist {
pub tracks_playlist_id: Option<String>, pub tracks_playlist_id: Option<String>,
/// ID of the playlist containging the artist's videos /// ID of the playlist containging the artist's videos
pub videos_playlist_id: Option<String>, pub videos_playlist_id: Option<String>,
/// ID of the artist radio
pub radio_id: Option<String>,
} }
/// YouTube Music search result /// YouTube Music search result

View file

@ -316,4 +316,5 @@ MusicArtist(
similar_artists: "[artists]", similar_artists: "[artists]",
tracks_playlist_id: Some("OLAK5uy_n6aX-F_lCQxgyTIv4FJhp78bXV93b9NUM"), tracks_playlist_id: Some("OLAK5uy_n6aX-F_lCQxgyTIv4FJhp78bXV93b9NUM"),
videos_playlist_id: Some("OLAK5uy_nrePwvOEzmO7SydszEFfCDu8gAJxKfFtw"), videos_playlist_id: Some("OLAK5uy_nrePwvOEzmO7SydszEFfCDu8gAJxKfFtw"),
radio_id: Some("RDEMdgjzN3Qrk_GD7BooQbkJ4A"),
) )

View file

@ -661,4 +661,5 @@ MusicArtist(
similar_artists: "[artists]", similar_artists: "[artists]",
tracks_playlist_id: Some("OLAK5uy_n6aX-F_lCQxgyTIv4FJhp78bXV93b9NUM"), tracks_playlist_id: Some("OLAK5uy_n6aX-F_lCQxgyTIv4FJhp78bXV93b9NUM"),
videos_playlist_id: Some("OLAK5uy_nrePwvOEzmO7SydszEFfCDu8gAJxKfFtw"), videos_playlist_id: Some("OLAK5uy_nrePwvOEzmO7SydszEFfCDu8gAJxKfFtw"),
radio_id: Some("RDEMdgjzN3Qrk_GD7BooQbkJ4A"),
) )

View file

@ -15,4 +15,5 @@ MusicArtist(
similar_artists: "[artists]", similar_artists: "[artists]",
tracks_playlist_id: None, tracks_playlist_id: None,
videos_playlist_id: None, videos_playlist_id: None,
radio_id: None,
) )

View file

@ -151,4 +151,5 @@ MusicArtist(
similar_artists: "[artists]", similar_artists: "[artists]",
tracks_playlist_id: Some("OLAK5uy_miHesZCUQY5S9EwqfoNP2tZR9nZ0NBAeU"), tracks_playlist_id: Some("OLAK5uy_miHesZCUQY5S9EwqfoNP2tZR9nZ0NBAeU"),
videos_playlist_id: Some("OLAK5uy_mqbgE6T9uvusUWrAxJGiImf4_P4dM7IvQ"), videos_playlist_id: Some("OLAK5uy_mqbgE6T9uvusUWrAxJGiImf4_P4dM7IvQ"),
radio_id: Some("RDEM7AbogW0cCnElSU0WYm1GqA"),
) )

View file

@ -31,4 +31,5 @@ MusicArtist(
similar_artists: "[artists]", similar_artists: "[artists]",
tracks_playlist_id: None, tracks_playlist_id: None,
videos_playlist_id: Some("OLAK5uy_lmH3iVq6lqjsnLkBWzpvRTh0DidLzbU-I"), videos_playlist_id: Some("OLAK5uy_lmH3iVq6lqjsnLkBWzpvRTh0DidLzbU-I"),
radio_id: Some("RDEMYsk_DTFHAng1G7n5toi_oA"),
) )

View file

@ -2031,7 +2031,34 @@ async fn music_radio_playlist_not_found() {
.music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlZZZZZZZ") .music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlZZZZZZZ")
.await; .await;
// Currently this returns valid data if let Err(err) = res {
assert!(
matches!(
err,
Error::Extraction(ExtractionError::ContentUnavailable(_))
),
"got: {}",
err
);
}
}
#[tokio::test]
async fn music_radio_artist() {
let rp = RustyPipe::builder().strict().build();
let tracks = rp
.query()
.music_radio("RDEM_Ktu-TilkxtLvmc9wX1MLQ")
.await
.unwrap();
assert_next_items(tracks, rp.query(), 20).await;
}
#[tokio::test]
async fn music_radio_not_found() {
let rp = RustyPipe::builder().strict().build();
let res = rp.query().music_radio("RDEM_Ktu-TilkxtLvmc9wXZZZZ").await;
if let Err(err) = res { if let Err(err) = res {
assert!( assert!(
matches!( matches!(