fix: shorts duration parsing, playlist dates (no), number_nd_tokens (is)

This commit is contained in:
ThetaDev 2023-05-11 17:40:53 +02:00
parent b862d2d1f9
commit ef1cdbc91a
19 changed files with 302 additions and 230 deletions

View file

@ -19,7 +19,8 @@ testintl:
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
LANGUAGES=( LANGUAGES=(
"af" "am" "ar" "as" "az" "be" "bg" "bn" "bs" "ca" "cs" "da" "de" "el" "en" "en-GB" "en-IN" "af" "am" "ar" "as" "az" "be" "bg" "bn" "bs" "ca" "cs" "da" "de" "el"
"en" "en-GB" "en-IN"
"es" "es-419" "es-US" "et" "eu" "fa" "fi" "fil" "fr" "fr-CA" "gl" "gu" "es" "es-419" "es-US" "et" "eu" "fa" "fi" "fil" "fr" "fr-CA" "gl" "gu"
"hi" "hr" "hu" "hy" "id" "is" "it" "iw" "ja" "ka" "kk" "km" "kn" "ko" "ky" "hi" "hr" "hu" "hy" "id" "is" "it" "iw" "ja" "ka" "kk" "km" "kn" "ko" "ky"
"lo" "lt" "lv" "mk" "ml" "mn" "mr" "ms" "my" "ne" "nl" "no" "or" "pa" "pl" "lo" "lt" "lv" "mk" "ml" "mn" "mr" "ms" "my" "ne" "nl" "no" "or" "pa" "pl"

View file

@ -66,8 +66,8 @@ pub async fn collect_dates(concurrency: usize) {
// These are the sample playlists // These are the sample playlists
let cases = [ let cases = [
(DateCase::Today, "PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj"), (DateCase::Today, "PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj"),
(DateCase::Yesterday, "PLcirGkCPmbmFeQ1sm4wFciF03D_EroIfr"), (DateCase::Yesterday, "PL3oW2tjiIxvQ98ZTLhBh5soCbE1mC3uAT"),
(DateCase::Ago, "PLmB6td997u3kUOrfFwkULZ910ho44oQSy"), (DateCase::Ago, "PLeDakahyfrO9Amk2GFrzpI4UWOkgqzoIE"),
(DateCase::Jan, "PL1J-6JOckZtFjcni6Xj1pLYglJp6JCpKD"), (DateCase::Jan, "PL1J-6JOckZtFjcni6Xj1pLYglJp6JCpKD"),
(DateCase::Feb, "PL1J-6JOckZtETrbzwZE7mRIIK6BzWNLAs"), (DateCase::Feb, "PL1J-6JOckZtETrbzwZE7mRIIK6BzWNLAs"),
(DateCase::Mar, "PL1J-6JOckZtG3AVdvBXhMO64mB2k3BtKi"), (DateCase::Mar, "PL1J-6JOckZtG3AVdvBXhMO64mB2k3BtKi"),

View file

@ -208,7 +208,9 @@ pub(crate) struct CoverMusicItem {
/// ///
/// `"2022"` Artist singles /// `"2022"` Artist singles
/// ///
/// `"Playlist", " • ", <"ThetaDev"> " • ", "26 songs"` /// `"Playlist", " • ", <"YouTube Music"> " • ", "53 songs"`
///
/// `"Playlist", " • ", <"Vevo Playlists"> " • ", "13M views"`
/// ///
/// `"Playlist", " • ", "YouTube Music" Featured on /// `"Playlist", " • ", "YouTube Music" Featured on
#[serde(default)] #[serde(default)]
@ -737,8 +739,9 @@ impl MusicListMapper {
let channel = channel_p.and_then(|p| { let channel = channel_p.and_then(|p| {
p.0.into_iter().find_map(|c| ChannelId::try_from(c).ok()) p.0.into_iter().find_map(|c| ChannelId::try_from(c).ok())
}); });
let track_count = let track_count = tcount_p
tcount_p.and_then(|p| util::parse_numeric(p.first_str()).ok()); .filter(|_| from_ytm)
.and_then(|p| util::parse_numeric(p.first_str()).ok());
self.items.push(MusicItem::Playlist(MusicPlaylistItem { self.items.push(MusicItem::Playlist(MusicPlaylistItem {
id, id,
@ -772,7 +775,6 @@ impl MusicListMapper {
let mut subtitle_parts = item.subtitle.split(util::DOT_SEPARATOR).into_iter(); let mut subtitle_parts = item.subtitle.split(util::DOT_SEPARATOR).into_iter();
let subtitle_p1 = subtitle_parts.next(); let subtitle_p1 = subtitle_parts.next();
let subtitle_p2 = subtitle_parts.next(); let subtitle_p2 = subtitle_parts.next();
let subtitle_p3 = subtitle_parts.next();
match item.navigation_endpoint.music_page() { match item.navigation_endpoint.music_page() {
Some((page_type, id)) => match page_type { Some((page_type, id)) => match page_type {
@ -879,15 +881,13 @@ impl MusicListMapper {
let channel = subtitle_p2.and_then(|p| { let channel = subtitle_p2.and_then(|p| {
p.0.into_iter().find_map(|c| ChannelId::try_from(c).ok()) p.0.into_iter().find_map(|c| ChannelId::try_from(c).ok())
}); });
let track_count =
subtitle_p3.and_then(|p| util::parse_numeric(p.first_str()).ok());
self.items.push(MusicItem::Playlist(MusicPlaylistItem { self.items.push(MusicItem::Playlist(MusicPlaylistItem {
id, id,
name: item.title, name: item.title,
thumbnail: item.thumbnail_renderer.into(), thumbnail: item.thumbnail_renderer.into(),
channel, channel,
track_count, track_count: None,
from_ytm, from_ytm,
})); }));
Ok(Some(MusicItemType::Playlist)) Ok(Some(MusicItemType::Playlist))

View file

@ -1,3 +1,5 @@
use once_cell::sync::Lazy;
use regex::Regex;
use serde::Deserialize; use serde::Deserialize;
use serde_with::{ use serde_with::{
json::JsonString, rust::deserialize_ignore_any, serde_as, DefaultOnError, VecSkipError, json::JsonString, rust::deserialize_ignore_any, serde_as, DefaultOnError, VecSkipError,
@ -382,6 +384,10 @@ impl IsShort for Vec<TimeOverlay> {
} }
} }
static ACCESSIBILITY_SEP_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new("(?:[ \u{00a0}][-\u{2013}\u{2014}] )|\u{2013}|(?:\u{055d} )|(?:\", )").unwrap()
});
/// Result of mapping a list of different YouTube enities /// Result of mapping a list of different YouTube enities
/// (videos, channels, playlists) /// (videos, channels, playlists)
#[derive(Debug)] #[derive(Debug)]
@ -496,14 +502,29 @@ impl<T> YouTubeListMapper<T> {
.timestamp_text .timestamp_text
}); });
let length = video.accessibility.and_then(|acc| {
let parts = ACCESSIBILITY_SEP_REGEX.split(&acc).collect::<Vec<_>>();
if parts.len() > 2 {
let i = match lang {
Language::Ru => 1,
_ => 2,
};
timeago::parse_video_duration_or_warn(
self.lang,
parts[parts.len() - i],
&mut self.warnings,
)
} else {
self.warnings
.push(format!("could not split video duration `{acc}`"));
None
}
});
VideoItem { VideoItem {
id: video.video_id, id: video.video_id,
name: video.headline, name: video.headline,
length: video.accessibility.and_then(|acc| { length,
acc.rsplit(" - ").nth(1).and_then(|s| {
timeago::parse_video_duration_or_warn(self.lang, s, &mut self.warnings)
})
}),
thumbnail: video.thumbnail.into(), thumbnail: video.thumbnail.into(),
channel: self.channel.clone(), channel: self.channel.clone(),
publish_date: pub_date_txt.as_ref().and_then(|txt| { publish_date: pub_date_txt.as_ref().and_then(|txt| {
@ -704,3 +725,50 @@ impl YouTubeListMapper<PlaylistItem> {
res.c.into_iter().for_each(|item| self.map_item(item)); res.c.into_iter().for_each(|item| self.map_item(item));
} }
} }
#[cfg(test)]
mod tests {
use super::ACCESSIBILITY_SEP_REGEX;
use rstest::rstest;
#[rstest]
#[case::af(
"BTS - Permission to Dance Cover #shorts #pinkfong 50 sekondes speel video",
"50 sekondes"
)]
#[case::de(
"Point of view: Me VS My mom #shorts  8 Sekunden  Video wiedergeben",
"8 Sekunden"
)]
#[case::be(
"Point of view: Me VS My mom #shorts8 секунд прайграць відэа",
"8 секунд"
)]
#[case::fil("do u wanna get swole? - 53 segundo - i-play ang video", "53 segundo")]
#[case::ar(
"«the holy trinity of korean street food»՝ 1 րոպե՝ նվագարկել տեսանյութը",
"1 րոպե"
)]
#[case::lv(
"what i ate in google japan — 1 minūte — atskaņot videoklipu",
"1 minūte"
)]
#[case::sq("When you impulse buy... - 1 minutë - luaj videon", "1 minutë")]
#[case::uk(
"\"Point of view: Me VS My mom #shorts\", 8 секунд відтворити відео",
"8 секунд"
)]
// INFO: sw is unparseable "coming soonsekunde 58 - cheza video"
fn split_duration_txt(#[case] s: &str, #[case] expect: &str) {
let parts = ACCESSIBILITY_SEP_REGEX.split(s).collect::<Vec<_>>();
assert_eq!(parts[parts.len() - 2], expect);
}
#[test]
fn split_duration_txt_ru() {
let s = "Воспроизвести видео – \"the holy trinity of korean street food\". Его продолжительность – 1 минута.";
let parts = ACCESSIBILITY_SEP_REGEX.split(s).collect::<Vec<_>>();
assert_eq!(parts[parts.len() - 1], "1 минута.");
}
}

View file

@ -57,7 +57,7 @@ MusicArtist(
id: "UCh8gHdtzO2tXd593_bjErWg", id: "UCh8gHdtzO2tXd593_bjErWg",
name: "Doobydobap", name: "Doobydobap",
)), )),
track_count: Some(6), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -79,7 +79,7 @@ MusicArtist(
id: "UCh8gHdtzO2tXd593_bjErWg", id: "UCh8gHdtzO2tXd593_bjErWg",
name: "Doobydobap", name: "Doobydobap",
)), )),
track_count: Some(59), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -101,7 +101,7 @@ MusicArtist(
id: "UCh8gHdtzO2tXd593_bjErWg", id: "UCh8gHdtzO2tXd593_bjErWg",
name: "Doobydobap", name: "Doobydobap",
)), )),
track_count: Some(10), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -123,7 +123,7 @@ MusicArtist(
id: "UCh8gHdtzO2tXd593_bjErWg", id: "UCh8gHdtzO2tXd593_bjErWg",
name: "Doobydobap", name: "Doobydobap",
)), )),
track_count: Some(12), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -145,7 +145,7 @@ MusicArtist(
id: "UCh8gHdtzO2tXd593_bjErWg", id: "UCh8gHdtzO2tXd593_bjErWg",
name: "Doobydobap", name: "Doobydobap",
)), )),
track_count: Some(40), track_count: None,
from_ytm: false, from_ytm: false,
), ),
], ],

