Compare commits

..

5 commits

Author SHA1 Message Date
bb4c92c70b
ci: upload test reports
Some checks failed
CI / Test (push) Failing after 1m56s
2024-06-16 02:23:22 +02:00
da1d1bd2a0
feat: make get_visitor_data() public 2024-06-16 02:18:04 +02:00
27b1cd1aa7
test: fix tests 2024-06-16 00:21:25 +02:00
74946f9ea0
test: fix tests 2024-06-14 17:58:07 +02:00
e75ffbb5da
chore: vscode: enable rss feature by default 2024-06-14 16:16:05 +02:00
14 changed files with 589 additions and 461 deletions

View file

@ -10,8 +10,6 @@ jobs:
steps: steps:
- name: 📦 Checkout repository - name: 📦 Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🦀 Setup Rust cache - name: 🦀 Setup Rust cache
uses: https://github.com/Swatinem/rust-cache@v2 uses: https://github.com/Swatinem/rust-cache@v2
@ -22,4 +20,13 @@ jobs:
run: cargo clippy --all --features=rss -- -D warnings run: cargo clippy --all --features=rss -- -D warnings
- name: 🧪 Test - name: 🧪 Test
run: cargo test --features=rss --workspace run: cargo nextest run --config-file ~/.config/nextest.toml --profile ci --features rss --workspace
- name: 💌 Upload test report
if: always()
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
with:
name: test
path: |
target/nextest/ci/junit.xml
rustypipe_reports/*

3
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"rust-analyzer.cargo.features": ["rss"]
}

View file

@ -1,14 +1,15 @@
test: test:
cargo test --features=rss # cargo test --features=rss
cargo nextest run --features=rss --no-fail-fast --failure-output final
unittest: unittest:
cargo test --features=rss --lib cargo nextest run --features=rss --no-fail-fast --failure-output final --lib
testyt: testyt:
cargo test --features=rss --test youtube cargo nextest run --features=rss --no-fail-fast --failure-output final --test youtube
testyt-localized: testyt-localized:
YT_LANG=th cargo test --features=rss --test youtube YT_LANG=th cargo nextest run --features=rss --no-fail-fast --failure-output final --test youtube
testintl: testintl:
#!/usr/bin/env bash #!/usr/bin/env bash

View file

@ -79,7 +79,6 @@ pub async fn run_test(
let rp = RustyPipe::new(); let rp = RustyPipe::new();
let pb = ProgressBar::new(n as u64); let pb = ProgressBar::new(n as u64);
let http = reqwest::Client::default();
pb.set_style( pb.set_style(
ProgressStyle::with_template( ProgressStyle::with_template(
"{msg} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len}", "{msg} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len}",
@ -91,9 +90,8 @@ pub async fn run_test(
.map(|_| { .map(|_| {
let rp = rp.clone(); let rp = rp.clone();
let pb = pb.clone(); let pb = pb.clone();
let http = http.clone();
async move { async move {
let visitor_data = get_visitor_data(&http).await; let visitor_data = rp.query().get_visitor_data().await.unwrap();
let query = rp.query().visitor_data(&visitor_data); let query = rp.query().visitor_data(&visitor_data);
let is_present = match ab { let is_present = match ab {
ABTest::AttributedTextDescription => attributed_text_description(&query).await, ABTest::AttributedTextDescription => attributed_text_description(&query).await,
@ -133,22 +131,6 @@ pub async fn run_test(
(count, vd_present, vd_absent) (count, vd_present, vd_absent)
} }
async fn get_visitor_data(http: &reqwest::Client) -> String {
let resp = http.get("https://www.youtube.com").send().await.unwrap();
resp.headers()
.get_all(reqwest::header::SET_COOKIE)
.iter()
.find_map(|c| {
if let Ok(cookie) = c.to_str() {
if let Some(after) = cookie.strip_prefix("__Secure-YEC=") {
return after.split_once(';').map(|s| s.0.to_owned());
}
}
None
})
.unwrap()
}
pub async fn run_all_tests(n: usize, concurrency: usize) -> Vec<ABTestRes> { pub async fn run_all_tests(n: usize, concurrency: usize) -> Vec<ABTestRes> {
let mut results = Vec::new(); let mut results = Vec::new();

View file

@ -26,6 +26,7 @@ to the new feature.
**Status:** **Status:**
- Discontinued (0%)
- Experimental (<3%) - Experimental (<3%)
- Common (>3%) - Common (>3%)
- Frequent (>40%) - Frequent (>40%)
@ -488,7 +489,7 @@ looks needlessly complex but contains the same parsing-relevant data as the old
- **Encountered on:** 29.01.2024 - **Encountered on:** 29.01.2024
- **Impact:** 🟢 Low - **Impact:** 🟢 Low
- **Endpoint:** browse - **Endpoint:** browse
- **Status:** Experimental (<1%) - **Status:** Frequent (55%)
YouTube introduced a new data model for channel headers, based on a YouTube introduced a new data model for channel headers, based on a
`"pageHeaderRenderer"`. The new model comes with more needless complexity that needs to `"pageHeaderRenderer"`. The new model comes with more needless complexity that needs to
@ -597,7 +598,7 @@ be accomodated. There are also no mobile/TV header images available any more.
- **Encountered on:** 29.02.2024 - **Encountered on:** 29.02.2024
- **Impact:** 🟢 Low - **Impact:** 🟢 Low
- **Endpoint:** browse - **Endpoint:** browse
- **Status:** Common (6%) - **Status:** Discontinued (0%)
![A/B test 13 screenshot](./_img/ab_13.png) ![A/B test 13 screenshot](./_img/ab_13.png)
@ -609,7 +610,7 @@ cover on the left side of the playlist content.
- **Encountered on:** 31.01.2024 - **Encountered on:** 31.01.2024
- **Impact:** 🟢 Low - **Impact:** 🟢 Low
- **Endpoint:** next - **Endpoint:** next
- **Status:** Common (50%) - **Status:** Frequent (98%)
YouTube changed the data model for YouTube comments, now putting the content into a YouTube changed the data model for YouTube comments, now putting the content into a
seperate framework update object seperate framework update object

View file

@ -1259,7 +1259,7 @@ impl RustyPipeQuery {
} }
/// Get a YouTube visitor data cookie, which is necessary for certain requests /// Get a YouTube visitor data cookie, which is necessary for certain requests
async fn get_visitor_data(&self) -> Result<String, Error> { pub async fn get_visitor_data(&self) -> Result<String, Error> {
match &self.opts.visitor_data { match &self.opts.visitor_data {
Some(vd) => Ok(vd.clone()), Some(vd) => Ok(vd.clone()),
None => self.client.get_visitor_data().await, None => self.client.get_visitor_data().await,

View file

@ -3,32 +3,36 @@ source: tests/youtube.rs
expression: album expression: album
--- ---
MusicAlbum( MusicAlbum(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
playlist_id: Some("OLAK5uy_mUiRbMqeQXFUH6h9KB87RcEmNtm45Qvs0"), playlist_id: Some("OLAK5uy_l4sJyKllp77ht_HPYCUFo-sA6N8fNFNsY"),
name: "Pedha Rasi Peddamma Katha", name: "June Compilation",
cover: "[cover]", cover: "[cover]",
artists: [], artists: [],
artist_id: None, artist_id: None,
description: None, description: None,
album_type: Ep, album_type: Album,
year: Some(1968), year: Some(2024),
by_va: false, by_va: true,
tracks: [ tracks: [
TrackItem( TrackItem(
id: "EX7-pOQHPyE", id: "ilNEztApdjI",
name: "Siva Manoranjani", name: "Shanghai",
duration: Some(267), duration: Some(259),
cover: [], cover: [],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UC1C05NyYICFB2mVGn9_ttEw"), id: Some("UC9MB9dkvCCpM3qVF71TZL7g"),
name: "Dr. M. Balamuralikrishna", name: "Crubbixz",
),
ArtistId(
id: Some("UCMYTb0sib5ppwQL9FAGmYTw"),
name: "Tank",
), ),
], ],
artist_id: Some("UC1C05NyYICFB2mVGn9_ttEw"), artist_id: Some("UC9MB9dkvCCpM3qVF71TZL7g"),
album: Some(AlbumId( album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
name: "Pedha Rasi Peddamma Katha", name: "June Compilation",
)), )),
view_count: "[view_count]", view_count: "[view_count]",
is_video: false, is_video: false,
@ -36,20 +40,20 @@ MusicAlbum(
by_va: false, by_va: false,
), ),
TrackItem( TrackItem(
id: "0AyWB-Quj4A", id: "s-qSnZyyvzs",
name: "Kuluku Nadakula", name: "Always Be With UExtended Mix",
duration: Some(179), duration: Some(165),
cover: [], cover: [],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UCDqpyYkgWy2h03HamIfODjw"), id: Some("UCpAZ1Ap_nuAEk9RiT-nUsWQ"),
name: "Ghantasala, Chorus", name: "陈海择HeizerChan",
), ),
], ],
artist_id: Some("UCDqpyYkgWy2h03HamIfODjw"), artist_id: Some("UCpAZ1Ap_nuAEk9RiT-nUsWQ"),
album: Some(AlbumId( album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
name: "Pedha Rasi Peddamma Katha", name: "June Compilation",
)), )),
view_count: "[view_count]", view_count: "[view_count]",
is_video: false, is_video: false,
@ -57,20 +61,20 @@ MusicAlbum(
by_va: false, by_va: false,
), ),
TrackItem( TrackItem(
id: "s0Sb-GZLXSM", id: "4jXoRBcQ8PY",
name: "Gulabi Buggalunna", name: "Elude (Extended Mix)",
duration: Some(155), duration: Some(329),
cover: [], cover: [],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UC_KQPMiRQl3CFAIKTVfCHwA"), id: None,
name: "L.r. Eswari", name: "Julius Beat & SinDj",
), ),
], ],
artist_id: Some("UC_KQPMiRQl3CFAIKTVfCHwA"), artist_id: Some("UCCRiYE0dTFA_pc23-97GfSg"),
album: Some(AlbumId( album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
name: "Pedha Rasi Peddamma Katha", name: "June Compilation",
)), )),
view_count: "[view_count]", view_count: "[view_count]",
is_video: false, is_video: false,
@ -78,57 +82,252 @@ MusicAlbum(
by_va: false, by_va: false,
), ),
TrackItem( TrackItem(
id: "P4XAaXjlCDA", id: "DRES9S4VQI8",
name: "Oh Javaraala", name: "Venus (Extended Mix)",
duration: Some(229), duration: Some(202),
cover: [], cover: [],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"), id: Some("UC_y8p7fi6t3z10R2UEMQG_A"),
name: "S.p. Balasubrahmanyam, S. Janaki", name: "Andymion",
), ),
], ],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"), artist_id: Some("UC_y8p7fi6t3z10R2UEMQG_A"),
album: Some(AlbumId( album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
name: "Pedha Rasi Peddamma Katha", name: "June Compilation",
)), )),
view_count: "[view_count]", view_count: "[view_count]",
is_video: false, is_video: false,
track_nr: Some(4), track_nr: Some(4),
by_va: false, by_va: false,
), ),
], TrackItem(
variants: [ id: "yhZVimwD4B4",
AlbumItem( name: "Arise",
id: "MPREb_h8ltx5oKvyY", duration: Some(213),
name: "Pedha Rasi Peddamma Katha", cover: [],
cover: [
Thumbnail(
url: "https://lh3.googleusercontent.com/iZtBdPWBGNB-GAWvOp9seuYj5QqKrUYGSe-B5J026yxHqFSWv4zsxHy-LxX5LbFlnepOPRWNLrajO-_-=w226-h226-l90-rj",
width: 226,
height: 226,
),
Thumbnail(
url: "https://lh3.googleusercontent.com/iZtBdPWBGNB-GAWvOp9seuYj5QqKrUYGSe-B5J026yxHqFSWv4zsxHy-LxX5LbFlnepOPRWNLrajO-_-=w544-h544-l90-rj",
width: 544,
height: 544,
),
],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"), id: Some("UCYAzELapKjDUHMGRbzjJtgw"),
name: "S P Balasubramaniam", name: "Takahiro Yoshihira",
), ),
ArtistId( ArtistId(
id: Some("UCWgAqlYG7mXTUxrFiLyDSsg"), id: Some("UCN2Ji-D6Tzn5CTC7iCWoX8w"),
name: "S Janaki", name: "TOMI-NORI",
), ),
], ],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"), artist_id: Some("UCYAzELapKjDUHMGRbzjJtgw"),
album_type: Ep, album: Some(AlbumId(
year: None, id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(5),
by_va: false,
),
TrackItem(
id: "5d6YiFkdzLM",
name: "Acid Rave (Extended Mix)",
duration: Some(191),
cover: [],
artists: [
ArtistId(
id: Some("UCFqaoKXGfCsd9VRQNXzhIjQ"),
name: "SteelDrum",
),
],
artist_id: Some("UCFqaoKXGfCsd9VRQNXzhIjQ"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(6),
by_va: false,
),
TrackItem(
id: "3Qe7-uN2PjU",
name: "Destiny (Extended Mix)",
duration: Some(446),
cover: [],
artists: [
ArtistId(
id: Some("UCjqRwXhXgFW7RDDPn_TlAbw"),
name: "Tyranix",
),
ArtistId(
id: Some("UCy69bQ95ovXIquWzY5jfAIA"),
name: "Jawzcirclesix",
),
],
artist_id: Some("UCjqRwXhXgFW7RDDPn_TlAbw"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(7),
by_va: false,
),
TrackItem(
id: "SKZ_MTsXFP4",
name: "Darksiders (Extended Mix)",
duration: Some(376),
cover: [],
artists: [
ArtistId(
id: Some("UCEUUFTUZpm1MmANCfLN5_9Q"),
name: "Kruky",
),
],
artist_id: Some("UCEUUFTUZpm1MmANCfLN5_9Q"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(8),
by_va: false,
),
TrackItem(
id: "n5-ujUwazDA",
name: "Mind Game (Extended Mix)",
duration: Some(335),
cover: [],
artists: [
ArtistId(
id: Some("UCxByvsK9hDZk2MnnF9jsFGw"),
name: "Herbrido",
),
],
artist_id: Some("UCxByvsK9hDZk2MnnF9jsFGw"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(9),
by_va: false,
),
TrackItem(
id: "VaREivfDJeY",
name: "Caronte (Extended Mix)",
duration: Some(268),
cover: [],
artists: [
ArtistId(
id: Some("UCG2o9g3Yl6jBL21_z7XBMVw"),
name: "Foodydrop",
),
],
artist_id: Some("UCG2o9g3Yl6jBL21_z7XBMVw"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(10),
by_va: false,
),
TrackItem(
id: "cWcD0WIK2PA",
name: "Left Right Go (Extended Mix)",
duration: Some(198),
cover: [],
artists: [
ArtistId(
id: Some("UCiIDz3M3cDn2QeYjLbhIdBQ"),
name: "Fly飞",
),
ArtistId(
id: Some("UChLPGmjYa8bmKShqMBFP_DA"),
name: "MARSJONE 鸡万",
),
],
artist_id: Some("UCiIDz3M3cDn2QeYjLbhIdBQ"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(11),
by_va: false,
),
TrackItem(
id: "QRELvH564T4",
name: "Terminal Zero (Extended Mix)",
duration: Some(325),
cover: [],
artists: [
ArtistId(
id: Some("UCbiVmjdLA5PKZcUnZMExqCA"),
name: "Reivax",
),
],
artist_id: Some("UCbiVmjdLA5PKZcUnZMExqCA"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(12),
by_va: false,
),
TrackItem(
id: "eCY0-GyG46s",
name: "The Unknown (Extended Mix)",
duration: Some(198),
cover: [],
artists: [
ArtistId(
id: Some("UC-thVg_PSz894f5mVqMFMeQ"),
name: "Elia Akita",
),
],
artist_id: Some("UC-thVg_PSz894f5mVqMFMeQ"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(13),
by_va: false,
),
TrackItem(
id: "UIrHYTEyUfA",
name: "This is Acid (Extended Mix)",
duration: Some(213),
cover: [],
artists: [
ArtistId(
id: Some("UC2pJL-Kp6yJtARS8MC0N8Ag"),
name: "Monored",
),
ArtistId(
id: Some("UCpmZakvqLLUZ4G_YkKjoy6g"),
name: "Egemen Kızıltekin",
),
],
artist_id: Some("UC2pJL-Kp6yJtARS8MC0N8Ag"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "June Compilation",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(14),
by_va: false, by_va: false,
), ),
], ],
variants: [],
) )

View file

@ -3,31 +3,35 @@ source: tests/youtube.rs
expression: album expression: album
--- ---
MusicAlbum( MusicAlbum(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
playlist_id: Some("OLAK5uy_mUiRbMqeQXFUH6h9KB87RcEmNtm45Qvs0"), playlist_id: Some("OLAK5uy_l4sJyKllp77ht_HPYCUFo-sA6N8fNFNsY"),
name: "[name]", name: "[name]",
cover: "[cover]", cover: "[cover]",
artists: [], artists: [],
artist_id: None, artist_id: None,
description: "[description]", description: "[description]",
album_type: Ep, album_type: Album,
year: Some(1968), year: Some(2024),
by_va: false, by_va: true,
tracks: [ tracks: [
TrackItem( TrackItem(
id: "EX7-pOQHPyE", id: "ilNEztApdjI",
name: "[name]", name: "[name]",
duration: Some(267), duration: Some(259),
cover: [], cover: [],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UC1C05NyYICFB2mVGn9_ttEw"), id: Some("UC9MB9dkvCCpM3qVF71TZL7g"),
name: "[name]",
),
ArtistId(
id: Some("UCMYTb0sib5ppwQL9FAGmYTw"),
name: "[name]", name: "[name]",
), ),
], ],
artist_id: Some("UC1C05NyYICFB2mVGn9_ttEw"), artist_id: Some("UC9MB9dkvCCpM3qVF71TZL7g"),
album: Some(AlbumId( album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
name: "[name]", name: "[name]",
)), )),
view_count: "[view_count]", view_count: "[view_count]",
@ -36,19 +40,19 @@ MusicAlbum(
by_va: false, by_va: false,
), ),
TrackItem( TrackItem(
id: "0AyWB-Quj4A", id: "s-qSnZyyvzs",
name: "[name]", name: "[name]",
duration: Some(179), duration: Some(165),
cover: [], cover: [],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UCDqpyYkgWy2h03HamIfODjw"), id: Some("UCpAZ1Ap_nuAEk9RiT-nUsWQ"),
name: "[name]", name: "[name]",
), ),
], ],
artist_id: Some("UCDqpyYkgWy2h03HamIfODjw"), artist_id: Some("UCpAZ1Ap_nuAEk9RiT-nUsWQ"),
album: Some(AlbumId( album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
name: "[name]", name: "[name]",
)), )),
view_count: "[view_count]", view_count: "[view_count]",
@ -57,19 +61,19 @@ MusicAlbum(
by_va: false, by_va: false,
), ),
TrackItem( TrackItem(
id: "s0Sb-GZLXSM", id: "4jXoRBcQ8PY",
name: "[name]", name: "[name]",
duration: Some(155), duration: Some(329),
cover: [], cover: [],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UC_KQPMiRQl3CFAIKTVfCHwA"), id: None,
name: "[name]", name: "[name]",
), ),
], ],
artist_id: Some("UC_KQPMiRQl3CFAIKTVfCHwA"), artist_id: Some("UCCRiYE0dTFA_pc23-97GfSg"),
album: Some(AlbumId( album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
name: "[name]", name: "[name]",
)), )),
view_count: "[view_count]", view_count: "[view_count]",
@ -78,19 +82,19 @@ MusicAlbum(
by_va: false, by_va: false,
), ),
TrackItem( TrackItem(
id: "P4XAaXjlCDA", id: "DRES9S4VQI8",
name: "[name]", name: "[name]",
duration: Some(229), duration: Some(202),
cover: [], cover: [],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"), id: Some("UC_y8p7fi6t3z10R2UEMQG_A"),
name: "[name]", name: "[name]",
), ),
], ],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"), artist_id: Some("UC_y8p7fi6t3z10R2UEMQG_A"),
album: Some(AlbumId( album: Some(AlbumId(
id: "MPREb_bqWA6mAZFWS", id: "MPREb_Z81wHtF9fhC",
name: "[name]", name: "[name]",
)), )),
view_count: "[view_count]", view_count: "[view_count]",
@ -98,37 +102,232 @@ MusicAlbum(
track_nr: Some(4), track_nr: Some(4),
by_va: false, by_va: false,
), ),
], TrackItem(
variants: [ id: "yhZVimwD4B4",
AlbumItem( name: "[name]",
id: "MPREb_h8ltx5oKvyY", duration: Some(213),
name: "Pedha Rasi Peddamma Katha", cover: [],
cover: [
Thumbnail(
url: "https://lh3.googleusercontent.com/iZtBdPWBGNB-GAWvOp9seuYj5QqKrUYGSe-B5J026yxHqFSWv4zsxHy-LxX5LbFlnepOPRWNLrajO-_-=w226-h226-l90-rj",
width: 226,
height: 226,
),
Thumbnail(
url: "https://lh3.googleusercontent.com/iZtBdPWBGNB-GAWvOp9seuYj5QqKrUYGSe-B5J026yxHqFSWv4zsxHy-LxX5LbFlnepOPRWNLrajO-_-=w544-h544-l90-rj",
width: 544,
height: 544,
),
],
artists: [ artists: [
ArtistId( ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"), id: Some("UCYAzELapKjDUHMGRbzjJtgw"),
name: "[name]", name: "[name]",
), ),
ArtistId( ArtistId(
id: Some("UCWgAqlYG7mXTUxrFiLyDSsg"), id: Some("UCN2Ji-D6Tzn5CTC7iCWoX8w"),
name: "[name]", name: "[name]",
), ),
], ],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"), artist_id: Some("UCYAzELapKjDUHMGRbzjJtgw"),
album_type: Ep, album: Some(AlbumId(
year: None, id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(5),
by_va: false,
),
TrackItem(
id: "5d6YiFkdzLM",
name: "[name]",
duration: Some(191),
cover: [],
artists: [
ArtistId(
id: Some("UCFqaoKXGfCsd9VRQNXzhIjQ"),
name: "[name]",
),
],
artist_id: Some("UCFqaoKXGfCsd9VRQNXzhIjQ"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(6),
by_va: false,
),
TrackItem(
id: "3Qe7-uN2PjU",
name: "[name]",
duration: Some(446),
cover: [],
artists: [
ArtistId(
id: Some("UCjqRwXhXgFW7RDDPn_TlAbw"),
name: "[name]",
),
ArtistId(
id: Some("UCy69bQ95ovXIquWzY5jfAIA"),
name: "[name]",
),
],
artist_id: Some("UCjqRwXhXgFW7RDDPn_TlAbw"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(7),
by_va: false,
),
TrackItem(
id: "SKZ_MTsXFP4",
name: "[name]",
duration: Some(376),
cover: [],
artists: [
ArtistId(
id: Some("UCEUUFTUZpm1MmANCfLN5_9Q"),
name: "[name]",
),
],
artist_id: Some("UCEUUFTUZpm1MmANCfLN5_9Q"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(8),
by_va: false,
),
TrackItem(
id: "n5-ujUwazDA",
name: "[name]",
duration: Some(335),
cover: [],
artists: [
ArtistId(
id: Some("UCxByvsK9hDZk2MnnF9jsFGw"),
name: "[name]",
),
],
artist_id: Some("UCxByvsK9hDZk2MnnF9jsFGw"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(9),
by_va: false,
),
TrackItem(
id: "VaREivfDJeY",
name: "[name]",
duration: Some(268),
cover: [],
artists: [
ArtistId(
id: Some("UCG2o9g3Yl6jBL21_z7XBMVw"),
name: "[name]",
),
],
artist_id: Some("UCG2o9g3Yl6jBL21_z7XBMVw"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(10),
by_va: false,
),
TrackItem(
id: "cWcD0WIK2PA",
name: "[name]",
duration: Some(198),
cover: [],
artists: [
ArtistId(
id: Some("UCiIDz3M3cDn2QeYjLbhIdBQ"),
name: "[name]",
),
ArtistId(
id: Some("UChLPGmjYa8bmKShqMBFP_DA"),
name: "[name]",
),
],
artist_id: Some("UCiIDz3M3cDn2QeYjLbhIdBQ"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(11),
by_va: false,
),
TrackItem(
id: "QRELvH564T4",
name: "[name]",
duration: Some(325),
cover: [],
artists: [
ArtistId(
id: Some("UCbiVmjdLA5PKZcUnZMExqCA"),
name: "[name]",
),
],
artist_id: Some("UCbiVmjdLA5PKZcUnZMExqCA"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(12),
by_va: false,
),
TrackItem(
id: "eCY0-GyG46s",
name: "[name]",
duration: Some(198),
cover: [],
artists: [
ArtistId(
id: Some("UC-thVg_PSz894f5mVqMFMeQ"),
name: "[name]",
),
],
artist_id: Some("UC-thVg_PSz894f5mVqMFMeQ"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(13),
by_va: false,
),
TrackItem(
id: "UIrHYTEyUfA",
name: "[name]",
duration: Some(213),
cover: [],
artists: [
ArtistId(
id: Some("UC2pJL-Kp6yJtARS8MC0N8Ag"),
name: "[name]",
),
ArtistId(
id: Some("UCpmZakvqLLUZ4G_YkKjoy6g"),
name: "[name]",
),
],
artist_id: Some("UC2pJL-Kp6yJtARS8MC0N8Ag"),
album: Some(AlbumId(
id: "MPREb_Z81wHtF9fhC",
name: "[name]",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(14),
by_va: false, by_va: false,
), ),
], ],
variants: [],
) )

View file

@ -1,138 +0,0 @@
---
source: tests/youtube.rs
expression: album
---
MusicAlbum(
id: "MPREb_h8ltx5oKvyY",
playlist_id: Some("OLAK5uy_lIDfTi_k8V1RJ54MeJJGK_BduAeYbm-0s"),
name: "Pedha Rasi Peddamma Katha",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
name: "S P Balasubramaniam",
),
ArtistId(
id: Some("UCWgAqlYG7mXTUxrFiLyDSsg"),
name: "S Janaki",
),
],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
description: None,
album_type: Ep,
year: Some(1968),
by_va: false,
tracks: [
TrackItem(
id: "AKJ3IJZKPWc",
name: "Oh Javaraala",
duration: Some(229),
cover: [],
artists: [
ArtistId(
id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
name: "S P Balasubramaniam",
),
ArtistId(
id: Some("UCWgAqlYG7mXTUxrFiLyDSsg"),
name: "S Janaki",
),
],
artist_id: Some("UCl4iPtukwe7m0kIxUMskkgA"),
album: Some(AlbumId(
id: "MPREb_h8ltx5oKvyY",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(1),
by_va: false,
),
TrackItem(
id: "WnpZuHNB33E",
name: "Siva Manoranjani",
duration: Some(267),
cover: [],
artists: [
ArtistId(
id: Some("UC1C05NyYICFB2mVGn9_ttEw"),
name: "M Balamuralikrishna",
),
],
artist_id: Some("UC1C05NyYICFB2mVGn9_ttEw"),
album: Some(AlbumId(
id: "MPREb_h8ltx5oKvyY",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(2),
by_va: false,
),
TrackItem(
id: "pRqoDGXg1-I",
name: "Gulabi Buggalunna",
duration: Some(155),
cover: [],
artists: [
ArtistId(
id: Some("UC_KQPMiRQl3CFAIKTVfCHwA"),
name: "L R Eswari",
),
],
artist_id: Some("UC_KQPMiRQl3CFAIKTVfCHwA"),
album: Some(AlbumId(
id: "MPREb_h8ltx5oKvyY",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(3),
by_va: false,
),
TrackItem(
id: "20vIKLJxjBY",
name: "Kuluku Nadakula",
duration: Some(179),
cover: [],
artists: [
ArtistId(
id: None,
name: "Ghantasala & Chorus",
),
],
artist_id: Some("UCDqpyYkgWy2h03HamIfODjw"),
album: Some(AlbumId(
id: "MPREb_h8ltx5oKvyY",
name: "Pedha Rasi Peddamma Katha",
)),
view_count: "[view_count]",
is_video: false,
track_nr: Some(4),
by_va: false,
),
],
variants: [
AlbumItem(
id: "MPREb_bqWA6mAZFWS",
name: "Pedha Rasi Peddamma Katha",
cover: [
Thumbnail(
url: "https://lh3.googleusercontent.com/cyKTDdyucqYv8xfv0t3Vs9CkhmvssXRKsGzlWN_DU6A9uapXvovV0Ys2fXc9-r7Jv7V4UB1OD48iYH5z=w226-h226-l90-rj",
width: 226,
height: 226,
),
Thumbnail(
url: "https://lh3.googleusercontent.com/cyKTDdyucqYv8xfv0t3Vs9CkhmvssXRKsGzlWN_DU6A9uapXvovV0Ys2fXc9-r7Jv7V4UB1OD48iYH5z=w544-h544-l90-rj",
width: 544,
height: 544,
),
],
artists: [],
artist_id: None,
album_type: Ep,
year: None,
by_va: true,
),
],
)

View file

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

View file

@ -6,7 +6,7 @@ MusicArtist(
id: "UC7cl4MmM6ZZ2TcFyMk_b4pg", id: "UC7cl4MmM6ZZ2TcFyMk_b4pg",
name: "Unheilig", name: "Unheilig",
header_image: "[header_image]", header_image: "[header_image]",
description: Some("Unheilig was a German band that featured a variety of influences, including various pop and electronic styles as well as harder, nihilistic hard rock. The band was founded in 1999 and principally consisted of singer Bernd Heinrich \"Der Graf\" along with various musical partners. He was accompanied for live shows with musicians Christoph \"Licky\" Termühlen, Henning Verlage, and Martin \"Potti\" Potthoff. The group\'s debut, Phosphor, came out in 2000.\n\nFrom Wikipedia (https://en.wikipedia.org/wiki/Unheilig) under Creative Commons Attribution CC-BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/legalcode)"), description: Some("Unheilig is a German band that draws from a variety of influences, including various pop and electronic styles as well as heavier, nihilistic hard rock. The band was founded in Aachen in 1999 and principally consisted of singer Bernd Heinrich \"Der Graf\" along with various musical partners. He was accompanied for live shows with musicians Christoph \"Licky\" Termühlen, Henning Verlage, and Martin \"Potti\" Potthoff. The group\'s debut, Phosphor, came out in 2000.\n\nFrom Wikipedia (https://en.wikipedia.org/wiki/Unheilig) under Creative Commons Attribution CC-BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/legalcode)"),
wikipedia_url: Some("https://en.wikipedia.org/wiki/Unheilig"), wikipedia_url: Some("https://en.wikipedia.org/wiki/Unheilig"),
subscriber_count: "[subscriber_count]", subscriber_count: "[subscriber_count]",
tracks: "[tracks]", tracks: "[tracks]",
@ -56,21 +56,6 @@ MusicArtist(
year: Some(2008), year: Some(2008),
by_va: false, by_va: false,
), ),
AlbumItem(
id: "MPREb_88p7e6nBtgz",
name: "Lichter der Stadt",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "Unheilig",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2012),
by_va: false,
),
AlbumItem( AlbumItem(
id: "MPREb_Md2aZrjaqHX", id: "MPREb_Md2aZrjaqHX",
name: "Stille Winternacht", name: "Stille Winternacht",
@ -101,6 +86,21 @@ MusicArtist(
year: Some(2018), year: Some(2018),
by_va: false, by_va: false,
), ),
AlbumItem(
id: "MPREb_QEClJsuO9xM",
name: "So wie Du warst",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "Unheilig",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2012),
by_va: false,
),
AlbumItem( AlbumItem(
id: "MPREb_QyGCcLWExXj", id: "MPREb_QyGCcLWExXj",
name: "Als wär\'s das erste Mal (Exklusive Piano Version)", name: "Als wär\'s das erste Mal (Exklusive Piano Version)",

View file

@ -56,21 +56,6 @@ MusicArtist(
year: Some(2008), year: Some(2008),
by_va: false, by_va: false,
), ),
AlbumItem(
id: "MPREb_88p7e6nBtgz",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2012),
by_va: false,
),
AlbumItem( AlbumItem(
id: "MPREb_Md2aZrjaqHX", id: "MPREb_Md2aZrjaqHX",
name: "[name]", name: "[name]",
@ -101,6 +86,21 @@ MusicArtist(
year: Some(2018), year: Some(2018),
by_va: false, by_va: false,
), ),
AlbumItem(
id: "MPREb_QEClJsuO9xM",
name: "[name]",
cover: "[cover]",
artists: [
ArtistId(
id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
name: "[name]",
),
],
artist_id: Some("UC7cl4MmM6ZZ2TcFyMk_b4pg"),
album_type: Single,
year: Some(2012),
by_va: false,
),
AlbumItem( AlbumItem(
id: "MPREb_QyGCcLWExXj", id: "MPREb_QyGCcLWExXj",
name: "[name]", name: "[name]",

View file

@ -6,7 +6,7 @@ MusicArtist(
id: "UCfwCE5VhPMGxNPFxtVv7lRw", id: "UCfwCE5VhPMGxNPFxtVv7lRw",
name: "Sulli", name: "Sulli",
header_image: "[header_image]", header_image: "[header_image]",
description: Some("Choi Jin-ri, better known by her stage name Sulli, was a South Korean singer and actress. She first made her debut as a child actress, appearing as a supporting cast member on the SBS historical drama Ballad of Seodong. Following this, she earned a number of guest roles, appearing in the television series Love Needs a Miracle and Drama City, and the film Vacation. She then subsequently appeared in the independent films Punch Lady and BA:BO, the former being her first time cast in a substantial dramatic role.\nAfter signing a record deal with SM Entertainment, Sulli rose to prominence as a member of the girl group f(x) formed in 2009. The group achieved both critical and commercial success, with four Korean number-one singles and international recognition after becoming the first K-pop act to perform at SXSW. Concurrently with her music career, Sulli returned to acting by starring in the SBS romantic comedy series, To the Beautiful You, a Korean adaptation of the shōjo manga Hana-Kimi where her performance was positively received and earned her two SBS Drama Awards and a nomination at the 49th Paeksang Arts Awards.\n\nFrom Wikipedia (https://en.wikipedia.org/wiki/Sulli) under Creative Commons Attribution CC-BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/legalcode)"), description: Some("Choi Jin-ri, known professionally as Sulli, was a South Korean singer and actress. She first made her debut as a child actress, appearing as a supporting cast member on the SBS historical drama Ballad of Seodong. Following this, she earned a number of guest roles, appearing in the television series Love Needs a Miracle and Drama City, and the film Vacation. She then subsequently appeared in the independent films Punch Lady and BA:BO, the former being her first time cast in a substantial dramatic role.\nAfter signing a record deal with SM Entertainment, Sulli rose to prominence as a member of the girl group f(x) formed in 2009. The group achieved both critical and commercial success, with four Korean number-one singles and international recognition after becoming the first K-pop act to perform at SXSW. Concurrently with her music career, Sulli returned to acting by starring in the SBS romantic comedy series, To the Beautiful You, a Korean adaptation of the shōjo manga Hana-Kimi where her performance was positively received and earned her two SBS Drama Awards and a nomination at the 49th Paeksang Arts Awards.\n\nFrom Wikipedia (https://en.wikipedia.org/wiki/Sulli) under Creative Commons Attribution CC-BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/legalcode)"),
wikipedia_url: Some("https://en.wikipedia.org/wiki/Sulli"), wikipedia_url: Some("https://en.wikipedia.org/wiki/Sulli"),
subscriber_count: "[subscriber_count]", subscriber_count: "[subscriber_count]",
tracks: "[tracks]", tracks: "[tracks]",

View file

@ -14,7 +14,7 @@ use rustypipe::model::{
richtext::ToPlaintext, richtext::ToPlaintext,
traits::{FromYtItem, YtStream}, traits::{FromYtItem, YtStream},
AlbumType, AudioCodec, AudioFormat, AudioTrackType, Channel, Frameset, MusicGenre, MusicItem, AlbumType, AudioCodec, AudioFormat, AudioTrackType, Channel, Frameset, MusicGenre, MusicItem,
UrlTarget, Verification, VideoCodec, VideoFormat, YouTubeItem, UrlTarget, Verification, VideoCodec, VideoFormat, VideoId, YouTubeItem,
}; };
use rustypipe::param::{ use rustypipe::param::{
search_filter::{self, SearchFilter}, search_filter::{self, SearchFilter},
@ -67,8 +67,8 @@ async fn get_player_from_client(#[case] client_type: ClientType, rp: RustyPipe)
let video = player_data let video = player_data
.video_only_streams .video_only_streams
.into_iter() .into_iter()
.find(|s| s.itag == 247) .find(|s| s.itag == 136)
.expect("video #247"); .expect("video #136");
let audio = player_data let audio = player_data
.audio_streams .audio_streams
.into_iter() .into_iter()
@ -76,17 +76,17 @@ async fn get_player_from_client(#[case] client_type: ClientType, rp: RustyPipe)
.expect("audio #140"); .expect("audio #140");
// Bitrates may change between requests // Bitrates may change between requests
assert_approx(video.bitrate, 1_500_162); assert_approx(video.bitrate, 2_341_408);
assert_eq!(video.average_bitrate, 1_360_266); assert_eq!(video.average_bitrate, 1_660_210);
assert_eq!(video.size, Some(44_042_868)); assert_eq!(video.size, Some(53_754_490));
assert_eq!(video.width, 1280); assert_eq!(video.width, 1280);
assert_eq!(video.height, 720); assert_eq!(video.height, 720);
assert_eq!(video.fps, 30); assert_eq!(video.fps, 30);
assert_eq!(video.quality, "720p"); assert_eq!(video.quality, "720p");
assert!(!video.hdr); assert!(!video.hdr);
assert_eq!(video.mime, "video/webm; codecs=\"vp09.00.31.08\""); assert_eq!(video.mime, "video/mp4; codecs=\"avc1.4D401F\"");
assert_eq!(video.format, VideoFormat::Webm); assert_eq!(video.format, VideoFormat::Mp4);
assert_eq!(video.codec, VideoCodec::Vp9); assert_eq!(video.codec, VideoCodec::Avc1);
assert_approx(audio.bitrate, 130_685); assert_approx(audio.bitrate, 130_685);
assert_approx(audio.average_bitrate, 129_496); assert_approx(audio.average_bitrate, 129_496);
@ -418,6 +418,8 @@ async fn playlist_cont(rp: RustyPipe) {
.extend_pages(rp.query(), usize::MAX) .extend_pages(rp.query(), usize::MAX)
.await .await
.unwrap(); .unwrap();
check_duplicates(&playlist.videos.items);
assert_gte(playlist.videos.items.len(), 101, "video items"); assert_gte(playlist.videos.items.len(), 101, "video items");
assert_gteo(playlist.videos.count, 101, "video count"); assert_gteo(playlist.videos.count, 101, "video count");
} }
@ -432,6 +434,7 @@ async fn playlist_cont2(rp: RustyPipe) {
.unwrap(); .unwrap();
playlist.videos.extend_limit(rp.query(), 101).await.unwrap(); playlist.videos.extend_limit(rp.query(), 101).await.unwrap();
check_duplicates(&playlist.videos.items);
assert_gte(playlist.videos.items.len(), 101, "video items"); assert_gte(playlist.videos.items.len(), 101, "video items");
assert_gteo(playlist.videos.count, 101, "video count"); assert_gteo(playlist.videos.count, 101, "video count");
} }
@ -1527,6 +1530,8 @@ async fn music_playlist_cont(#[case] id: &str, rp: RustyPipe) {
playlist.tracks.extend_pages(rp.query(), 5).await.unwrap(); playlist.tracks.extend_pages(rp.query(), 5).await.unwrap();
check_duplicates(&playlist.tracks.items);
let track_count = playlist.track_count.unwrap(); let track_count = playlist.track_count.unwrap();
assert_gte(track_count, 100, "tracks"); assert_gte(track_count, 100, "tracks");
@ -1576,12 +1581,11 @@ async 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_aDDw2kVEFtM")] #[case::show("show", "MPREb_aDDw2kVEFtM")]
#[case::unavailable("unavailable", "MPREb_AzuWg8qAVVl")] #[case::unavailable("unavailable", "MPREb_AzuWg8qAVVl")]
#[case::no_year("no_year", "MPREb_F3Af9UZZVxX")] #[case::no_year("no_year", "MPREb_F3Af9UZZVxX")]
#[case::version_no_artist("version_no_artist", "MPREb_h8ltx5oKvyY")] #[case::no_artist("no_artist", "MPREb_Z81wHtF9fhC")]
#[case::no_artist("no_artist", "MPREb_bqWA6mAZFWS")]
#[tokio::test] #[tokio::test]
async fn music_album(#[case] name: &str, #[case] id: &str, rp: RustyPipe, unlocalized: bool) { async fn music_album(#[case] name: &str, #[case] id: &str, rp: RustyPipe, unlocalized: bool) {
let album = rp.query().music_album(id).await.unwrap(); let album = rp.query().music_album(id).await.unwrap();
@ -1627,8 +1631,7 @@ async fn music_album_not_found(rp: RustyPipe) {
#[rstest] #[rstest]
#[case::basic_all("basic_all", "UCFKUUtHjT4iq3p0JJA13SOA", true, 15, 1)] #[case::basic_all("basic_all", "UCFKUUtHjT4iq3p0JJA13SOA", true, 15, 1)]
// TODO: wait for A/B test 6 to stabilize #[case::basic("basic", "UC7cl4MmM6ZZ2TcFyMk_b4pg", false, 15, 2)]
// #[case::basic("basic", "UC7cl4MmM6ZZ2TcFyMk_b4pg", false, 15, 2)]
#[case::no_more_albums("no_more_albums", "UCOR4_bSVIXPsGa4BbCSt60Q", true, 15, 0)] #[case::no_more_albums("no_more_albums", "UCOR4_bSVIXPsGa4BbCSt60Q", true, 15, 0)]
#[case::only_singles("only_singles", "UCfwCE5VhPMGxNPFxtVv7lRw", false, 13, 0)] #[case::only_singles("only_singles", "UCfwCE5VhPMGxNPFxtVv7lRw", false, 13, 0)]
#[case::no_artist("no_artist", "UCh8gHdtzO2tXd593_bjErWg", false, 0, 0)] #[case::no_artist("no_artist", "UCh8gHdtzO2tXd593_bjErWg", false, 0, 0)]
@ -2780,3 +2783,12 @@ fn assert_frameset(frameset: &Frameset) {
let n = frameset.urls().count() as u32; let n = frameset.urls().count() as u32;
assert_eq!(n, frameset.page_count); assert_eq!(n, frameset.page_count);
} }
#[track_caller]
fn check_duplicates<T: Clone + Into<VideoId>>(items: &[T]) {
let ids = items
.iter()
.map(|itm| itm.clone().into().id)
.collect::<HashSet<String>>();
assert_eq!(ids.len(), items.len(), "duplicate items");
}