fix: music item mapping, small refactor
fix: music item mapping, small refactor
This commit is contained in:
parent
fe8ff37f66
commit
fc8bce43fd
3 changed files with 235 additions and 203 deletions
|
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
url_endpoint::{BrowseEndpointWrap, NavigationEndpoint, PageType},
|
url_endpoint::{BrowseEndpointWrap, MusicPageType, NavigationEndpoint, PageType},
|
||||||
ContentsRenderer, MusicContinuationData, Thumbnails, ThumbnailsWrap,
|
ContentsRenderer, MusicContinuationData, Thumbnails, ThumbnailsWrap,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -408,119 +408,30 @@ impl MusicListMapper {
|
||||||
let c2 = columns.next();
|
let c2 = columns.next();
|
||||||
let c3 = columns.next();
|
let c3 = columns.next();
|
||||||
|
|
||||||
match item.navigation_endpoint {
|
let first_tn = item
|
||||||
// Artist / Album / Playlist
|
.thumbnail
|
||||||
Some(ne) => {
|
.music_thumbnail_renderer
|
||||||
let mut subtitle_parts = c2
|
.thumbnail
|
||||||
.ok_or_else(|| "could not get subtitle".to_owned())?
|
.thumbnails
|
||||||
.renderer
|
.first();
|
||||||
.text
|
|
||||||
.split(util::DOT_SEPARATOR)
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
let (page_type, id) = match ne.music_page() {
|
let pt_id = item
|
||||||
Some(music_page) => music_page,
|
.navigation_endpoint
|
||||||
None => {
|
.and_then(|ne| ne.music_page())
|
||||||
// Ignore radio items
|
.or_else(|| {
|
||||||
if subtitle_parts.len() == 1 {
|
item.playlist_item_data
|
||||||
return Ok(None);
|
.map(|d| (MusicPageType::Track, d.video_id))
|
||||||
}
|
})
|
||||||
return Err("invalid navigation endpoint".to_string());
|
.or_else(|| {
|
||||||
}
|
first_tn.and_then(|tn| {
|
||||||
};
|
util::video_id_from_thumbnail_url(&tn.url)
|
||||||
|
.map(|id| (MusicPageType::Track, id))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
let title =
|
match pt_id {
|
||||||
title.ok_or_else(|| format!("track {}: could not get title", id))?;
|
|
||||||
|
|
||||||
let subtitle_p1 = subtitle_parts.next();
|
|
||||||
let subtitle_p2 = subtitle_parts.next();
|
|
||||||
let subtitle_p3 = subtitle_parts.next();
|
|
||||||
|
|
||||||
match page_type {
|
|
||||||
PageType::Artist => {
|
|
||||||
let subscriber_count = subtitle_p2.and_then(|p| {
|
|
||||||
util::parse_large_numstr(p.first_str(), self.lang)
|
|
||||||
});
|
|
||||||
|
|
||||||
self.items.push(MusicItem::Artist(ArtistItem {
|
|
||||||
id,
|
|
||||||
name: title,
|
|
||||||
avatar: item.thumbnail.into(),
|
|
||||||
subscriber_count,
|
|
||||||
}));
|
|
||||||
Ok(Some(MusicEntityType::Artist))
|
|
||||||
}
|
|
||||||
PageType::Album => {
|
|
||||||
let album_type = subtitle_p1
|
|
||||||
.map(|st| map_album_type(st.first_str(), self.lang))
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let (artists, by_va) = map_artists(subtitle_p2);
|
|
||||||
|
|
||||||
let year = subtitle_p3
|
|
||||||
.and_then(|st| util::parse_numeric(st.first_str()).ok());
|
|
||||||
|
|
||||||
self.items.push(MusicItem::Album(AlbumItem {
|
|
||||||
id,
|
|
||||||
name: title,
|
|
||||||
cover: item.thumbnail.into(),
|
|
||||||
artists,
|
|
||||||
album_type,
|
|
||||||
year,
|
|
||||||
by_va,
|
|
||||||
}));
|
|
||||||
Ok(Some(MusicEntityType::Album))
|
|
||||||
}
|
|
||||||
PageType::Playlist => {
|
|
||||||
// Part 1 may be the "Playlist" label
|
|
||||||
let (channel_p, tcount_p) = match subtitle_p3 {
|
|
||||||
Some(_) => (subtitle_p2, subtitle_p3),
|
|
||||||
None => (subtitle_p1, subtitle_p2),
|
|
||||||
};
|
|
||||||
|
|
||||||
let from_ytm = channel_p
|
|
||||||
.as_ref()
|
|
||||||
.map(|p| p.first_str() == util::YT_MUSIC_NAME)
|
|
||||||
.unwrap_or_default();
|
|
||||||
let channel = channel_p.and_then(|p| {
|
|
||||||
p.0.into_iter().find_map(|c| ChannelId::try_from(c).ok())
|
|
||||||
});
|
|
||||||
let track_count =
|
|
||||||
tcount_p.and_then(|p| util::parse_numeric(p.first_str()).ok());
|
|
||||||
|
|
||||||
self.items.push(MusicItem::Playlist(MusicPlaylistItem {
|
|
||||||
id,
|
|
||||||
name: title,
|
|
||||||
thumbnail: item.thumbnail.into(),
|
|
||||||
channel,
|
|
||||||
track_count,
|
|
||||||
from_ytm,
|
|
||||||
}));
|
|
||||||
Ok(Some(MusicEntityType::Playlist))
|
|
||||||
}
|
|
||||||
PageType::Channel => {
|
|
||||||
// There may be broken YT channels from the artist search. They can be skipped.
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Track
|
// Track
|
||||||
None => {
|
Some((MusicPageType::Track, id)) => {
|
||||||
let first_tn = item
|
|
||||||
.thumbnail
|
|
||||||
.music_thumbnail_renderer
|
|
||||||
.thumbnail
|
|
||||||
.thumbnails
|
|
||||||
.first();
|
|
||||||
|
|
||||||
let id = item
|
|
||||||
.playlist_item_data
|
|
||||||
.map(|d| d.video_id)
|
|
||||||
.or_else(|| {
|
|
||||||
first_tn.and_then(|tn| util::video_id_from_thumbnail_url(&tn.url))
|
|
||||||
})
|
|
||||||
.ok_or_else(|| "no video id".to_owned())?;
|
|
||||||
|
|
||||||
let title =
|
let title =
|
||||||
title.ok_or_else(|| format!("track {}: could not get title", id))?;
|
title.ok_or_else(|| format!("track {}: could not get title", id))?;
|
||||||
|
|
||||||
|
|
@ -633,6 +544,92 @@ impl MusicListMapper {
|
||||||
}));
|
}));
|
||||||
Ok(Some(MusicEntityType::Track))
|
Ok(Some(MusicEntityType::Track))
|
||||||
}
|
}
|
||||||
|
// Artist / Album / Playlist
|
||||||
|
Some((page_type, id)) => {
|
||||||
|
let mut subtitle_parts = c2
|
||||||
|
.ok_or_else(|| "could not get subtitle".to_owned())?
|
||||||
|
.renderer
|
||||||
|
.text
|
||||||
|
.split(util::DOT_SEPARATOR)
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
let title =
|
||||||
|
title.ok_or_else(|| format!("track {}: could not get title", id))?;
|
||||||
|
|
||||||
|
let subtitle_p1 = subtitle_parts.next();
|
||||||
|
let subtitle_p2 = subtitle_parts.next();
|
||||||
|
let subtitle_p3 = subtitle_parts.next();
|
||||||
|
|
||||||
|
match page_type {
|
||||||
|
MusicPageType::Artist => {
|
||||||
|
let subscriber_count = subtitle_p2.and_then(|p| {
|
||||||
|
util::parse_large_numstr(p.first_str(), self.lang)
|
||||||
|
});
|
||||||
|
|
||||||
|
self.items.push(MusicItem::Artist(ArtistItem {
|
||||||
|
id,
|
||||||
|
name: title,
|
||||||
|
avatar: item.thumbnail.into(),
|
||||||
|
subscriber_count,
|
||||||
|
}));
|
||||||
|
Ok(Some(MusicEntityType::Artist))
|
||||||
|
}
|
||||||
|
MusicPageType::Album => {
|
||||||
|
let album_type = subtitle_p1
|
||||||
|
.map(|st| map_album_type(st.first_str(), self.lang))
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let (artists, by_va) = map_artists(subtitle_p2);
|
||||||
|
|
||||||
|
let year = subtitle_p3
|
||||||
|
.and_then(|st| util::parse_numeric(st.first_str()).ok());
|
||||||
|
|
||||||
|
self.items.push(MusicItem::Album(AlbumItem {
|
||||||
|
id,
|
||||||
|
name: title,
|
||||||
|
cover: item.thumbnail.into(),
|
||||||
|
artists,
|
||||||
|
album_type,
|
||||||
|
year,
|
||||||
|
by_va,
|
||||||
|
}));
|
||||||
|
Ok(Some(MusicEntityType::Album))
|
||||||
|
}
|
||||||
|
MusicPageType::Playlist => {
|
||||||
|
// Part 1 may be the "Playlist" label
|
||||||
|
let (channel_p, tcount_p) = match subtitle_p3 {
|
||||||
|
Some(_) => (subtitle_p2, subtitle_p3),
|
||||||
|
None => (subtitle_p1, subtitle_p2),
|
||||||
|
};
|
||||||
|
|
||||||
|
let from_ytm = channel_p
|
||||||
|
.as_ref()
|
||||||
|
.map(|p| p.first_str() == util::YT_MUSIC_NAME)
|
||||||
|
.unwrap_or_default();
|
||||||
|
let channel = channel_p.and_then(|p| {
|
||||||
|
p.0.into_iter().find_map(|c| ChannelId::try_from(c).ok())
|
||||||
|
});
|
||||||
|
let track_count =
|
||||||
|
tcount_p.and_then(|p| util::parse_numeric(p.first_str()).ok());
|
||||||
|
|
||||||
|
self.items.push(MusicItem::Playlist(MusicPlaylistItem {
|
||||||
|
id,
|
||||||
|
name: title,
|
||||||
|
thumbnail: item.thumbnail.into(),
|
||||||
|
channel,
|
||||||
|
track_count,
|
||||||
|
from_ytm,
|
||||||
|
}));
|
||||||
|
Ok(Some(MusicEntityType::Playlist))
|
||||||
|
}
|
||||||
|
MusicPageType::None => {
|
||||||
|
// There may be broken YT channels from the artist search. They can be skipped.
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
MusicPageType::Track => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Err("could not determine item type".to_owned()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Tile
|
// Tile
|
||||||
|
|
@ -642,44 +639,45 @@ impl MusicListMapper {
|
||||||
let subtitle_p2 = subtitle_parts.next();
|
let subtitle_p2 = subtitle_parts.next();
|
||||||
let subtitle_p3 = subtitle_parts.next();
|
let subtitle_p3 = subtitle_parts.next();
|
||||||
|
|
||||||
match item.navigation_endpoint.watch_endpoint {
|
match item.navigation_endpoint.music_page() {
|
||||||
// Music video
|
Some((page_type, id)) => match page_type {
|
||||||
Some(wep) => {
|
MusicPageType::Track => {
|
||||||
let artists = map_artists(subtitle_p1).0;
|
let artists = map_artists(subtitle_p1).0;
|
||||||
|
|
||||||
self.items.push(MusicItem::Track(TrackItem {
|
self.items.push(MusicItem::Track(TrackItem {
|
||||||
id: wep.video_id,
|
id,
|
||||||
title: item.title,
|
title: item.title,
|
||||||
duration: None,
|
duration: None,
|
||||||
cover: item.thumbnail_renderer.into(),
|
cover: item.thumbnail_renderer.into(),
|
||||||
artist_id: artists.first().and_then(|a| a.id.to_owned()),
|
artist_id: artists.first().and_then(|a| a.id.to_owned()),
|
||||||
artists,
|
artists,
|
||||||
album: None,
|
album: None,
|
||||||
view_count: subtitle_p2
|
view_count: subtitle_p2.and_then(|c| {
|
||||||
.and_then(|c| util::parse_large_numstr(c.first_str(), self.lang)),
|
util::parse_large_numstr(c.first_str(), self.lang)
|
||||||
is_video: true,
|
}),
|
||||||
track_nr: None,
|
is_video: true,
|
||||||
}));
|
track_nr: None,
|
||||||
Ok(Some(MusicEntityType::Track))
|
}));
|
||||||
}
|
Ok(Some(MusicEntityType::Track))
|
||||||
// Artist / Album / Playlist
|
}
|
||||||
None => {
|
MusicPageType::Artist => {
|
||||||
let (page_type, id) = item
|
let subscriber_count = subtitle_p1
|
||||||
.navigation_endpoint
|
.and_then(|p| util::parse_large_numstr(p.first_str(), self.lang));
|
||||||
.music_page()
|
|
||||||
.ok_or_else(|| "could not get navigation endpoint".to_owned())?;
|
|
||||||
|
|
||||||
match page_type {
|
self.items.push(MusicItem::Artist(ArtistItem {
|
||||||
PageType::Album => {
|
id,
|
||||||
let mut year = None;
|
name: item.title,
|
||||||
let mut album_type = AlbumType::Single;
|
avatar: item.thumbnail_renderer.into(),
|
||||||
|
subscriber_count,
|
||||||
|
}));
|
||||||
|
Ok(Some(MusicEntityType::Artist))
|
||||||
|
}
|
||||||
|
MusicPageType::Album => {
|
||||||
|
let mut year = None;
|
||||||
|
let mut album_type = AlbumType::Single;
|
||||||
|
|
||||||
let (artists, by_va) = match (
|
let (artists, by_va) =
|
||||||
subtitle_p1,
|
match (subtitle_p1, subtitle_p2, &self.artists, self.artist_page) {
|
||||||
subtitle_p2,
|
|
||||||
&self.artists,
|
|
||||||
self.artist_page,
|
|
||||||
) {
|
|
||||||
// "2022" (Artist singles)
|
// "2022" (Artist singles)
|
||||||
(Some(year_txt), None, Some(artists), true) => {
|
(Some(year_txt), None, Some(artists), true) => {
|
||||||
year = util::parse_numeric(year_txt.first_str()).ok();
|
year = util::parse_numeric(year_txt.first_str()).ok();
|
||||||
|
|
@ -706,56 +704,41 @@ impl MusicListMapper {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.items.push(MusicItem::Album(AlbumItem {
|
self.items.push(MusicItem::Album(AlbumItem {
|
||||||
id,
|
id,
|
||||||
name: item.title,
|
name: item.title,
|
||||||
cover: item.thumbnail_renderer.into(),
|
cover: item.thumbnail_renderer.into(),
|
||||||
artists,
|
artists,
|
||||||
album_type,
|
album_type,
|
||||||
year,
|
year,
|
||||||
by_va,
|
by_va,
|
||||||
}));
|
}));
|
||||||
Ok(Some(MusicEntityType::Album))
|
Ok(Some(MusicEntityType::Album))
|
||||||
}
|
|
||||||
PageType::Playlist => {
|
|
||||||
let from_ytm = subtitle_p2
|
|
||||||
.as_ref()
|
|
||||||
.map(|p| p.first_str() == util::YT_MUSIC_NAME)
|
|
||||||
.unwrap_or_default();
|
|
||||||
let channel = subtitle_p2.and_then(|p| {
|
|
||||||
p.0.into_iter().find_map(|c| ChannelId::try_from(c).ok())
|
|
||||||
});
|
|
||||||
let track_count = subtitle_p3
|
|
||||||
.and_then(|p| util::parse_numeric(p.first_str()).ok());
|
|
||||||
|
|
||||||
self.items.push(MusicItem::Playlist(MusicPlaylistItem {
|
|
||||||
id,
|
|
||||||
name: item.title,
|
|
||||||
thumbnail: item.thumbnail_renderer.into(),
|
|
||||||
channel,
|
|
||||||
track_count,
|
|
||||||
from_ytm,
|
|
||||||
}));
|
|
||||||
Ok(Some(MusicEntityType::Playlist))
|
|
||||||
}
|
|
||||||
PageType::Artist => {
|
|
||||||
let subscriber_count = subtitle_p1.and_then(|p| {
|
|
||||||
util::parse_large_numstr(p.first_str(), self.lang)
|
|
||||||
});
|
|
||||||
|
|
||||||
self.items.push(MusicItem::Artist(ArtistItem {
|
|
||||||
id,
|
|
||||||
name: item.title,
|
|
||||||
avatar: item.thumbnail_renderer.into(),
|
|
||||||
subscriber_count,
|
|
||||||
}));
|
|
||||||
Ok(Some(MusicEntityType::Artist))
|
|
||||||
}
|
|
||||||
PageType::Channel => {
|
|
||||||
Err(format!("channel items unsupported. id: {}", id))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
MusicPageType::Playlist => {
|
||||||
|
let from_ytm = subtitle_p2
|
||||||
|
.as_ref()
|
||||||
|
.map(|p| p.first_str() == util::YT_MUSIC_NAME)
|
||||||
|
.unwrap_or_default();
|
||||||
|
let channel = subtitle_p2.and_then(|p| {
|
||||||
|
p.0.into_iter().find_map(|c| ChannelId::try_from(c).ok())
|
||||||
|
});
|
||||||
|
let track_count =
|
||||||
|
subtitle_p3.and_then(|p| util::parse_numeric(p.first_str()).ok());
|
||||||
|
|
||||||
|
self.items.push(MusicItem::Playlist(MusicPlaylistItem {
|
||||||
|
id,
|
||||||
|
name: item.title,
|
||||||
|
thumbnail: item.thumbnail_renderer.into(),
|
||||||
|
channel,
|
||||||
|
track_count,
|
||||||
|
from_ytm,
|
||||||
|
}));
|
||||||
|
Ok(Some(MusicEntityType::Playlist))
|
||||||
|
}
|
||||||
|
MusicPageType::None => Ok(None),
|
||||||
|
},
|
||||||
|
None => Err("could not determine item type".to_owned()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ pub(crate) struct NavigationEndpoint {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub(crate) struct WatchEndpoint {
|
pub(crate) struct WatchEndpoint {
|
||||||
pub video_id: String,
|
pub video_id: String,
|
||||||
|
pub playlist_id: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub start_time_seconds: u32,
|
pub start_time_seconds: u32,
|
||||||
}
|
}
|
||||||
|
|
@ -146,17 +147,51 @@ impl PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub(crate) enum MusicPageType {
|
||||||
|
Artist,
|
||||||
|
Album,
|
||||||
|
Playlist,
|
||||||
|
Track,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PageType> for MusicPageType {
|
||||||
|
fn from(t: PageType) -> Self {
|
||||||
|
match t {
|
||||||
|
PageType::Artist => MusicPageType::Artist,
|
||||||
|
PageType::Album => MusicPageType::Album,
|
||||||
|
PageType::Playlist => MusicPageType::Playlist,
|
||||||
|
PageType::Channel => MusicPageType::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NavigationEndpoint {
|
impl NavigationEndpoint {
|
||||||
pub(crate) fn music_page(self) -> Option<(PageType, String)> {
|
pub(crate) fn music_page(self) -> Option<(MusicPageType, String)> {
|
||||||
match self.browse_endpoint {
|
match self.browse_endpoint {
|
||||||
Some(browse) => match browse.browse_endpoint_context_supported_configs {
|
Some(browse) => match browse.browse_endpoint_context_supported_configs {
|
||||||
Some(config) => Some((
|
Some(config) => Some((
|
||||||
config.browse_endpoint_context_music_config.page_type,
|
config.browse_endpoint_context_music_config.page_type.into(),
|
||||||
browse.browse_id,
|
browse.browse_id,
|
||||||
)),
|
)),
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
|
.or_else(|| {
|
||||||
|
self.watch_endpoint.map(|watch| {
|
||||||
|
if watch
|
||||||
|
.playlist_id
|
||||||
|
.map(|plid| plid.starts_with("RDQM"))
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
// Genre radios (e.g. "pop radio") will be skipped
|
||||||
|
(MusicPageType::None, watch.video_id)
|
||||||
|
} else {
|
||||||
|
(MusicPageType::Track, watch.video_id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1700,12 +1700,14 @@ async fn music_search_artists() {
|
||||||
let rp = RustyPipe::builder().strict().build();
|
let rp = RustyPipe::builder().strict().build();
|
||||||
let res = rp.query().music_search_artists("namika").await.unwrap();
|
let res = rp.query().music_search_artists("namika").await.unwrap();
|
||||||
|
|
||||||
let artist = res
|
let (i, artist) = res
|
||||||
.items
|
.items
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.find(|a| a.id == "UCIh4j8fXWf2U0ro0qnGU8Mg")
|
.enumerate()
|
||||||
|
.find(|(_, a)| a.id == "UCIh4j8fXWf2U0ro0qnGU8Mg")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
assert!(i < 3);
|
||||||
assert_eq!(artist.name, "Namika");
|
assert_eq!(artist.name, "Namika");
|
||||||
assert!(!artist.avatar.is_empty(), "got no avatar");
|
assert!(!artist.avatar.is_empty(), "got no avatar");
|
||||||
assert!(
|
assert!(
|
||||||
|
|
@ -1741,9 +1743,15 @@ async fn music_search_playlists(#[case] with_community: bool) {
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(res.corrected_query, None);
|
assert_eq!(res.corrected_query, None);
|
||||||
let playlist = &res.items.items[0];
|
let (i, playlist) = res
|
||||||
|
.items
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, p)| p.id == "RDCLAK5uy_kFQXdnqMaQCVx2wpUM4ZfbsGCDibZtkJk")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(playlist.id, "RDCLAK5uy_kFQXdnqMaQCVx2wpUM4ZfbsGCDibZtkJk");
|
assert!(i < 3);
|
||||||
assert_eq!(playlist.name, "Easy Pop");
|
assert_eq!(playlist.name, "Easy Pop");
|
||||||
assert!(!playlist.thumbnail.is_empty(), "got no thumbnail");
|
assert!(!playlist.thumbnail.is_empty(), "got no thumbnail");
|
||||||
assert_gte(playlist.track_count.unwrap(), 80, "tracks");
|
assert_gte(playlist.track_count.unwrap(), 80, "tracks");
|
||||||
|
|
@ -1761,9 +1769,15 @@ async fn music_search_playlists_community() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(res.corrected_query, None);
|
assert_eq!(res.corrected_query, None);
|
||||||
let playlist = &res.items.items[0];
|
let (i, playlist) = res
|
||||||
|
.items
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, p)| p.id == "PLMC9KNkIncKtGvr2kFRuXBVmBev6cAJ2u")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(playlist.id, "PLMC9KNkIncKtGvr2kFRuXBVmBev6cAJ2u");
|
assert!(i < 3);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
playlist.name,
|
playlist.name,
|
||||||
"Best Pop Music Videos - Top Pop Hits Playlist"
|
"Best Pop Music Videos - Top Pop Hits Playlist"
|
||||||
|
|
|
||||||
Reference in a new issue