tests: run tests with different lang settings

fix: parsing subscriber count on channel search itms
fix: add warnings for all date and numstr parsing
fix: error parsing search suggestions
This commit is contained in:
ThetaDev 2023-05-04 21:44:10 +02:00
parent 6a99540ef5
commit b88faa9d05
32 changed files with 6501 additions and 214 deletions

View file

@ -179,8 +179,11 @@ impl MapResponse<Channel<Paginator<VideoItem>>> for response::Channel {
lang, lang,
)?; )?;
let mut mapper = let mut mapper = response::YouTubeListMapper::<VideoItem>::with_channel(
response::YouTubeListMapper::<VideoItem>::with_channel(lang, &channel_data); lang,
&channel_data.c,
channel_data.warnings,
);
mapper.map_response(content.content); mapper.map_response(content.content);
let p = Paginator::new_ext( let p = Paginator::new_ext(
None, None,
@ -191,7 +194,7 @@ impl MapResponse<Channel<Paginator<VideoItem>>> for response::Channel {
); );
Ok(MapResult { Ok(MapResult {
c: combine_channel_data(channel_data, p), c: combine_channel_data(channel_data.c, p),
warnings: mapper.warnings, warnings: mapper.warnings,
}) })
} }
@ -219,13 +222,16 @@ impl MapResponse<Channel<Paginator<PlaylistItem>>> for response::Channel {
lang, lang,
)?; )?;
let mut mapper = let mut mapper = response::YouTubeListMapper::<PlaylistItem>::with_channel(
response::YouTubeListMapper::<PlaylistItem>::with_channel(lang, &channel_data); lang,
&channel_data.c,
channel_data.warnings,
);
mapper.map_response(content.content); mapper.map_response(content.content);
let p = Paginator::new(None, mapper.items, mapper.ctoken); let p = Paginator::new(None, mapper.items, mapper.ctoken);
Ok(MapResult { Ok(MapResult {
c: combine_channel_data(channel_data, p), c: combine_channel_data(channel_data.c, p),
warnings: mapper.warnings, warnings: mapper.warnings,
}) })
} }
@ -266,7 +272,7 @@ impl MapResponse<Channel<ChannelInfo>> for response::Channel {
}); });
Ok(MapResult { Ok(MapResult {
c: combine_channel_data(channel_data, cinfo), c: combine_channel_data(channel_data.c, cinfo),
warnings, warnings,
}) })
} }
@ -297,7 +303,7 @@ fn map_channel(
d: MapChannelData, d: MapChannelData,
id: &str, id: &str,
lang: Language, lang: Language,
) -> Result<Channel<()>, ExtractionError> { ) -> Result<MapResult<Channel<()>>, ExtractionError> {
let header = d let header = d
.header .header
.ok_or(ExtractionError::ContentUnavailable(Cow::Borrowed( .ok_or(ExtractionError::ContentUnavailable(Cow::Borrowed(
@ -326,33 +332,35 @@ fn map_channel(
.vanity_channel_url .vanity_channel_url
.as_ref() .as_ref()
.and_then(|url| map_vanity_url(url, id)); .and_then(|url| map_vanity_url(url, id));
let mut warnings = Vec::new();
Ok(match header { Ok(MapResult {
response::channel::Header::C4TabbedHeaderRenderer(header) => Channel { c: match header {
id: metadata.external_id, response::channel::Header::C4TabbedHeaderRenderer(header) => Channel {
name: metadata.title, id: metadata.external_id,
subscriber_count: header name: metadata.title,
.subscriber_count_text subscriber_count: header
.and_then(|txt| util::parse_large_numstr(&txt, lang)), .subscriber_count_text
avatar: header.avatar.into(), .and_then(|txt| util::parse_large_numstr_or_warn(&txt, lang, &mut warnings)),
verification: header.badges.into(), avatar: header.avatar.into(),
description: metadata.description, verification: header.badges.into(),
tags: microformat.microformat_data_renderer.tags, description: metadata.description,
vanity_url, tags: microformat.microformat_data_renderer.tags,
banner: header.banner.into(), vanity_url,
mobile_banner: header.mobile_banner.into(), banner: header.banner.into(),
tv_banner: header.tv_banner.into(), mobile_banner: header.mobile_banner.into(),
has_shorts: d.has_shorts, tv_banner: header.tv_banner.into(),
has_live: d.has_live, has_shorts: d.has_shorts,
visitor_data: d.visitor_data, has_live: d.has_live,
content: (), visitor_data: d.visitor_data,
}, content: (),
response::channel::Header::CarouselHeaderRenderer(carousel) => { },
let hdata = carousel response::channel::Header::CarouselHeaderRenderer(carousel) => {
.contents let hdata = carousel
.into_iter() .contents
.filter_map(|item| { .into_iter()
match item { .filter_map(|item| {
match item {
response::channel::CarouselHeaderRendererItem::TopicChannelDetailsRenderer { response::channel::CarouselHeaderRendererItem::TopicChannelDetailsRenderer {
subscriber_count_text, subscriber_count_text,
subtitle, subtitle,
@ -360,32 +368,33 @@ fn map_channel(
} => Some((subscriber_count_text.or(subtitle), avatar)), } => Some((subscriber_count_text.or(subtitle), avatar)),
response::channel::CarouselHeaderRendererItem::None => None, response::channel::CarouselHeaderRendererItem::None => None,
} }
}) })
.next(); .next();
Channel { Channel {
id: metadata.external_id, id: metadata.external_id,
name: metadata.title, name: metadata.title,
subscriber_count: hdata.as_ref().and_then(|hdata| { subscriber_count: hdata.as_ref().and_then(|hdata| {
hdata hdata.0.as_ref().and_then(|txt| {
.0 util::parse_large_numstr_or_warn(txt, lang, &mut warnings)
.as_ref() })
.and_then(|txt| util::parse_large_numstr(txt, lang)) }),
}), avatar: hdata.map(|hdata| hdata.1.into()).unwrap_or_default(),
avatar: hdata.map(|hdata| hdata.1.into()).unwrap_or_default(), verification: crate::model::Verification::Verified,
verification: crate::model::Verification::Verified, description: metadata.description,
description: metadata.description, tags: microformat.microformat_data_renderer.tags,
tags: microformat.microformat_data_renderer.tags, vanity_url,
vanity_url, banner: Vec::new(),
banner: Vec::new(), mobile_banner: Vec::new(),
mobile_banner: Vec::new(), tv_banner: Vec::new(),
tv_banner: Vec::new(), has_shorts: d.has_shorts,
has_shorts: d.has_shorts, has_live: d.has_live,
has_live: d.has_live, visitor_data: d.visitor_data,
visitor_data: d.visitor_data, content: (),
content: (), }
} }
} },
warnings,
}) })
} }

View file

@ -269,7 +269,7 @@ fn map_artist_page(
} }
} }
let mapped = mapper.group_items(); let mut mapped = mapper.group_items();
static WIKIPEDIA_REGEX: Lazy<Regex> = static WIKIPEDIA_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"\(?https://[a-z\d-]+\.wikipedia.org/wiki/[^\s]+").unwrap()); Lazy::new(|| Regex::new(r"\(?https://[a-z\d-]+\.wikipedia.org/wiki/[^\s]+").unwrap());
@ -302,9 +302,10 @@ fn map_artist_page(
description: header.description, description: header.description,
wikipedia_url, wikipedia_url,
subscriber_count: header.subscription_button.and_then(|btn| { subscriber_count: header.subscription_button.and_then(|btn| {
util::parse_large_numstr( util::parse_large_numstr_or_warn(
&btn.subscribe_button_renderer.subscriber_count_text, &btn.subscribe_button_renderer.subscriber_count_text,
lang, lang,
&mut mapped.warnings,
) )
}), }),
tracks: mapped.c.tracks, tracks: mapped.c.tracks,

View file

@ -207,22 +207,25 @@ impl MapResponse<TrackDetails> for response::MusicDetails {
response::music_item::PlaylistPanelVideo::None => None, response::music_item::PlaylistPanelVideo::None => None,
}) })
.ok_or(ExtractionError::InvalidData(Cow::Borrowed("no video item")))?; .ok_or(ExtractionError::InvalidData(Cow::Borrowed("no video item")))?;
let track = map_queue_item(track_item, lang); let mut track = map_queue_item(track_item, lang);
if track.id != id { if track.c.id != id {
return Err(ExtractionError::WrongResult(format!( return Err(ExtractionError::WrongResult(format!(
"got wrong video id {}, expected {}", "got wrong video id {}, expected {}",
track.id, id track.c.id, id
))); )));
} }
let mut warnings = content.contents.warnings;
warnings.append(&mut track.warnings);
Ok(MapResult { Ok(MapResult {
c: TrackDetails { c: TrackDetails {
track, track: track.c,
lyrics_id, lyrics_id,
related_id, related_id,
}, },
warnings: content.contents.warnings, warnings,
}) })
} }
} }
@ -251,13 +254,17 @@ impl MapResponse<Paginator<TrackItem>> for response::MusicDetails {
.content .content
.playlist_panel_renderer; .playlist_panel_renderer;
let mut warnings = content.contents.warnings;
let tracks = content let tracks = content
.contents .contents
.c .c
.into_iter() .into_iter()
.filter_map(|item| match item { .filter_map(|item| match item {
response::music_item::PlaylistPanelVideo::PlaylistPanelVideoRenderer(item) => { response::music_item::PlaylistPanelVideo::PlaylistPanelVideoRenderer(item) => {
Some(map_queue_item(item, lang)) let mut track = map_queue_item(item, lang);
warnings.append(&mut track.warnings);
Some(track.c)
} }
response::music_item::PlaylistPanelVideo::None => None, response::music_item::PlaylistPanelVideo::None => None,
}) })
@ -277,7 +284,7 @@ impl MapResponse<Paginator<TrackItem>> for response::MusicDetails {
None, None,
crate::model::paginator::ContinuationEndpoint::MusicNext, crate::model::paginator::ContinuationEndpoint::MusicNext,
), ),
warnings: content.contents.warnings, warnings,
}) })
} }
} }

View file

@ -157,7 +157,9 @@ impl MapResponse<Paginator<MusicItem>> for response::MusicContinuation {
mapper.add_warnings(&mut panel.contents.warnings); mapper.add_warnings(&mut panel.contents.warnings);
panel.contents.c.into_iter().for_each(|item| { panel.contents.c.into_iter().for_each(|item| {
if let PlaylistPanelVideo::PlaylistPanelVideoRenderer(item) = item { if let PlaylistPanelVideo::PlaylistPanelVideoRenderer(item) = item {
mapper.add_item(MusicItem::Track(map_queue_item(item, lang))) let mut track = map_queue_item(item, lang);
mapper.add_item(MusicItem::Track(track.c));
mapper.add_warnings(&mut track.warnings);
} }
}); });
} }

View file

