diff --git a/src/client/mod.rs b/src/client/mod.rs index 09e59b7..ccf9f21 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -492,10 +492,9 @@ impl RustyPipe { Ok(response) => { let status = response.status(); // Immediately return in case of success or unrecoverable status code - if status.is_success() || !status.is_server_error() { + if status.is_success() || (!status.is_server_error() && status != 429) { return res; } - // TODO: handle 429 (captcha) status.to_string() } Err(e) => { diff --git a/src/client/response/music_item.rs b/src/client/response/music_item.rs index 26da4ec..4c3ab6c 100644 --- a/src/client/response/music_item.rs +++ b/src/client/response/music_item.rs @@ -71,28 +71,59 @@ pub(crate) struct ListMusicItem { #[serde(default)] #[serde_as(deserialize_as = "DefaultOnError")] pub playlist_item_data: Option, - /// `[<"Das Beste">], [<"Silbermond">], [<"Laut Gedacht (Re-Edition)">]` - /// Playlist track (title, artist, album) + /// ### Playlist track /// - /// `[<"Der Himmel reißt auf">]` Album track (title) + /// `[<"Das Beste">], [<"Silbermond">], [<"Laut Gedacht (Re-Edition)">]` + /// + /// (title, artist, album) + /// + /// ### Album track + /// + /// `[<"Der Himmel reißt auf">]` + /// + /// (title) + /// + /// ### Search track /// /// `[<"Girls">], ["Song", " • ", <"aespa">, " • ", <"Girls - The 2nd Mini Album">, " • ", "4:01"]` - /// Search track (title, artist, album, duration). + /// + /// (title, artist, album, duration) /// /// Info: "Song" label is missing in the "Songs" tab /// + /// ### Search video + /// /// `[<"Black Mamba">], ["Video", " • ", <"aespa">, " • ", "235M views", " • ", "3:50"]` - /// Search video (title, artist, view count, duration) + /// + /// (title, artist, view count, duration) /// /// Info: "Video" label is missing in the "Videos" tab /// - /// `["Next Level"], ["Single", " • ", <"aespa">, " • ", "2021"]` - /// Search album (title, type, artist, year) + /// ### Search podcast episode /// - /// `["Test Shot Starfish"], ["Artist", " • ", "1660 subscribers"]` Search artist + /// `["Blond - Da muss man dabei..."], ["Episode", " • ", "Dec 24, 2020", " • ", <"BLOND_OFFICIAL">], ["Dec 24, 2020"]` + /// + /// (title, date, artist, date again?) + /// + /// Info: "Episode" label is missing in the "Videos" tab + /// + /// ### Search album + /// + /// `["Next Level"], ["Single", " • ", <"aespa">, " • ", "2021"]` + /// + /// (title, type, artist, year) + /// + /// ### Search artist + /// + /// `["Test Shot Starfish"], ["Artist", " • ", "1660 subscribers"]` + /// + /// (subscriber count) + /// + /// ### Search playlist /// /// `["aespa - All Songs & MV"], ["Playlist", " • ", <"Jerwen">, " • ", "49 songs"]` - /// Search playlist (title, creator, track count) + /// + /// (title, creator, track count) /// /// Info: "Playlist" label is missing in the "Playlists" tab pub flex_columns: Vec, @@ -414,6 +445,7 @@ impl MusicListMapper { let (artists_p, album_p, duration_p) = match item.flex_column_display_style { + // Search result FlexColumnDisplayStyle::TwoLines => { let mut subtitle_parts = c2 .ok_or_else(|| format!("track {}: could not get subtitle", id))? @@ -421,16 +453,24 @@ impl MusicListMapper { .text .split(util::DOT_SEPARATOR) .into_iter(); - // Skip first part (track type) - if subtitle_parts.len() > 3 { - subtitle_parts.next(); + + // Is it a podcast episode? + if subtitle_parts.len() <= 3 && c3.is_some() { + (subtitle_parts.rev().next(), None, None) + } else { + // Skip first part (track type) + if subtitle_parts.len() > 3 { + subtitle_parts.next(); + } + + ( + subtitle_parts.next(), + subtitle_parts.next(), + subtitle_parts.next(), + ) } - ( - subtitle_parts.next(), - subtitle_parts.next(), - subtitle_parts.next(), - ) } + // Playlist item FlexColumnDisplayStyle::Default => { let mut fixed_columns = item.fixed_columns; ( diff --git a/tests/youtube.rs b/tests/youtube.rs index 3dc4bb2..dd1601a 100644 --- a/tests/youtube.rs +++ b/tests/youtube.rs @@ -1557,6 +1557,24 @@ async fn music_search_videos() { assert_next(res.items, &rp.query(), 15, 2).await; } +#[tokio::test] +async fn music_search_episode() { + let rp = RustyPipe::builder().strict().build(); + let res = rp + .query() + .music_search_videos("Blond - Da muss man dabei gewesen sein: Das Hörspiel - Fall #1") + .await + .unwrap(); + + let track = &res.items.items[0]; + assert_eq!(track.id, "Zq_-LDy7AgE"); + assert_eq!( + track.title, + "Blond - Da muss man dabei gewesen sein: Das Hörspiel - Fall #1" + ); + assert!(!track.cover.is_empty(), "got no cover"); +} + #[rstest] #[case::single( "black mamba",