View file

@ -989,7 +989,7 @@ MusicRelated(
id: "UCteCDkIcXeK0Hy2jfDyjAvg", id: "UCteCDkIcXeK0Hy2jfDyjAvg",
name: "느양이", name: "느양이",
)), )),
track_count: Some(24), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -1011,7 +1011,7 @@ MusicRelated(
id: "UCMbDcEEUG_qlfEWuEmSWK4w", id: "UCMbDcEEUG_qlfEWuEmSWK4w",
name: "몰라", name: "몰라",
)), )),
track_count: Some(26), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -1033,7 +1033,7 @@ MusicRelated(
id: "UCbP0WNlLgrnjAm4bBayYCHg", id: "UCbP0WNlLgrnjAm4bBayYCHg",
name: "zekeira Jackson", name: "zekeira Jackson",
)), )),
track_count: Some(25), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -1055,7 +1055,7 @@ MusicRelated(
id: "UCt0wIbpQkTfojRTMm0c7fVg", id: "UCt0wIbpQkTfojRTMm0c7fVg",
name: "Ashlyn Anahí Perez xitumul", name: "Ashlyn Anahí Perez xitumul",
)), )),
track_count: Some(25), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -1077,7 +1077,7 @@ MusicRelated(
id: "UCceFVAj8BxG0_aLdypfdcew", id: "UCceFVAj8BxG0_aLdypfdcew",
name: "YANA24", name: "YANA24",
)), )),
track_count: Some(48), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -1099,7 +1099,7 @@ MusicRelated(
id: "UCX-Fmn_USQ2PuFxnibdv_tw", id: "UCX-Fmn_USQ2PuFxnibdv_tw",
name: "BLÆZY", name: "BLÆZY",
)), )),
track_count: Some(29), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -1121,7 +1121,7 @@ MusicRelated(
id: "UCC2CZv7mdAkCbwHH10c9m9g", id: "UCC2CZv7mdAkCbwHH10c9m9g",
name: "aideed razali", name: "aideed razali",
)), )),
track_count: Some(27), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -1143,7 +1143,7 @@ MusicRelated(
id: "UCAR5UBWbSjZZojV4q5jBuPw", id: "UCAR5UBWbSjZZojV4q5jBuPw",
name: "Terry Zarrato", name: "Terry Zarrato",
)), )),
track_count: Some(26), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -1165,7 +1165,7 @@ MusicRelated(
id: "UCSd74nw3xjGGyBQ4I7-vAVQ", id: "UCSd74nw3xjGGyBQ4I7-vAVQ",
name: "Changmin Park", name: "Changmin Park",
)), )),
track_count: Some(25), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -1187,7 +1187,7 @@ MusicRelated(
id: "UC2XFk1E2pia0DH8iZHWX7uQ", id: "UC2XFk1E2pia0DH8iZHWX7uQ",
name: "Gorgeous_Celebs", name: "Gorgeous_Celebs",
)), )),
track_count: Some(22), track_count: None,
from_ytm: false, from_ytm: false,
), ),
], ],