@ -618,7 +618,11 @@ impl MusicListMapper {
(FlexColumnDisplayStyle::TwoLines, true) => ( (FlexColumnDisplayStyle::TwoLines, true) => (
None, None,
album_p.and_then(|p| { album_p.and_then(|p| {
util::parse_large_numstr(p.first_str(), self.lang) util::parse_large_numstr_or_warn(
p.first_str(),
self.lang,
&mut self.warnings,
)
}), }),
), ),
(_, false) => ( (_, false) => (
@ -692,7 +696,11 @@ impl MusicListMapper {
match page_type { match page_type {
MusicPageType::Artist => { MusicPageType::Artist => {
let subscriber_count = subtitle_p2.and_then(|p| { let subscriber_count = subtitle_p2.and_then(|p| {
util::parse_large_numstr(p.first_str(), self.lang) util::parse_large_numstr_or_warn(
p.first_str(),
self.lang,
&mut self.warnings,
)
}); });
self.items.push(MusicItem::Artist(ArtistItem { self.items.push(MusicItem::Artist(ArtistItem {
@ -792,7 +800,11 @@ impl MusicListMapper {
artists, artists,
album: None, album: None,
view_count: subtitle_p2.and_then(|c| { view_count: subtitle_p2.and_then(|c| {
util::parse_large_numstr(c.first_str(), self.lang) util::parse_large_numstr_or_warn(
c.first_str(),
self.lang,
&mut self.warnings,
)
}), }),
is_video, is_video,
track_nr: None, track_nr: None,
@ -801,8 +813,13 @@ impl MusicListMapper {
Ok(Some(MusicItemType::Track)) Ok(Some(MusicItemType::Track))
} }
MusicPageType::Artist => { MusicPageType::Artist => {
let subscriber_count = subtitle_p1 let subscriber_count = subtitle_p1.and_then(|p| {
.and_then(|p| util::parse_large_numstr(p.first_str(), self.lang)); util::parse_large_numstr_or_warn(
p.first_str(),
self.lang,
&mut self.warnings,
)
});
self.items.push(MusicItem::Artist(ArtistItem { self.items.push(MusicItem::Artist(ArtistItem {
id, id,
@ -927,8 +944,13 @@ impl MusicListMapper {
let item_type = match card.on_tap.music_page() { let item_type = match card.on_tap.music_page() {
Some((page_type, id)) => match page_type { Some((page_type, id)) => match page_type {
MusicPageType::Artist => { MusicPageType::Artist => {
let subscriber_count = subtitle_p2 let subscriber_count = subtitle_p2.and_then(|p| {
.and_then(|p| util::parse_large_numstr(p.first_str(), self.lang)); util::parse_large_numstr_or_warn(
p.first_str(),
self.lang,
&mut self.warnings,
)
});
self.items.push(MusicItem::Artist(ArtistItem { self.items.push(MusicItem::Artist(ArtistItem {
id, id,
@ -963,8 +985,13 @@ impl MusicListMapper {
let (album, view_count) = if is_video { let (album, view_count) = if is_video {
( (
None, None,
subtitle_p3 subtitle_p3.and_then(|p| {
.and_then(|p| util::parse_large_numstr(p.first_str(), self.lang)), util::parse_large_numstr_or_warn(
p.first_str(),
self.lang,
&mut self.warnings,
)
}),
) )
} else { } else {
( (
@ -1149,7 +1176,8 @@ pub(crate) fn map_album_type(txt: &str, lang: Language) -> AlbumType {
.unwrap_or_default() .unwrap_or_default()
} }
pub(crate) fn map_queue_item(item: QueueMusicItem, lang: Language) -> TrackItem { pub(crate) fn map_queue_item(item: QueueMusicItem, lang: Language) -> MapResult<TrackItem> {
let mut warnings = Vec::new();
let mut subtitle_parts = item.long_byline_text.split(util::DOT_SEPARATOR).into_iter(); let mut subtitle_parts = item.long_byline_text.split(util::DOT_SEPARATOR).into_iter();
let is_video = !item let is_video = !item
@ -1167,7 +1195,8 @@ pub(crate) fn map_queue_item(item: QueueMusicItem, lang: Language) -> TrackItem
let (album, view_count) = if is_video { let (album, view_count) = if is_video {
( (
None, None,
subtitle_p2.and_then(|p| util::parse_large_numstr(p.first_str(), lang)), subtitle_p2
.and_then(|p| util::parse_large_numstr_or_warn(p.first_str(), lang, &mut warnings)),
) )
} else { } else {
( (
@ -1176,20 +1205,23 @@ pub(crate) fn map_queue_item(item: QueueMusicItem, lang: Language) -> TrackItem
) )
}; };
TrackItem { MapResult {
id: item.video_id, c: TrackItem {
name: item.title, id: item.video_id,
duration: item name: item.title,
.length_text duration: item
.and_then(|txt| util::parse_video_length(&txt)), .length_text
cover: item.thumbnail.into(), .and_then(|txt| util::parse_video_length(&txt)),
artists, cover: item.thumbnail.into(),
artist_id, artists,
album, artist_id,
view_count, album,
is_video, view_count,
track_nr: None, is_video,
by_va, track_nr: None,
by_va,
},
warnings,
} }
} }

View file

@ -1,4 +1,7 @@
use serde::{de::IgnoredAny, Deserialize}; use serde::{
de::{IgnoredAny, Visitor},
Deserialize,
};
use serde_with::{json::JsonString, serde_as}; use serde_with::{json::JsonString, serde_as};
use super::{video_item::YouTubeListRendererWrap, ResponseContext}; use super::{video_item::YouTubeListRendererWrap, ResponseContext};
@ -26,8 +29,40 @@ pub(crate) struct TwoColumnSearchResultsRenderer {
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub(crate) struct SearchSuggestion( pub(crate) struct SearchSuggestion(IgnoredAny, pub Vec<SearchSuggestionItem>, IgnoredAny);
IgnoredAny,
pub Vec<(String, IgnoredAny, IgnoredAny)>, #[derive(Debug)]
IgnoredAny, pub(crate) struct SearchSuggestionItem(pub String);
);
impl<'de> Deserialize<'de> for SearchSuggestionItem {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ItemVisitor;
impl<'de> Visitor<'de> for ItemVisitor {
type Value = SearchSuggestionItem;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("search suggestion item")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
match seq.next_element::<String>()? {
Some(s) => {
// Ignore the rest of the list
while seq.next_element::<IgnoredAny>()?.is_some() {}
Ok(SearchSuggestionItem(s))
}
None => Err(serde::de::Error::invalid_length(0, &"1")),
}
}
}
deserializer.deserialize_seq(ItemVisitor)
}
}

View file

@ -536,6 +536,8 @@ pub(crate) struct CommentRenderer {
pub author_comment_badge: Option<AuthorCommentBadge>, pub author_comment_badge: Option<AuthorCommentBadge>,
#[serde(default)] #[serde(default)]
pub reply_count: u64, pub reply_count: u64,
#[serde_as(as = "Option<Text>")]
pub vote_count: Option<String>,
/// Buttons for comment interaction (Like/Dislike/Reply) /// Buttons for comment interaction (Like/Dislike/Reply)
pub action_buttons: CommentActionButtons, pub action_buttons: CommentActionButtons,
} }
@ -581,7 +583,6 @@ pub(crate) struct CommentActionButtons {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub(crate) struct CommentActionButtonsRenderer { pub(crate) struct CommentActionButtonsRenderer {
pub like_button: ToggleButtonWrap,
pub creator_heart: Option<CreatorHeart>, pub creator_heart: Option<CreatorHeart>,
} }

View file

@ -415,7 +415,7 @@ impl<T> YouTubeListMapper<T> {
} }
} }
pub fn with_channel<C>(lang: Language, channel: &Channel<C>) -> Self { pub fn with_channel<C>(lang: Language, channel: &Channel<C>, warnings: Vec<String>) -> Self {
Self { Self {
lang, lang,
channel: Some(ChannelTag { channel: Some(ChannelTag {
@ -426,7 +426,7 @@ impl<T> YouTubeListMapper<T> {
subscriber_count: channel.subscriber_count, subscriber_count: channel.subscriber_count,
}), }),
items: Vec::new(), items: Vec::new(),
warnings: Vec::new(), warnings,
ctoken: None, ctoken: None,
corrected_query: None, corrected_query: None,
channel_info: None, channel_info: None,
@ -572,10 +572,12 @@ impl<T> YouTubeListMapper<T> {
name: channel.title, name: channel.title,
avatar: channel.thumbnail.into(), avatar: channel.thumbnail.into(),
verification: channel.owner_badges.into(), verification: channel.owner_badges.into(),
subscriber_count: sc_txt subscriber_count: sc_txt.and_then(|txt| {
.and_then(|txt| util::parse_numeric_or_warn(&txt, &mut self.warnings)), util::parse_large_numstr_or_warn(&txt, self.lang, &mut self.warnings)
video_count: vc_text }),
.and_then(|txt| util::parse_numeric_or_warn(&txt, &mut self.warnings)), video_count: vc_text.and_then(|txt| {
util::parse_large_numstr_or_warn(&txt, self.lang, &mut self.warnings)
}),
short_description: channel.description_snippet, short_description: channel.description_snippet,
} }
} }

View file

@ -22,7 +22,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(582), subscriber_count: Some(582000),
video_count: None, video_count: None,
short_description: "Music Submissions: https://monstafluff.edmdistrict.com/", short_description: "Music Submissions: https://monstafluff.edmdistrict.com/",
)), )),
@ -42,7 +42,7 @@ SearchResult(
), ),
], ],
verification: Artist, verification: Artist,
subscriber_count: Some(403), subscriber_count: Some(4030000),
video_count: None, video_count: None,
short_description: "Welcome to the official Music Travel Love YouTube channel! We travel the world making music, friends, videos and memories!", short_description: "Welcome to the official Music Travel Love YouTube channel! We travel the world making music, friends, videos and memories!",
)), )),
@ -62,7 +62,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(167), subscriber_count: Some(167000),
video_count: None, video_count: None,
short_description: "MUSIC IN HARMONY WITH YOUR LIFE!!! If any producer, label, artist or photographer has an issue with any of the music or\u{a0}...", short_description: "MUSIC IN HARMONY WITH YOUR LIFE!!! If any producer, label, artist or photographer has an issue with any of the music or\u{a0}...",
)), )),
@ -82,7 +82,7 @@ SearchResult(
), ),
], ],
verification: Artist, verification: Artist,
subscriber_count: Some(411), subscriber_count: Some(411000),
video_count: None, video_count: None,
short_description: "The official YouTube channel of HAEVN Music. Receiving a piano from his grandfather had a great impact on Jorrit\'s life.", short_description: "The official YouTube channel of HAEVN Music. Receiving a piano from his grandfather had a great impact on Jorrit\'s life.",
)), )),
@ -102,7 +102,7 @@ SearchResult(
), ),
], ],
verification: None, verification: None,
subscriber_count: Some(312), subscriber_count: Some(31200),
video_count: None, video_count: None,
short_description: "Hello and welcome to \"Artemis Music\"! Music can play an effective role in helping us lead a better and more productive life.", short_description: "Hello and welcome to \"Artemis Music\"! Music can play an effective role in helping us lead a better and more productive life.",
)), )),
@ -122,7 +122,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(372), subscriber_count: Some(372000),
video_count: None, video_count: None,
short_description: "Music is the only language in which you cannot say a mean or sarcastic thing. Have fun listening to music.", short_description: "Music is the only language in which you cannot say a mean or sarcastic thing. Have fun listening to music.",
)), )),
@ -142,7 +142,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(178), subscriber_count: Some(178000),
video_count: None, video_count: None,
short_description: "S!X - Music is an independent Hip-Hop label. Soundcloud : https://soundcloud.com/s1xmusic Facebook\u{a0}...", short_description: "S!X - Music is an independent Hip-Hop label. Soundcloud : https://soundcloud.com/s1xmusic Facebook\u{a0}...",
)), )),
@ -162,7 +162,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(104), subscriber_count: Some(1040000),
video_count: None, video_count: None,
short_description: "Welcome to Shake Music, a Trap & Bass Channel / Record Label dedicated to bringing you the best tracks. All tracks on Shake\u{a0}...", short_description: "Welcome to Shake Music, a Trap & Bass Channel / Record Label dedicated to bringing you the best tracks. All tracks on Shake\u{a0}...",
)), )),
@ -182,7 +182,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(822), subscriber_count: Some(822000),
video_count: None, video_count: None,
short_description: "Welcome to Miracle Music! On this channel you will find a wide variety of different Deep House, Tropical House, Chill Out, EDM,.", short_description: "Welcome to Miracle Music! On this channel you will find a wide variety of different Deep House, Tropical House, Chill Out, EDM,.",
)), )),
@ -202,7 +202,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(462), subscriber_count: Some(4620000),
video_count: None, video_count: None,
short_description: "", short_description: "",
)), )),
@ -222,7 +222,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(105), subscriber_count: Some(1050000),
video_count: None, video_count: None,
short_description: "BRINGING YOU ONLY THE BEST EDM - TRAP Submit your own track for promotion here:\u{a0}...", short_description: "BRINGING YOU ONLY THE BEST EDM - TRAP Submit your own track for promotion here:\u{a0}...",
)), )),
@ -242,7 +242,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(709), subscriber_count: Some(709000),
video_count: None, video_count: None,
short_description: "Hey there! I am Mr MoMo My channel focus on Japan music, lofi, trap & bass type beat and Japanese instrumental. I mindfully\u{a0}...", short_description: "Hey there! I am Mr MoMo My channel focus on Japan music, lofi, trap & bass type beat and Japanese instrumental. I mindfully\u{a0}...",
)), )),
@ -262,7 +262,7 @@ SearchResult(
), ),
], ],
verification: None, verification: None,
subscriber_count: Some(544), subscriber_count: Some(54400),
video_count: None, video_count: None,
short_description: "", short_description: "",
)), )),
@ -282,7 +282,7 @@ SearchResult(
), ),
], ],
verification: None, verification: None,
subscriber_count: Some(359), subscriber_count: Some(3590),
video_count: None, video_count: None,
short_description: "Welcome to our Energy Transformation Relaxing Music . This chakra music channel will focus on developing the best chakra\u{a0}...", short_description: "Welcome to our Energy Transformation Relaxing Music . This chakra music channel will focus on developing the best chakra\u{a0}...",
)), )),
@ -302,7 +302,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(416), subscriber_count: Some(416000),
video_count: None, video_count: None,
short_description: "Nonstop Music - Home of 1h videos of your favourite songs and mixes. Nonstop Genres: Pop • Chillout • Tropical House • Deep\u{a0}...", short_description: "Nonstop Music - Home of 1h videos of your favourite songs and mixes. Nonstop Genres: Pop • Chillout • Tropical House • Deep\u{a0}...",
)), )),
@ -322,7 +322,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(3), subscriber_count: Some(3000000),
video_count: None, video_count: None,
short_description: "Vibe Music strives to bring the best lyric videos of popular Rap & Hip Hop songs. Be sure to Subscribe to see new videos we\u{a0}...", short_description: "Vibe Music strives to bring the best lyric videos of popular Rap & Hip Hop songs. Be sure to Subscribe to see new videos we\u{a0}...",
)), )),
@ -342,7 +342,7 @@ SearchResult(
), ),
], ],
verification: None, verification: None,
subscriber_count: Some(120), subscriber_count: Some(120000),
video_count: None, video_count: None,
short_description: "", short_description: "",
)), )),
@ -362,7 +362,7 @@ SearchResult(
), ),
], ],
verification: None, verification: None,
subscriber_count: Some(817), subscriber_count: Some(81700),
video_count: None, video_count: None,
short_description: "", short_description: "",
)), )),
@ -382,7 +382,7 @@ SearchResult(
), ),
], ],
verification: None, verification: None,
subscriber_count: Some(53), subscriber_count: Some(53000),
video_count: None, video_count: None,
short_description: "Welcome to my channel - Helios Music. I created this channel to help people have the most relaxing, refreshing and comfortable\u{a0}...", short_description: "Welcome to my channel - Helios Music. I created this channel to help people have the most relaxing, refreshing and comfortable\u{a0}...",
)), )),
@ -402,7 +402,7 @@ SearchResult(
), ),
], ],
verification: None, verification: None,
subscriber_count: Some(129), subscriber_count: Some(129000),
video_count: None, video_count: None,
short_description: "Music On (UNOFFICIAL CHANNEL)", short_description: "Music On (UNOFFICIAL CHANNEL)",
)), )),

