fix: parsing error when no music_related content available

This commit is contained in:
ThetaDev 2024-04-18 19:50:06 +02:00
parent e73a1056e8
commit 5f1e1a2a5c
2 changed files with 52 additions and 45 deletions

View file

@ -306,19 +306,14 @@ impl MapResponse<Lyrics> for response::MusicLyrics {
) -> Result<MapResult<Lyrics>, ExtractionError> { ) -> Result<MapResult<Lyrics>, ExtractionError> {
let lyrics = self let lyrics = self
.contents .contents
.section_list_renderer .into_res()
.and_then(|sl| { .map_err(|msg| ExtractionError::NotFound {
sl.contents id: id.to_owned(),
.into_iter() msg: msg.into(),
.find_map(|item| item.music_description_shelf_renderer) })?
}) .into_iter()
.ok_or(match self.contents.message_renderer { .find_map(|item| item.music_description_shelf_renderer)
Some(msg) => ExtractionError::NotFound { .ok_or(ExtractionError::InvalidData(Cow::Borrowed("no content")))?;
id: id.to_owned(),
msg: msg.text.into(),
},
None => ExtractionError::InvalidData(Cow::Borrowed("no content")),
})?;
Ok(MapResult { Ok(MapResult {
c: Lyrics { c: Lyrics {
@ -333,36 +328,39 @@ impl MapResponse<Lyrics> for response::MusicLyrics {
impl MapResponse<MusicRelated> for response::MusicRelated { impl MapResponse<MusicRelated> for response::MusicRelated {
fn map_response( fn map_response(
self, self,
_id: &str, id: &str,
lang: Language, lang: Language,
_deobf: Option<&crate::deobfuscate::DeobfData>, _deobf: Option<&crate::deobfuscate::DeobfData>,
_vdata: Option<&str>, _vdata: Option<&str>,
) -> Result<MapResult<MusicRelated>, ExtractionError> { ) -> Result<MapResult<MusicRelated>, ExtractionError> {
let contents = self
.contents
.into_res()
.map_err(|msg| ExtractionError::NotFound {
id: id.to_owned(),
msg: msg.into(),
})?;
// Find artist // Find artist
let artist_id = self let artist_id = contents.iter().find_map(|section| match section {
.contents response::music_item::ItemSection::MusicCarouselShelfRenderer(shelf) => {
.section_list_renderer shelf.header.as_ref().and_then(|h| {
.contents h.music_carousel_shelf_basic_header_renderer
.iter() .title
.find_map(|section| match section { .0
response::music_item::ItemSection::MusicCarouselShelfRenderer(shelf) => { .iter()
shelf.header.as_ref().and_then(|h| { .find_map(|c| {
h.music_carousel_shelf_basic_header_renderer let artist = ArtistId::from(c.clone());
.title if artist.id.is_some() {
.0 Some(artist)
.iter() } else {
.find_map(|c| { None
let artist = ArtistId::from(c.clone()); }
if artist.id.is_some() { })
Some(artist) })
} else { }
None _ => None,
} });
})
})
}
_ => None,
});
let mut mapper_tracks = MusicListMapper::new(lang); let mut mapper_tracks = MusicListMapper::new(lang);
let mut mapper = match artist_id { let mut mapper = match artist_id {
@ -370,7 +368,7 @@ impl MapResponse<MusicRelated> for response::MusicRelated {
None => MusicListMapper::new(lang), None => MusicListMapper::new(lang),
}; };
let mut sections = self.contents.section_list_renderer.contents.into_iter(); let mut sections = contents.into_iter();
if let Some(response::music_item::ItemSection::MusicCarouselShelfRenderer(shelf)) = if let Some(response::music_item::ItemSection::MusicCarouselShelfRenderer(shelf)) =
sections.next() sections.next()
{ {

View file

@ -7,7 +7,7 @@ use super::AlertRenderer;
use super::ContentsRenderer; use super::ContentsRenderer;
use super::{ use super::{
music_item::{ItemSection, PlaylistPanelRenderer}, music_item::{ItemSection, PlaylistPanelRenderer},
ContentRenderer, SectionList, ContentRenderer,
}; };
/// Response model for YouTube Music track details /// Response model for YouTube Music track details
@ -108,14 +108,14 @@ pub(crate) struct PlaylistPanel {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct MusicLyrics { pub(crate) struct MusicLyrics {
pub contents: LyricsContents, pub contents: ListOrMessage<LyricsSection>,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct LyricsContents { pub(crate) enum ListOrMessage<T> {
pub message_renderer: Option<AlertRenderer>, SectionListRenderer(ContentsRenderer<T>),
pub section_list_renderer: Option<ContentsRenderer<LyricsSection>>, MessageRenderer(AlertRenderer),
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -137,5 +137,14 @@ pub(crate) struct LyricsRenderer {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct MusicRelated { pub(crate) struct MusicRelated {
pub contents: SectionList<ItemSection>, pub contents: ListOrMessage<ItemSection>,
}
impl<T> ListOrMessage<T> {
pub fn into_res(self) -> Result<Vec<T>, String> {
match self {
ListOrMessage::SectionListRenderer(c) => Ok(c.contents),
ListOrMessage::MessageRenderer(msg) => Err(msg.text),
}
}
} }