View file

@ -507,7 +507,7 @@ MusicSearchResult(
id: "UC0tDRlJxvcgAhXiHwZm4wcQ", id: "UC0tDRlJxvcgAhXiHwZm4wcQ",
name: "Elyssa Hamilton", name: "Elyssa Hamilton",
)), )),
track_count: Some(155), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -534,7 +534,7 @@ MusicSearchResult(
id: "UCNpa7-_q_H17TGFfUccs6mw", id: "UCNpa7-_q_H17TGFfUccs6mw",
name: "Spencer Ramirez Salas", name: "Spencer Ramirez Salas",
)), )),
track_count: Some(43), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -561,7 +561,7 @@ MusicSearchResult(
id: "UCrESzB-SUekVTY3QI3Jfqlg", id: "UCrESzB-SUekVTY3QI3Jfqlg",
name: "N.J. Music", name: "N.J. Music",
)), )),
track_count: Some(96), track_count: None,
from_ytm: false, from_ytm: false,
), ),
], ],

View file

@ -389,7 +389,7 @@ MusicSearchResult(
id: "UCtZaFx5MXZHIh7VTItJK1lQ", id: "UCtZaFx5MXZHIh7VTItJK1lQ",
name: "Lajos Fülöp", name: "Lajos Fülöp",
)), )),
track_count: Some(29), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -416,7 +416,7 @@ MusicSearchResult(
id: "UCwFT0vvkbtbohtzVbwx7WjQ", id: "UCwFT0vvkbtbohtzVbwx7WjQ",
name: "Toshihiko KOMINAMI", name: "Toshihiko KOMINAMI",
)), )),
track_count: Some(6), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -443,7 +443,7 @@ MusicSearchResult(
id: "UCEdZAdnnKqbaHOlv8nM6OtA", id: "UCEdZAdnnKqbaHOlv8nM6OtA",
name: "aespa", name: "aespa",
)), )),
track_count: Some(39), track_count: None,
from_ytm: false, from_ytm: false,
), ),
], ],