View file

@ -22,7 +22,7 @@ SearchResult(
), ),
], ],
verification: Verified, verification: Verified,
subscriber_count: Some(292), subscriber_count: Some(2920000),
video_count: Some(219), video_count: Some(219),
short_description: "Hi, I\'m Tina, aka Doobydobap! Food is the medium I use to tell stories and connect with people who share the same passion as I\u{a0}...", short_description: "Hi, I\'m Tina, aka Doobydobap! Food is the medium I use to tell stories and connect with people who share the same passion as I\u{a0}...",
)), )),

View file

@ -191,9 +191,10 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
}; };
let comment_count = comment_count_section.and_then(|s| { let comment_count = comment_count_section.and_then(|s| {
util::parse_large_numstr::<u64>( util::parse_large_numstr_or_warn::<u64>(
&s.comments_entry_point_header_renderer.comment_count, &s.comments_entry_point_header_renderer.comment_count,
lang, lang,
&mut warnings,
) )
}); });
@ -331,9 +332,9 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
name: channel_name, name: channel_name,
avatar: owner.thumbnail.into(), avatar: owner.thumbnail.into(),
verification: owner.badges.into(), verification: owner.badges.into(),
subscriber_count: owner subscriber_count: owner.subscriber_count_text.and_then(|txt| {
.subscriber_count_text util::parse_large_numstr_or_warn(&txt, lang, &mut warnings)
.and_then(|txt| util::parse_large_numstr(&txt, lang)), }),
}, },
view_count, view_count,
like_count, like_count,
@ -505,16 +506,16 @@ fn map_comment(
}), }),
_ => None, _ => None,
}, },
publish_date: timeago::parse_timeago_to_dt(lang, &c.published_time_text), publish_date: timeago::parse_timeago_dt_or_warn(
publish_date_txt: c.published_time_text, lang,
like_count: util::parse_numeric_or_warn( &c.published_time_text,
&c.action_buttons
.comment_action_buttons_renderer
.like_button
.toggle_button_renderer
.accessibility_data,
&mut warnings, &mut warnings,
), ),
publish_date_txt: c.published_time_text,
like_count: match c.vote_count {
Some(txt) => util::parse_numeric_or_warn(&txt, &mut warnings),
None => Some(0),
},
reply_count: c.reply_count as u32, reply_count: c.reply_count as u32,
replies: replies replies: replies
.map(|items| Paginator::new(Some(c.reply_count), items, reply_ctoken)) .map(|items| Paginator::new(Some(c.reply_count), items, reply_ctoken))

View file

