refactor: update trends response model

This commit is contained in:
Theta-Dev 2022-10-17 11:04:18 +02:00
parent 6a10909377
commit db6b1ab8a7
9 changed files with 936 additions and 1044 deletions

View file

@ -1,18 +1,15 @@
use crate::{
error::{Error, ExtractionError},
model::{Paginator, SearchVideo},
model::{Paginator, VideoItem},
param::Language,
serializer::MapResult,
util::TryRemove,
};
use super::{
response::{self, TryFromWLang},
ClientType, MapResponse, QBrowse, QContinuation, RustyPipeQuery,
};
use super::{response, ClientType, MapResponse, QBrowse, RustyPipeQuery};
impl RustyPipeQuery {
pub async fn startpage(self) -> Result<Paginator<SearchVideo>, Error> {
pub async fn startpage(self) -> Result<Paginator<VideoItem>, Error> {
let context = self.get_context(ClientType::Desktop, true).await;
let request_body = QBrowse {
context,
@ -29,33 +26,7 @@ impl RustyPipeQuery {
.await
}
pub async fn startpage_continuation(
self,
ctoken: &str,
visitor_data: &str,
) -> Result<Paginator<SearchVideo>, Error> {
let mut context = self.get_context(ClientType::Desktop, true).await;
context.client.visitor_data = Some(visitor_data.to_owned());
let request_body = QContinuation {
context,
continuation: ctoken,
};
self.execute_request::<response::StartpageCont, _, _>(
ClientType::Desktop,
"startpage_continuation",
ctoken,
"browse",
&request_body,
)
.await
.map(|res| Paginator {
visitor_data: Some(visitor_data.to_owned()),
..res
})
}
pub async fn trending(self) -> Result<Vec<SearchVideo>, Error> {
pub async fn trending(self) -> Result<Vec<VideoItem>, Error> {
let context = self.get_context(ClientType::Desktop, true).await;
let request_body = QBrowse {
context,
@ -73,13 +44,13 @@ impl RustyPipeQuery {
}
}
impl MapResponse<Paginator<SearchVideo>> for response::Startpage {
impl MapResponse<Paginator<VideoItem>> for response::Startpage {
fn map_response(
self,
_id: &str,
lang: crate::param::Language,
_deobf: Option<&crate::deobfuscate::Deobfuscator>,
) -> Result<MapResult<Paginator<SearchVideo>>, ExtractionError> {
) -> Result<MapResult<Paginator<VideoItem>>, ExtractionError> {
let mut contents = self.contents.two_column_browse_results_renderer.tabs;
let grid = contents
.try_swap_remove(0)
@ -97,33 +68,15 @@ impl MapResponse<Paginator<SearchVideo>> for response::Startpage {
}
}
impl MapResponse<Paginator<SearchVideo>> for response::StartpageCont {
impl MapResponse<Vec<VideoItem>> for response::Trending {
fn map_response(
self,
_id: &str,
lang: crate::param::Language,
_deobf: Option<&crate::deobfuscate::Deobfuscator>,
) -> Result<MapResult<Paginator<SearchVideo>>, ExtractionError> {
let mut received_actions = self.on_response_received_actions;
let items = received_actions
.try_swap_remove(0)
.ok_or_else(|| ExtractionError::InvalidData("no contents".into()))?
.append_continuation_items_action
.continuation_items;
Ok(map_startpage_videos(items, lang, None))
}
}
impl MapResponse<Vec<SearchVideo>> for response::Trending {
fn map_response(
self,
_id: &str,
lang: crate::param::Language,
_deobf: Option<&crate::deobfuscate::Deobfuscator>,
) -> Result<MapResult<Vec<SearchVideo>>, ExtractionError> {
) -> Result<MapResult<Vec<VideoItem>>, ExtractionError> {
let mut contents = self.contents.two_column_browse_results_renderer.tabs;
let sections = contents
let items = contents
.try_swap_remove(0)
.ok_or_else(|| ExtractionError::InvalidData("no contents".into()))?
.tab_renderer
@ -131,76 +84,27 @@ impl MapResponse<Vec<SearchVideo>> for response::Trending {
.section_list_renderer
.contents;
let mut items = Vec::new();
let mut warnings = Vec::new();
let mut mapper = response::YouTubeListMapper::<VideoItem>::new(lang);
mapper.map_response(items);
for mut section in sections {
let shelf = section
.item_section_renderer
.contents
.try_swap_remove(0)
.and_then(|shelf| {
shelf
.shelf_renderer
.content
.expanded_shelf_contents_renderer
});
if let Some(mut shelf) = shelf {
warnings.append(&mut shelf.items.warnings);
for item in shelf.items.c {
if let response::trends::TrendingListItem::VideoRenderer(video) = item {
match SearchVideo::from_w_lang(video, lang) {
Ok(video) => {
items.push(video);
}
Err(e) => {
warnings.push(e.to_string());
}
}
}
}
}
}
Ok(MapResult { c: items, warnings })
Ok(MapResult {
c: mapper.items,
warnings: mapper.warnings,
})
}
}
fn map_startpage_videos(
videos: MapResult<Vec<response::VideoListItem>>,
videos: MapResult<Vec<response::YouTubeListItem>>,
lang: Language,
visitor_data: Option<String>,
) -> MapResult<Paginator<SearchVideo>> {
let mut warnings = videos.warnings;
let mut ctoken = None;
let items = videos
.c
.into_iter()
.filter_map(|item| match item {
response::VideoListItem::RichItemRenderer {
content: response::RichItem::VideoRenderer(video),
} => match SearchVideo::from_w_lang(video, lang) {
Ok(video) => Some(video),
Err(e) => {
warnings.push(e.to_string());
None
}
},
response::VideoListItem::ContinuationItemRenderer {
continuation_endpoint,
} => {
ctoken = Some(continuation_endpoint.continuation_command.token);
None
}
_ => None,
})
.collect();
) -> MapResult<Paginator<VideoItem>> {
let mut mapper = response::YouTubeListMapper::<VideoItem>::new(lang);
mapper.map_response(videos);
MapResult {
c: Paginator::new_with_vdata(None, items, ctoken, visitor_data),
warnings,
c: Paginator::new_with_vdata(None, mapper.items, mapper.ctoken, visitor_data),
warnings: mapper.warnings,
}
}
@ -210,7 +114,7 @@ mod tests {
use crate::{
client::{response, MapResponse},
model::{Paginator, SearchVideo},
model::{Paginator, VideoItem},
param::Language,
serializer::MapResult,
};
@ -223,7 +127,7 @@ mod tests {
let startpage: response::Startpage =
serde_json::from_reader(BufReader::new(json_file)).unwrap();
let map_res: MapResult<Paginator<SearchVideo>> =
let map_res: MapResult<Paginator<VideoItem>> =
startpage.map_response("", Language::En, None).unwrap();
assert!(
@ -237,28 +141,6 @@ mod tests {
});
}
#[test]
fn map_startpage_cont() {
let filename = "testfiles/trends/startpage_cont.json";
let json_path = Path::new(&filename);
let json_file = File::open(json_path).unwrap();
let startpage: response::StartpageCont =
serde_json::from_reader(BufReader::new(json_file)).unwrap();
let map_res: MapResult<Paginator<SearchVideo>> =
startpage.map_response("", Language::En, None).unwrap();
assert!(
map_res.warnings.is_empty(),
"deserialization/mapping warnings: {:?}",
map_res.warnings
);
insta::assert_ron_snapshot!("map_startpage_cont", map_res.c, {
".items[].publish_date" => "[date]",
});
}
#[test]
fn map_trending() {
let filename = "testfiles/trends/trending.json";
@ -267,7 +149,7 @@ mod tests {
let startpage: response::Trending =
serde_json::from_reader(BufReader::new(json_file)).unwrap();
let map_res: MapResult<Vec<SearchVideo>> =
let map_res: MapResult<Vec<VideoItem>> =
startpage.map_response("", Language::En, None).unwrap();
assert!(