View file

@ -438,7 +438,7 @@ MusicSearchResult(
id: "UCEYgc2eKzQXQ9OGCuT4JVPQ", id: "UCEYgc2eKzQXQ9OGCuT4JVPQ",
name: "Redlist - International Playlists", name: "Redlist - International Playlists",
)), )),
track_count: Some(100), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -465,7 +465,7 @@ MusicSearchResult(
id: "UCjD0UddJFWadpaTrBJPOVGw", id: "UCjD0UddJFWadpaTrBJPOVGw",
name: "Raphaël Weissreiner", name: "Raphaël Weissreiner",
)), )),
track_count: Some(176), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -492,7 +492,7 @@ MusicSearchResult(
id: "UCesP91XKnuZVd6OJN06hokg", id: "UCesP91XKnuZVd6OJN06hokg",
name: "Startup Records", name: "Startup Records",
)), )),
track_count: Some(171), track_count: None,
from_ytm: false, from_ytm: false,
), ),
], ],

View file

@ -397,7 +397,7 @@ MusicSearchResult(
id: "UC2iUWrsf_RJIskqCZZHz4tg", id: "UC2iUWrsf_RJIskqCZZHz4tg",
name: "Saskia Wehmeyer", name: "Saskia Wehmeyer",
)), )),
track_count: Some(16), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -424,7 +424,7 @@ MusicSearchResult(
id: "UCSj8sEcs5CEUmeIZMSPB7Ew", id: "UCSj8sEcs5CEUmeIZMSPB7Ew",
name: "Daniel Switali", name: "Daniel Switali",
)), )),
track_count: Some(16), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -451,7 +451,7 @@ MusicSearchResult(
id: "UCs2uL32TTzWX0oVoblPF1nQ", id: "UCs2uL32TTzWX0oVoblPF1nQ",
name: "Nicole Kr", name: "Nicole Kr",
)), )),
track_count: Some(6), track_count: None,
from_ytm: false, from_ytm: false,
), ),
], ],

