refactor: generic search API

This commit is contained in:
ThetaDev 2023-11-18 01:19:47 +01:00
parent 48ccfc5c06
commit 8458d878e7
21 changed files with 2185 additions and 2262 deletions

View file

@ -5,25 +5,22 @@ use std::fmt::Display;
use std::str::FromStr;
use rstest::{fixture, rstest};
use rustypipe::model::paginator::ContinuationEndpoint;
use rustypipe::param::{ChannelOrder, ChannelVideoTab, Language};
use rustypipe::validate;
use time::macros::date;
use time::OffsetDateTime;
use time::{macros::date, OffsetDateTime};
use rustypipe::client::{ClientType, RustyPipe, RustyPipeQuery};
use rustypipe::error::{Error, ExtractionError, UnavailabilityReason};
use rustypipe::model::{
paginator::Paginator,
paginator::{ContinuationEndpoint, Paginator},
richtext::ToPlaintext,
traits::{FromYtItem, YtStream},
AlbumType, AudioCodec, AudioFormat, AudioTrackType, Channel, Frameset, MusicGenre,
MusicItemType, UrlTarget, Verification, VideoCodec, VideoFormat, YouTubeItem,
AlbumType, AudioCodec, AudioFormat, AudioTrackType, Channel, Frameset, MusicGenre, MusicItem,
UrlTarget, Verification, VideoCodec, VideoFormat, YouTubeItem,
};
use rustypipe::param::{
search_filter::{self, SearchFilter},
Country,
ChannelOrder, ChannelVideoTab, Country, Language,
};
use rustypipe::validate;
//#PLAYER
@ -1162,7 +1159,7 @@ mod channel_rss {
#[rstest]
fn search(rp: RustyPipe, unlocalized: bool) {
let result = tokio_test::block_on(rp.query().search("doobydoobap")).unwrap();
let result = tokio_test::block_on(rp.query().search::<YouTubeItem, _>("doobydoobap")).unwrap();
assert_gte(
result.items.count.unwrap(),
@ -1182,10 +1179,10 @@ fn search(rp: RustyPipe, unlocalized: bool) {
#[case::channel(search_filter::ItemType::Channel)]
#[case::playlist(search_filter::ItemType::Playlist)]
fn search_filter_item_type(#[case] item_type: search_filter::ItemType, rp: RustyPipe) {
let mut result = tokio_test::block_on(
rp.query()
.search_filter("with no videos", &SearchFilter::new().item_type(item_type)),
)
let mut result = tokio_test::block_on(rp.query().search_filter::<YouTubeItem, _>(
"with no videos",
&SearchFilter::new().item_type(item_type),
))
.unwrap();
tokio_test::block_on(result.items.extend(rp.query())).unwrap();
@ -1207,7 +1204,7 @@ fn search_filter_item_type(#[case] item_type: search_filter::ItemType, rp: Rusty
#[rstest]
fn search_empty(rp: RustyPipe) {
let result = tokio_test::block_on(
rp.query().search_filter(
rp.query().search_filter::<YouTubeItem, _>(
"3gig84hgi34gu8vj34gj489",
&search_filter::SearchFilter::new()
.feature(search_filter::Feature::IsLive)
@ -1602,18 +1599,15 @@ fn music_artist_albums_not_found(rp: RustyPipe) {
#[rstest]
#[case::default(false)]
#[case::typo(true)]
fn music_search(#[case] typo: bool, rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search(match typo {
fn music_search_main(#[case] typo: bool, rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search_main(match typo {
false => "lieblingsmensch namika",
true => "lieblingsmesch namika",
}))
.unwrap();
let items = res.items.items;
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], MusicItemType::Track);
check_search_result(&items);
if typo {
if unlocalized {
@ -1623,12 +1617,21 @@ fn music_search(#[case] typo: bool, rp: RustyPipe, unlocalized: bool) {
assert_eq!(res.corrected_query, None);
}
let track = &res
.tracks
let track = items
.iter()
.find(|a| a.id == "6485PhOtHzY")
.find_map(|itm| {
if let MusicItem::Track(track) = itm {
if track.id == "6485PhOtHzY" {
Some(track)
} else {
None
}
} else {
None
}
})
.unwrap_or_else(|| {
panic!("could not find track, got {:#?}", &res.tracks);
panic!("could not find track, got {:#?}", &items);
});
assert_eq!(track.name, "Lieblingsmensch");
@ -1654,21 +1657,27 @@ fn music_search(#[case] typo: bool, rp: RustyPipe, unlocalized: bool) {
}
#[rstest]
fn music_search2(rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search("taylor swift")).unwrap();
fn music_search_main2(rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search_main("taylor swift")).unwrap();
let items = res.items.items;
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], MusicItemType::Artist);
check_search_result(&items);
let artist = &res
.artists
let artist = items
.iter()
.find(|a| a.id == "UCPC0L1d253x-KuMNwa05TpA")
.find_map(|itm| {
if let MusicItem::Artist(artist) = itm {
if artist.id == "UCPC0L1d253x-KuMNwa05TpA" {
Some(artist)
} else {
None
}
} else {
None
}
})
.unwrap_or_else(|| {
panic!("could not find artist, got {:#?}", &res.artists);
panic!("could not find artist, got {:#?}", &items);
});
if unlocalized {
@ -1677,6 +1686,37 @@ fn music_search2(rp: RustyPipe, unlocalized: bool) {
assert!(!artist.avatar.is_empty(), "got no avatar");
}
fn check_search_result(items: &[MusicItem]) {
assert_gte(items.len(), 10, "search results");
let mut has_tracks = false;
let mut has_videos = false;
let mut has_albums = false;
let mut has_artists = false;
let mut has_playlists = false;
for itm in items {
match itm {
MusicItem::Track(t) => {
if t.is_video {
has_videos = true
} else {
has_tracks = true
}
}
MusicItem::Album(_) => has_albums = true,
MusicItem::Artist(_) => has_artists = true,
MusicItem::Playlist(_) => has_playlists = true,
}
}
assert!(has_tracks, "no tracks");
assert!(has_videos, "no videos");
assert!(has_albums, "no albums");
assert!(has_artists, "no artists");
assert!(has_playlists, "no playlists");
}
#[rstest]
fn music_search_tracks(rp: RustyPipe, unlocalized: bool) {
let res = tokio_test::block_on(rp.query().music_search_tracks("black mamba")).unwrap();
@ -1754,23 +1794,35 @@ fn music_search_videos(rp: RustyPipe, unlocalized: bool) {
#[case::videos(true)]
fn music_search_episode(rp: RustyPipe, #[case] videos: bool) {
let query = "Blond - Da muss man dabei gewesen sein: Das Hörspiel - Fall #1";
let tracks = if videos {
tokio_test::block_on(rp.query().music_search_videos(query))
.unwrap()
.items
.items
} else {
tokio_test::block_on(rp.query().music_search(query))
.unwrap()
.tracks
};
let track_id = "Zq_-LDy7AgE";
let track = &tracks
.iter()
.find(|a| a.id == "Zq_-LDy7AgE")
.unwrap_or_else(|| {
panic!("could not find episode, got {:#?}", &tracks);
});
let track = if videos {
let items = tokio_test::block_on(rp.query().music_search_videos(query))
.unwrap()
.items
.items;
items.iter().find(|a| a.id == track_id).cloned()
} else {
let items = tokio_test::block_on(rp.query().music_search_main(query))
.unwrap()
.items
.items;
items
.iter()
.find_map(|itm| {
if let MusicItem::Track(track) = itm {
if track.id == track_id {
Some(track)
} else {
None
}
} else {
None
}
})
.cloned()
}
.expect("could not find episode");
assert_eq!(track.artists.len(), 1);
let track_artist = &track.artists[0];
@ -1967,7 +2019,7 @@ fn music_search_playlists_community(rp: RustyPipe) {
/// The YouTube Music search sometimes shows genre radio items. They should be skipped.
#[rstest]
fn music_search_genre_radio(rp: RustyPipe) {
tokio_test::block_on(rp.query().music_search("pop radio")).unwrap();
tokio_test::block_on(rp.query().music_search_main("pop radio")).unwrap();
}
#[rstest]
@ -2372,7 +2424,7 @@ const VISITOR_DATA_SEARCH_CHANNEL_HANDLES: &str = "CgszYlc1Yk1WZGRCSSjrwOSbBg%3D
fn ab3_search_channel_handles() {
let rp = rp_visitor_data(VISITOR_DATA_SEARCH_CHANNEL_HANDLES);
tokio_test::block_on(rp.query().search_filter(
tokio_test::block_on(rp.query().search_filter::<YouTubeItem, _>(
"test",
&SearchFilter::new().item_type(search_filter::ItemType::Channel),
))