@ -198,7 +198,7 @@ pub fn parse_timeago(lang: Language, textual_date: &str) -> Option<TimeAgo> {
/// Parse a TimeAgo string (e.g. "29 minutes ago") into a Chrono DateTime object. /// Parse a TimeAgo string (e.g. "29 minutes ago") into a Chrono DateTime object.
/// ///
/// Returns None if the date could not be parsed. /// Returns None if the date could not be parsed.
pub fn parse_timeago_to_dt(lang: Language, textual_date: &str) -> Option<OffsetDateTime> { pub fn parse_timeago_dt(lang: Language, textual_date: &str) -> Option<OffsetDateTime> {
parse_timeago(lang, textual_date).map(|ta| ta.into()) parse_timeago(lang, textual_date).map(|ta| ta.into())
} }
@ -219,7 +219,7 @@ pub(crate) fn parse_timeago_dt_or_warn(
textual_date: &str, textual_date: &str,
warnings: &mut Vec<String>, warnings: &mut Vec<String>,
) -> Option<OffsetDateTime> { ) -> Option<OffsetDateTime> {
let res = parse_timeago_to_dt(lang, textual_date); let res = parse_timeago_dt(lang, textual_date);
if res.is_none() { if res.is_none() {
warnings.push(format!("could not parse timeago `{textual_date}`")); warnings.push(format!("could not parse timeago `{textual_date}`"));
} }

View file

@ -5571,17 +5571,19 @@ pub(crate) fn entry(lang: Language) -> Entry {
timeago_tokens: ::phf::Map { timeago_tokens: ::phf::Map {
key: 15467950696543387533, key: 15467950696543387533,
disps: &[ disps: &[
(3, 5), (0, 1),
(0, 0), (2, 0),
], ],
entries: &[ entries: &[
("\u{e34}นาท\u{e35}\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
("\u{e31}นท\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
("นาท\u{e35}\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Minute) }), ("นาท\u{e35}\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
("\u{e31}\u{e48}วโมงท\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
("\u{e31}ปดาห\u{e4c}\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
("\u{e35}\u{e35}\u{e48}แล\u{e49}", TaToken { n: 1, unit: Some(TimeUnit::Year) }), ("\u{e35}\u{e35}\u{e48}แล\u{e49}", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
("เด\u{e37}อนท\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Month) }), ("เด\u{e37}อนท\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
("\u{e31}\u{e48}วโมงท\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
("นาท\u{e35}", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
("\u{e31}นท\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
("\u{e31}ปดาห\u{e4c}\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
("\u{e34}นาท\u{e35}", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
("\u{e34}นาท\u{e35}\u{e35}\u{e48}\u{e48}านมา", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
], ],
}, },
date_order: &[DateCmp::D, DateCmp::Y], date_order: &[DateCmp::D, DateCmp::Y],

View file

@ -328,6 +328,21 @@ where
.ok() .ok()
} }
pub fn parse_large_numstr_or_warn<F>(
string: &str,
lang: Language,
warnings: &mut Vec<String>,
) -> Option<F>
where
F: TryFrom<u64>,
{
let res = parse_large_numstr::<F>(string, lang);
if res.is_none() {
warnings.push(format!("could not parse numstr `{string}`"));
}
res
}
/// Replace all html control characters to make a string safe for inserting into HTML. /// Replace all html control characters to make a string safe for inserting into HTML.
pub fn escape_html(input: &str) -> String { pub fn escape_html(input: &str) -> String {
let mut buf = String::with_capacity(input.len()); let mut buf = String::with_capacity(input.len());

View file

@ -141,7 +141,8 @@
"آلاف": 3, "آلاف": 3,
"ألف": 3, "ألف": 3,
"مليار": 9, "مليار": 9,
"مليون": 6 "مليون": 6,
"واحد": 0
}, },
"album_types": { "album_types": {
"أغنية منفردة": "Single", "أغنية منفردة": "Single",
@ -666,10 +667,7 @@
} }
}, },
"en": { "en": {
"equivalent": [ "equivalent": ["en-GB", "en-IN"],
"en-GB",
"en-IN"
],
"by_char": false, "by_char": false,
"timeago_tokens": { "timeago_tokens": {
"day": "D", "day": "D",
@ -774,9 +772,7 @@
} }
}, },
"es-US": { "es-US": {
"equivalent": [ "equivalent": ["es-419"],
"es-419"
],
"by_char": false, "by_char": false,
"timeago_tokens": { "timeago_tokens": {
"año": "Y", "año": "Y",
@ -1055,9 +1051,7 @@
} }
}, },
"fr": { "fr": {
"equivalent": [ "equivalent": ["fr-CA"],
"fr-CA"
],
"by_char": false, "by_char": false,
"timeago_tokens": { "timeago_tokens": {
"an": "Y", "an": "Y",
@ -3294,7 +3288,9 @@
"วันที่ผ่านมา": "D", "วันที่ผ่านมา": "D",
"วินาทีที่ผ่านมา": "s", "วินาทีที่ผ่านมา": "s",
"สัปดาห์ที่ผ่านมา": "W", "สัปดาห์ที่ผ่านมา": "W",
"เดือนที่ผ่านมา": "M" "เดือนที่ผ่านมา": "M",
"นาที": "m",
"วินาที": "s"
}, },
"date_order": "DY", "date_order": "DY",
"months": { "months": {

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,129 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_u1I69lSAe5v",
playlist_id: Some("OLAK5uy_lGP_zv0vJDUlecQDzugUJmjcF7pvyVNyY"),
name: "Waldbrand",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "[name]",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
description: None,
album_type: Ep,
year: Some(2016),
by_va: false,
tracks: [
TrackItem(
id: "aGd3VKSOTxY",
name: "[name]",
duration: Some(221),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "[name]",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: None,
is_video: false,
track_nr: Some(1),
by_va: false,
),
TrackItem(
id: "Jz-26iiDuYs",
name: "[name]",
duration: Some(208),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "[name]",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: None,
is_video: false,
track_nr: Some(2),
by_va: false,
),
TrackItem(
id: "Bu26uFtpt58",
name: "[name]",
duration: Some(223),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "[name]",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: None,
is_video: false,
track_nr: Some(3),
by_va: false,
),
TrackItem(
id: "RgwNqqiVqdY",
name: "[name]",
duration: Some(221),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "[name]",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: None,
is_video: false,
track_nr: Some(4),
by_va: false,
),
TrackItem(
id: "2TuOh30XbCI",
name: "[name]",
duration: Some(197),
cover: [],
artists: [
ArtistId(
id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
name: "[name]",
),
],
artist_id: Some("UCpJyCbFbdTrx0M90HCNBHFQ"),
album: Some(AlbumId(
id: "MPREb_u1I69lSAe5v",
name: "Waldbrand",
)),
view_count: None,
is_video: false,
track_nr: Some(5),
by_va: false,
),
],
variants: [],
)

View file

@ -0,0 +1,134 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_bqWA6mAZFWS",
playlist_id: Some("OLAK5uy_mUiRbMqeQXFUH6h9KB87RcEmNtm45Qvs0"),
name: "Pedha Rasi Peddamma Katha",
cover: "[cover]",
artists: [],
artist_id: None,
description: None,
album_type: Ep,
year: Some(1968),
by_va: false,
tracks: [
TrackItem(
id: "EX7-pOQHPyE",
name: "[name]",
duration: Some(267),
cover: [],
artists: [
ArtistId(
id: Some("UC1C05NyYICFB2mVGn9_ttEw"),
name: "[name]",
),
],
artist_id: Some("UC1C05NyYICFB2mVGn9_ttEw"),
album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: None,
is_video: false,
track_nr: Some(1),
by_va: false,
),
TrackItem(
id: "0AyWB-Quj4A",
name: "[name]",
duration: Some(179),
cover: [],
artists: [
ArtistId(
id: Some("UCDqpyYkgWy2h03HamIfODjw"),
name: "[name]",
),
],
artist_id: Some("UCDqpyYkgWy2h03HamIfODjw"),
album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: None,
is_video: false,
track_nr: Some(2),
by_va: false,
),
TrackItem(
id: "s0Sb-GZLXSM",
name: "[name]",
duration: Some(155),
cover: [],
artists: [
ArtistId(
id: None,
name: "[name]",
),
],
artist_id: None,
album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: None,
is_video: false,
track_nr: Some(3),
by_va: false,
),
TrackItem(
id: "P4XAaXjlCDA",
name: "[name]",
duration: Some(229),
cover: [],
artists: [
ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
name: "[name]",
),
],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: None,
is_video: false,
track_nr: Some(4),
by_va: false,
),
],
variants: [
AlbumItem(
id: "MPREb_h8ltx5oKvyY",
name: "Pedha Rasi Peddamma Katha",
cover: [
Thumbnail(
url: "https://lh3.googleusercontent.com/iZtBdPWBGNB-GAWvOp9seuYj5QqKrUYGSe-B5J026yxHqFSWv4zsxHy-LxX5LbFlnepOPRWNLrajO-_-=w226-h226-l90-rj",
width: 226,
height: 226,
),
Thumbnail(
url: "https://lh3.googleusercontent.com/iZtBdPWBGNB-GAWvOp9seuYj5QqKrUYGSe-B5J026yxHqFSWv4zsxHy-LxX5LbFlnepOPRWNLrajO-_-=w544-h544-l90-rj",
width: 544,
height: 544,
),
],
artists: [
ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
name: "S P Balasubramaniam",
),
ArtistId(
id: Some("UCWgAqlYG7mXTUxrFiLyDSsg"),
name: "S Janaki",
),
],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
album_type: Ep,
year: None,
by_va: false,
),
],
)

View file

@ -0,0 +1,61 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_F3Af9UZZVxX",
playlist_id: Some("OLAK5uy_nim4i4eycEtlBtS3Ci6j4SvvTmdfBcRX4"),
name: "La Ultima Vez (Remix)",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCAJwa_1l4rHzBJyWbeBtGZw"),
name: "[name]",
),
ArtistId(
id: Some("UCbBaYg2UToDaoOwo-R6xi4g"),
name: "[name]",
),
ArtistId(
id: Some("UCiY3z8HAGD6BlSNKVn2kSvQ"),
name: "[name]",
),
],
artist_id: Some("UCAJwa_1l4rHzBJyWbeBtGZw"),
description: None,
album_type: Single,
year: None,
by_va: false,
tracks: [
TrackItem(
id: "1Sz3lUVGBSM",
name: "[name]",
duration: Some(229),
cover: [],
artists: [
ArtistId(
id: Some("UCAJwa_1l4rHzBJyWbeBtGZw"),
name: "[name]",
),
ArtistId(
id: Some("UCbBaYg2UToDaoOwo-R6xi4g"),
name: "[name]",
),
ArtistId(
id: Some("UCiY3z8HAGD6BlSNKVn2kSvQ"),
name: "[name]",
),
],
artist_id: Some("UCAJwa_1l4rHzBJyWbeBtGZw"),
album: Some(AlbumId(
id: "MPREb_F3Af9UZZVxX",
name: "La Ultima Vez (Remix)",
)),
view_count: None,
is_video: false,
track_nr: Some(1),
by_va: false,
),
],
variants: [],
)

View file

@ -0,0 +1,429 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_nlBWQROfvjo",
playlist_id: Some("OLAK5uy_myZkBX2d2TzcrlQhIwLy3hCj2MkAMaPR4"),
name: "Märchen enden gut",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
description: None,
album_type: Album,
year: Some(2016),
by_va: false,
tracks: [
TrackItem(
id: "g0iRiJ_ck48",
name: "[name]",
duration: Some(216),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(1),
by_va: false,
),
TrackItem(
id: "rREEBXp0y9s",
name: "[name]",
duration: Some(224),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(2),
by_va: false,
),
TrackItem(
id: "zvU5Y8Q19hU",
name: "[name]",
duration: Some(176),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(3),
by_va: false,
),
TrackItem(
id: "ARKLrzzTQA0",
name: "[name]",
duration: Some(215),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(4),
by_va: false,
),
TrackItem(
id: "tstLgN8A_Ng",
name: "[name]",
duration: Some(268),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(5),
by_va: false,
),
TrackItem(
id: "k2DjgQOY3Ts",
name: "[name]",
duration: Some(202),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(6),
by_va: false,
),
TrackItem(
id: "azHwhecxEsI",
name: "[name]",
duration: Some(185),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(7),
by_va: false,
),
TrackItem(
id: "_FcsdYIQ2co",
name: "[name]",
duration: Some(226),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(8),
by_va: false,
),
TrackItem(
id: "27bOWEbshyE",
name: "[name]",
duration: Some(207),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(9),
by_va: false,
),
TrackItem(
id: "riD_3oZwt8w",
name: "[name]",
duration: Some(211),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(10),
by_va: false,
),
TrackItem(
id: "8GNvjF3no9s",
name: "[name]",
duration: Some(179),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(11),
by_va: false,
),
TrackItem(
id: "YHMFzf1uN2U",
name: "[name]",
duration: Some(218),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(12),
by_va: false,
),
TrackItem(
id: "jvV-z5F3oAo",
name: "[name]",
duration: Some(277),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(13),
by_va: false,
),
TrackItem(
id: "u8_9cxlrh8k",
name: "[name]",
duration: Some(204),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(14),
by_va: false,
),
TrackItem(
id: "gSvKcvM1Wk0",
name: "[name]",
duration: Some(202),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(15),
by_va: false,
),
TrackItem(
id: "wQHgKRJ0pDQ",
name: "[name]",
duration: Some(222),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(16),
by_va: false,
),
TrackItem(
id: "Ckz5i6-hzf0",
name: "[name]",
duration: Some(177),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(17),
by_va: false,
),
TrackItem(
id: "y5zuUgyFqrc",
name: "[name]",
duration: Some(220),
cover: [],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "[name]",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album: Some(AlbumId(
id: "MPREb_nlBWQROfvjo",
name: "Märchen enden gut",
)),
view_count: None,
is_video: false,
track_nr: Some(18),
by_va: false,
),
],
variants: [
AlbumItem(
id: "MPREb_jk6Msw8izou",
name: "Märchen enden gut (Nyáre Ranta (Märchenedition))",
cover: [
Thumbnail(
url: "https://lh3.googleusercontent.com/BKgnW_-hapCHk599AtRfTYZGdXVIo0C4bJp1Bh7qUpGK7fNAXGW8Bhv2x-ukeFM8cuxKbGqqGaTo8fZASA=w226-h226-l90-rj",
width: 226,
height: 226,
),
Thumbnail(
url: "https://lh3.googleusercontent.com/BKgnW_-hapCHk599AtRfTYZGdXVIo0C4bJp1Bh7qUpGK7fNAXGW8Bhv2x-ukeFM8cuxKbGqqGaTo8fZASA=w544-h544-l90-rj",
width: 544,
height: 544,
),
],
artists: [
ArtistId(
id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
name: "Oonagh",
),
],
artist_id: Some("UC_vmjW5e1xEHhYjY2a0kK1A"),
album_type: Album,
year: None,
by_va: false,
),
],
)

View file

@ -0,0 +1,318 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_cwzk8EUwypZ",
playlist_id: Some("OLAK5uy_kODvYZ5CEpYdtd4VPsmg0eRTlpazG0dvA"),
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
description: None,
album_type: Show,
year: Some(2022),
by_va: false,
tracks: [
TrackItem(
id: "lSbKz5LWvKE",
name: "[name]",
duration: Some(229),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(1),
by_va: false,
),
TrackItem(
id: "fdO6gu4qjRw",
name: "[name]",
duration: Some(235),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(2),
by_va: false,
),
TrackItem(
id: "muCxstXirvY",
name: "[name]",
duration: Some(197),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(3),
by_va: false,
),
TrackItem(
id: "aG1N0vo__Ng",
name: "[name]",
duration: Some(186),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(4),
by_va: false,
),
TrackItem(
id: "roHhLNYS9yo",
name: "[name]",
duration: Some(188),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(5),
by_va: false,
),
TrackItem(
id: "nJ49NuLvcAw",
name: "[name]",
duration: Some(205),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(6),
by_va: false,
),
TrackItem(
id: "Me119D570h0",
name: "[name]",
duration: Some(219),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(7),
by_va: false,
),
TrackItem(
id: "YXnRLK-qKG8",
name: "[name]",
duration: Some(240),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(8),
by_va: false,
),
TrackItem(
id: "A61wz1jz9X0",
name: "[name]",
duration: Some(239),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(9),
by_va: false,
),
TrackItem(
id: "u_S08EJOTUg",
name: "[name]",
duration: Some(197),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(10),
by_va: false,
),
TrackItem(
id: "0qwYJihV1EU",
name: "[name]",
duration: Some(201),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(11),
by_va: false,
),
TrackItem(
id: "zjhoyTnEzuQ",
name: "[name]",
duration: Some(187),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(12),
by_va: false,
),
TrackItem(
id: "oDjDd0UBzAY",
name: "[name]",
duration: Some(183),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(13),
by_va: false,
),
TrackItem(
id: "_3-WVmqgi-Q",
name: "[name]",
duration: Some(193),
cover: [],
artists: [
ArtistId(
id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
name: "[name]",
),
],
artist_id: Some("UCNoyEM0e2A7WlsBmP2w3avg"),
album: Some(AlbumId(
id: "MPREb_cwzk8EUwypZ",
name: "Folge 2: Eiszeit (Das Original-Hörspiel zur TV-Serie)",
)),
view_count: None,
is_video: false,
track_nr: Some(14),
by_va: false,
),
],
variants: [],
)

View file

@ -0,0 +1,53 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_bHfHGoy7vuv",
playlist_id: Some("OLAK5uy_kdSWBZ-9AZDkYkuy0QCc3p0KO9DEHVNH0"),
name: "Der Himmel reißt auf",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCXGYZ-OhdOpPBamHX3K9YRg"),
name: "[name]",
),
ArtistId(
id: Some("UCFTcSVPYRWlDoHisR-ZKwgw"),
name: "[name]",
),
],
artist_id: Some("UCXGYZ-OhdOpPBamHX3K9YRg"),
description: None,
album_type: Single,
year: Some(2020),
by_va: false,
tracks: [
TrackItem(
id: "VU6lEv0PKAo",
name: "[name]",
duration: Some(183),
cover: [],
artists: [
ArtistId(
id: Some("UCXGYZ-OhdOpPBamHX3K9YRg"),
name: "[name]",
),
ArtistId(
id: Some("UCFTcSVPYRWlDoHisR-ZKwgw"),
name: "[name]",
),
],
artist_id: Some("UCXGYZ-OhdOpPBamHX3K9YRg"),
album: Some(AlbumId(
id: "MPREb_bHfHGoy7vuv",
name: "Der Himmel reißt auf",
)),
view_count: None,
is_video: false,
track_nr: Some(1),
by_va: false,
),
],
variants: [],
)

View file

@ -0,0 +1,271 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_AzuWg8qAVVl",
playlist_id: Some("OLAK5uy_mux5ygfN9sbiR1ma3yh1GHTmqNekZNoAI"),
name: "13 Reasons Why (Season 3)",
cover: "[cover]",
artists: [],
artist_id: None,
description: None,
album_type: Album,
year: Some(2019),
by_va: true,
tracks: [
TrackItem(
id: "R3VIKRtzAdE",
name: "[name]",
duration: Some(205),
cover: [],
artists: [
ArtistId(
id: Some("UCCj0RlDqqahEB5BXVtDcPqg"),
name: "[name]",
),
],
artist_id: Some("UCCj0RlDqqahEB5BXVtDcPqg"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(1),
by_va: false,
),
TrackItem(
id: "t0v0UOgOt18",
name: "[name]",
duration: Some(174),
cover: [],
artists: [
ArtistId(
id: Some("UCMrCoizKiBxqeg5pTpBXn1A"),
name: "[name]",
),
],
artist_id: Some("UCMrCoizKiBxqeg5pTpBXn1A"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(2),
by_va: false,
),
TrackItem(
id: "HjJYAkUXrxI",
name: "[name]",
duration: Some(199),
cover: [],
artists: [
ArtistId(
id: Some("UCWjoDY2SXJ5dvcdunWI6mjQ"),
name: "[name]",
),
],
artist_id: Some("UCWjoDY2SXJ5dvcdunWI6mjQ"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(3),
by_va: false,
),
TrackItem(
id: "Hg0KUOTL06I",
name: "[name]",
duration: Some(187),
cover: [],
artists: [
ArtistId(
id: Some("UChzK2t3sjnQkWzGnyKXOSSg"),
name: "[name]",
),
],
artist_id: Some("UChzK2t3sjnQkWzGnyKXOSSg"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(5),
by_va: false,
),
TrackItem(
id: "c8AfY6yhdkM",
name: "[name]",
duration: Some(159),
cover: [],
artists: [
ArtistId(
id: Some("UCvsgN5NKOzXnAURfaf3TOig"),
name: "[name]",
),
],
artist_id: Some("UCvsgN5NKOzXnAURfaf3TOig"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(6),
by_va: false,
),
TrackItem(
id: "_ZmdHjVvwhc",
name: "[name]",
duration: Some(186),
cover: [],
artists: [
ArtistId(
id: Some("UCI4YNnmHjXFaaKvfdmpWvJQ"),
name: "[name]",
),
],
artist_id: Some("UCI4YNnmHjXFaaKvfdmpWvJQ"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(7),
by_va: false,
),
TrackItem(
id: "wBe1Zi3q1n8",
name: "[name]",
duration: Some(209),
cover: [],
artists: [
ArtistId(
id: Some("UCDaFVUr2n8T7_X1f5yJ1xlw"),
name: "[name]",
),
],
artist_id: Some("UCDaFVUr2n8T7_X1f5yJ1xlw"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(8),
by_va: false,
),
TrackItem(
id: "l8Pj8s9uPGc",
name: "[name]",
duration: Some(209),
cover: [],
artists: [
ArtistId(
id: Some("UCZcc-WkffIMBVGUr6j9e6aQ"),
name: "[name]",
),
],
artist_id: Some("UCZcc-WkffIMBVGUr6j9e6aQ"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(9),
by_va: false,
),
TrackItem(
id: "Kn3cruxYj0c",
name: "[name]",
duration: Some(174),
cover: [],
artists: [
ArtistId(
id: Some("UCQPPz_A65SWYi2wXX8z76AQ"),
name: "[name]",
),
],
artist_id: Some("UCQPPz_A65SWYi2wXX8z76AQ"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(11),
by_va: false,
),
TrackItem(
id: "Sy1lIOl1YN0",
name: "[name]",
duration: Some(185),
cover: [],
artists: [
ArtistId(
id: Some("UChTOXkDhGJ0JftnfMWjpCCg"),
name: "[name]",
),
],
artist_id: Some("UChTOXkDhGJ0JftnfMWjpCCg"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(12),
by_va: false,
),
TrackItem(
id: "njdlNT1RRo4",
name: "[name]",
duration: Some(237),
cover: [],
artists: [
ArtistId(
id: Some("UCMUB52aO4CqrUXmLwbfRWYA"),
name: "[name]",
),
],
artist_id: Some("UCMUB52aO4CqrUXmLwbfRWYA"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(13),
by_va: false,
),
TrackItem(
id: "Si-CXM8CHqQ",
name: "[name]",
duration: Some(246),
cover: [],
artists: [
ArtistId(
id: Some("UC4YvDAbE1EYwZpj6gQ-lpLw"),
name: "[name]",
),
],
artist_id: Some("UC4YvDAbE1EYwZpj6gQ-lpLw"),
album: Some(AlbumId(
id: "MPREb_AzuWg8qAVVl",
name: "13 Reasons Why (Season 3)",
)),
view_count: None,
is_video: false,
track_nr: Some(18),
by_va: false,
),
],
variants: [],
)

View file

@ -0,0 +1,145 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_8QkDeEIawvX",
playlist_id: Some("OLAK5uy_mEX9ljZeeEWgTM1xLL1isyiGaWXoPyoOk"),
name: "Queendom2 FINAL",
cover: "[cover]",
artists: [],
artist_id: None,
description: None,
album_type: Single,
year: Some(2022),
by_va: true,
tracks: [
TrackItem(
id: "Tzai7JXo45w",
name: "[name]",
duration: Some(274),
cover: [],
artists: [
ArtistId(
id: None,
name: "[name]",
),
],
artist_id: None,
album: Some(AlbumId(
id: "MPREb_8QkDeEIawvX",
name: "Queendom2 FINAL",
)),
view_count: None,
is_video: false,
track_nr: Some(1),
by_va: false,
),
TrackItem(
id: "9WYpLYAEub0",
name: "[name]",
duration: Some(216),
cover: [],
artists: [
ArtistId(
id: None,
name: "[name]",
),
],
artist_id: None,
album: Some(AlbumId(
id: "MPREb_8QkDeEIawvX",
name: "Queendom2 FINAL",
)),
view_count: None,
is_video: false,
track_nr: Some(2),
by_va: false,
),
TrackItem(
id: "R48tE237bW4",
name: "[name]",
duration: Some(239),
cover: [],
artists: [
ArtistId(
id: Some("UCAKvDuIX3m1AUdPpDSqV_3w"),
name: "[name]",
),
],
artist_id: Some("UCAKvDuIX3m1AUdPpDSqV_3w"),
album: Some(AlbumId(
id: "MPREb_8QkDeEIawvX",
name: "Queendom2 FINAL",
)),
view_count: None,
is_video: false,
track_nr: Some(3),
by_va: false,
),
TrackItem(
id: "-UzsoR6z-vg",
name: "[name]",
duration: Some(254),
cover: [],
artists: [
ArtistId(
id: None,
name: "[name]",
),
],
artist_id: None,
album: Some(AlbumId(
id: "MPREb_8QkDeEIawvX",
name: "Queendom2 FINAL",
)),
view_count: None,
is_video: false,
track_nr: Some(4),
by_va: false,
),
TrackItem(
id: "kbNVyn8Ex28",
name: "[name]",
duration: Some(187),
cover: [],
artists: [
ArtistId(
id: None,
name: "[name]",
),
],
artist_id: None,
album: Some(AlbumId(
id: "MPREb_8QkDeEIawvX",
name: "Queendom2 FINAL",
)),
view_count: None,
is_video: false,
track_nr: Some(5),
by_va: false,
),
TrackItem(
id: "NJrQZUzWP5Y",
name: "[name]",
duration: Some(224),
cover: [],
artists: [
ArtistId(
id: None,
name: "[name]",
),
],
artist_id: None,
album: Some(AlbumId(
id: "MPREb_8QkDeEIawvX",
name: "Queendom2 FINAL",
)),
view_count: None,
is_video: false,
track_nr: Some(6),
by_va: false,
),
],
variants: [],
)

View file

@ -0,0 +1,138 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_h8ltx5oKvyY",
playlist_id: Some("OLAK5uy_lIDfTi_k8V1RJ54MeJJGK_BduAeYbm-0s"),
name: "Pedha Rasi Peddamma Katha",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
name: "[name]",
),
ArtistId(
id: Some("UCWgAqlYG7mXTUxrFiLyDSsg"),
name: "[name]",
),
],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
description: None,
album_type: Ep,
year: Some(1968),
by_va: false,
tracks: [
TrackItem(
id: "AKJ3IJZKPWc",
name: "[name]",
duration: Some(228),
cover: [],
artists: [
ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
name: "[name]",
),
ArtistId(
id: Some("UCWgAqlYG7mXTUxrFiLyDSsg"),
name: "[name]",
),
],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
album: Some(AlbumId(
id: "MPREb_h8ltx5oKvyY",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: None,
is_video: false,
track_nr: Some(1),
by_va: false,
),
TrackItem(
id: "WnpZuHNB33E",
name: "[name]",
duration: Some(266),
cover: [],
artists: [
ArtistId(
id: Some("UC1C05NyYICFB2mVGn9_ttEw"),
name: "[name]",
),
],
artist_id: Some("UC1C05NyYICFB2mVGn9_ttEw"),
album: Some(AlbumId(
id: "MPREb_h8ltx5oKvyY",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: None,
is_video: false,
track_nr: Some(2),
by_va: false,
),
TrackItem(
id: "pRqoDGXg1-I",
name: "[name]",
duration: Some(154),
cover: [],
artists: [
ArtistId(
id: Some("UC_KQPMiRQl3CFAIKTVfCHwA"),
name: "[name]",
),
],
artist_id: Some("UC_KQPMiRQl3CFAIKTVfCHwA"),
album: Some(AlbumId(
id: "MPREb_h8ltx5oKvyY",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: None,
is_video: false,
track_nr: Some(3),
by_va: false,
),
TrackItem(
id: "20vIKLJxjBY",
name: "[name]",
duration: Some(178),
cover: [],
artists: [
ArtistId(
id: None,
name: "[name]",
),
],
artist_id: Some("UCDqpyYkgWy2h03HamIfODjw"),
album: Some(AlbumId(
id: "MPREb_h8ltx5oKvyY",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: None,
is_video: false,
track_nr: Some(4),
by_va: false,
),
],
variants: [
AlbumItem(
id: "MPREb_bqWA6mAZFWS",
name: "Pedha Rasi Peddamma Katha",
cover: [
Thumbnail(
url: "https://lh3.googleusercontent.com/cyKTDdyucqYv8xfv0t3Vs9CkhmvssXRKsGzlWN_DU6A9uapXvovV0Ys2fXc9-r7Jv7V4UB1OD48iYH5z=w226-h226-l90-rj",
width: 226,
height: 226,
),
Thumbnail(
url: "https://lh3.googleusercontent.com/cyKTDdyucqYv8xfv0t3Vs9CkhmvssXRKsGzlWN_DU6A9uapXvovV0Ys2fXc9-r7Jv7V4UB1OD48iYH5z=w544-h544-l90-rj",
width: 544,
height: 544,
),
],
artists: [],
artist_id: None,
album_type: Ep,
year: None,
by_va: true,
),
],
)

View file

@ -0,0 +1,665 @@
---
source: tests/youtube.rs
expression: artist
---
MusicArtist(
id: "UC7cl4MmM6ZZ2TcFyMk_b4pg",
name: "[name]",
header_image: "[header_image]",
description: "[description]",
wikipedia_url: "[wikipedia_url]",
subscriber_count: "[subscriber_count]",
tracks: "[tracks]",
albums: [
AlbumItem(
id: "MPREb_43NWLzXChnh",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2010),
by_va: false,
),
AlbumItem(
id: "MPREb_585fV7eqUP8",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_6PEkIQE7sWY",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Ep,
year: Some(2008),
by_va: false,
),
AlbumItem(
id: "MPREb_7nIPO6oeETY",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2012),
by_va: false,
),
AlbumItem(
id: "MPREb_88p7e6nBtgz",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2012),
by_va: false,
),
AlbumItem(
id: "MPREb_8rukEzdytkN",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2015),
by_va: false,
),
AlbumItem(
id: "MPREb_BJKvCuKo7nJ",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2015),
by_va: false,
),
AlbumItem(
id: "MPREb_EAiIEvINDHB",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2012),
by_va: false,
),
AlbumItem(
id: "MPREb_HrCgErOdgCv",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2004),
by_va: false,
),
AlbumItem(
id: "MPREb_Md2aZrjaqHX",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2021),
by_va: false,
),
AlbumItem(
id: "MPREb_OW1GOBZ64ap",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2018),
by_va: false,
),
AlbumItem(
id: "MPREb_Oq0WKqNwSVY",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2003),
by_va: false,
),
AlbumItem(
id: "MPREb_QEClJsuO9xM",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2012),
by_va: false,
),
AlbumItem(
id: "MPREb_QyGCcLWExXj",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_R3p5kDRIGKL",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2006),
by_va: false,
),
AlbumItem(
id: "MPREb_T4fJMmrfxXk",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2000),
by_va: false,
),
AlbumItem(
id: "MPREb_TiIBQqCFttT",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2016),
by_va: false,
),
AlbumItem(
id: "MPREb_U9HLD8nF7H5",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2017),
by_va: false,
),
AlbumItem(
id: "MPREb_U9dMPQUeR9q",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2012),
by_va: false,
),
AlbumItem(
id: "MPREb_V0FEmw2pj2u",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2017),
by_va: false,
),
AlbumItem(
id: "MPREb_WYx2c0e95TA",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2008),
by_va: false,
),
AlbumItem(
id: "MPREb_Wc8Ehka0R0T",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2021),
by_va: false,
),
AlbumItem(
id: "MPREb_Yj49s4xy7fM",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2021),
by_va: false,
),
AlbumItem(
id: "MPREb_baIxpKBcYbF",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Ep,
year: Some(2003),
by_va: false,
),
AlbumItem(
id: "MPREb_eiYjUXT1Mn3",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2010),
by_va: false,
),
AlbumItem(
id: "MPREb_f4MhYbccbPi",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2006),
by_va: false,
),
AlbumItem(
id: "MPREb_gHlGAdNjEZI",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2010),
by_va: false,
),
AlbumItem(
id: "MPREb_kW2NAMSZElX",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2015),
by_va: false,
),
AlbumItem(
id: "MPREb_m5U1xZasDSy",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2002),
by_va: false,
),
AlbumItem(
id: "MPREb_n1H3JiFyGkv",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Ep,
year: Some(2015),
by_va: false,
),
AlbumItem(
id: "MPREb_ohcGTZrqKPZ",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2004),
by_va: false,
),
AlbumItem(
id: "MPREb_pWpeXxATZYb",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_ptO8gh250LP",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Ep,
year: Some(2003),
by_va: false,
),
AlbumItem(
id: "MPREb_qbJv3f0ijrk",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2007),
by_va: false,
),
AlbumItem(
id: "MPREb_rHhaDLqalbT",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Ep,
year: Some(2010),
by_va: false,
),
AlbumItem(
id: "MPREb_rdrfznTDhSX",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2012),
by_va: false,
),
AlbumItem(
id: "MPREb_saXgTKNPaSu",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_t6zStv8YrVG",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2010),
by_va: false,
),
AlbumItem(
id: "MPREb_vM0cMpn8pHh",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2008),
by_va: false,
),
AlbumItem(
id: "MPREb_wgm3k1qxpbF",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2010),
by_va: false,
),
AlbumItem(
id: "MPREb_wmSecJVDwPB",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2008),
by_va: false,
),
AlbumItem(
id: "MPREb_xCehp2mGhCk",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2010),
by_va: false,
),
AlbumItem(
id: "MPREb_y5fUQ2toJwT",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2017),
by_va: false,
),
],
playlists: "[playlists]",
similar_artists: "[artists]",
tracks_playlist_id: Some("OLAK5uy_n6aX-F_lCQxgyTIv4FJhp78bXV93b9NUM"),
videos_playlist_id: Some("OLAK5uy_nrePwvOEzmO7SydszEFfCDu8gAJxKfFtw"),
radio_id: Some("RDEMdgjzN3Qrk_GD7BooQbkJ4A"),
)

