test: add integration tests for YTM albums/search
This commit is contained in:
parent
c7ae2f8531
commit
b38bc711c7
16 changed files with 3743 additions and 286 deletions
|
|
@ -63,3 +63,10 @@ Dec PL1J-6JOckZtHo91uApeb10Qlf2XhkfM-9 24.12.2021
|
|||
10e3: 5K UC0QEucPrn0-Ddi3JBTcs5Kw
|
||||
10e2: 388 UCllyEQfcoiPN68zHv6mGHDQ
|
||||
10e1: 37 UCGiJh0NZ52wRhYKYnuZI08Q
|
||||
|
||||
# Album types
|
||||
Album: MPREb_nlBWQROfvjo
|
||||
Single: MPREb_bHfHGoy7vuv
|
||||
EP: MPREb_u1I69lSAe5v
|
||||
Show: MPREb_cwzk8EUwypZ
|
||||
Audiobook: MPREb_gaoNzsQHedo
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ impl MapResponse<Paginator<MusicItem>> for response::MusicContinuation {
|
|||
_deobf: Option<&crate::deobfuscate::Deobfuscator>,
|
||||
) -> Result<MapResult<Paginator<MusicItem>>, ExtractionError> {
|
||||
let mut mapper = MusicListMapper::new(lang);
|
||||
let mut shelf = self.continuation_contents.music_playlist_shelf_continuation;
|
||||
let mut shelf = self.continuation_contents.music_shelf_continuation;
|
||||
mapper.map_response(shelf.contents);
|
||||
let map_res = mapper.items();
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,8 @@ pub(crate) struct MusicContinuation {
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ContinuationContents {
|
||||
pub music_playlist_shelf_continuation: MusicShelf,
|
||||
#[serde(alias = "musicPlaylistShelfContinuation")]
|
||||
pub music_shelf_continuation: MusicShelf,
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -36,13 +36,47 @@ pub(crate) struct WatchEndpoint {
|
|||
pub start_time_seconds: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct BrowseEndpoint {
|
||||
pub browse_id: String,
|
||||
pub browse_endpoint_context_supported_configs: Option<BrowseEndpointConfig>,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for BrowseEndpoint {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct BEp {
|
||||
pub browse_id: String,
|
||||
pub browse_endpoint_context_supported_configs: Option<BrowseEndpointConfig>,
|
||||
}
|
||||
|
||||
let bep = BEp::deserialize(deserializer)?;
|
||||
|
||||
// Remove the VL prefix from the playlist id
|
||||
let browse_id = bep
|
||||
.browse_endpoint_context_supported_configs
|
||||
.as_ref()
|
||||
.and_then(
|
||||
|cfg| match cfg.browse_endpoint_context_music_config.page_type {
|
||||
PageType::Playlist => bep.browse_id.strip_prefix("VL"),
|
||||
_ => None,
|
||||
},
|
||||
)
|
||||
.map(str::to_owned)
|
||||
.unwrap_or(bep.browse_id);
|
||||
|
||||
Ok(Self {
|
||||
browse_id,
|
||||
browse_endpoint_context_supported_configs: bep
|
||||
.browse_endpoint_context_supported_configs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct UrlEndpoint {
|
||||
|
|
@ -75,9 +109,12 @@ pub(crate) struct WebCommandMetadata {
|
|||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
|
||||
pub(crate) enum PageType {
|
||||
#[serde(rename = "MUSIC_PAGE_TYPE_ARTIST")]
|
||||
#[serde(
|
||||
rename = "MUSIC_PAGE_TYPE_ARTIST",
|
||||
alias = "MUSIC_PAGE_TYPE_AUDIOBOOK_ARTIST"
|
||||
)]
|
||||
Artist,
|
||||
#[serde(rename = "MUSIC_PAGE_TYPE_ALBUM")]
|
||||
#[serde(rename = "MUSIC_PAGE_TYPE_ALBUM", alias = "MUSIC_PAGE_TYPE_AUDIOBOOK")]
|
||||
Album,
|
||||
#[serde(
|
||||
rename = "WEB_PAGE_TYPE_CHANNEL",
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ MusicSearchResult(
|
|||
],
|
||||
playlists: [
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLk76iSbFqNJsu_Gozn9SkEXxQ7t-bpXid",
|
||||
id: "PLk76iSbFqNJsu_Gozn9SkEXxQ7t-bpXid",
|
||||
name: "IRMA MIRTILLA Black Mamba",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -383,7 +383,7 @@ MusicSearchResult(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLIL9Q2jz6euDEJZKHd4QaG4iic944_vKY",
|
||||
id: "PLIL9Q2jz6euDEJZKHd4QaG4iic944_vKY",
|
||||
name: "Black Mamba",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -410,7 +410,7 @@ MusicSearchResult(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLinm7-cvTdN7RqadpfNrncUGqkdyKNpn6",
|
||||
id: "PLinm7-cvTdN7RqadpfNrncUGqkdyKNpn6",
|
||||
name: "Black Mamba",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ MusicSearchFiltered(
|
|||
count: None,
|
||||
items: [
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLDIoUOhQQPlVr3qepMVRsDe4T8vNQsvno",
|
||||
id: "PLDIoUOhQQPlVr3qepMVRsDe4T8vNQsvno",
|
||||
name: "Türkçe Pop Şarkılar 2022 - Yeni Hit Şarkılar 2022",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -34,7 +34,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLI_7Mg2Z_-4Lf7IYeiTEOV8HBn-nMqz5N",
|
||||
id: "PLI_7Mg2Z_-4Lf7IYeiTEOV8HBn-nMqz5N",
|
||||
name: "Pop 2022 ♫ Mix Pop En Ingles (English Pop Songs 2022)",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -61,7 +61,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLTC7VQ12-9raqhLCx1S1E_ic35t94dj28",
|
||||
id: "PLTC7VQ12-9raqhLCx1S1E_ic35t94dj28",
|
||||
name: "Pop & Pop Rock Hits 🔥 2012 - 2022",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -88,7 +88,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLPssMy7y6ygl-Kzi9Mc7TVFFPWwyAXIwW",
|
||||
id: "PLPssMy7y6ygl-Kzi9Mc7TVFFPWwyAXIwW",
|
||||
name: "Bester deutscher Pop/Best of German Pop music",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -115,7 +115,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj",
|
||||
id: "PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj",
|
||||
name: "Pop Music Playlist - Timeless Pop Songs (Updated Weekly 2022)",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -142,7 +142,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLX6L4t7t6ZanfCJ1wBxRdGZ_mk9ygmKqo",
|
||||
id: "PLX6L4t7t6ZanfCJ1wBxRdGZ_mk9ygmKqo",
|
||||
name: "Deutsch Pop Hits NEU 2022",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -169,7 +169,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPL1jMjCxDqxLvomtUMbqa_4pAjMmzpfgUy",
|
||||
id: "PL1jMjCxDqxLvomtUMbqa_4pAjMmzpfgUy",
|
||||
name: "Top 100 Músicas Internacionais Pop 2022",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -196,7 +196,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLgRdph0qPLy53IhYrQLPpATDDA2TpFey5",
|
||||
id: "PLgRdph0qPLy53IhYrQLPpATDDA2TpFey5",
|
||||
name: "Teen-Pop 90-2000",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -223,7 +223,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLV9Y77TQ4I9dXpIF-r54ZTLM5T7C4k5jf",
|
||||
id: "PLV9Y77TQ4I9dXpIF-r54ZTLM5T7C4k5jf",
|
||||
name: "Most Popular Soft Pop Songs of 2022 Playlist - Best Soft Pop Music Hits of the Year 2022",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -250,7 +250,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLlYKDqBVDxX2TXAf8ruuF3FVZgzF3wCTx",
|
||||
id: "PLlYKDqBVDxX2TXAf8ruuF3FVZgzF3wCTx",
|
||||
name: "Pop 2022 ♫ Best Pop Songs Playlist 2022",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -277,7 +277,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLMC9KNkIncKvYin_USF1qoJQnIyMAfRxl",
|
||||
id: "PLMC9KNkIncKvYin_USF1qoJQnIyMAfRxl",
|
||||
name: "Best Pop Songs of All Time: Playlist of Good Songs (Throwback Hits & Pop Music 2022)",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -304,7 +304,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLKUA473MWUv2jmkqIxzQR3YL4kuPArj4G",
|
||||
id: "PLKUA473MWUv2jmkqIxzQR3YL4kuPArj4G",
|
||||
name: "Best Pop Music for Office – Good Songs for Work: Pop Hits Collection (Playlist Updated in 2022)",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -331,7 +331,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLkqz3S84Tw-RfPS9HHi3MRmrinOBKxIr8",
|
||||
id: "PLkqz3S84Tw-RfPS9HHi3MRmrinOBKxIr8",
|
||||
name: "Top POP Hits 2022 – Biggest Pop Music Videos - Vevo",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -358,7 +358,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLEBX04z4REEaHbC7ghEqFwwL4ptIw8qaZ",
|
||||
id: "PLEBX04z4REEaHbC7ghEqFwwL4ptIw8qaZ",
|
||||
name: "Playlist Pop Rock 2022 ♫ Musique Pop Rock 2022 Nouveauté",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -385,7 +385,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLMC9KNkIncKtGvr2kFRuXBVmBev6cAJ2u",
|
||||
id: "PLMC9KNkIncKtGvr2kFRuXBVmBev6cAJ2u",
|
||||
name: "Best Pop Music Videos - Top Pop Hits Playlist",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -412,7 +412,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPL9NY5axt700FjL6HlEhqlMFT1gjMGVBgy",
|
||||
id: "PL9NY5axt700FjL6HlEhqlMFT1gjMGVBgy",
|
||||
name: "Pop Music Songs 2022",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -439,7 +439,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLTariUrSxayvzHkCnEiX5-NSeFgLTqzHE",
|
||||
id: "PLTariUrSxayvzHkCnEiX5-NSeFgLTqzHE",
|
||||
name: "Pop Music Playlist 2022",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -466,7 +466,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLB8HqqmpyIBcPirb5lDm-ol01trE6dOuM",
|
||||
id: "PLB8HqqmpyIBcPirb5lDm-ol01trE6dOuM",
|
||||
name: "Mix Internacional 2022 ♫ As Mais Tocadas 2022 Internacionais (Playlist Musicas Pop As Melhores)",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -493,7 +493,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLkqz3S84Tw-Qlth8bNBpXGO7L4J1PkCW7",
|
||||
id: "PLkqz3S84Tw-Qlth8bNBpXGO7L4J1PkCW7",
|
||||
name: "POP INTERNATIONAL HOTLIST - Pop Hits 2022- Brandneue Pop Videos | Vevo Playlist",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -520,7 +520,7 @@ MusicSearchFiltered(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLkqz3S84Tw-SvUSUY5Ov8LTP3KWuWxFab",
|
||||
id: "PLkqz3S84Tw-SvUSUY5Ov8LTP3KWuWxFab",
|
||||
name: "Cheesy Sing-Along Pop Hits!",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ MusicSearchFiltered(
|
|||
count: None,
|
||||
items: [
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_nmS3YoxSwVVQk9lEQJ0UX4ZCjXsW_psU8",
|
||||
id: "RDCLAK5uy_nmS3YoxSwVVQk9lEQJ0UX4ZCjXsW_psU8",
|
||||
name: "Pop\'s Biggest Hits",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -36,7 +36,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_nfs_t4FUu00E5ED6lveEBBX1VMYe1mFjk",
|
||||
id: "RDCLAK5uy_nfs_t4FUu00E5ED6lveEBBX1VMYe1mFjk",
|
||||
name: "Dance-Pop Bangers",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -65,7 +65,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_nH_fdBVCcbNaVwi_tmZajZRq-ekddiuFY",
|
||||
id: "RDCLAK5uy_nH_fdBVCcbNaVwi_tmZajZRq-ekddiuFY",
|
||||
name: "Pop Meets Country",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -94,7 +94,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_lb6CVU6S4uVugLVNTU9WhqfaomWAgnho4",
|
||||
id: "RDCLAK5uy_lb6CVU6S4uVugLVNTU9WhqfaomWAgnho4",
|
||||
name: "Shout-Out Pop Hits",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -123,7 +123,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_mfdqvCAl8wodlx2P2_Ai2gNkiRDAufkkI",
|
||||
id: "RDCLAK5uy_mfdqvCAl8wodlx2P2_Ai2gNkiRDAufkkI",
|
||||
name: "Happy Pop Hits",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -152,7 +152,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_nHSqCJjDrW9HBhCNdF6tWPdnOMngOv0wA",
|
||||
id: "RDCLAK5uy_nHSqCJjDrW9HBhCNdF6tWPdnOMngOv0wA",
|
||||
name: "Pop Gold",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -181,7 +181,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_kLB769E3eFSzgy4fbpu6-1YPLh90b0JAY",
|
||||
id: "RDCLAK5uy_kLB769E3eFSzgy4fbpu6-1YPLh90b0JAY",
|
||||
name: "Pop Hotlist",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -210,7 +210,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_m_0U5VQNyyzwwH1lRi7cPAAGXqNQnAOqY",
|
||||
id: "RDCLAK5uy_m_0U5VQNyyzwwH1lRi7cPAAGXqNQnAOqY",
|
||||
name: "Laid-Back Sofa Pop",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -239,7 +239,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_mHW5bcduhjB-PkTePAe6EoRMj1xNT8gzY",
|
||||
id: "RDCLAK5uy_mHW5bcduhjB-PkTePAe6EoRMj1xNT8gzY",
|
||||
name: "K-Pop Girl Crush",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -268,7 +268,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_nWFLXjO1mIJnP4wAmxjfDS40Zmu6nF9DU",
|
||||
id: "RDCLAK5uy_nWFLXjO1mIJnP4wAmxjfDS40Zmu6nF9DU",
|
||||
name: "Se Habla Pop",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -297,7 +297,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_lHu_HYAQ0A-OfCwhuky240HOdM1UduuyA",
|
||||
id: "RDCLAK5uy_lHu_HYAQ0A-OfCwhuky240HOdM1UduuyA",
|
||||
name: "Presenting Pop Smoke",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -326,7 +326,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_lw21MuKaqFsDBIPZSbRmZcoDrHmV_c6uY",
|
||||
id: "RDCLAK5uy_lw21MuKaqFsDBIPZSbRmZcoDrHmV_c6uY",
|
||||
name: "Happy latin pop",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -355,7 +355,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_lY6JFrs7W9yIhFjUN_yxQ_ubkjcrqQaVs",
|
||||
id: "RDCLAK5uy_lY6JFrs7W9yIhFjUN_yxQ_ubkjcrqQaVs",
|
||||
name: "Bedroom Pop",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -384,7 +384,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_nbK9qSkqYZvtMXH1fLCMmC1yn8HEm0W90",
|
||||
id: "RDCLAK5uy_nbK9qSkqYZvtMXH1fLCMmC1yn8HEm0W90",
|
||||
name: "J-Hits!",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -413,7 +413,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_kIcfhFcnJ9fdkKHw96Gvr6Q0_bAyWiZbM",
|
||||
id: "RDCLAK5uy_kIcfhFcnJ9fdkKHw96Gvr6Q0_bAyWiZbM",
|
||||
name: "Reiwa Era J-Pop",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -442,7 +442,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_nDL8KeBrUagwyISwNmyEiSfYgz1gVCesg",
|
||||
id: "RDCLAK5uy_nDL8KeBrUagwyISwNmyEiSfYgz1gVCesg",
|
||||
name: "Mellow Pop Classics",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -471,7 +471,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_l7K78k4EkjcFojhd1617rmUjY-aet6-t0",
|
||||
id: "RDCLAK5uy_l7K78k4EkjcFojhd1617rmUjY-aet6-t0",
|
||||
name: "K-Pop Party Hits",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -500,7 +500,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_nCVF_zUZizzRcojIUuYmaXxMoPgg2WMDo",
|
||||
id: "RDCLAK5uy_nCVF_zUZizzRcojIUuYmaXxMoPgg2WMDo",
|
||||
name: "Klangfarbe: German Pop Hits",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -529,7 +529,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_nGKsW16ocmP8l8wL1oMIyR53cu4N5fyKI",
|
||||
id: "RDCLAK5uy_nGKsW16ocmP8l8wL1oMIyR53cu4N5fyKI",
|
||||
name: "GIF Pop BR",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -558,7 +558,7 @@ MusicSearchFiltered(
|
|||
from_ytm: true,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLRDCLAK5uy_mVJ3RRi_YBfUJnZnQxLAedQQcXHujbUcg",
|
||||
id: "RDCLAK5uy_mVJ3RRi_YBfUJnZnQxLAedQQcXHujbUcg",
|
||||
name: "Pump-Up Pop",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ MusicSearchResult(
|
|||
],
|
||||
playlists: [
|
||||
MusicPlaylistItem(
|
||||
id: "VLPL46jG0sBz4EabjYqv0tVEd1RvrZRjfJ8m",
|
||||
id: "PL46jG0sBz4EabjYqv0tVEd1RvrZRjfJ8m",
|
||||
name: "Lieblingsmensch",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -391,7 +391,7 @@ MusicSearchResult(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPL-2Z-8cOvEixQ2EKumbXXW8XivJG6U7-D",
|
||||
id: "PL-2Z-8cOvEixQ2EKumbXXW8XivJG6U7-D",
|
||||
name: "Namika - Lieblingsmensch",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
@ -418,7 +418,7 @@ MusicSearchResult(
|
|||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "VLPLDnJKuRrOR5sx_jZ8-dsweq1OdayL_kpz",
|
||||
id: "PLDnJKuRrOR5sx_jZ8-dsweq1OdayL_kpz",
|
||||
name: "Lieblingsmensch",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ mod ordering;
|
|||
mod paginator;
|
||||
pub mod richtext;
|
||||
|
||||
pub(crate) use convert::FromYtItem;
|
||||
pub use convert::FromYtItem;
|
||||
pub use paginator::Paginator;
|
||||
use serde_with::serde_as;
|
||||
|
||||
|
|
@ -955,6 +955,7 @@ pub struct MusicPlaylistItem {
|
|||
|
||||
/// YouTube Music album type
|
||||
#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum AlbumType {
|
||||
/// Regular album (default)
|
||||
#[default]
|
||||
|
|
@ -1031,9 +1032,13 @@ pub struct MusicAlbum {
|
|||
/// YouTube Music search result
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct MusicSearchResult {
|
||||
/// Found tracks
|
||||
pub tracks: Vec<TrackItem>,
|
||||
/// Found albums
|
||||
pub albums: Vec<AlbumItem>,
|
||||
/// Found artists
|
||||
pub artists: Vec<ArtistItem>,
|
||||
/// Found playlists
|
||||
pub playlists: Vec<MusicPlaylistItem>,
|
||||
/// Corrected search query
|
||||
///
|
||||
|
|
@ -1041,6 +1046,8 @@ pub struct MusicSearchResult {
|
|||
/// for the corrected search term and displays it on top of the
|
||||
/// search results page.
|
||||
pub corrected_query: Option<String>,
|
||||
/// Order of the item sections of the search page, starting with
|
||||
/// the most relevant.
|
||||
pub order: Vec<MusicEntityType>,
|
||||
}
|
||||
|
||||
|
|
|
|||
2418
tests/snapshots/youtube__music_album_audiobook.snap
Normal file
2418
tests/snapshots/youtube__music_album_audiobook.snap
Normal file
File diff suppressed because it is too large
Load diff
108
tests/snapshots/youtube__music_album_ep.snap
Normal file
108
tests/snapshots/youtube__music_album_ep.snap
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
source: tests/youtube.rs
|
||||
expression: album
|
||||
---
|
||||
MusicAlbum(
|
||||
id: "MPREb_u1I69lSAe5v",
|
||||
playlist_id: Some("OLAK5uy_lGP_zv0vJDUlecQDzugUJmjcF7pvyVNyY"),
|
||||
name: "Waldbrand",
|
||||
cover: "[cover]",
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCpJyCbFbdTrx0M90HCNBHFQ",
|
||||
name: "Madeline Juno",
|
||||
),
|
||||
],
|
||||
artists_txt: "Madeline Juno",
|
||||
album_type: Ep,
|
||||
year: Some(2016),
|
||||
by_va: false,
|
||||
tracks: [
|
||||
TrackItem(
|
||||
id: "aGd3VKSOTxY",
|
||||
title: "Ich wache auf",
|
||||
duration: 221,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCpJyCbFbdTrx0M90HCNBHFQ",
|
||||
name: "Madeline Juno",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Madeline Juno"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(1),
|
||||
),
|
||||
TrackItem(
|
||||
id: "lhPOMUjV4rE",
|
||||
title: "Waldbrand",
|
||||
duration: 208,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCpJyCbFbdTrx0M90HCNBHFQ",
|
||||
name: "Madeline Juno",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Madeline Juno"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(2),
|
||||
),
|
||||
TrackItem(
|
||||
id: "Bu26uFtpt58",
|
||||
title: "Verlernt",
|
||||
duration: 223,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCpJyCbFbdTrx0M90HCNBHFQ",
|
||||
name: "Madeline Juno",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Madeline Juno"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(3),
|
||||
),
|
||||
TrackItem(
|
||||
id: "RgwNqqiVqdY",
|
||||
title: "In Farbe",
|
||||
duration: 221,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCpJyCbFbdTrx0M90HCNBHFQ",
|
||||
name: "Madeline Juno",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Madeline Juno"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(4),
|
||||
),
|
||||
TrackItem(
|
||||
id: "2TuOh30XbCI",
|
||||
title: "Stadt im Hinterland",
|
||||
duration: 197,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCpJyCbFbdTrx0M90HCNBHFQ",
|
||||
name: "Madeline Juno",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Madeline Juno"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(5),
|
||||
),
|
||||
],
|
||||
variants: [],
|
||||
)
|
||||
355
tests/snapshots/youtube__music_album_one_artist.snap
Normal file
355
tests/snapshots/youtube__music_album_one_artist.snap
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
---
|
||||
source: tests/youtube.rs
|
||||
expression: album
|
||||
---
|
||||
MusicAlbum(
|
||||
id: "MPREb_nlBWQROfvjo",
|
||||
playlist_id: Some("OLAK5uy_myZkBX2d2TzcrlQhIwLy3hCj2MkAMaPR4"),
|
||||
name: "Märchen enden gut",
|
||||
cover: "[cover]",
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: "Oonagh",
|
||||
album_type: Album,
|
||||
year: Some(2016),
|
||||
by_va: false,
|
||||
tracks: [
|
||||
TrackItem(
|
||||
id: "g0iRiJ_ck48",
|
||||
title: "Aulë und Yavanna",
|
||||
duration: 216,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(1),
|
||||
),
|
||||
TrackItem(
|
||||
id: "rREEBXp0y9s",
|
||||
title: "Numenor",
|
||||
duration: 224,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(2),
|
||||
),
|
||||
TrackItem(
|
||||
id: "zvU5Y8Q19hU",
|
||||
title: "Das Mädchen und die Liebe (feat. Santiano)",
|
||||
duration: 176,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(3),
|
||||
),
|
||||
TrackItem(
|
||||
id: "ARKLrzzTQA0",
|
||||
title: "Niënna",
|
||||
duration: 215,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(4),
|
||||
),
|
||||
TrackItem(
|
||||
id: "tstLgN8A_Ng",
|
||||
title: "Der fahle Mond",
|
||||
duration: 268,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(5),
|
||||
),
|
||||
TrackItem(
|
||||
id: "k2DjgQOY3Ts",
|
||||
title: "Weise den Weg",
|
||||
duration: 202,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(6),
|
||||
),
|
||||
TrackItem(
|
||||
id: "azHwhecxEsI",
|
||||
title: "Zeit der Sommernächte",
|
||||
duration: 185,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(7),
|
||||
),
|
||||
TrackItem(
|
||||
id: "_FcsdYIQ2co",
|
||||
title: "Märchen enden gut",
|
||||
duration: 226,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(8),
|
||||
),
|
||||
TrackItem(
|
||||
id: "27bOWEbshyE",
|
||||
title: "Das Mädchen und der Tod",
|
||||
duration: 207,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(9),
|
||||
),
|
||||
TrackItem(
|
||||
id: "riD_3oZwt8w",
|
||||
title: "Wir sehn uns wieder",
|
||||
duration: 211,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(10),
|
||||
),
|
||||
TrackItem(
|
||||
id: "8GNvjF3no9s",
|
||||
title: "Tanz mit mir",
|
||||
duration: 179,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(11),
|
||||
),
|
||||
TrackItem(
|
||||
id: "YHMFzf1uN2U",
|
||||
title: "Nachtigall",
|
||||
duration: 218,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(12),
|
||||
),
|
||||
TrackItem(
|
||||
id: "jvV-z5F3oAo",
|
||||
title: "Gayatri Mantra",
|
||||
duration: 277,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(13),
|
||||
),
|
||||
TrackItem(
|
||||
id: "u8_9cxlrh8k",
|
||||
title: "Sing mir deine Lieder",
|
||||
duration: 204,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(14),
|
||||
),
|
||||
TrackItem(
|
||||
id: "gSvKcvM1Wk0",
|
||||
title: "Laurië lantar",
|
||||
duration: 202,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(15),
|
||||
),
|
||||
TrackItem(
|
||||
id: "wQHgKRJ0pDQ",
|
||||
title: "Wächter vor dem Tor",
|
||||
duration: 222,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(16),
|
||||
),
|
||||
TrackItem(
|
||||
id: "Ckz5i6-hzf0",
|
||||
title: "Stroh zu Gold",
|
||||
duration: 177,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(17),
|
||||
),
|
||||
TrackItem(
|
||||
id: "y5zuUgyFqrc",
|
||||
title: "Sonnenwendnacht",
|
||||
duration: 220,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Oonagh"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(18),
|
||||
),
|
||||
],
|
||||
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: [
|
||||
ChannelId(
|
||||
id: "UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
name: "Oonagh",
|
||||
),
|
||||
],
|
||||
artists_txt: "Oonagh",
|
||||
album_type: Album,
|
||||
year: None,
|
||||
),
|
||||
],
|
||||
)
|
||||
261
tests/snapshots/youtube__music_album_show.snap
Normal file
261
tests/snapshots/youtube__music_album_show.snap
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
---
|
||||
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: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: "Kingdom Force",
|
||||
album_type: Album,
|
||||
year: Some(2022),
|
||||
by_va: false,
|
||||
tracks: [
|
||||
TrackItem(
|
||||
id: "lSbKz5LWvKE",
|
||||
title: "Achtung, Waldbrand - Teil 1",
|
||||
duration: 229,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(1),
|
||||
),
|
||||
TrackItem(
|
||||
id: "fdO6gu4qjRw",
|
||||
title: "Achtung, Waldbrand - Teil 2",
|
||||
duration: 235,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(2),
|
||||
),
|
||||
TrackItem(
|
||||
id: "muCxstXirvY",
|
||||
title: "Achtung, Waldbrand - Teil 3",
|
||||
duration: 197,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(3),
|
||||
),
|
||||
TrackItem(
|
||||
id: "aG1N0vo__Ng",
|
||||
title: "Eiszeit - Teil 1",
|
||||
duration: 186,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(4),
|
||||
),
|
||||
TrackItem(
|
||||
id: "roHhLNYS9yo",
|
||||
title: "Eiszeit - Teil 2",
|
||||
duration: 188,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(5),
|
||||
),
|
||||
TrackItem(
|
||||
id: "nJ49NuLvcAw",
|
||||
title: "Eiszeit - Teil 3",
|
||||
duration: 205,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(6),
|
||||
),
|
||||
TrackItem(
|
||||
id: "Me119D570h0",
|
||||
title: "Eiszeit - Teil 4",
|
||||
duration: 219,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(7),
|
||||
),
|
||||
TrackItem(
|
||||
id: "YXnRLK-qKG8",
|
||||
title: "Im Sinkloch - Teil 1",
|
||||
duration: 240,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(8),
|
||||
),
|
||||
TrackItem(
|
||||
id: "A61wz1jz9X0",
|
||||
title: "Im Sinkloch - Teil 2",
|
||||
duration: 239,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(9),
|
||||
),
|
||||
TrackItem(
|
||||
id: "u_S08EJOTUg",
|
||||
title: "Im Sinkloch - Teil 3",
|
||||
duration: 197,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(10),
|
||||
),
|
||||
TrackItem(
|
||||
id: "0qwYJihV1EU",
|
||||
title: "Vorsicht, heiß - Teil 1",
|
||||
duration: 201,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(11),
|
||||
),
|
||||
TrackItem(
|
||||
id: "zjhoyTnEzuQ",
|
||||
title: "Vorsicht, heiß - Teil 2",
|
||||
duration: 187,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(12),
|
||||
),
|
||||
TrackItem(
|
||||
id: "oDjDd0UBzAY",
|
||||
title: "Vorsicht, heiß - Teil 3",
|
||||
duration: 183,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(13),
|
||||
),
|
||||
TrackItem(
|
||||
id: "_3-WVmqgi-Q",
|
||||
title: "Vorsicht, heiß - Teil 4",
|
||||
duration: 193,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCNoyEM0e2A7WlsBmP2w3avg",
|
||||
name: "Kingdom Force",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kingdom Force"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(14),
|
||||
),
|
||||
],
|
||||
variants: [],
|
||||
)
|
||||
48
tests/snapshots/youtube__music_album_single.snap
Normal file
48
tests/snapshots/youtube__music_album_single.snap
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
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: [
|
||||
ChannelId(
|
||||
id: "UCXGYZ-OhdOpPBamHX3K9YRg",
|
||||
name: "Joel Brandenstein",
|
||||
),
|
||||
ChannelId(
|
||||
id: "UCFTcSVPYRWlDoHisR-ZKwgw",
|
||||
name: "Vanessa Mai",
|
||||
),
|
||||
],
|
||||
artists_txt: "Joel Brandenstein & Vanessa Mai",
|
||||
album_type: Single,
|
||||
year: Some(2020),
|
||||
by_va: false,
|
||||
tracks: [
|
||||
TrackItem(
|
||||
id: "XX0epju-YvY",
|
||||
title: "Der Himmel reißt auf",
|
||||
duration: 183,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCXGYZ-OhdOpPBamHX3K9YRg",
|
||||
name: "Joel Brandenstein",
|
||||
),
|
||||
ChannelId(
|
||||
id: "UCFTcSVPYRWlDoHisR-ZKwgw",
|
||||
name: "Vanessa Mai",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Joel Brandenstein & Vanessa Mai"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(1),
|
||||
),
|
||||
],
|
||||
variants: [],
|
||||
)
|
||||
95
tests/snapshots/youtube__music_album_various_artists.snap
Normal file
95
tests/snapshots/youtube__music_album_various_artists.snap
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
---
|
||||
source: tests/youtube.rs
|
||||
expression: album
|
||||
---
|
||||
MusicAlbum(
|
||||
id: "MPREb_8QkDeEIawvX",
|
||||
playlist_id: Some("OLAK5uy_mEX9ljZeeEWgTM1xLL1isyiGaWXoPyoOk"),
|
||||
name: "<Queendom2> FINAL",
|
||||
cover: "[cover]",
|
||||
artists: [],
|
||||
artists_txt: "Various Artists",
|
||||
album_type: Single,
|
||||
year: Some(2022),
|
||||
by_va: true,
|
||||
tracks: [
|
||||
TrackItem(
|
||||
id: "8IqLxg0GqXc",
|
||||
title: "Waka Boom (My Way) (feat. Lee Young Ji)",
|
||||
duration: 274,
|
||||
cover: [],
|
||||
artists: [],
|
||||
artists_txt: Some("HYOLYN"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(1),
|
||||
),
|
||||
TrackItem(
|
||||
id: "9WYpLYAEub0",
|
||||
title: "AURA",
|
||||
duration: 216,
|
||||
cover: [],
|
||||
artists: [],
|
||||
artists_txt: Some("WJSN"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(2),
|
||||
),
|
||||
TrackItem(
|
||||
id: "R48tE237bW4",
|
||||
title: "THE GIRLS (Can’t turn me down)",
|
||||
duration: 239,
|
||||
cover: [],
|
||||
artists: [
|
||||
ChannelId(
|
||||
id: "UCAKvDuIX3m1AUdPpDSqV_3w",
|
||||
name: "Kep1er",
|
||||
),
|
||||
],
|
||||
artists_txt: Some("Kep1er"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(3),
|
||||
),
|
||||
TrackItem(
|
||||
id: "-UzsoR6z-vg",
|
||||
title: "Red Sun!",
|
||||
duration: 254,
|
||||
cover: [],
|
||||
artists: [],
|
||||
artists_txt: Some("VIVIZ"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(4),
|
||||
),
|
||||
TrackItem(
|
||||
id: "kbNVyn8Ex28",
|
||||
title: "POSE",
|
||||
duration: 187,
|
||||
cover: [],
|
||||
artists: [],
|
||||
artists_txt: Some("LOONA"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(5),
|
||||
),
|
||||
TrackItem(
|
||||
id: "NJrQZUzWP5Y",
|
||||
title: "Whistle",
|
||||
duration: 224,
|
||||
cover: [],
|
||||
artists: [],
|
||||
artists_txt: Some("Brave Girls"),
|
||||
album: None,
|
||||
view_count: None,
|
||||
is_video: true,
|
||||
track_nr: Some(6),
|
||||
),
|
||||
],
|
||||
variants: [],
|
||||
)
|
||||
586
tests/youtube.rs
586
tests/youtube.rs
|
|
@ -1,14 +1,16 @@
|
|||
use std::collections::HashSet;
|
||||
use std::fmt::Display;
|
||||
|
||||
use rstest::rstest;
|
||||
use time::macros::date;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
use rustypipe::client::{ClientType, RustyPipe};
|
||||
use rustypipe::client::{ClientType, RustyPipe, RustyPipeQuery};
|
||||
use rustypipe::error::{Error, ExtractionError};
|
||||
use rustypipe::model::richtext::ToPlaintext;
|
||||
use rustypipe::model::{
|
||||
AudioCodec, AudioFormat, Channel, UrlTarget, Verification, VideoCodec, VideoFormat, YouTubeItem,
|
||||
AlbumType, AudioCodec, AudioFormat, Channel, FromYtItem, MusicEntityType, Paginator, UrlTarget,
|
||||
Verification, VideoCodec, VideoFormat, YouTubeItem,
|
||||
};
|
||||
use rustypipe::param::search_filter::{self, SearchFilter};
|
||||
|
||||
|
|
@ -45,7 +47,7 @@ async fn get_player_from_client(#[case] client_type: ClientType) {
|
|||
assert!(!player_data.details.thumbnail.is_empty());
|
||||
assert_eq!(player_data.details.channel.id, "UC_aEa8K-EOJ3D6gOs7HcyNg");
|
||||
assert_eq!(player_data.details.channel.name, "NoCopyrightSounds");
|
||||
assert!(player_data.details.view_count > 146_818_808);
|
||||
assert_gte(player_data.details.view_count, 146_818_808, "view count");
|
||||
assert_eq!(player_data.details.keywords[0], "spektrem");
|
||||
assert_eq!(player_data.details.is_live_content, false);
|
||||
|
||||
|
|
@ -76,7 +78,7 @@ async fn get_player_from_client(#[case] client_type: ClientType) {
|
|||
|
||||
assert_approx(audio.bitrate as f64, 130685.0);
|
||||
assert_approx(audio.average_bitrate as f64, 129496.0);
|
||||
assert_eq!(audio.size, 4193863);
|
||||
assert_approx(audio.size as f64, 4193863.0);
|
||||
assert_eq!(audio.mime, "audio/mp4; codecs=\"mp4a.40.2\"");
|
||||
assert_eq!(audio.format, AudioFormat::M4a);
|
||||
assert_eq!(audio.codec, AudioCodec::Mp4a);
|
||||
|
|
@ -207,12 +209,7 @@ async fn get_player(
|
|||
assert_eq!(details.length, length);
|
||||
assert_eq!(details.channel.id, channel_id);
|
||||
assert_eq!(details.channel.name, channel_name);
|
||||
assert!(
|
||||
details.view_count > views,
|
||||
"expected > {} views, got {}",
|
||||
views,
|
||||
details.view_count
|
||||
);
|
||||
assert_gte(details.view_count, views, "views");
|
||||
assert_eq!(details.is_live, is_live);
|
||||
assert_eq!(details.is_live_content, is_live_content);
|
||||
|
||||
|
|
@ -255,7 +252,7 @@ async fn get_player(
|
|||
_ => {}
|
||||
};
|
||||
|
||||
assert!(player_data.expires_in_seconds > 10000);
|
||||
assert_gte(player_data.expires_in_seconds, 10_000, "expiry time");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -425,22 +422,13 @@ async fn get_video_details() {
|
|||
assert_eq!(details.channel.name, "SMTOWN");
|
||||
assert!(!details.channel.avatar.is_empty(), "no channel avatars");
|
||||
assert_eq!(details.channel.verification, Verification::Verified);
|
||||
assert!(
|
||||
details.channel.subscriber_count.unwrap() > 30000000,
|
||||
"expected >30M subs, got {}",
|
||||
details.channel.subscriber_count.unwrap()
|
||||
);
|
||||
|
||||
assert!(
|
||||
details.view_count > 232000000,
|
||||
"expected > 232M views, got {}",
|
||||
details.view_count
|
||||
);
|
||||
assert!(
|
||||
details.like_count.unwrap() > 4000000,
|
||||
"expected > 4M likes, got {}",
|
||||
details.like_count.unwrap()
|
||||
assert_gte(
|
||||
details.channel.subscriber_count.unwrap(),
|
||||
30_000_000,
|
||||
"subscribers",
|
||||
);
|
||||
assert_gte(details.view_count, 232_000_000, "views");
|
||||
assert_gte(details.like_count.unwrap(), 4_000_000, "likes");
|
||||
|
||||
let date = details.publish_date.unwrap();
|
||||
assert_eq!(date.date(), date!(2020 - 11 - 17));
|
||||
|
|
@ -448,14 +436,9 @@ async fn get_video_details() {
|
|||
assert!(!details.is_live);
|
||||
assert!(!details.is_ccommons);
|
||||
|
||||
assert!(!details.recommended.items.is_empty());
|
||||
assert!(!details.recommended.is_exhausted());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
|
||||
assert!(
|
||||
details.top_comments.count.unwrap() > 700000,
|
||||
"expected > 700K comments, got {}",
|
||||
details.top_comments.count.unwrap()
|
||||
);
|
||||
assert_gte(details.top_comments.count.unwrap(), 700_000, "comments");
|
||||
assert!(!details.top_comments.is_exhausted());
|
||||
assert!(!details.latest_comments.is_exhausted());
|
||||
}
|
||||
|
|
@ -476,22 +459,13 @@ async fn get_video_details_music() {
|
|||
assert_eq!(details.channel.name, "Sentamusic");
|
||||
assert!(!details.channel.avatar.is_empty(), "no channel avatars");
|
||||
assert_eq!(details.channel.verification, Verification::Artist);
|
||||
assert!(
|
||||
details.channel.subscriber_count.unwrap() > 33000,
|
||||
"expected >33K subs, got {}",
|
||||
details.channel.subscriber_count.unwrap()
|
||||
);
|
||||
|
||||
assert!(
|
||||
details.view_count > 20309,
|
||||
"expected > 20309 views, got {}",
|
||||
details.view_count
|
||||
);
|
||||
assert!(
|
||||
details.like_count.unwrap() > 145,
|
||||
"expected > 145 likes, got {}",
|
||||
details.like_count.unwrap()
|
||||
assert_gte(
|
||||
details.channel.subscriber_count.unwrap(),
|
||||
33_000,
|
||||
"subscribers",
|
||||
);
|
||||
assert_gte(details.view_count, 20_309, "views");
|
||||
assert_gte(details.like_count.unwrap(), 145, "likes");
|
||||
|
||||
let date = details.publish_date.unwrap();
|
||||
assert_eq!(date.date(), date!(2020 - 8 - 6));
|
||||
|
|
@ -499,8 +473,7 @@ async fn get_video_details_music() {
|
|||
assert!(!details.is_live);
|
||||
assert!(!details.is_ccommons);
|
||||
|
||||
assert!(!details.recommended.items.is_empty());
|
||||
assert!(!details.recommended.is_exhausted());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
|
||||
// Update(01.11.2022): comments are sometimes enabled
|
||||
/*
|
||||
|
|
@ -534,22 +507,13 @@ async fn get_video_details_ccommons() {
|
|||
assert_eq!(details.channel.name, "media.ccc.de");
|
||||
assert!(!details.channel.avatar.is_empty(), "no channel avatars");
|
||||
assert_eq!(details.channel.verification, Verification::None);
|
||||
assert!(
|
||||
details.channel.subscriber_count.unwrap() > 170000,
|
||||
"expected >170K subs, got {}",
|
||||
details.channel.subscriber_count.unwrap()
|
||||
);
|
||||
|
||||
assert!(
|
||||
details.view_count > 2517358,
|
||||
"expected > 2517358 views, got {}",
|
||||
details.view_count
|
||||
);
|
||||
assert!(
|
||||
details.like_count.unwrap() > 52330,
|
||||
"expected > 52330 likes, got {}",
|
||||
details.like_count.unwrap()
|
||||
assert_gte(
|
||||
details.channel.subscriber_count.unwrap(),
|
||||
170_000,
|
||||
"subscribers",
|
||||
);
|
||||
assert_gte(details.view_count, 2_517_358, "views");
|
||||
assert_gte(details.like_count.unwrap(), 52_330, "likes");
|
||||
|
||||
let date = details.publish_date.unwrap();
|
||||
assert_eq!(date.date(), date!(2019 - 12 - 29));
|
||||
|
|
@ -557,14 +521,9 @@ async fn get_video_details_ccommons() {
|
|||
assert!(!details.is_live);
|
||||
assert!(details.is_ccommons);
|
||||
|
||||
assert!(!details.recommended.items.is_empty());
|
||||
assert!(!details.recommended.is_exhausted());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
|
||||
assert!(
|
||||
details.top_comments.count.unwrap() > 2199,
|
||||
"expected > 2199 comments, got {}",
|
||||
details.top_comments.count.unwrap()
|
||||
);
|
||||
assert_gte(details.top_comments.count.unwrap(), 2199, "comments");
|
||||
assert!(!details.top_comments.is_exhausted());
|
||||
assert!(!details.latest_comments.is_exhausted());
|
||||
}
|
||||
|
|
@ -589,22 +548,13 @@ async fn get_video_details_chapters() {
|
|||
assert_eq!(details.channel.name, "Linus Tech Tips");
|
||||
assert!(!details.channel.avatar.is_empty(), "no channel avatars");
|
||||
assert_eq!(details.channel.verification, Verification::Verified);
|
||||
assert!(
|
||||
details.channel.subscriber_count.unwrap() > 14700000,
|
||||
"expected >14.7M subs, got {}",
|
||||
details.channel.subscriber_count.unwrap()
|
||||
);
|
||||
|
||||
assert!(
|
||||
details.view_count > 1157262,
|
||||
"expected > 1157262 views, got {}",
|
||||
details.view_count
|
||||
);
|
||||
assert!(
|
||||
details.like_count.unwrap() > 54670,
|
||||
"expected > 54670 likes, got {}",
|
||||
details.like_count.unwrap()
|
||||
assert_gte(
|
||||
details.channel.subscriber_count.unwrap(),
|
||||
14_700_000,
|
||||
"subscribers",
|
||||
);
|
||||
assert_gte(details.view_count, 1_157_262, "views");
|
||||
assert_gte(details.like_count.unwrap(), 54_670, "likes");
|
||||
|
||||
let date = details.publish_date.unwrap();
|
||||
assert_eq!(date.date(), date!(2022 - 9 - 15));
|
||||
|
|
@ -695,14 +645,9 @@ async fn get_video_details_chapters() {
|
|||
"###);
|
||||
}
|
||||
|
||||
assert!(!details.recommended.items.is_empty());
|
||||
assert!(!details.recommended.is_exhausted());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
|
||||
assert!(
|
||||
details.top_comments.count.unwrap() > 3199,
|
||||
"expected > 3199 comments, got {}",
|
||||
details.top_comments.count.unwrap()
|
||||
);
|
||||
assert_gte(details.top_comments.count.unwrap(), 3200, "comments");
|
||||
assert!(!details.top_comments.is_exhausted());
|
||||
assert!(!details.latest_comments.is_exhausted());
|
||||
}
|
||||
|
|
@ -730,22 +675,13 @@ async fn get_video_details_live() {
|
|||
assert_eq!(details.channel.name, "Space Videos");
|
||||
assert!(!details.channel.avatar.is_empty(), "no channel avatars");
|
||||
assert_eq!(details.channel.verification, Verification::Verified);
|
||||
assert!(
|
||||
details.channel.subscriber_count.unwrap() > 5500000,
|
||||
"expected >5.5M subs, got {}",
|
||||
details.channel.subscriber_count.unwrap()
|
||||
);
|
||||
|
||||
assert!(
|
||||
details.view_count > 10,
|
||||
"expected > 10 views, got {}",
|
||||
details.view_count
|
||||
);
|
||||
assert!(
|
||||
details.like_count.unwrap() > 872290,
|
||||
"expected > 872290 likes, got {}",
|
||||
details.like_count.unwrap()
|
||||
assert_gte(
|
||||
details.channel.subscriber_count.unwrap(),
|
||||
5_500_000,
|
||||
"subscribers",
|
||||
);
|
||||
assert_gte(details.view_count, 10, "views");
|
||||
assert_gte(details.like_count.unwrap(), 872_290, "likes");
|
||||
|
||||
let date = details.publish_date.unwrap();
|
||||
assert_eq!(date.date(), date!(2021 - 9 - 23));
|
||||
|
|
@ -753,8 +689,7 @@ async fn get_video_details_live() {
|
|||
assert!(details.is_live);
|
||||
assert!(!details.is_ccommons);
|
||||
|
||||
assert!(!details.recommended.items.is_empty());
|
||||
assert!(!details.recommended.is_exhausted());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
|
||||
// No comments because livestream
|
||||
assert_eq!(details.top_comments.count, Some(0));
|
||||
|
|
@ -781,17 +716,12 @@ async fn get_video_details_agegate() {
|
|||
assert_eq!(details.channel.name, "PrinceOfFALLEN");
|
||||
assert!(!details.channel.avatar.is_empty(), "no channel avatars");
|
||||
assert_eq!(details.channel.verification, Verification::None);
|
||||
assert!(
|
||||
details.channel.subscriber_count.unwrap() > 1400,
|
||||
"expected >1400 subs, got {}",
|
||||
details.channel.subscriber_count.unwrap()
|
||||
);
|
||||
|
||||
assert!(
|
||||
details.view_count > 200,
|
||||
"expected > 200 views, got {}",
|
||||
details.view_count
|
||||
assert_gte(
|
||||
details.channel.subscriber_count.unwrap(),
|
||||
1400,
|
||||
"subscribers",
|
||||
);
|
||||
assert_gte(details.view_count, 200, "views");
|
||||
assert!(details.like_count.is_none(), "like count not hidden");
|
||||
|
||||
let date = details.publish_date.unwrap();
|
||||
|
|
@ -820,26 +750,6 @@ async fn get_video_details_not_found() {
|
|||
)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_video_recommendations() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let details = rp.query().video_details("ZeerrnuLi5E").await.unwrap();
|
||||
let next_recommendations = details
|
||||
.recommended
|
||||
.next(&rp.query())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
// dbg!(&next_recommendations);
|
||||
|
||||
assert!(
|
||||
next_recommendations.items.len() > 10,
|
||||
"expected > 10 next recommendations, got {}",
|
||||
next_recommendations.items.len()
|
||||
);
|
||||
assert!(!next_recommendations.is_exhausted());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_video_comments() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
|
|
@ -851,21 +761,17 @@ async fn get_video_comments() {
|
|||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert!(
|
||||
top_comments.items.len() > 10,
|
||||
"expected > 10 next comments, got {}",
|
||||
top_comments.items.len()
|
||||
);
|
||||
assert_gte(top_comments.items.len(), 10, "comments");
|
||||
assert!(!top_comments.is_exhausted());
|
||||
|
||||
let n_comments = top_comments.count.unwrap();
|
||||
assert_gte(n_comments, 700_000, "comments");
|
||||
// Comment count should be exact after fetching first page
|
||||
assert!(
|
||||
n_comments > 700000,
|
||||
"expected > 700k comments, got {}",
|
||||
n_comments % 1000 != 0,
|
||||
"estimated comment count: {}",
|
||||
n_comments
|
||||
);
|
||||
// Comment count should be exact after fetching first page
|
||||
assert!(n_comments % 1000 != 0);
|
||||
|
||||
let latest_comments = details
|
||||
.latest_comments
|
||||
|
|
@ -873,11 +779,7 @@ async fn get_video_comments() {
|
|||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert!(
|
||||
latest_comments.items.len() > 10,
|
||||
"expected > 10 next comments, got {}",
|
||||
latest_comments.items.len()
|
||||
);
|
||||
assert_gte(latest_comments.items.len(), 10, "next comments");
|
||||
assert!(!latest_comments.is_exhausted());
|
||||
}
|
||||
|
||||
|
|
@ -906,11 +808,7 @@ async fn channel_videos() {
|
|||
|
||||
assert!(age_days < 60, "latest video older than 60 days");
|
||||
|
||||
let next = channel.content.next(&rp.query()).await.unwrap().unwrap();
|
||||
assert!(
|
||||
!next.is_exhausted() && !next.items.is_empty(),
|
||||
"no more videos"
|
||||
);
|
||||
assert_next(channel.content, &rp.query(), 15, 2).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -928,11 +826,7 @@ async fn channel_shorts() {
|
|||
// dbg!(&channel);
|
||||
assert_eq!(channel.id, "UCh8gHdtzO2tXd593_bjErWg");
|
||||
assert_eq!(channel.name, "Doobydobap");
|
||||
assert!(
|
||||
channel.subscriber_count.unwrap() > 2800000,
|
||||
"expected >2.8M subscribers, got {}",
|
||||
channel.subscriber_count.unwrap()
|
||||
);
|
||||
assert_gte(channel.subscriber_count.unwrap(), 2_800_000, "subscribers");
|
||||
assert!(!channel.avatar.is_empty(), "got no thumbnails");
|
||||
assert_eq!(channel.verification, Verification::Verified);
|
||||
assert!(channel
|
||||
|
|
@ -951,11 +845,7 @@ async fn channel_shorts() {
|
|||
"got no shorts"
|
||||
);
|
||||
|
||||
let next = channel.content.next(&rp.query()).await.unwrap().unwrap();
|
||||
assert!(
|
||||
!next.is_exhausted() && !next.items.is_empty(),
|
||||
"no more shorts"
|
||||
);
|
||||
assert_next(channel.content, &rp.query(), 15, 1).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -978,8 +868,7 @@ async fn channel_livestreams() {
|
|||
"got no streams"
|
||||
);
|
||||
|
||||
let next = channel.content.next(&rp.query()).await.unwrap().unwrap();
|
||||
assert!(!next.items.is_empty(), "no more streams");
|
||||
assert_next(channel.content, &rp.query(), 5, 1).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -998,11 +887,7 @@ async fn channel_playlists() {
|
|||
"got no playlists"
|
||||
);
|
||||
|
||||
let next = channel.content.next(&rp.query()).await.unwrap().unwrap();
|
||||
assert!(
|
||||
!next.is_exhausted() && !next.items.is_empty(),
|
||||
"no more playlists"
|
||||
);
|
||||
assert_next(channel.content, &rp.query(), 15, 1).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -1020,10 +905,10 @@ async fn channel_info() {
|
|||
let created = channel.content.create_date.unwrap();
|
||||
assert_eq!(created, date!(2009 - 4 - 4));
|
||||
|
||||
assert!(
|
||||
channel.content.view_count.unwrap() > 186854340,
|
||||
"exp >186M views, got {}",
|
||||
channel.content.view_count.unwrap()
|
||||
assert_gte(
|
||||
channel.content.view_count.unwrap(),
|
||||
186854340,
|
||||
"channel views",
|
||||
);
|
||||
|
||||
insta::assert_ron_snapshot!(channel.content.links, @r###"
|
||||
|
|
@ -1048,11 +933,7 @@ async fn channel_info() {
|
|||
fn assert_channel_eevblog<T>(channel: &Channel<T>) {
|
||||
assert_eq!(channel.id, "UC2DjFE7Xf11URZqWBigcVOQ");
|
||||
assert_eq!(channel.name, "EEVblog");
|
||||
assert!(
|
||||
channel.subscriber_count.unwrap() > 880000,
|
||||
"exp >880K subscribers, got {}",
|
||||
channel.subscriber_count.unwrap()
|
||||
);
|
||||
assert_gte(channel.subscriber_count.unwrap(), 880_000, "subscribers");
|
||||
assert!(!channel.avatar.is_empty(), "got no thumbnails");
|
||||
assert_eq!(channel.verification, Verification::Verified);
|
||||
assert_eq!(channel.description, "NO SCRIPT, NO FEAR, ALL OPINION\nAn off-the-cuff Video Blog about Electronics Engineering, for engineers, hobbyists, enthusiasts, hackers and Makers\nHosted by Dave Jones from Sydney Australia\n\nDONATIONS:\nBitcoin: 3KqyH1U3qrMPnkLufM2oHDU7YB4zVZeFyZ\nEthereum: 0x99ccc4d2654ba40744a1f678d9868ecb15e91206\nPayPal: david@alternatezone.com\n\nPatreon: https://www.patreon.com/eevblog\n\nEEVblog2: http://www.youtube.com/EEVblog2\nEEVdiscover: https://www.youtube.com/channel/UCkGvUEt8iQLmq3aJIMjT2qQ\n\nEMAIL:\nAdvertising/Commercial: eevblog+business@gmail.com\nFan mail: eevblog+fan@gmail.com\nHate Mail: eevblog+hate@gmail.com\n\nI DON'T DO PAID VIDEO SPONSORSHIPS, DON'T ASK!\n\nPLEASE:\nDo NOT ask for personal advice on something, post it in the EEVblog forum.\nI read ALL email, but please don't be offended if I don't have time to reply, I get a LOT of email.\n\nMailbag\nPO Box 7949\nBaulkham Hills NSW 2153\nAUSTRALIA");
|
||||
|
|
@ -1191,22 +1072,9 @@ async fn search() {
|
|||
"expected > 7000 total results, got {}",
|
||||
result.items.count.unwrap()
|
||||
);
|
||||
assert!(
|
||||
result.items.items.len() > 10,
|
||||
"expected > 10 search results, got {}",
|
||||
result.items.items.len()
|
||||
);
|
||||
assert!(!result.items.is_exhausted());
|
||||
|
||||
assert_eq!(result.corrected_query.unwrap(), "doobydobap");
|
||||
|
||||
let next = result.items.next(&rp.query()).await.unwrap().unwrap();
|
||||
assert!(
|
||||
next.items.len() > 10,
|
||||
"expected > 10 continuation results, got {}",
|
||||
next.items.len()
|
||||
);
|
||||
assert!(!next.is_exhausted());
|
||||
assert_next(result.items, &rp.query(), 10, 2).await;
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -1216,18 +1084,14 @@ async fn search() {
|
|||
#[tokio::test]
|
||||
async fn search_filter_entity(#[case] entity: search_filter::Entity) {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let result = rp
|
||||
let mut result = rp
|
||||
.query()
|
||||
.search_filter("music", &SearchFilter::new().entity(entity))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
result.items.items.len() > 10,
|
||||
"expected > 10 search results, got {}",
|
||||
result.items.items.len()
|
||||
);
|
||||
assert!(!result.items.is_exhausted());
|
||||
result.items.extend(&rp.query()).await.unwrap();
|
||||
assert_gte(result.items.items.len(), 20, "items");
|
||||
|
||||
result.items.items.iter().for_each(|item| match item {
|
||||
YouTubeItem::Video(_) => {
|
||||
|
|
@ -1343,30 +1207,10 @@ async fn resolve_channel_not_found() {
|
|||
|
||||
#[tokio::test]
|
||||
async fn startpage() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let result = rp.query().startpage().await.unwrap();
|
||||
|
||||
assert!(
|
||||
result.items.len() >= 20,
|
||||
"expected >= 20 items, got {}",
|
||||
result.items.len()
|
||||
);
|
||||
assert!(!result.is_exhausted());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn startpage_cont() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let startpage = rp.query().startpage().await.unwrap();
|
||||
|
||||
let next = startpage.next(&rp.query()).await.unwrap().unwrap();
|
||||
|
||||
assert!(
|
||||
next.items.len() >= 20,
|
||||
"expected >= 20 items, got {}",
|
||||
next.items.len()
|
||||
);
|
||||
assert!(!next.is_exhausted());
|
||||
assert_next(startpage, &rp.query(), 20, 2).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -1374,11 +1218,7 @@ async fn trending() {
|
|||
let rp = RustyPipe::builder().strict().build();
|
||||
let result = rp.query().trending().await.unwrap();
|
||||
|
||||
assert!(
|
||||
result.len() >= 50,
|
||||
"expected >= 50 items, got {}",
|
||||
result.len()
|
||||
);
|
||||
assert_gte(result.len(), 50, "items");
|
||||
}
|
||||
|
||||
//#MUSIC
|
||||
|
|
@ -1474,6 +1314,263 @@ async fn music_playlist_not_found() {
|
|||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::one_artist("one_artist", "MPREb_nlBWQROfvjo")]
|
||||
#[case::various_artists("various_artists", "MPREb_8QkDeEIawvX")]
|
||||
#[case::single("single", "MPREb_bHfHGoy7vuv")]
|
||||
#[case::ep("ep", "MPREb_u1I69lSAe5v")]
|
||||
#[case::audiobook("audiobook", "MPREb_gaoNzsQHedo")]
|
||||
#[case::show("show", "MPREb_cwzk8EUwypZ")]
|
||||
#[tokio::test]
|
||||
async fn music_album(#[case] name: &str, #[case] id: &str) {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let album = rp.query().music_album(id).await.unwrap();
|
||||
|
||||
assert!(!album.cover.is_empty(), "got no cover");
|
||||
|
||||
insta::assert_ron_snapshot!(format!("music_album_{}", name), album,
|
||||
{".cover" => "[cover]"}
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn music_album_not_found() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let err = rp
|
||||
.query()
|
||||
.music_album("MPREb_nlBWQROfvjoz")
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
err,
|
||||
Error::Extraction(ExtractionError::ContentUnavailable(_))
|
||||
),
|
||||
"got: {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::default(false)]
|
||||
#[case::typo(true)]
|
||||
#[tokio::test]
|
||||
async fn music_search(#[case] typo: bool) {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let res = rp
|
||||
.query()
|
||||
.music_search(match typo {
|
||||
false => "black mamba",
|
||||
true => "blck mamba",
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(!res.tracks.is_empty(), "no tracks");
|
||||
assert!(!res.albums.is_empty(), "no albums");
|
||||
assert!(!res.artists.is_empty(), "no artists");
|
||||
assert!(!res.playlists.is_empty(), "no playlists");
|
||||
assert_eq!(res.order[0], MusicEntityType::Track);
|
||||
|
||||
if typo {
|
||||
assert_eq!(res.corrected_query.unwrap(), "black mamba");
|
||||
} else {
|
||||
assert_eq!(res.corrected_query, None);
|
||||
}
|
||||
|
||||
let track = &res.tracks[0];
|
||||
dbg!(&track);
|
||||
assert_eq!(track.id, "ZeerrnuLi5E");
|
||||
assert_eq!(track.title, "Black Mamba");
|
||||
assert_eq!(track.duration, 230);
|
||||
assert!(!track.cover.is_empty(), "got no cover");
|
||||
|
||||
let track_artist = &track.artists[0];
|
||||
assert_eq!(track_artist.id, "UCEdZAdnnKqbaHOlv8nM6OtA");
|
||||
assert_eq!(track_artist.name, "aespa");
|
||||
assert_eq!(track.artists_txt.as_ref().unwrap(), "aespa");
|
||||
assert_eq!(track.album, None);
|
||||
assert_gte(track.view_count.unwrap(), 230_000_000, "views");
|
||||
assert!(track.is_video, "got no video");
|
||||
assert_eq!(track.track_nr, None);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::tracks(false)]
|
||||
#[case::videos(true)]
|
||||
#[tokio::test]
|
||||
async fn music_search_tracks(#[case] videos: bool) {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let res = rp
|
||||
.query()
|
||||
.music_search_tracks("black mamba", videos)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let track = &res.items.items[0];
|
||||
assert_eq!(track.title, "Black Mamba");
|
||||
assert!(!track.cover.is_empty(), "got no cover");
|
||||
assert_eq!(track.is_video, videos);
|
||||
assert_eq!(track.track_nr, None);
|
||||
|
||||
let track_artist = &track.artists[0];
|
||||
assert_eq!(track_artist.id, "UCEdZAdnnKqbaHOlv8nM6OtA");
|
||||
assert_eq!(track_artist.name, "aespa");
|
||||
assert_eq!(track.artists_txt.as_ref().unwrap(), "aespa");
|
||||
|
||||
if videos {
|
||||
assert_eq!(track.id, "ZeerrnuLi5E");
|
||||
assert_eq!(track.duration, 230);
|
||||
assert_eq!(track.album, None);
|
||||
assert_gte(track.view_count.unwrap(), 230_000_000, "views");
|
||||
} else {
|
||||
assert_eq!(track.id, "BL-aIpCLWnU");
|
||||
assert_eq!(track.duration, 175);
|
||||
|
||||
let album = track.album.as_ref().unwrap();
|
||||
assert_eq!(album.id, "MPREb_OpHWHwyNOuY");
|
||||
assert_eq!(album.name, "Black Mamba");
|
||||
}
|
||||
|
||||
assert_next(res.items, &rp.query(), 15, 2).await;
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::single(
|
||||
"black mamba",
|
||||
"Black Mamba",
|
||||
"MPREb_OpHWHwyNOuY",
|
||||
"aespa",
|
||||
"UCEdZAdnnKqbaHOlv8nM6OtA",
|
||||
2020,
|
||||
AlbumType::Single,
|
||||
2
|
||||
)]
|
||||
#[case::ep(
|
||||
"waldbrand",
|
||||
"Waldbrand",
|
||||
"MPREb_u1I69lSAe5v",
|
||||
"Madeline Juno",
|
||||
"UCpJyCbFbdTrx0M90HCNBHFQ",
|
||||
2016,
|
||||
AlbumType::Ep,
|
||||
1
|
||||
)]
|
||||
#[case::album(
|
||||
"märchen enden gut",
|
||||
"Märchen enden gut",
|
||||
"MPREb_nlBWQROfvjo",
|
||||
"Oonagh",
|
||||
"UC_vmjW5e1xEHhYjY2a0kK1A",
|
||||
2016,
|
||||
AlbumType::Album,
|
||||
1
|
||||
)]
|
||||
#[tokio::test]
|
||||
async fn music_search_albums(
|
||||
#[case] query: &str,
|
||||
#[case] name: &str,
|
||||
#[case] id: &str,
|
||||
#[case] artist: &str,
|
||||
#[case] artist_id: &str,
|
||||
#[case] year: u16,
|
||||
#[case] album_type: AlbumType,
|
||||
#[case] n_pages: usize,
|
||||
) {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let res = rp.query().music_search_albums(query).await.unwrap();
|
||||
|
||||
let album = &res.items.items[0];
|
||||
assert_eq!(album.name, name);
|
||||
assert_eq!(album.id, id);
|
||||
assert_eq!(album.artists_txt, artist);
|
||||
|
||||
let album_artist = &album.artists[0];
|
||||
assert_eq!(album_artist.id, artist_id);
|
||||
assert_eq!(album_artist.name, artist);
|
||||
|
||||
assert!(!album.cover.is_empty(), "got no cover");
|
||||
assert_eq!(album.year.as_ref().unwrap(), &year);
|
||||
assert_eq!(album.album_type, album_type);
|
||||
|
||||
assert_eq!(res.corrected_query, None);
|
||||
|
||||
assert_next(res.items, &rp.query(), 15, n_pages).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn music_search_artists() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let res = rp.query().music_search_artists("namika").await.unwrap();
|
||||
|
||||
let artist = &res.items.items[0];
|
||||
assert_eq!(artist.id, "UCIh4j8fXWf2U0ro0qnGU8Mg");
|
||||
assert_eq!(artist.name, "Namika");
|
||||
assert!(!artist.avatar.is_empty(), "got no avatar");
|
||||
assert!(
|
||||
artist.subscriber_count.unwrap() > 735_000,
|
||||
"expected >735K subscribers, got {}",
|
||||
artist.subscriber_count.unwrap()
|
||||
);
|
||||
assert_eq!(res.corrected_query, None);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn music_search_artists_cont() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let res = rp.query().music_search_artists("band").await.unwrap();
|
||||
|
||||
assert_eq!(res.corrected_query, None);
|
||||
assert_next(res.items, &rp.query(), 15, 2).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn music_search_playlists() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let res = rp
|
||||
.query()
|
||||
.music_search_playlists("easy pop", false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(res.corrected_query, None);
|
||||
let playlist = &res.items.items[0];
|
||||
|
||||
assert_eq!(playlist.id, "RDCLAK5uy_kFQXdnqMaQCVx2wpUM4ZfbsGCDibZtkJk");
|
||||
assert_eq!(playlist.name, "Easy Pop");
|
||||
assert!(!playlist.thumbnail.is_empty(), "got no thumbnail");
|
||||
assert_gte(playlist.track_count.unwrap(), 80, "tracks");
|
||||
assert_eq!(playlist.channel, None);
|
||||
assert!(playlist.from_ytm);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn music_search_playlists_community() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let res = rp
|
||||
.query()
|
||||
.music_search_playlists("Best Pop Music Videos - Top Pop Hits Playlist", true)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(res.corrected_query, None);
|
||||
let playlist = &res.items.items[0];
|
||||
|
||||
assert_eq!(playlist.id, "PLMC9KNkIncKtGvr2kFRuXBVmBev6cAJ2u");
|
||||
assert_eq!(
|
||||
playlist.name,
|
||||
"Best Pop Music Videos - Top Pop Hits Playlist"
|
||||
);
|
||||
assert!(!playlist.thumbnail.is_empty(), "got no thumbnail");
|
||||
assert_gte(playlist.track_count.unwrap(), 250, "tracks");
|
||||
|
||||
let channel = playlist.channel.as_ref().unwrap();
|
||||
assert_eq!(channel.id, "UCs72iRpTEuwV3y6pdWYLgiw");
|
||||
assert_eq!(channel.name, "Redlist - Just Hits");
|
||||
assert!(!playlist.from_ytm);
|
||||
}
|
||||
|
||||
//#TESTUTIL
|
||||
|
||||
/// Assert equality within 10% margin
|
||||
|
|
@ -1488,3 +1585,26 @@ fn assert_approx(left: f64, right: f64) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_gte<T: PartialOrd + Display>(a: T, b: T, msg: &str) {
|
||||
assert!(a >= b, "expected {} {}, got {}", b, msg, a);
|
||||
}
|
||||
|
||||
async fn assert_next<T: FromYtItem>(
|
||||
paginator: Paginator<T>,
|
||||
query: &RustyPipeQuery,
|
||||
min_items: usize,
|
||||
n_pages: usize,
|
||||
) {
|
||||
let mut p = paginator;
|
||||
assert_gte(p.items.len(), min_items, "items on page 0");
|
||||
|
||||
for i in 0..n_pages {
|
||||
p = p.next(query).await.unwrap().expect("paginator exhausted");
|
||||
assert_gte(
|
||||
p.items.len(),
|
||||
min_items,
|
||||
&format!("items on page {}", i + 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Reference in a new issue