View file

@ -30,7 +30,7 @@ MusicSearchFiltered(
id: "UCX9oPuvJYZsG8wnHTwOBVPA", id: "UCX9oPuvJYZsG8wnHTwOBVPA",
name: "Chillax", name: "Chillax",
)), )),
track_count: Some(220), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -57,7 +57,7 @@ MusicSearchFiltered(
id: "UC8Ojfs-1VLiAO_MosLwvjpQ", id: "UC8Ojfs-1VLiAO_MosLwvjpQ",
name: "Redlist - Ultimate Music", name: "Redlist - Ultimate Music",
)), )),
track_count: Some(70), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -84,7 +84,7 @@ MusicSearchFiltered(
id: "UCE2DEoWWdlUlZsOpolWOgog", id: "UCE2DEoWWdlUlZsOpolWOgog",
name: "Jeff Co", name: "Jeff Co",
)), )),
track_count: Some(321), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -111,7 +111,7 @@ MusicSearchFiltered(
id: "UCf7eNY2yY-cRuYshHmg4IIg", id: "UCf7eNY2yY-cRuYshHmg4IIg",
name: "Frank Denker", name: "Frank Denker",
)), )),
track_count: Some(106), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -138,7 +138,7 @@ MusicSearchFiltered(
id: "UCs72iRpTEuwV3y6pdWYLgiw", id: "UCs72iRpTEuwV3y6pdWYLgiw",
name: "Redlist - Just Hits", name: "Redlist - Just Hits",
)), )),
track_count: Some(204), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -165,7 +165,7 @@ MusicSearchFiltered(
id: "UCesP91XKnuZVd6OJN06hokg", id: "UCesP91XKnuZVd6OJN06hokg",
name: "Startup Records", name: "Startup Records",
)), )),
track_count: Some(164), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -192,7 +192,7 @@ MusicSearchFiltered(
id: "UCHuFqDbnqNhBsZB3KBj_Y0g", id: "UCHuFqDbnqNhBsZB3KBj_Y0g",
name: "Redlist - Músicas Internacionais", name: "Redlist - Músicas Internacionais",
)), )),
track_count: Some(102), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -219,7 +219,7 @@ MusicSearchFiltered(
id: "UCv9O2E_G8U46Paz8828THJw", id: "UCv9O2E_G8U46Paz8828THJw",
name: "Victor Vaz", name: "Victor Vaz",
)), )),
track_count: Some(50), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -246,7 +246,7 @@ MusicSearchFiltered(
id: "UCkX96b0MIXbisaGNCYXSRCQ", id: "UCkX96b0MIXbisaGNCYXSRCQ",
name: "Redlist - Music Tops", name: "Redlist - Music Tops",
)), )),
track_count: Some(50), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -273,7 +273,7 @@ MusicSearchFiltered(
id: "UCRnu4ZIsaCCDOJdFKIJgirw", id: "UCRnu4ZIsaCCDOJdFKIJgirw",
name: "Redlist - Fresh Hits", name: "Redlist - Fresh Hits",
)), )),
track_count: Some(100), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -300,7 +300,7 @@ MusicSearchFiltered(
id: "UCs72iRpTEuwV3y6pdWYLgiw", id: "UCs72iRpTEuwV3y6pdWYLgiw",
name: "Redlist - Just Hits", name: "Redlist - Just Hits",
)), )),
track_count: Some(180), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -327,7 +327,7 @@ MusicSearchFiltered(
id: "UCGUHgJb6ZaJoOqQ6FHgV6zw", id: "UCGUHgJb6ZaJoOqQ6FHgV6zw",
name: "Redlist - World Songs", name: "Redlist - World Songs",
)), )),
track_count: Some(91), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -354,7 +354,7 @@ MusicSearchFiltered(
id: "UCPVhZsC2od1xjGhgEc2NEPQ", id: "UCPVhZsC2od1xjGhgEc2NEPQ",
name: "Vevo Playlists", name: "Vevo Playlists",
)), )),
track_count: Some(82), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -381,7 +381,7 @@ MusicSearchFiltered(
id: "UCNAPgBbQ2iXE94osjz3-m_A", id: "UCNAPgBbQ2iXE94osjz3-m_A",
name: "Redlist - Top Hits", name: "Redlist - Top Hits",
)), )),
track_count: Some(42), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -408,7 +408,7 @@ MusicSearchFiltered(
id: "UCs72iRpTEuwV3y6pdWYLgiw", id: "UCs72iRpTEuwV3y6pdWYLgiw",
name: "Redlist - Just Hits", name: "Redlist - Just Hits",
)), )),
track_count: Some(254), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -435,7 +435,7 @@ MusicSearchFiltered(
id: "UC1crMgATGeegnQTZTImZuqA", id: "UC1crMgATGeegnQTZTImZuqA",
name: "AXEG UK", name: "AXEG UK",
)), )),
track_count: Some(236), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -462,7 +462,7 @@ MusicSearchFiltered(
id: "UCSjPP6ccJ3MbsK7v-NfhFtw", id: "UCSjPP6ccJ3MbsK7v-NfhFtw",
name: "Redlist Grama", name: "Redlist Grama",
)), )),
track_count: Some(150), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -489,7 +489,7 @@ MusicSearchFiltered(
id: "UCdeukGMkFDh8Zs662Z-d2pA", id: "UCdeukGMkFDh8Zs662Z-d2pA",
name: "Redlist - Melhores Músicas", name: "Redlist - Melhores Músicas",
)), )),
track_count: Some(101), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -516,7 +516,7 @@ MusicSearchFiltered(
id: "UCPVhZsC2od1xjGhgEc2NEPQ", id: "UCPVhZsC2od1xjGhgEc2NEPQ",
name: "Vevo Playlists", name: "Vevo Playlists",
)), )),
track_count: Some(261), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(
@ -543,7 +543,7 @@ MusicSearchFiltered(
id: "UCPVhZsC2od1xjGhgEc2NEPQ", id: "UCPVhZsC2od1xjGhgEc2NEPQ",
name: "Vevo Playlists", name: "Vevo Playlists",
)), )),
track_count: Some(52), track_count: None,
from_ytm: false, from_ytm: false,
), ),
], ],