View file

@ -0,0 +1,320 @@
---
source: tests/youtube.rs
expression: artist
---
MusicArtist(
id: "UC7cl4MmM6ZZ2TcFyMk_b4pg",
name: "[name]",
header_image: "[header_image]",
description: "[description]",
wikipedia_url: "[wikipedia_url]",
subscriber_count: "[subscriber_count]",
tracks: "[tracks]",
albums: [
AlbumItem(
id: "MPREb_43NWLzXChnh",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2010),
by_va: false,
),
AlbumItem(
id: "MPREb_585fV7eqUP8",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_6PEkIQE7sWY",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Ep,
year: Some(2008),
by_va: false,
),
AlbumItem(
id: "MPREb_88p7e6nBtgz",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2012),
by_va: false,
),
AlbumItem(
id: "MPREb_Md2aZrjaqHX",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2021),
by_va: false,
),
AlbumItem(
id: "MPREb_OW1GOBZ64ap",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2018),
by_va: false,
),
AlbumItem(
id: "MPREb_QyGCcLWExXj",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_R3p5kDRIGKL",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2006),
by_va: false,
),
AlbumItem(
id: "MPREb_TiIBQqCFttT",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2016),
by_va: false,
),
AlbumItem(
id: "MPREb_U9HLD8nF7H5",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2017),
by_va: false,
),
AlbumItem(
id: "MPREb_V0FEmw2pj2u",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2017),
by_va: false,
),
AlbumItem(
id: "MPREb_WYx2c0e95TA",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2008),
by_va: false,
),
AlbumItem(
id: "MPREb_Yj49s4xy7fM",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2021),
by_va: false,
),
AlbumItem(
id: "MPREb_f4MhYbccbPi",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2006),
by_va: false,
),
AlbumItem(
id: "MPREb_kW2NAMSZElX",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2015),
by_va: false,
),
AlbumItem(
id: "MPREb_n1H3JiFyGkv",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Ep,
year: Some(2015),
by_va: false,
),
AlbumItem(
id: "MPREb_pWpeXxATZYb",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_rHhaDLqalbT",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Ep,
year: Some(2010),
by_va: false,
),
AlbumItem(
id: "MPREb_saXgTKNPaSu",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_wmSecJVDwPB",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Album,
year: Some(2008),
by_va: false,
),
],
playlists: "[playlists]",
similar_artists: "[artists]",
tracks_playlist_id: Some("OLAK5uy_n6aX-F_lCQxgyTIv4FJhp78bXV93b9NUM"),
videos_playlist_id: Some("OLAK5uy_nrePwvOEzmO7SydszEFfCDu8gAJxKfFtw"),
radio_id: Some("RDEMdgjzN3Qrk_GD7BooQbkJ4A"),
)

