fix: use AsRef generics for pagination
This commit is contained in:
parent
85cac83070
commit
94b55711cb
4 changed files with 68 additions and 60 deletions
|
|
@ -208,7 +208,7 @@ async fn playlist_cont(testfiles: &Path) {
|
|||
.unwrap();
|
||||
|
||||
let rp = rp_testfile(&json_path);
|
||||
playlist.videos.next(&rp.query()).await.unwrap().unwrap();
|
||||
playlist.videos.next(rp.query()).await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
async fn video_details(testfiles: &Path) {
|
||||
|
|
@ -246,7 +246,7 @@ async fn comments_top(testfiles: &Path) {
|
|||
let rp = rp_testfile(&json_path);
|
||||
details
|
||||
.top_comments
|
||||
.next(&rp.query())
|
||||
.next(rp.query())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
|
@ -266,7 +266,7 @@ async fn comments_latest(testfiles: &Path) {
|
|||
let rp = rp_testfile(&json_path);
|
||||
details
|
||||
.latest_comments
|
||||
.next(&rp.query())
|
||||
.next(rp.query())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
|
@ -284,7 +284,7 @@ async fn recommendations(testfiles: &Path) {
|
|||
let details = rp.query().video_details("ZeerrnuLi5E").await.unwrap();
|
||||
|
||||
let rp = rp_testfile(&json_path);
|
||||
details.recommended.next(&rp.query()).await.unwrap();
|
||||
details.recommended.next(rp.query()).await.unwrap();
|
||||
}
|
||||
|
||||
async fn channel_videos(testfiles: &Path) {
|
||||
|
|
@ -384,7 +384,7 @@ async fn channel_videos_cont(testfiles: &Path) {
|
|||
.unwrap();
|
||||
|
||||
let rp = rp_testfile(&json_path);
|
||||
videos.content.next(&rp.query()).await.unwrap().unwrap();
|
||||
videos.content.next(rp.query()).await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
async fn channel_playlists_cont(testfiles: &Path) {
|
||||
|
|
@ -403,7 +403,7 @@ async fn channel_playlists_cont(testfiles: &Path) {
|
|||
.unwrap();
|
||||
|
||||
let rp = rp_testfile(&json_path);
|
||||
playlists.content.next(&rp.query()).await.unwrap().unwrap();
|
||||
playlists.content.next(rp.query()).await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
async fn search(testfiles: &Path) {
|
||||
|
|
@ -430,7 +430,7 @@ async fn search_cont(testfiles: &Path) {
|
|||
let search = rp.query().search("doobydoobap").await.unwrap();
|
||||
|
||||
let rp = rp_testfile(&json_path);
|
||||
search.items.next(&rp.query()).await.unwrap().unwrap();
|
||||
search.items.next(rp.query()).await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
async fn search_playlists(testfiles: &Path) {
|
||||
|
|
@ -492,7 +492,7 @@ async fn startpage_cont(testfiles: &Path) {
|
|||
let startpage = rp.query().startpage().await.unwrap();
|
||||
|
||||
let rp = rp_testfile(&json_path);
|
||||
startpage.next(&rp.query()).await.unwrap();
|
||||
startpage.next(rp.query()).await.unwrap();
|
||||
}
|
||||
|
||||
async fn trending(testfiles: &Path) {
|
||||
|
|
@ -541,7 +541,7 @@ async fn music_playlist_cont(testfiles: &Path) {
|
|||
.unwrap();
|
||||
|
||||
let rp = rp_testfile(&json_path);
|
||||
playlist.tracks.next(&rp.query()).await.unwrap().unwrap();
|
||||
playlist.tracks.next(rp.query()).await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
async fn music_playlist_related(testfiles: &Path) {
|
||||
|
|
@ -562,7 +562,7 @@ async fn music_playlist_related(testfiles: &Path) {
|
|||
let rp = rp_testfile(&json_path);
|
||||
playlist
|
||||
.related_playlists
|
||||
.next(&rp.query())
|
||||
.next(rp.query())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
|
@ -688,7 +688,7 @@ async fn music_search_cont(testfiles: &Path) {
|
|||
let res = rp.query().music_search_tracks("black mamba").await.unwrap();
|
||||
|
||||
let rp = rp_testfile(&json_path);
|
||||
res.items.next(&rp.query()).await.unwrap().unwrap();
|
||||
res.items.next(rp.query()).await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
async fn music_search_suggestion(testfiles: &Path) {
|
||||
|
|
@ -801,7 +801,7 @@ async fn music_radio_cont(testfiles: &Path) {
|
|||
let res = rp.query().music_radio("RDAMVM7nigXQS1Xb0").await.unwrap();
|
||||
|
||||
let rp = rp_testfile(&json_path);
|
||||
res.next(&rp.query()).await.unwrap().unwrap();
|
||||
res.next(rp.query()).await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
async fn music_new_albums(testfiles: &Path) {
|
||||
|
|
|
|||
|
|
@ -1164,6 +1164,12 @@ impl RustyPipeQuery {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsRef<RustyPipeQuery> for RustyPipeQuery {
|
||||
fn as_ref(&self) -> &RustyPipeQuery {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement this for YouTube API response structs that need to be mapped to
|
||||
/// RustyPipe models.
|
||||
trait MapResponse<T> {
|
||||
|
|
|
|||
|
|
@ -176,10 +176,11 @@ impl MapResponse<Paginator<MusicItem>> for response::MusicContinuation {
|
|||
}
|
||||
|
||||
impl<T: FromYtItem> Paginator<T> {
|
||||
pub async fn next(&self, query: &RustyPipeQuery) -> Result<Option<Self>, Error> {
|
||||
pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> {
|
||||
Ok(match &self.ctoken {
|
||||
Some(ctoken) => Some(
|
||||
query
|
||||
.as_ref()
|
||||
.continuation(ctoken, self.endpoint, self.visitor_data.as_deref())
|
||||
.await?,
|
||||
),
|
||||
|
|
@ -187,7 +188,7 @@ impl<T: FromYtItem> Paginator<T> {
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn extend(&mut self, query: &RustyPipeQuery) -> Result<bool, Error> {
|
||||
pub async fn extend<Q: AsRef<RustyPipeQuery>>(&mut self, query: Q) -> Result<bool, Error> {
|
||||
match self.next(query).await {
|
||||
Ok(Some(paginator)) => {
|
||||
let mut items = paginator.items;
|
||||
|
|
@ -200,11 +201,12 @@ impl<T: FromYtItem> Paginator<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn extend_pages(
|
||||
pub async fn extend_pages<Q: AsRef<RustyPipeQuery>>(
|
||||
&mut self,
|
||||
query: &RustyPipeQuery,
|
||||
query: Q,
|
||||
n_pages: usize,
|
||||
) -> Result<(), Error> {
|
||||
let query = query.as_ref();
|
||||
for _ in 0..n_pages {
|
||||
match self.extend(query).await {
|
||||
Ok(false) => break,
|
||||
|
|
@ -215,11 +217,12 @@ impl<T: FromYtItem> Paginator<T> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn extend_limit(
|
||||
pub async fn extend_limit<Q: AsRef<RustyPipeQuery>>(
|
||||
&mut self,
|
||||
query: &RustyPipeQuery,
|
||||
query: Q,
|
||||
n_items: usize,
|
||||
) -> Result<(), Error> {
|
||||
let query = query.as_ref();
|
||||
while self.items.len() < n_items {
|
||||
match self.extend(query).await {
|
||||
Ok(false) => break,
|
||||
|
|
@ -232,10 +235,11 @@ impl<T: FromYtItem> Paginator<T> {
|
|||
}
|
||||
|
||||
impl Paginator<Comment> {
|
||||
pub async fn next(&self, query: &RustyPipeQuery) -> Result<Option<Self>, Error> {
|
||||
pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> {
|
||||
Ok(match &self.ctoken {
|
||||
Some(ctoken) => Some(
|
||||
query
|
||||
.as_ref()
|
||||
.video_comments(ctoken, self.visitor_data.as_deref())
|
||||
.await?,
|
||||
),
|
||||
|
|
@ -245,9 +249,9 @@ impl Paginator<Comment> {
|
|||
}
|
||||
|
||||
impl Paginator<PlaylistVideo> {
|
||||
pub async fn next(&self, query: &RustyPipeQuery) -> Result<Option<Self>, Error> {
|
||||
pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> {
|
||||
Ok(match &self.ctoken {
|
||||
Some(ctoken) => Some(query.playlist_continuation(ctoken).await?),
|
||||
Some(ctoken) => Some(query.as_ref().playlist_continuation(ctoken).await?),
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
|
|
@ -256,7 +260,10 @@ impl Paginator<PlaylistVideo> {
|
|||
macro_rules! paginator {
|
||||
($entity_type:ty) => {
|
||||
impl Paginator<$entity_type> {
|
||||
pub async fn extend(&mut self, query: &RustyPipeQuery) -> Result<bool, Error> {
|
||||
pub async fn extend<Q: AsRef<RustyPipeQuery>>(
|
||||
&mut self,
|
||||
query: Q,
|
||||
) -> Result<bool, Error> {
|
||||
match self.next(query).await {
|
||||
Ok(Some(paginator)) => {
|
||||
let mut items = paginator.items;
|
||||
|
|
@ -269,11 +276,12 @@ macro_rules! paginator {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn extend_pages(
|
||||
pub async fn extend_pages<Q: AsRef<RustyPipeQuery>>(
|
||||
&mut self,
|
||||
query: &RustyPipeQuery,
|
||||
query: Q,
|
||||
n_pages: usize,
|
||||
) -> Result<(), Error> {
|
||||
let query = query.as_ref();
|
||||
for _ in 0..n_pages {
|
||||
match self.extend(query).await {
|
||||
Ok(false) => break,
|
||||
|
|
@ -284,11 +292,12 @@ macro_rules! paginator {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn extend_limit(
|
||||
pub async fn extend_limit<Q: AsRef<RustyPipeQuery>>(
|
||||
&mut self,
|
||||
query: &RustyPipeQuery,
|
||||
query: Q,
|
||||
n_items: usize,
|
||||
) -> Result<(), Error> {
|
||||
let query = query.as_ref();
|
||||
while self.items.len() < n_items {
|
||||
match self.extend(query).await {
|
||||
Ok(false) => break,
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ async fn playlist_cont() {
|
|||
|
||||
playlist
|
||||
.videos
|
||||
.extend_pages(&rp.query(), usize::MAX)
|
||||
.extend_pages(rp.query(), usize::MAX)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(playlist.videos.items.len() > 100);
|
||||
|
|
@ -396,11 +396,7 @@ async fn playlist_cont2() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
playlist
|
||||
.videos
|
||||
.extend_limit(&rp.query(), 101)
|
||||
.await
|
||||
.unwrap();
|
||||
playlist.videos.extend_limit(rp.query(), 101).await.unwrap();
|
||||
assert!(playlist.videos.items.len() > 100);
|
||||
assert!(playlist.videos.count.unwrap() > 100);
|
||||
}
|
||||
|
|
@ -461,7 +457,7 @@ async fn get_video_details() {
|
|||
assert!(!details.is_ccommons);
|
||||
|
||||
assert!(details.recommended.visitor_data.is_some());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
assert_next(details.recommended, rp.query(), 10, 2).await;
|
||||
|
||||
assert_gte(details.top_comments.count.unwrap(), 700_000, "comments");
|
||||
assert!(!details.top_comments.is_exhausted());
|
||||
|
|
@ -499,7 +495,7 @@ async fn get_video_details_music() {
|
|||
assert!(!details.is_ccommons);
|
||||
|
||||
assert!(details.recommended.visitor_data.is_some());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
assert_next(details.recommended, rp.query(), 10, 2).await;
|
||||
|
||||
// Update(01.11.2022): comments are sometimes enabled
|
||||
/*
|
||||
|
|
@ -548,7 +544,7 @@ async fn get_video_details_ccommons() {
|
|||
assert!(details.is_ccommons);
|
||||
|
||||
assert!(details.recommended.visitor_data.is_some());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
assert_next(details.recommended, rp.query(), 10, 2).await;
|
||||
|
||||
assert_gte(details.top_comments.count.unwrap(), 2199, "comments");
|
||||
assert!(!details.top_comments.is_exhausted());
|
||||
|
|
@ -673,7 +669,7 @@ async fn get_video_details_chapters() {
|
|||
}
|
||||
|
||||
assert!(details.recommended.visitor_data.is_some());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
assert_next(details.recommended, rp.query(), 10, 2).await;
|
||||
|
||||
assert_gte(details.top_comments.count.unwrap(), 3200, "comments");
|
||||
assert!(!details.top_comments.is_exhausted());
|
||||
|
|
@ -718,7 +714,7 @@ async fn get_video_details_live() {
|
|||
assert!(!details.is_ccommons);
|
||||
|
||||
assert!(details.recommended.visitor_data.is_some());
|
||||
assert_next(details.recommended, &rp.query(), 10, 2).await;
|
||||
assert_next(details.recommended, rp.query(), 10, 2).await;
|
||||
|
||||
// No comments because livestream
|
||||
assert_eq!(details.top_comments.count, Some(0));
|
||||
|
|
@ -786,7 +782,7 @@ async fn get_video_comments() {
|
|||
|
||||
let top_comments = details
|
||||
.top_comments
|
||||
.next(&rp.query())
|
||||
.next(rp.query())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
|
@ -805,7 +801,7 @@ async fn get_video_comments() {
|
|||
|
||||
let latest_comments = details
|
||||
.latest_comments
|
||||
.next(&rp.query())
|
||||
.next(rp.query())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
|
@ -839,7 +835,7 @@ async fn channel_videos() {
|
|||
|
||||
assert!(age_days < 60, "latest video older than 60 days");
|
||||
|
||||
assert_next(channel.content, &rp.query(), 15, 2).await;
|
||||
assert_next(channel.content, rp.query(), 15, 2).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -873,7 +869,7 @@ async fn channel_shorts() {
|
|||
"got no shorts"
|
||||
);
|
||||
|
||||
assert_next(channel.content, &rp.query(), 15, 1).await;
|
||||
assert_next(channel.content, rp.query(), 15, 1).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -893,7 +889,7 @@ async fn channel_livestreams() {
|
|||
"got no streams"
|
||||
);
|
||||
|
||||
assert_next(channel.content, &rp.query(), 5, 1).await;
|
||||
assert_next(channel.content, rp.query(), 5, 1).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -912,7 +908,7 @@ async fn channel_playlists() {
|
|||
"got no playlists"
|
||||
);
|
||||
|
||||
assert_next(channel.content, &rp.query(), 15, 1).await;
|
||||
assert_next(channel.content, rp.query(), 15, 1).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -1099,7 +1095,7 @@ async fn search() {
|
|||
);
|
||||
assert_eq!(result.corrected_query.unwrap(), "doobydobap");
|
||||
|
||||
assert_next(result.items, &rp.query(), 10, 2).await;
|
||||
assert_next(result.items, rp.query(), 10, 2).await;
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -1115,7 +1111,7 @@ async fn search_filter_entity(#[case] entity: search_filter::Entity) {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
result.items.extend(&rp.query()).await.unwrap();
|
||||
result.items.extend(rp.query()).await.unwrap();
|
||||
assert_gte(result.items.items.len(), 20, "items");
|
||||
|
||||
result.items.items.iter().for_each(|item| match item {
|
||||
|
|
@ -1243,7 +1239,7 @@ async fn startpage() {
|
|||
// The startpage requires visitor data to fetch continuations
|
||||
assert!(startpage.visitor_data.is_some());
|
||||
|
||||
assert_next(startpage, &rp.query(), 20, 2).await;
|
||||
assert_next(startpage, rp.query(), 20, 2).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -1321,7 +1317,7 @@ async fn music_playlist_cont() {
|
|||
|
||||
playlist
|
||||
.tracks
|
||||
.extend_pages(&rp.query(), usize::MAX)
|
||||
.extend_pages(rp.query(), usize::MAX)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -1338,11 +1334,7 @@ async fn music_playlist_related() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
playlist
|
||||
.related_playlists
|
||||
.extend(&rp.query())
|
||||
.await
|
||||
.unwrap();
|
||||
playlist.related_playlists.extend(rp.query()).await.unwrap();
|
||||
|
||||
assert_gte(
|
||||
playlist.related_playlists.items.len(),
|
||||
|
|
@ -1571,7 +1563,7 @@ async fn music_search_tracks() {
|
|||
assert_eq!(album.id, "MPREb_OpHWHwyNOuY");
|
||||
assert_eq!(album.name, "Black Mamba");
|
||||
|
||||
assert_next(res.items, &rp.query(), 15, 2).await;
|
||||
assert_next(res.items, rp.query(), 15, 2).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -1605,7 +1597,7 @@ async fn music_search_videos() {
|
|||
assert_eq!(track.album, None);
|
||||
assert_gte(track.view_count.unwrap(), 230_000_000, "views");
|
||||
|
||||
assert_next(res.items, &rp.query(), 15, 2).await;
|
||||
assert_next(res.items, rp.query(), 15, 2).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -1692,7 +1684,7 @@ async fn music_search_albums(
|
|||
|
||||
assert_eq!(res.corrected_query, None);
|
||||
|
||||
assert_next(res.items, &rp.query(), 15, n_pages).await;
|
||||
assert_next(res.items, rp.query(), 15, n_pages).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -1724,7 +1716,7 @@ async fn music_search_artists_cont() {
|
|||
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;
|
||||
assert_next(res.items, rp.query(), 15, 2).await;
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -2000,7 +1992,7 @@ async fn music_details_not_found() {
|
|||
async fn music_radio_track() {
|
||||
let rp = RustyPipe::builder().strict().build();
|
||||
let tracks = rp.query().music_radio_track("ZeerrnuLi5E").await.unwrap();
|
||||
assert_next(tracks, &rp.query(), 20, 3).await;
|
||||
assert_next(tracks, rp.query(), 20, 3).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -2030,7 +2022,7 @@ async fn music_radio_playlist() {
|
|||
.music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlRbE7PiJ")
|
||||
.await
|
||||
.unwrap();
|
||||
assert_next(tracks, &rp.query(), 10, 1).await;
|
||||
assert_next(tracks, rp.query(), 10, 1).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -2121,13 +2113,14 @@ 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>(
|
||||
async fn assert_next<T: FromYtItem, Q: AsRef<RustyPipeQuery>>(
|
||||
paginator: Paginator<T>,
|
||||
query: &RustyPipeQuery,
|
||||
query: Q,
|
||||
min_items: usize,
|
||||
n_pages: usize,
|
||||
) {
|
||||
let mut p = paginator;
|
||||
let query = query.as_ref();
|
||||
assert_gte(p.items.len(), min_items, "items on page 0");
|
||||
|
||||
for i in 0..n_pages {
|
||||
|
|
|
|||
Reference in a new issue