View file

@ -157,7 +157,7 @@ Paginator(
id: "UCnOnrhWLv3YMoTVWqF4k82w", id: "UCnOnrhWLv3YMoTVWqF4k82w",
name: "botevpd", name: "botevpd",
)), )),
track_count: Some(49), track_count: None,
from_ytm: false, from_ytm: false,
), ),
MusicPlaylistItem( MusicPlaylistItem(

View file

@ -2827,11 +2827,12 @@ pub(crate) fn entry(lang: Language) -> Entry {
], ],
}, },
number_nd_tokens: ::phf::Map { number_nd_tokens: ::phf::Map {
key: 10121458955350035957, key: 7485420634051515786,
disps: &[ disps: &[
(1, 0), (2, 0),
], ],
entries: &[ entries: &[
("eitt", 1),
("ekkert", 0), ("ekkert", 0),
("einn", 1), ("einn", 1),
], ],
@ -4613,23 +4614,25 @@ pub(crate) fn entry(lang: Language) -> Entry {
months: ::phf::Map { months: ::phf::Map {
key: 15467950696543387533, key: 15467950696543387533,
disps: &[ disps: &[
(0, 6), (4, 10),
(9, 10), (9, 6),
(0, 0), (0, 0),
], ],
entries: &[ entries: &[
("aug.", 8), ("okt.", 10),
("jan.", 1),
("des.", 12),
("mar.", 3), ("mar.", 3),
("jun.", 6), ("juli", 7),
("jul.", 7), ("nov.", 11),
("feb.", 2), ("des.", 12),
("apr.", 4), ("apr.", 4),
("mai", 5), ("mai", 5),
("nov.", 11), ("juni", 6),
("okt.", 10), ("feb.", 2),
("sep.", 9), ("sep.", 9),
("aug.", 8),
("jan.", 1),
("jun.", 6),
("jul.", 7),
], ],
}, },
timeago_nd_tokens: ::phf::Map { timeago_nd_tokens: ::phf::Map {

View file

@ -350,7 +350,7 @@ fn split_duration_txt(txt: &str, start_c: bool) -> Vec<DurationTxtSegment> {
let mut state: u8 = 0; let mut state: u8 = 0;
let mut seg = DurationTxtSegment::default(); let mut seg = DurationTxtSegment::default();
for c in txt.chars() { for c in txt.trim().chars() {
if c.is_ascii_digit() { if c.is_ascii_digit() {
if state == 2 && (!seg.digits.is_empty() || (!start_c && segments.is_empty())) { if state == 2 && (!seg.digits.is_empty() || (!start_c && segments.is_empty())) {
segments.push(seg); segments.push(seg);
@ -363,7 +363,7 @@ fn split_duration_txt(txt: &str, start_c: bool) -> Vec<DurationTxtSegment> {
segments.push(seg); segments.push(seg);
seg = DurationTxtSegment::default(); seg = DurationTxtSegment::default();
} }
if c != ',' { if !matches!(c, '.' | ',') {
c.to_lowercase().for_each(|c| seg.word.push(c)); c.to_lowercase().for_each(|c| seg.word.push(c));
} }
state = 2; state = 2;

View file

@ -1621,6 +1621,7 @@
}, },
"number_nd_tokens": { "number_nd_tokens": {
"einn": 1, "einn": 1,
"eitt": 1,
"ekkert": 0 "ekkert": 0
}, },
"album_types": { "album_types": {
@ -2646,7 +2647,9 @@
"feb.": 2, "feb.": 2,
"jan.": 1, "jan.": 1,
"jul.": 7, "jul.": 7,
"juli": 7,
"jun.": 6, "jun.": 6,
"juni": 6,
"mai": 5, "mai": 5,
"mar.": 3, "mar.": 3,
"nov.": 11, "nov.": 11,

View file

@ -13500,7 +13500,8 @@
"99 þ. áhorf": 99029, "99 þ. áhorf": 99029,
"9 þ. áhorf": 9087, "9 þ. áhorf": 9087,
"Einn áskrifandi": 1, "Einn áskrifandi": 1,
"Ekkert áhorf enn": 0 "Ekkert áhorf enn": 0,
"Eitt vídeó": 1
}, },
"it": { "it": {
"1 iscritto": 1, "1 iscritto": 1,

View file

@ -943,8 +943,8 @@
"Mar": "Sist oppdatert 9. mar. 2015", "Mar": "Sist oppdatert 9. mar. 2015",
"Apr": "Sist oppdatert 2. apr. 2017", "Apr": "Sist oppdatert 2. apr. 2017",
"May": "Sist oppdatert 22. mai 2014", "May": "Sist oppdatert 22. mai 2014",
"Jun": "Sist oppdatert 28. jun. 2014", "Jun": "Sist oppdatert 28. juni 2014",
"Jul": "Sist oppdatert 2. jul. 2014", "Jul": "Sist oppdatert 2. juli 2014",
"Aug": "Sist oppdatert 23. aug. 2015", "Aug": "Sist oppdatert 23. aug. 2015",
"Sep": "Sist oppdatert 16. sep. 2018", "Sep": "Sist oppdatert 16. sep. 2018",
"Oct": "Sist oppdatert 31. okt. 2014", "Oct": "Sist oppdatert 31. okt. 2014",

View file

@ -796,6 +796,7 @@ fn channel_videos(rp: RustyPipe) {
fn channel_shorts(rp: RustyPipe) { fn channel_shorts(rp: RustyPipe) {
let channel = tokio_test::block_on( let channel = tokio_test::block_on(
rp.query() rp.query()
.lang(Language::Sq)
.channel_videos_tab("UCh8gHdtzO2tXd593_bjErWg", ChannelVideoTab::Shorts), .channel_videos_tab("UCh8gHdtzO2tXd593_bjErWg", ChannelVideoTab::Shorts),
) )
.unwrap(); .unwrap();
@ -1005,7 +1006,7 @@ fn channel_order(
} }
} }
} }
assert_next(latest, rp.query(), 15, 2); assert_next(latest, rp.query(), 15, 1);
let popular = tokio_test::block_on(rp.query().channel_videos_tab_order( let popular = tokio_test::block_on(rp.query().channel_videos_tab_order(
id, id,
@ -1030,7 +1031,7 @@ fn channel_order(
); );
} }
} }
assert_next(popular, rp.query(), 15, 2); assert_next(popular, rp.query(), 15, 1);
} }
#[rstest] #[rstest]
@ -1156,7 +1157,7 @@ fn search_filter_item_type(#[case] item_type: search_filter::ItemType, rp: Rusty
fn search_empty(rp: RustyPipe) { fn search_empty(rp: RustyPipe) {
let result = tokio_test::block_on( let result = tokio_test::block_on(
rp.query().search_filter( rp.query().search_filter(
"test", "3gig84hgi34gu8vj34gj489",
&search_filter::SearchFilter::new() &search_filter::SearchFilter::new()
.feature(search_filter::Feature::IsLive) .feature(search_filter::Feature::IsLive)
.feature(search_filter::Feature::Is3d), .feature(search_filter::Feature::Is3d),
@ -1171,7 +1172,7 @@ fn search_empty(rp: RustyPipe) {
fn search_suggestion(rp: RustyPipe) { fn search_suggestion(rp: RustyPipe) {
let result = tokio_test::block_on(rp.query().search_suggestion("hunger ga")).unwrap(); let result = tokio_test::block_on(rp.query().search_suggestion("hunger ga")).unwrap();
assert!(result.iter().any(|s| s.starts_with("hunger games "))); assert!(result.iter().any(|s| s.starts_with("hunger games")));
assert_gte(result.len(), 10, "search suggestions"); assert_gte(result.len(), 10, "search suggestions");
} }
@ -1373,7 +1374,7 @@ fn music_playlist_not_found(rp: RustyPipe) {
#[case::various_artists("various_artists", "MPREb_8QkDeEIawvX")] #[case::various_artists("various_artists", "MPREb_8QkDeEIawvX")]
#[case::single("single", "MPREb_bHfHGoy7vuv")] #[case::single("single", "MPREb_bHfHGoy7vuv")]
#[case::ep("ep", "MPREb_u1I69lSAe5v")] #[case::ep("ep", "MPREb_u1I69lSAe5v")]
#[case::audiobook("audiobook", "MPREb_gaoNzsQHedo")] // #[case::audiobook("audiobook", "MPREb_gaoNzsQHedo")]
#[case::show("show", "MPREb_cwzk8EUwypZ")] #[case::show("show", "MPREb_cwzk8EUwypZ")]
#[case::unavailable("unavailable", "MPREb_AzuWg8qAVVl")] #[case::unavailable("unavailable", "MPREb_AzuWg8qAVVl")]
#[case::no_year("no_year", "MPREb_F3Af9UZZVxX")] #[case::no_year("no_year", "MPREb_F3Af9UZZVxX")]
@ -1835,7 +1836,6 @@ fn music_search_playlists_community(rp: RustyPipe) {
"Best Pop Music Videos - Top Pop Hits Playlist" "Best Pop Music Videos - Top Pop Hits Playlist"
); );
assert!(!playlist.thumbnail.is_empty(), "got no thumbnail"); assert!(!playlist.thumbnail.is_empty(), "got no thumbnail");
assert_gte(playlist.track_count.unwrap(), 250, "tracks");
let channel = playlist.channel.as_ref().unwrap(); let channel = playlist.channel.as_ref().unwrap();
assert_eq!(channel.id, "UCs72iRpTEuwV3y6pdWYLgiw"); assert_eq!(channel.id, "UCs72iRpTEuwV3y6pdWYLgiw");
@ -2019,8 +2019,6 @@ fn music_related(#[case] id: &str, #[case] full: bool, rp: RustyPipe) {
let channel = playlist.channel.unwrap(); let channel = playlist.channel.unwrap();
assert_channel_id(&channel.id); assert_channel_id(&channel.id);
assert!(!channel.name.is_empty()); assert!(!channel.name.is_empty());
assert_gte(playlist.track_count.unwrap(), 2, "tracks");
} else { } else {
assert!(playlist.channel.is_none()); assert!(playlist.channel.is_none());
} }
@ -2216,8 +2214,6 @@ fn music_genre(#[case] id: &str, #[case] name: &str, rp: RustyPipe, unlocalized:
let channel = playlist.channel.as_ref().unwrap(); let channel = playlist.channel.as_ref().unwrap();
assert_channel_id(&channel.id); assert_channel_id(&channel.id);
assert!(!channel.name.is_empty()); assert!(!channel.name.is_empty());
assert_gte(playlist.track_count.unwrap(), 1, "tracks");
} else { } else {
assert!(playlist.channel.is_none()); assert!(playlist.channel.is_none());
} }