View file

@ -0,0 +1,19 @@
---
source: tests/youtube.rs
expression: artist
---
MusicArtist(
id: "UCh8gHdtzO2tXd593_bjErWg",
name: "[name]",
header_image: "[header_image]",
description: "[description]",
wikipedia_url: "[wikipedia_url]",
subscriber_count: "[subscriber_count]",
tracks: "[tracks]",
albums: [],
playlists: "[playlists]",
similar_artists: "[artists]",
tracks_playlist_id: None,
videos_playlist_id: None,
radio_id: None,
)

View file

@ -0,0 +1,155 @@
---
source: tests/youtube.rs
expression: artist
---
MusicArtist(
id: "UCOR4_bSVIXPsGa4BbCSt60Q",
name: "[name]",
header_image: "[header_image]",
description: "[description]",
wikipedia_url: "[wikipedia_url]",
subscriber_count: "[subscriber_count]",
tracks: "[tracks]",
albums: [
AlbumItem(
id: "MPREb_8PsIyll0LFV",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
name: "[name]",
),
],
artist_id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
album_type: Single,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_HPXN9BBzFpV",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
name: "[name]",
),
],
artist_id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
album_type: Single,
year: Some(2017),
by_va: false,
),
AlbumItem(
id: "MPREb_POeT6m0bw9q",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
name: "[name]",
),
],
artist_id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
album_type: Ep,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_R6EV2L1q0oc",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
name: "[name]",
),
],
artist_id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
album_type: Single,
year: Some(2017),
by_va: false,
),
AlbumItem(
id: "MPREb_UYdRV1nnK2J",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
name: "[name]",
),
],
artist_id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
album_type: Album,
year: Some(2017),
by_va: false,
),
AlbumItem(
id: "MPREb_bi34SGT1xlc",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
name: "[name]",
),
],
artist_id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
album_type: Album,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_hcK0fXETEf9",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
name: "[name]",
),
],
artist_id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
album_type: Single,
year: Some(2017),
by_va: false,
),
AlbumItem(
id: "MPREb_kLvmX2AzYBL",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
name: "[name]",
),
],
artist_id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
album_type: Single,
year: Some(2014),
by_va: false,
),
AlbumItem(
id: "MPREb_oHieBHkXn3A",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
name: "[name]",
),
],
artist_id: Some("UCOR4_bSVIXPsGa4BbCSt60Q"),
album_type: Single,
year: Some(2014),
by_va: false,
),
],
playlists: "[playlists]",
similar_artists: "[artists]",
tracks_playlist_id: Some("OLAK5uy_miHesZCUQY5S9EwqfoNP2tZR9nZ0NBAeU"),
videos_playlist_id: Some("OLAK5uy_mqbgE6T9uvusUWrAxJGiImf4_P4dM7IvQ"),
radio_id: Some("RDEM7AbogW0cCnElSU0WYm1GqA"),
)

View file

@ -0,0 +1,35 @@
---
source: tests/youtube.rs
expression: artist
---
MusicArtist(
id: "UCfwCE5VhPMGxNPFxtVv7lRw",
name: "[name]",
header_image: "[header_image]",
description: "[description]",
wikipedia_url: "[wikipedia_url]",
subscriber_count: "[subscriber_count]",
tracks: "[tracks]",
albums: [
AlbumItem(
id: "MPREb_vq8dZfFBEdx",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCfwCE5VhPMGxNPFxtVv7lRw"),
name: "[name]",
),
],
artist_id: Some("UCfwCE5VhPMGxNPFxtVv7lRw"),
album_type: Single,
year: Some(2019),
by_va: false,
),
],
playlists: "[playlists]",
similar_artists: "[artists]",
tracks_playlist_id: None,
videos_playlist_id: Some("OLAK5uy_lmH3iVq6lqjsnLkBWzpvRTh0DidLzbU-I"),
radio_id: Some("RDEMYsk_DTFHAng1G7n5toi_oA"),
)

View file

@ -1,8 +1,5 @@
--- ---
source: tests/youtube.rs source: tests/youtube.rs
expression: lyrics expression: lyrics.body
--- ---
Lyrics( "Eyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it\'s no use\n\'Cause you can\'t stop it from shining through\nIt\'s true\nBaby let the light shine through\nIf you believe it\'s true\nBaby won\'t you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nWon\'t you let the light shine through\n\nEyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it\'s no use\n\'Cause you can\'t stop it from shining through\nIt\'s true\nBaby let the light shine through\nIf you believe it\'s true\nBaby won\'t you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you"
body: "Eyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it\'s no use\n\'Cause you can\'t stop it from shining through\nIt\'s true\nBaby let the light shine through\nIf you believe it\'s true\nBaby won\'t you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nWon\'t you let the light shine through\n\nEyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it\'s no use\n\'Cause you can\'t stop it from shining through\nIt\'s true\nBaby let the light shine through\nIf you believe it\'s true\nBaby won\'t you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you",
footer: "Source: Musixmatch",
)

View file

@ -1,8 +1,10 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt::Display; use std::fmt::Display;
use std::str::FromStr;
use rstest::{fixture, rstest}; use rstest::{fixture, rstest};
use rustypipe::model::paginator::ContinuationEndpoint; use rustypipe::model::paginator::ContinuationEndpoint;
use rustypipe::param::Language;
use rustypipe::validate; use rustypipe::validate;
use time::macros::date; use time::macros::date;
use time::OffsetDateTime; use time::OffsetDateTime;
@ -921,35 +923,46 @@ fn assert_channel_eevblog<T>(channel: &Channel<T>) {
} }
#[rstest] #[rstest]
#[case::artist("UC_vmjW5e1xEHhYjY2a0kK1A", "Oonagh - Topic", false, false)] #[case::artist("UC_vmjW5e1xEHhYjY2a0kK1A", "Oonagh - Topic", false, false, false)]
#[case::shorts("UCh8gHdtzO2tXd593_bjErWg", "Doobydobap", true, true)] #[case::shorts("UCh8gHdtzO2tXd593_bjErWg", "Doobydobap", true, true, true)]
#[case::livestream( #[case::livestream(
"UChs0pSaEoNLV4mevBFGaoKA", "UChs0pSaEoNLV4mevBFGaoKA",
"The Good Life Radio x Sensual Musique", "The Good Life Radio x Sensual Musique",
true, true,
true,
true true
)] )]
#[case::music("UC-9-kyTW8ZkZNDHQJ6FgpwQ", "Music", false, false)] #[case::music("UC-9-kyTW8ZkZNDHQJ6FgpwQ", "Music", false, false, false)]
fn channel_more( fn channel_more(
#[case] id: &str, #[case] id: &str,
#[case] name: &str, #[case] name: &str,
#[case] has_videos: bool, #[case] has_videos: bool,
#[case] has_playlists: bool, #[case] has_playlists: bool,
#[case] name_unlocalized: bool,
rp: RustyPipe, rp: RustyPipe,
unlocalized: bool,
) { ) {
fn assert_channel<T>(channel: &Channel<T>, id: &str, name: &str) { fn assert_channel<T>(channel: &Channel<T>, id: &str, name: &str, unlocalized: bool) {
assert_eq!(channel.id, id); assert_eq!(channel.id, id);
assert_eq!(channel.name, name);
if unlocalized {
assert_eq!(channel.name, name);
}
} }
let channel_videos = tokio_test::block_on(rp.query().channel_videos(&id)).unwrap(); let channel_videos = tokio_test::block_on(rp.query().channel_videos(&id)).unwrap();
assert_channel(&channel_videos, id, name); assert_channel(&channel_videos, id, name, unlocalized || name_unlocalized);
if has_videos { if has_videos {
assert!(!channel_videos.content.items.is_empty(), "got no videos"); assert!(!channel_videos.content.items.is_empty(), "got no videos");
} }
let channel_playlists = tokio_test::block_on(rp.query().channel_playlists(&id)).unwrap(); let channel_playlists = tokio_test::block_on(rp.query().channel_playlists(&id)).unwrap();
assert_channel(&channel_playlists, id, name); assert_channel(
&channel_playlists,
id,
name,
unlocalized || name_unlocalized,
);
if has_playlists { if has_playlists {
assert!( assert!(
!channel_playlists.content.items.is_empty(), !channel_playlists.content.items.is_empty(),
@ -958,7 +971,7 @@ fn channel_more(
} }
let channel_info = tokio_test::block_on(rp.query().channel_info(&id)).unwrap(); let channel_info = tokio_test::block_on(rp.query().channel_info(&id)).unwrap();
assert_channel(&channel_info, id, name); assert_channel(&channel_info, id, name, unlocalized || name_unlocalized);
} }
#[rstest] #[rstest]
@ -968,7 +981,7 @@ fn channel_more(
#[case::sports("UCEgdi0XIXXZ-qJOFPf4JSKw")] #[case::sports("UCEgdi0XIXXZ-qJOFPf4JSKw")]
#[case::learning("UCtFRv9O2AHqOZjjynzrv-xg")] #[case::learning("UCtFRv9O2AHqOZjjynzrv-xg")]
#[case::live("UC4R8DWoMoI7CAwX8_LjQHig")] #[case::live("UC4R8DWoMoI7CAwX8_LjQHig")]
#[case::news("UCYfdidRxbB8Qhf0Nx7ioOYw")] // #[case::news("UCYfdidRxbB8Qhf0Nx7ioOYw")]
fn channel_not_found(#[case] id: &str, rp: RustyPipe) { fn channel_not_found(#[case] id: &str, rp: RustyPipe) {
let err = tokio_test::block_on(rp.query().channel_videos(&id)).unwrap_err(); let err = tokio_test::block_on(rp.query().channel_videos(&id)).unwrap_err();
@ -1030,15 +1043,17 @@ mod channel_rss {
//#SEARCH //#SEARCH
#[rstest] #[rstest]
fn search(rp: RustyPipe) { fn search(rp: RustyPipe, unlocalized: bool) {
let result = tokio_test::block_on(rp.query().search("doobydoobap")).unwrap(); let result = tokio_test::block_on(rp.query().search("doobydoobap")).unwrap();
assert!( assert!(
result.items.count.unwrap() > 7000, result.items.count.unwrap() > 1000,
"expected > 7000 total results, got {}", "expected > 1000 total results, got {}",
result.items.count.unwrap() result.items.count.unwrap()
); );
assert_eq!(result.corrected_query.unwrap(), "doobydobap"); if unlocalized {
assert_eq!(result.corrected_query.unwrap(), "doobydobap");
}
assert_next(result.items, rp.query(), 10, 2); assert_next(result.items, rp.query(), 10, 2);
} }
@ -1094,8 +1109,12 @@ fn search_suggestion(rp: RustyPipe) {
#[rstest] #[rstest]
fn search_suggestion_empty(rp: RustyPipe) { fn search_suggestion_empty(rp: RustyPipe) {
let result = let result = tokio_test::block_on(
tokio_test::block_on(rp.query().search_suggestion("fjew327%4ifjelwfvnewg49")).unwrap(); rp.query()
.lang(Language::Th)
.search_suggestion("fjew327p4ifjelwfvnewg49"),
)
.unwrap();
assert!(result.is_empty()); assert!(result.is_empty());
} }
@ -1214,6 +1233,7 @@ fn music_playlist(
#[case] channel: Option<(&str, &str)>, #[case] channel: Option<(&str, &str)>,
#[case] from_ytm: bool, #[case] from_ytm: bool,
rp: RustyPipe, rp: RustyPipe,
unlocalized: bool,
) { ) {
let playlist = tokio_test::block_on(rp.query().music_playlist(id)).unwrap(); let playlist = tokio_test::block_on(rp.query().music_playlist(id)).unwrap();
@ -1226,7 +1246,9 @@ fn music_playlist(
if is_long { 100 } else { 10 }, if is_long { 100 } else { 10 },
"track count", "track count",
); );
assert_eq!(playlist.description, description); if unlocalized {
assert_eq!(playlist.description, description);
}
if let Some(expect) = channel { if let Some(expect) = channel {
let c = playlist.channel.unwrap(); let c = playlist.channel.unwrap();
@ -1296,14 +1318,25 @@ fn music_playlist_not_found(rp: RustyPipe) {
#[case::no_year("no_year", "MPREb_F3Af9UZZVxX")] #[case::no_year("no_year", "MPREb_F3Af9UZZVxX")]
#[case::version_no_artist("version_no_artist", "MPREb_h8ltx5oKvyY")] #[case::version_no_artist("version_no_artist", "MPREb_h8ltx5oKvyY")]
#[case::no_artist("no_artist", "MPREb_bqWA6mAZFWS")] #[case::no_artist("no_artist", "MPREb_bqWA6mAZFWS")]
fn music_album(#[case] name: &str, #[case] id: &str, rp: RustyPipe) { fn music_album(#[case] name: &str, #[case] id: &str, rp: RustyPipe, unlocalized: bool) {
let album = tokio_test::block_on(rp.query().music_album(id)).unwrap(); let album = tokio_test::block_on(rp.query().music_album(id)).unwrap();
assert!(!album.cover.is_empty(), "got no cover"); assert!(!album.cover.is_empty(), "got no cover");
insta::assert_ron_snapshot!(format!("music_album_{name}"), album, if unlocalized {
{".cover" => "[cover]"} insta::assert_ron_snapshot!(format!("music_album_{name}"), album,
); {".cover" => "[cover]"}
);
} else {
insta::assert_ron_snapshot!(format!("music_album_{name}_intl"), album,
{
".cover" => "[cover]",
".artists[].name" => "[name]",
".tracks[].name" => "[name]",
".tracks[].artists[].name" => "[name]",
}
);
}
} }
#[rstest] #[rstest]
@ -1335,6 +1368,7 @@ fn music_artist(
#[case] min_tracks: usize, #[case] min_tracks: usize,
#[case] min_playlists: usize, #[case] min_playlists: usize,
rp: RustyPipe, rp: RustyPipe,
unlocalized: bool,
) { ) {
let mut artist = tokio_test::block_on(rp.query().music_artist(id, all_albums)).unwrap(); let mut artist = tokio_test::block_on(rp.query().music_artist(id, all_albums)).unwrap();
@ -1370,14 +1404,30 @@ fn music_artist(
// Sort albums to ensure consistent order // Sort albums to ensure consistent order
artist.albums.sort_by_key(|a| a.id.to_owned()); artist.albums.sort_by_key(|a| a.id.to_owned());
insta::assert_ron_snapshot!(format!("music_artist_{name}"), artist, { if unlocalized {
".header_image" => "[header_image]", insta::assert_ron_snapshot!(format!("music_artist_{name}"), artist, {
".subscriber_count" => "[subscriber_count]", ".header_image" => "[header_image]",
".albums[].cover" => "[cover]", ".subscriber_count" => "[subscriber_count]",
".tracks" => "[tracks]", ".albums[].cover" => "[cover]",
".playlists" => "[playlists]", ".tracks" => "[tracks]",
".similar_artists" => "[artists]", ".playlists" => "[playlists]",
}); ".similar_artists" => "[artists]",
});
} else {
insta::assert_ron_snapshot!(format!("music_artist_{name}_intl"), artist, {
".name" => "[name]",
".header_image" => "[header_image]",
".description" => "[description]",
".wikipedia_url" => "[wikipedia_url]",
".subscriber_count" => "[subscriber_count]",
".albums[].name" => "[name]",
".albums[].cover" => "[cover]",
".albums[].artists[].name" => "[name]",
".tracks" => "[tracks]",
".playlists" => "[playlists]",
".similar_artists" => "[artists]",
});
}
} }
#[rstest] #[rstest]
@ -1397,7 +1447,7 @@ fn music_artist_not_found(rp: RustyPipe) {
#[rstest] #[rstest]
#[case::default(false)] #[case::default(false)]
#[case::typo(true)] #[case::typo(true)]
fn music_search(#[case] typo: bool, rp: RustyPipe) { fn music_search(#[case] typo: bool, rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search(match typo { let res = tokio_test::block_on(rp.query().music_search(match typo {
false => "lieblingsmensch namika", false => "lieblingsmensch namika",
true => "lieblingsmesch namika", true => "lieblingsmesch namika",
@ -1434,7 +1484,9 @@ fn music_search(#[case] typo: bool, rp: RustyPipe) {
track_artist.id.as_ref().unwrap(), track_artist.id.as_ref().unwrap(),
"UCIh4j8fXWf2U0ro0qnGU8Mg" "UCIh4j8fXWf2U0ro0qnGU8Mg"
); );
assert_eq!(track_artist.name, "Namika"); if unlocalized {
assert_eq!(track_artist.name, "Namika");
}
let track_album = track.album.as_ref().unwrap(); let track_album = track.album.as_ref().unwrap();
assert_eq!(track_album.id, "MPREb_RXHxrUFfrvQ"); assert_eq!(track_album.id, "MPREb_RXHxrUFfrvQ");
@ -1446,7 +1498,7 @@ fn music_search(#[case] typo: bool, rp: RustyPipe) {
} }
#[rstest] #[rstest]
fn music_search2(rp: RustyPipe) { fn music_search2(rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search("taylor swift")).unwrap(); let res = tokio_test::block_on(rp.query().music_search("taylor swift")).unwrap();
assert!(!res.tracks.is_empty(), "no tracks"); assert!(!res.tracks.is_empty(), "no tracks");
@ -1463,12 +1515,14 @@ fn music_search2(rp: RustyPipe) {
panic!("could not find artist, got {:#?}", &res.artists); panic!("could not find artist, got {:#?}", &res.artists);
}); });
assert_eq!(artist.name, "Taylor Swift"); if unlocalized {
assert_eq!(artist.name, "Taylor Swift");
}
assert!(!artist.avatar.is_empty(), "got no avatar"); assert!(!artist.avatar.is_empty(), "got no avatar");
} }
#[rstest] #[rstest]
fn music_search_tracks(rp: RustyPipe) { fn music_search_tracks(rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search_tracks("black mamba")).unwrap(); let res = tokio_test::block_on(rp.query().music_search_tracks("black mamba")).unwrap();
let track = &res let track = &res
@ -1489,7 +1543,9 @@ fn music_search_tracks(rp: RustyPipe) {
track_artist.id.as_ref().unwrap(), track_artist.id.as_ref().unwrap(),
"UCEdZAdnnKqbaHOlv8nM6OtA" "UCEdZAdnnKqbaHOlv8nM6OtA"
); );
assert_eq!(track_artist.name, "aespa"); if unlocalized {
assert_eq!(track_artist.name, "aespa");
}
assert_eq!(track.duration.unwrap(), 175); assert_eq!(track.duration.unwrap(), 175);
@ -1501,7 +1557,7 @@ fn music_search_tracks(rp: RustyPipe) {
} }
#[rstest] #[rstest]
fn music_search_videos(rp: RustyPipe) { fn music_search_videos(rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search_videos("black mamba")).unwrap(); let res = tokio_test::block_on(rp.query().music_search_videos("black mamba")).unwrap();
let track = &res let track = &res
@ -1522,7 +1578,9 @@ fn music_search_videos(rp: RustyPipe) {
track_artist.id.as_ref().unwrap(), track_artist.id.as_ref().unwrap(),
"UCEdZAdnnKqbaHOlv8nM6OtA" "UCEdZAdnnKqbaHOlv8nM6OtA"
); );
assert_eq!(track_artist.name, "aespa"); if unlocalized {
assert_eq!(track_artist.name, "aespa");
}
assert_eq!(track.duration.unwrap(), 230); assert_eq!(track.duration.unwrap(), 230);
assert_eq!(track.album, None); assert_eq!(track.album, None);
@ -1621,7 +1679,7 @@ fn music_search_albums(
} }
#[rstest] #[rstest]
fn music_search_artists(rp: RustyPipe) { fn music_search_artists(rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search_artists("namika")).unwrap(); let res = tokio_test::block_on(rp.query().music_search_artists("namika")).unwrap();
let artist = res let artist = res
@ -1630,7 +1688,9 @@ fn music_search_artists(rp: RustyPipe) {
.iter() .iter()
.find(|a| a.id == "UCIh4j8fXWf2U0ro0qnGU8Mg") .find(|a| a.id == "UCIh4j8fXWf2U0ro0qnGU8Mg")
.unwrap(); .unwrap();
assert_eq!(artist.name, "Namika"); if unlocalized {
assert_eq!(artist.name, "Namika");
}
assert!(!artist.avatar.is_empty(), "got no avatar"); assert!(!artist.avatar.is_empty(), "got no avatar");
assert!( assert!(
artist.subscriber_count.unwrap() > 735_000, artist.subscriber_count.unwrap() > 735_000,
@ -1651,7 +1711,7 @@ fn music_search_artists_cont(rp: RustyPipe) {
#[rstest] #[rstest]
#[case::ytm(false)] #[case::ytm(false)]
#[case::default(true)] #[case::default(true)]
fn music_search_playlists(#[case] with_community: bool, rp: RustyPipe) { fn music_search_playlists(#[case] with_community: bool, rp: RustyPipe, unlocalized: bool) {
let res = if with_community { let res = if with_community {
tokio_test::block_on(rp.query().music_search_playlists("pop biggest hits")).unwrap() tokio_test::block_on(rp.query().music_search_playlists("pop biggest hits")).unwrap()
} else { } else {
@ -1670,7 +1730,9 @@ fn music_search_playlists(#[case] with_community: bool, rp: RustyPipe) {
.find(|p| p.id == "RDCLAK5uy_nmS3YoxSwVVQk9lEQJ0UX4ZCjXsW_psU8") .find(|p| p.id == "RDCLAK5uy_nmS3YoxSwVVQk9lEQJ0UX4ZCjXsW_psU8")
.unwrap(); .unwrap();
assert_eq!(playlist.name, "Pop's Biggest Hits"); if unlocalized {
assert_eq!(playlist.name, "Pop's Biggest Hits");
}
assert!(!playlist.thumbnail.is_empty(), "got no thumbnail"); assert!(!playlist.thumbnail.is_empty(), "got no thumbnail");
assert_gte(playlist.track_count.unwrap(), 100, "tracks"); assert_gte(playlist.track_count.unwrap(), 100, "tracks");
assert_eq!(playlist.channel, None); assert_eq!(playlist.channel, None);
@ -1784,7 +1846,12 @@ fn music_details(#[case] name: &str, #[case] id: &str, rp: RustyPipe) {
fn music_lyrics(rp: RustyPipe) { fn music_lyrics(rp: RustyPipe) {
let track = tokio_test::block_on(rp.query().music_details("60ImQ8DS3Vs")).unwrap(); let track = tokio_test::block_on(rp.query().music_details("60ImQ8DS3Vs")).unwrap();
let lyrics = tokio_test::block_on(rp.query().music_lyrics(&track.lyrics_id.unwrap())).unwrap(); let lyrics = tokio_test::block_on(rp.query().music_lyrics(&track.lyrics_id.unwrap())).unwrap();
insta::assert_ron_snapshot!(lyrics); insta::assert_ron_snapshot!(lyrics.body);
assert!(
lyrics.footer.contains("Musixmatch"),
"footer text: {}",
lyrics.footer
)
} }
#[rstest] #[rstest]
@ -2041,14 +2108,16 @@ fn music_new_videos(rp: RustyPipe) {
} }
#[rstest] #[rstest]
fn music_genres(rp: RustyPipe) { fn music_genres(rp: RustyPipe, unlocalized: bool) {
let genres = tokio_test::block_on(rp.query().music_genres()).unwrap(); let genres = tokio_test::block_on(rp.query().music_genres()).unwrap();
let chill = genres let chill = genres
.iter() .iter()
.find(|g| g.id == "ggMPOg1uX1JOQWZFeDByc2Jm") .find(|g| g.id == "ggMPOg1uX1JOQWZFeDByc2Jm")
.unwrap(); .unwrap();
assert_eq!(chill.name, "Chill"); if unlocalized {
assert_eq!(chill.name, "Chill");
}
assert!(chill.is_mood); assert!(chill.is_mood);
let pop = genres let pop = genres
@ -2067,12 +2136,19 @@ fn music_genres(rp: RustyPipe) {
#[rstest] #[rstest]
#[case::chill("ggMPOg1uX1JOQWZFeDByc2Jm", "Chill")] #[case::chill("ggMPOg1uX1JOQWZFeDByc2Jm", "Chill")]
#[case::pop("ggMPOg1uX1lMbVZmbzl6NlJ3", "Pop")] #[case::pop("ggMPOg1uX1lMbVZmbzl6NlJ3", "Pop")]
fn music_genre(#[case] id: &str, #[case] name: &str, rp: RustyPipe) { fn music_genre(#[case] id: &str, #[case] name: &str, rp: RustyPipe, unlocalized: bool) {
let genre = tokio_test::block_on(rp.query().music_genre(id)).unwrap(); let genre = tokio_test::block_on(rp.query().music_genre(id)).unwrap();
fn check_music_genre(genre: MusicGenre, id: &str, name: &str) -> Vec<(String, String)> { fn check_music_genre(
genre: MusicGenre,
id: &str,
name: &str,
unlocalized: bool,
) -> Vec<(String, String)> {
assert_eq!(genre.id, id); assert_eq!(genre.id, id);
assert_eq!(genre.name, name); if unlocalized {
assert_eq!(genre.name, name);
}
assert_gte(genre.sections.len(), 2, "genre sections"); assert_gte(genre.sections.len(), 2, "genre sections");
let mut subgenres = Vec::new(); let mut subgenres = Vec::new();
@ -2105,7 +2181,7 @@ fn music_genre(#[case] id: &str, #[case] name: &str, rp: RustyPipe) {
subgenres subgenres
} }
let subgenres = check_music_genre(genre, id, name); let subgenres = check_music_genre(genre, id, name, unlocalized);
if name == "Chill" { if name == "Chill" {
assert_gte(subgenres.len(), 2, "subgenres"); assert_gte(subgenres.len(), 2, "subgenres");
@ -2113,7 +2189,7 @@ fn music_genre(#[case] id: &str, #[case] name: &str, rp: RustyPipe) {
for (id, name) in subgenres { for (id, name) in subgenres {
let genre = tokio_test::block_on(rp.query().music_genre(&id)).unwrap(); let genre = tokio_test::block_on(rp.query().music_genre(&id)).unwrap();
check_music_genre(genre, &id, &name); check_music_genre(genre, &id, &name, unlocalized);
} }
} }
@ -2167,10 +2243,25 @@ fn invalid_ctoken(#[case] ep: ContinuationEndpoint, rp: RustyPipe) {
//#TESTUTIL //#TESTUTIL
/// Get the language setting from the environment variable
#[fixture]
fn lang() -> Language {
std::env::var("YT_LANG")
.ok()
.map(|l| Language::from_str(&l).unwrap())
.unwrap_or(Language::En)
}
/// Get a new RustyPipe instance /// Get a new RustyPipe instance
#[fixture] #[fixture]
fn rp() -> RustyPipe { fn rp(lang: Language) -> RustyPipe {
RustyPipe::builder().strict().build() RustyPipe::builder().strict().lang(lang).build()
}
/// Get a flag signaling if the language is set to English
#[fixture]
fn unlocalized(lang: Language) -> bool {
lang == Language::En
} }
/// Get a new RustyPipe instance with pre-set visitor data /// Get a new RustyPipe instance with pre-set visitor data