Compare commits
2 commits
6a10909377
...
999ebf7c36
Author | SHA1 | Date | |
---|---|---|---|
999ebf7c36 | |||
db6b1ab8a7 |
12 changed files with 959 additions and 1219 deletions
|
@ -280,10 +280,7 @@ async fn channel_videos_cont(testfiles: &Path) {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let rp = rp_testfile(&json_path);
|
let rp = rp_testfile(&json_path);
|
||||||
rp.query()
|
videos.content.next(rp.query()).await.unwrap().unwrap();
|
||||||
.channel_videos_continuation(&videos.content.ctoken.unwrap())
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn channel_playlists_cont(testfiles: &Path) {
|
async fn channel_playlists_cont(testfiles: &Path) {
|
||||||
|
@ -302,10 +299,7 @@ async fn channel_playlists_cont(testfiles: &Path) {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let rp = rp_testfile(&json_path);
|
let rp = rp_testfile(&json_path);
|
||||||
rp.query()
|
playlists.content.next(rp.query()).await.unwrap().unwrap();
|
||||||
.channel_playlists_continuation(&playlists.content.ctoken.unwrap())
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn search(testfiles: &Path) {
|
async fn search(testfiles: &Path) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::error::{Error, ExtractionError};
|
use crate::error::{Error, ExtractionError};
|
||||||
use crate::model::{
|
use crate::model::{
|
||||||
Comment, ContinuationEndpoint, Paginator, PlaylistVideo, RecommendedVideo, SearchVideo,
|
Comment, ContinuationEndpoint, Paginator, PlaylistVideo, RecommendedVideo, YouTubeItem,
|
||||||
YouTubeItem,
|
|
||||||
};
|
};
|
||||||
use crate::serializer::MapResult;
|
use crate::serializer::MapResult;
|
||||||
use crate::util::TryRemove;
|
use crate::util::TryRemove;
|
||||||
|
@ -13,8 +12,10 @@ impl RustyPipeQuery {
|
||||||
self,
|
self,
|
||||||
ctoken: &str,
|
ctoken: &str,
|
||||||
endpoint: ContinuationEndpoint,
|
endpoint: ContinuationEndpoint,
|
||||||
|
visitor_data: Option<&str>,
|
||||||
) -> Result<Paginator<T>, Error> {
|
) -> Result<Paginator<T>, Error> {
|
||||||
let context = self.get_context(ClientType::Desktop, true).await;
|
let mut context = self.get_context(ClientType::Desktop, true).await;
|
||||||
|
context.client.visitor_data = visitor_data.map(str::to_owned);
|
||||||
let request_body = QContinuation {
|
let request_body = QContinuation {
|
||||||
context,
|
context,
|
||||||
continuation: ctoken,
|
continuation: ctoken,
|
||||||
|
@ -140,64 +141,14 @@ paginator!(Comment, RustyPipeQuery::video_comments);
|
||||||
paginator!(PlaylistVideo, RustyPipeQuery::playlist_continuation);
|
paginator!(PlaylistVideo, RustyPipeQuery::playlist_continuation);
|
||||||
paginator!(RecommendedVideo, RustyPipeQuery::video_recommendations);
|
paginator!(RecommendedVideo, RustyPipeQuery::video_recommendations);
|
||||||
|
|
||||||
impl Paginator<SearchVideo> {
|
|
||||||
pub async fn next(&self, query: RustyPipeQuery) -> Result<Option<Self>, Error> {
|
|
||||||
Ok(match (&self.ctoken, &self.visitor_data) {
|
|
||||||
(Some(ctoken), Some(visitor_data)) => {
|
|
||||||
Some(query.startpage_continuation(ctoken, visitor_data).await?)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn extend(&mut self, query: RustyPipeQuery) -> Result<bool, Error> {
|
|
||||||
match self.next(query).await {
|
|
||||||
Ok(Some(paginator)) => {
|
|
||||||
let mut items = paginator.items;
|
|
||||||
self.items.append(&mut items);
|
|
||||||
self.ctoken = paginator.ctoken;
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
Ok(None) => Ok(false),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn extend_pages(
|
|
||||||
&mut self,
|
|
||||||
query: RustyPipeQuery,
|
|
||||||
n_pages: usize,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
for _ in 0..n_pages {
|
|
||||||
match self.extend(query.clone()).await {
|
|
||||||
Ok(false) => break,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn extend_limit(
|
|
||||||
&mut self,
|
|
||||||
query: RustyPipeQuery,
|
|
||||||
n_items: usize,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
while self.items.len() < n_items {
|
|
||||||
match self.extend(query.clone()).await {
|
|
||||||
Ok(false) => break,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: TryFrom<YouTubeItem>> Paginator<T> {
|
impl<T: TryFrom<YouTubeItem>> Paginator<T> {
|
||||||
pub async fn next(&self, query: RustyPipeQuery) -> Result<Option<Self>, Error> {
|
pub async fn next(&self, query: RustyPipeQuery) -> Result<Option<Self>, Error> {
|
||||||
Ok(match &self.ctoken {
|
Ok(match &self.ctoken {
|
||||||
Some(ctoken) => Some(query.continuation(ctoken, self.endpoint).await?),
|
Some(ctoken) => Some(
|
||||||
|
query
|
||||||
|
.continuation(ctoken, self.endpoint, self.visitor_data.as_deref())
|
||||||
|
.await?,
|
||||||
|
),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -261,6 +212,7 @@ mod tests {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case("search", "search/cont")]
|
#[case("search", "search/cont")]
|
||||||
|
#[case("startpage", "trends/startpage_cont")]
|
||||||
fn map_continuation_items(#[case] name: &str, #[case] path: &str) {
|
fn map_continuation_items(#[case] name: &str, #[case] path: &str) {
|
||||||
let filename = format!("testfiles/{}.json", path);
|
let filename = format!("testfiles/{}.json", path);
|
||||||
let json_path = Path::new(&filename);
|
let json_path = Path::new(&filename);
|
||||||
|
|
|
@ -23,15 +23,6 @@ pub struct Channel {
|
||||||
pub alerts: Option<Vec<Alert>>,
|
pub alerts: Option<Vec<Alert>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ChannelCont {
|
|
||||||
#[serde(default)]
|
|
||||||
#[serde_as(as = "VecSkipError<_>")]
|
|
||||||
pub on_response_received_actions: Vec<OnResponseReceivedAction>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Contents {
|
pub struct Contents {
|
||||||
|
@ -205,17 +196,3 @@ pub struct PrimaryLink {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub navigation_endpoint: NavigationEndpoint,
|
pub navigation_endpoint: NavigationEndpoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct OnResponseReceivedAction {
|
|
||||||
pub append_continuation_items_action: AppendAction,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct AppendAction {
|
|
||||||
#[serde_as(as = "VecLogError<_>")]
|
|
||||||
pub continuation_items: MapResult<Vec<YouTubeListItem>>,
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,15 +9,12 @@ pub mod video_details;
|
||||||
pub mod video_item;
|
pub mod video_item;
|
||||||
|
|
||||||
pub use channel::Channel;
|
pub use channel::Channel;
|
||||||
pub use channel::ChannelCont;
|
|
||||||
pub use player::Player;
|
pub use player::Player;
|
||||||
pub use playlist::Playlist;
|
pub use playlist::Playlist;
|
||||||
pub use playlist::PlaylistCont;
|
pub use playlist::PlaylistCont;
|
||||||
pub use playlist_music::PlaylistMusic;
|
pub use playlist_music::PlaylistMusic;
|
||||||
pub use search::Search;
|
pub use search::Search;
|
||||||
pub use search::SearchCont;
|
|
||||||
pub use trends::Startpage;
|
pub use trends::Startpage;
|
||||||
pub use trends::StartpageCont;
|
|
||||||
pub use trends::Trending;
|
pub use trends::Trending;
|
||||||
pub use url_endpoint::ResolvedUrl;
|
pub use url_endpoint::ResolvedUrl;
|
||||||
pub use video_details::VideoComments;
|
pub use video_details::VideoComments;
|
||||||
|
|
|
@ -1,14 +1,7 @@
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_with::json::JsonString;
|
use serde_with::{json::JsonString, serde_as};
|
||||||
use serde_with::{serde_as, VecSkipError};
|
|
||||||
|
|
||||||
use crate::serializer::ignore_any;
|
use super::video_item::YouTubeListRendererWrap;
|
||||||
use crate::serializer::{text::Text, MapResult, VecLogError};
|
|
||||||
|
|
||||||
use super::video_item::YouTubeListItem;
|
|
||||||
use super::{
|
|
||||||
ChannelRenderer, ContentsRenderer, ContinuationEndpoint, PlaylistRenderer, VideoRenderer,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -19,28 +12,6 @@ pub struct Search {
|
||||||
pub contents: Contents,
|
pub contents: Contents,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct SearchCont {
|
|
||||||
#[serde_as(as = "Option<JsonString>")]
|
|
||||||
pub estimated_results: Option<u64>,
|
|
||||||
#[serde_as(as = "VecSkipError<_>")]
|
|
||||||
pub on_response_received_commands: Vec<SearchContCommand>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct SearchContCommand {
|
|
||||||
pub append_continuation_items_action: SearchContAction,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct SearchContAction {
|
|
||||||
pub continuation_items: Vec<SectionListItem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Contents {
|
pub struct Contents {
|
||||||
|
@ -50,52 +21,5 @@ pub struct Contents {
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TwoColumnSearchResultsRenderer {
|
pub struct TwoColumnSearchResultsRenderer {
|
||||||
pub primary_contents: PrimaryContents,
|
pub primary_contents: YouTubeListRendererWrap,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct PrimaryContents {
|
|
||||||
pub section_list_renderer: ContentsRenderer<SectionListItem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub enum SectionListItem {
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
ItemSectionRenderer {
|
|
||||||
#[serde_as(as = "VecLogError<_>")]
|
|
||||||
contents: MapResult<Vec<YouTubeListItem>>,
|
|
||||||
},
|
|
||||||
/// Continuation token to fetch more search results
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
ContinuationItemRenderer {
|
|
||||||
continuation_endpoint: ContinuationEndpoint,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub enum SearchItem {
|
|
||||||
/// Video in search results
|
|
||||||
VideoRenderer(VideoRenderer),
|
|
||||||
/// Playlist in search results
|
|
||||||
PlaylistRenderer(PlaylistRenderer),
|
|
||||||
/// Channel displayed in search results
|
|
||||||
ChannelRenderer(ChannelRenderer),
|
|
||||||
|
|
||||||
/// Corrected search query
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
ShowingResultsForRenderer {
|
|
||||||
#[serde_as(as = "Text")]
|
|
||||||
corrected_query: String,
|
|
||||||
},
|
|
||||||
/// No search result item (e.g. ad) or unimplemented item
|
|
||||||
///
|
|
||||||
/// Unimplemented:
|
|
||||||
/// - shelfRenderer (e.g. Latest from channel, For you)
|
|
||||||
#[serde(other, deserialize_with = "ignore_any")]
|
|
||||||
None,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,33 @@
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_with::{serde_as, VecSkipError};
|
use serde_with::{serde_as, VecSkipError};
|
||||||
|
|
||||||
use crate::serializer::{ignore_any, MapResult, VecLogError};
|
use super::{video_item::YouTubeListRendererWrap, ContentRenderer};
|
||||||
|
|
||||||
use super::{ContentRenderer, ContentsRenderer, VideoListItem, VideoRenderer};
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Startpage {
|
pub struct Startpage {
|
||||||
pub contents: Contents<BrowseResultsStartpage>,
|
pub contents: Contents,
|
||||||
pub response_context: ResponseContext,
|
pub response_context: ResponseContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct StartpageCont {
|
pub struct Trending {
|
||||||
#[serde(default)]
|
pub contents: Contents,
|
||||||
#[serde_as(as = "VecSkipError<_>")]
|
|
||||||
pub on_response_received_actions: Vec<OnResponseReceivedAction>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Contents<T> {
|
pub struct Contents {
|
||||||
pub two_column_browse_results_renderer: T,
|
pub two_column_browse_results_renderer: BrowseResults,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct BrowseResultsStartpage {
|
pub struct BrowseResults {
|
||||||
#[serde_as(as = "VecSkipError<_>")]
|
#[serde_as(as = "VecSkipError<_>")]
|
||||||
pub tabs: Vec<Tab<StartpageTabContent>>,
|
pub tabs: Vec<Tab<YouTubeListRendererWrap>>,
|
||||||
}
|
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct BrowseResultsTrends {
|
|
||||||
#[serde_as(as = "VecSkipError<_>")]
|
|
||||||
pub tabs: Vec<Tab<TrendingTabContent>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -49,85 +36,8 @@ pub struct Tab<T> {
|
||||||
pub tab_renderer: ContentRenderer<T>,
|
pub tab_renderer: ContentRenderer<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct StartpageTabContent {
|
|
||||||
pub rich_grid_renderer: RichGridRenderer,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct RichGridRenderer {
|
|
||||||
#[serde_as(as = "VecLogError<_>")]
|
|
||||||
pub contents: MapResult<Vec<VideoListItem>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct Trending {
|
|
||||||
pub contents: Contents<BrowseResultsTrends>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct TrendingTabContent {
|
|
||||||
pub section_list_renderer: ContentsRenderer<ItemSectionRenderer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ItemSectionRenderer {
|
|
||||||
pub item_section_renderer: ContentsRenderer<ShelfRenderer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ShelfRenderer {
|
|
||||||
pub shelf_renderer: ContentRenderer<ShelfContents>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ShelfContents {
|
|
||||||
pub expanded_shelf_contents_renderer: Option<ShelfContentsRenderer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ShelfContentsRenderer {
|
|
||||||
#[serde_as(as = "VecLogError<_>")]
|
|
||||||
pub items: MapResult<Vec<TrendingListItem>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ResponseContext {
|
pub struct ResponseContext {
|
||||||
pub visitor_data: Option<String>,
|
pub visitor_data: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
pub enum TrendingListItem {
|
|
||||||
VideoRenderer(VideoRenderer),
|
|
||||||
|
|
||||||
#[serde(other, deserialize_with = "ignore_any")]
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct OnResponseReceivedAction {
|
|
||||||
pub append_continuation_items_action: AppendAction,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct AppendAction {
|
|
||||||
#[serde_as(as = "VecLogError<_>")]
|
|
||||||
pub continuation_items: MapResult<Vec<VideoListItem>>,
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ pub enum YouTubeListItem {
|
||||||
///
|
///
|
||||||
/// Seems to be currently A/B tested on the channel page,
|
/// Seems to be currently A/B tested on the channel page,
|
||||||
/// as of 11.10.2022
|
/// as of 11.10.2022
|
||||||
|
#[serde(alias = "shelfRenderer")]
|
||||||
RichItemRenderer {
|
RichItemRenderer {
|
||||||
content: Box<YouTubeListItem>,
|
content: Box<YouTubeListItem>,
|
||||||
},
|
},
|
||||||
|
@ -57,7 +58,9 @@ pub enum YouTubeListItem {
|
||||||
///
|
///
|
||||||
/// Seems to be currently A/B tested on the video details page,
|
/// Seems to be currently A/B tested on the video details page,
|
||||||
/// as of 11.10.2022
|
/// as of 11.10.2022
|
||||||
|
#[serde(alias = "expandedShelfContentsRenderer")]
|
||||||
ItemSectionRenderer {
|
ItemSectionRenderer {
|
||||||
|
#[serde(alias = "items")]
|
||||||
#[serde_as(as = "VecLogError<_>")]
|
#[serde_as(as = "VecLogError<_>")]
|
||||||
contents: MapResult<Vec<YouTubeListItem>>,
|
contents: MapResult<Vec<YouTubeListItem>>,
|
||||||
},
|
},
|
||||||
|
@ -162,6 +165,21 @@ pub struct ChannelRenderer {
|
||||||
pub owner_badges: Vec<ChannelBadge>,
|
pub owner_badges: Vec<ChannelBadge>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct YouTubeListRendererWrap {
|
||||||
|
#[serde(alias = "richGridRenderer")]
|
||||||
|
pub section_list_renderer: YouTubeListRenderer,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde_as]
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct YouTubeListRenderer {
|
||||||
|
#[serde_as(as = "VecLogError<_>")]
|
||||||
|
pub contents: MapResult<Vec<YouTubeListItem>>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Result of mapping a list of different YouTube enities
|
/// Result of mapping a list of different YouTube enities
|
||||||
/// (videos, channels, playlists)
|
/// (videos, channels, playlists)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -375,32 +393,3 @@ impl YouTubeListMapper<PlaylistItem> {
|
||||||
res.c.into_iter().for_each(|item| self.map_item(item));
|
res.c.into_iter().for_each(|item| self.map_item(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl YouTubeListMapper<ChannelItem> {
|
|
||||||
fn map_item(&mut self, item: YouTubeListItem) {
|
|
||||||
match item {
|
|
||||||
YouTubeListItem::ChannelRenderer(channel) => {
|
|
||||||
self.items.push(Self::map_channel(channel));
|
|
||||||
}
|
|
||||||
YouTubeListItem::ContinuationItemRenderer {
|
|
||||||
continuation_endpoint,
|
|
||||||
} => self.ctoken = Some(continuation_endpoint.continuation_command.token),
|
|
||||||
YouTubeListItem::ShowingResultsForRenderer { corrected_query } => {
|
|
||||||
self.corrected_query = Some(corrected_query);
|
|
||||||
}
|
|
||||||
YouTubeListItem::RichItemRenderer { content } => {
|
|
||||||
self.map_item(*content);
|
|
||||||
}
|
|
||||||
YouTubeListItem::ItemSectionRenderer { mut contents } => {
|
|
||||||
self.warnings.append(&mut contents.warnings);
|
|
||||||
contents.c.into_iter().for_each(|it| self.map_item(it));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_response(&mut self, mut res: MapResult<Vec<YouTubeListItem>>) {
|
|
||||||
self.warnings.append(&mut res.warnings);
|
|
||||||
res.c.into_iter().for_each(|item| self.map_item(item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -93,21 +93,19 @@ impl MapResponse<SearchResult> for response::Search {
|
||||||
lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&Deobfuscator>,
|
_deobf: Option<&Deobfuscator>,
|
||||||
) -> Result<MapResult<SearchResult>, ExtractionError> {
|
) -> Result<MapResult<SearchResult>, ExtractionError> {
|
||||||
let section_list_items = self
|
let items = self
|
||||||
.contents
|
.contents
|
||||||
.two_column_search_results_renderer
|
.two_column_search_results_renderer
|
||||||
.primary_contents
|
.primary_contents
|
||||||
.section_list_renderer
|
.section_list_renderer
|
||||||
.contents;
|
.contents;
|
||||||
|
|
||||||
let (items, ctoken) = map_section_list_items(section_list_items)?;
|
|
||||||
|
|
||||||
let mut mapper = response::YouTubeListMapper::<YouTubeItem>::new(lang);
|
let mut mapper = response::YouTubeListMapper::<YouTubeItem>::new(lang);
|
||||||
mapper.map_response(items);
|
mapper.map_response(items);
|
||||||
|
|
||||||
Ok(MapResult {
|
Ok(MapResult {
|
||||||
c: SearchResult {
|
c: SearchResult {
|
||||||
items: Paginator::new(self.estimated_results, mapper.items, ctoken),
|
items: Paginator::new(self.estimated_results, mapper.items, mapper.ctoken),
|
||||||
corrected_query: mapper.corrected_query,
|
corrected_query: mapper.corrected_query,
|
||||||
},
|
},
|
||||||
warnings: mapper.warnings,
|
warnings: mapper.warnings,
|
||||||
|
@ -115,32 +113,6 @@ impl MapResponse<SearchResult> for response::Search {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_section_list_items(
|
|
||||||
section_list_items: Vec<response::search::SectionListItem>,
|
|
||||||
) -> Result<(MapResult<Vec<response::YouTubeListItem>>, Option<String>), ExtractionError> {
|
|
||||||
let mut items = None;
|
|
||||||
let mut ctoken = None;
|
|
||||||
section_list_items.into_iter().for_each(|item| match item {
|
|
||||||
response::search::SectionListItem::ItemSectionRenderer { contents } => {
|
|
||||||
items = Some(contents);
|
|
||||||
}
|
|
||||||
response::search::SectionListItem::ContinuationItemRenderer {
|
|
||||||
continuation_endpoint,
|
|
||||||
} => {
|
|
||||||
ctoken = Some(continuation_endpoint.continuation_command.token);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let items = some_or_bail!(
|
|
||||||
items,
|
|
||||||
Err(ExtractionError::InvalidData(
|
|
||||||
"no item section renderer".into()
|
|
||||||
))
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok((items, ctoken))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{fs::File, io::BufReader, path::Path};
|
use std::{fs::File, io::BufReader, path::Path};
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
source: src/client/trends.rs
|
source: src/client/pagination.rs
|
||||||
expression: map_res.c
|
expression: map_res.c
|
||||||
---
|
---
|
||||||
Paginator(
|
Paginator(
|
||||||
count: None,
|
count: None,
|
||||||
items: [
|
items: [
|
||||||
SearchVideo(
|
Video(VideoItem(
|
||||||
id: "mRmlXh7Hams",
|
id: "mRmlXh7Hams",
|
||||||
title: "Extra 3 vom 12.10.2022 im NDR | extra 3 | NDR",
|
title: "Extra 3 vom 12.10.2022 im NDR | extra 3 | NDR",
|
||||||
length: Some(1839),
|
length: Some(1839),
|
||||||
|
@ -16,7 +16,7 @@ Paginator(
|
||||||
height: 270,
|
height: 270,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCjhkuC_Pi85wGjnB0I1ydxw",
|
id: "UCjhkuC_Pi85wGjnB0I1ydxw",
|
||||||
name: "extra 3",
|
name: "extra 3",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -28,15 +28,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("2 days ago"),
|
publish_date_txt: Some("2 days ago"),
|
||||||
view_count: 585257,
|
view_count: Some(585257),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Niedersachsen nach der Wahl: Schuld ist immer die Ampel | Die Grünen: Partei der erneuerbaren Prinzipien | Verhütung? Ist Frauensache! | Youtube: Handwerk mit goldenem Boden - Christian Ehring...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Niedersachsen nach der Wahl: Schuld ist immer die Ampel | Die Grünen: Partei der erneuerbaren Prinzipien | Verhütung? Ist Frauensache! | Youtube: Handwerk mit goldenem Boden - Christian Ehring..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "LsXC5r64Pvc",
|
id: "LsXC5r64Pvc",
|
||||||
title: "Most Rarest Plays In Baseball History",
|
title: "Most Rarest Plays In Baseball History",
|
||||||
length: Some(1975),
|
length: Some(1975),
|
||||||
|
@ -47,7 +48,7 @@ Paginator(
|
||||||
height: 270,
|
height: 270,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCRfKJZ7LHueFudiDgAJDr9Q",
|
id: "UCRfKJZ7LHueFudiDgAJDr9Q",
|
||||||
name: "Top All Sports",
|
name: "Top All Sports",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -59,15 +60,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("3 weeks ago"),
|
publish_date_txt: Some("3 weeks ago"),
|
||||||
view_count: 985521,
|
view_count: Some(985521),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "#baseball #mlb #mlbb",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("#baseball #mlb #mlbb"),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "dwPmd1GqQHE",
|
id: "dwPmd1GqQHE",
|
||||||
title: "90S RAP & HIPHOP MIX - Notorious B I G , Dr Dre, 50 Cent, Snoop Dogg, 2Pac, DMX, Lil Jon and more",
|
title: "90S RAP & HIPHOP MIX - Notorious B I G , Dr Dre, 50 Cent, Snoop Dogg, 2Pac, DMX, Lil Jon and more",
|
||||||
length: Some(5457),
|
length: Some(5457),
|
||||||
|
@ -78,7 +80,7 @@ Paginator(
|
||||||
height: 270,
|
height: 270,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCKICAAGtBLJJ5zRdIxn_B4g",
|
id: "UCKICAAGtBLJJ5zRdIxn_B4g",
|
||||||
name: "#Hip Hop 2022",
|
name: "#Hip Hop 2022",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -90,15 +92,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("5 months ago"),
|
publish_date_txt: Some("5 months ago"),
|
||||||
view_count: 1654055,
|
view_count: Some(1654055),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "",
|
is_upcoming: false,
|
||||||
),
|
short_description: None,
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "qxI-Ob8lpLE",
|
id: "qxI-Ob8lpLE",
|
||||||
title: "Schlatt\'s Chips Tier List",
|
title: "Schlatt\'s Chips Tier List",
|
||||||
length: Some(1071),
|
length: Some(1071),
|
||||||
|
@ -114,7 +117,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UC2mP7il3YV7TxM_3m6U0bwA",
|
id: "UC2mP7il3YV7TxM_3m6U0bwA",
|
||||||
name: "jschlattLIVE",
|
name: "jschlattLIVE",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -126,15 +129,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("1 year ago"),
|
publish_date_txt: Some("1 year ago"),
|
||||||
view_count: 9029628,
|
view_count: Some(9029628),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Schlatt ranks every chip ever made.\nCREATE YOUR OWN TIER LIST: https://tiermaker.com/create/chips-for-big-guy-1146620\n\nSubscribe to me on Twitch:\nhttps://twitch.tv/jschlatt\n\nFollow me on Twitter:...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Schlatt ranks every chip ever made.\nCREATE YOUR OWN TIER LIST: https://tiermaker.com/create/chips-for-big-guy-1146620\n\nSubscribe to me on Twitch:\nhttps://twitch.tv/jschlatt\n\nFollow me on Twitter:..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "qmrzTUmZ4UU",
|
id: "qmrzTUmZ4UU",
|
||||||
title: "850€ für den Verrat am System - UCS AT-AT LEGO® Star Wars 75313",
|
title: "850€ für den Verrat am System - UCS AT-AT LEGO® Star Wars 75313",
|
||||||
length: Some(2043),
|
length: Some(2043),
|
||||||
|
@ -150,7 +154,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UC_EZd3lsmxudu3IQzpTzOgw",
|
id: "UC_EZd3lsmxudu3IQzpTzOgw",
|
||||||
name: "Held der Steine Inh. Thomas Panke",
|
name: "Held der Steine Inh. Thomas Panke",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -162,15 +166,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("6 days ago"),
|
publish_date_txt: Some("6 days ago"),
|
||||||
view_count: 600516,
|
view_count: Some(600516),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Star Wars - erschienen 2021 - 6749 Teile\n\nDieses Set bei Amazon*:\nhttps://amzn.to/3yu9dHX\n\nErwähnt im Video*:\nTassen https://bit.ly/HdSBausteinecke\nBig Boy https://bit.ly/BBLokBigBoy\nBurg...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Star Wars - erschienen 2021 - 6749 Teile\n\nDieses Set bei Amazon*:\nhttps://amzn.to/3yu9dHX\n\nErwähnt im Video*:\nTassen https://bit.ly/HdSBausteinecke\nBig Boy https://bit.ly/BBLokBigBoy\nBurg..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "4q4vpQCIZ6w",
|
id: "4q4vpQCIZ6w",
|
||||||
title: "🌉 Manhattan Jazz 💖 l Relaxing Jazz Piano Music l Background Music",
|
title: "🌉 Manhattan Jazz 💖 l Relaxing Jazz Piano Music l Background Music",
|
||||||
length: Some(23229),
|
length: Some(23229),
|
||||||
|
@ -186,7 +191,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCBnMxlW70f0SB4ZTJx124lw",
|
id: "UCBnMxlW70f0SB4ZTJx124lw",
|
||||||
name: "몽키비지엠 MONKEYBGM",
|
name: "몽키비지엠 MONKEYBGM",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -198,15 +203,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("6 months ago"),
|
publish_date_txt: Some("6 months ago"),
|
||||||
view_count: 2343407,
|
view_count: Some(2343407),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "- Please Subscribe!\n\n🔺Disney OST Collection part 1 \n ➡\u{fe0f} https://youtu.be/lrzKFu85nhE\n\n🔺Disney OST Collection part 2 \n ➡\u{fe0f} https://youtu.be/EtE09lowIbk\n\n🔺Studio Ghibli...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("- Please Subscribe!\n\n🔺Disney OST Collection part 1 \n ➡\u{fe0f} https://youtu.be/lrzKFu85nhE\n\n🔺Disney OST Collection part 2 \n ➡\u{fe0f} https://youtu.be/EtE09lowIbk\n\n🔺Studio Ghibli..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "Z_k31kqZxaE",
|
id: "Z_k31kqZxaE",
|
||||||
title: "1 in 1,000,000 NBA Moments",
|
title: "1 in 1,000,000 NBA Moments",
|
||||||
length: Some(567),
|
length: Some(567),
|
||||||
|
@ -222,7 +228,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCpyoYVlp67N16Lg1_N4VnVw",
|
id: "UCpyoYVlp67N16Lg1_N4VnVw",
|
||||||
name: "dime",
|
name: "dime",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -234,15 +240,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("1 month ago"),
|
publish_date_txt: Some("1 month ago"),
|
||||||
view_count: 4334298,
|
view_count: Some(4334298),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "• Instagram - https://instagram.com/dime_nba\n• TikTok - https://tiktok.com/@dime_nba\n\ndime is a Swedish brand, founded in 2022. We produce some of the most entertaining NBA content on YouTube...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("• Instagram - https://instagram.com/dime_nba\n• TikTok - https://tiktok.com/@dime_nba\n\ndime is a Swedish brand, founded in 2022. We produce some of the most entertaining NBA content on YouTube..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "zE-a5eqvlv8",
|
id: "zE-a5eqvlv8",
|
||||||
title: "Dua Lipa, Coldplay, Martin Garrix & Kygo, The Chainsmokers Style - Feeling Me",
|
title: "Dua Lipa, Coldplay, Martin Garrix & Kygo, The Chainsmokers Style - Feeling Me",
|
||||||
length: None,
|
length: None,
|
||||||
|
@ -258,7 +265,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCX-USfenzQlhrEJR1zD5IYw",
|
id: "UCX-USfenzQlhrEJR1zD5IYw",
|
||||||
name: "Deep Mood.",
|
name: "Deep Mood.",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -270,15 +277,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: None,
|
publish_date_txt: None,
|
||||||
view_count: 889,
|
view_count: Some(889),
|
||||||
is_live: false,
|
is_live: true,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "#Summermix #DeepHouse #DeepHouseSummerMix\nDua Lipa, Coldplay, Martin Garrix & Kygo, The Chainsmokers Style - Feeling Me\n\n🎵 All songs in this spotify playlist: https://spoti.fi/2TJ4Dyj\nSubmit...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("#Summermix #DeepHouse #DeepHouseSummerMix\nDua Lipa, Coldplay, Martin Garrix & Kygo, The Chainsmokers Style - Feeling Me\n\n🎵 All songs in this spotify playlist: https://spoti.fi/2TJ4Dyj\nSubmit..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "gNlOk0LXi5M",
|
id: "gNlOk0LXi5M",
|
||||||
title: "Soll ich dir 1g GOLD schenken? oder JEMAND anderen DOPPELT?",
|
title: "Soll ich dir 1g GOLD schenken? oder JEMAND anderen DOPPELT?",
|
||||||
length: Some(704),
|
length: Some(704),
|
||||||
|
@ -294,7 +302,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCqcWNPTUVATZt0Dlr2jV0Wg",
|
id: "UCqcWNPTUVATZt0Dlr2jV0Wg",
|
||||||
name: "Mois",
|
name: "Mois",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -306,15 +314,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("8 days ago"),
|
publish_date_txt: Some("8 days ago"),
|
||||||
view_count: 463834,
|
view_count: Some(463834),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Je mehr Menschen mich abonnieren desto mehr Menschen werde ich glücklich machen \n\n24 std ab, viel Glück \n\nhttps://I-Clip.com/?sPartner=Mois",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Je mehr Menschen mich abonnieren desto mehr Menschen werde ich glücklich machen \n\n24 std ab, viel Glück \n\nhttps://I-Clip.com/?sPartner=Mois"),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "dbMvZjs8Yc8",
|
id: "dbMvZjs8Yc8",
|
||||||
title: "Brad Pitt- Die Revanche eines Sexsymbols | Doku HD | ARTE",
|
title: "Brad Pitt- Die Revanche eines Sexsymbols | Doku HD | ARTE",
|
||||||
length: Some(3137),
|
length: Some(3137),
|
||||||
|
@ -330,7 +339,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCsygZtQQSplGF6JA3XWvsdg",
|
id: "UCsygZtQQSplGF6JA3XWvsdg",
|
||||||
name: "Irgendwas mit ARTE und Kultur",
|
name: "Irgendwas mit ARTE und Kultur",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -342,15 +351,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("5 days ago"),
|
publish_date_txt: Some("5 days ago"),
|
||||||
view_count: 293878,
|
view_count: Some(293878),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Vom „People“-Magazin wurde er mehrfach zum „Sexiest Man Alive“ gekrönt. Aber sein Aussehen ist nicht alles: In 30 Jahren Karriere drehte Brad Pitt eine Vielzahl herausragender Filme....",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Vom „People“-Magazin wurde er mehrfach zum „Sexiest Man Alive“ gekrönt. Aber sein Aussehen ist nicht alles: In 30 Jahren Karriere drehte Brad Pitt eine Vielzahl herausragender Filme...."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "mFxi3lOAcFs",
|
id: "mFxi3lOAcFs",
|
||||||
title: "Craziest Soviet Machines You Won\'t Believe Exist - Part 1",
|
title: "Craziest Soviet Machines You Won\'t Believe Exist - Part 1",
|
||||||
length: Some(1569),
|
length: Some(1569),
|
||||||
|
@ -366,7 +376,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCkQO3QsgTpNTsOw6ujimT5Q",
|
id: "UCkQO3QsgTpNTsOw6ujimT5Q",
|
||||||
name: "BE AMAZED",
|
name: "BE AMAZED",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -378,15 +388,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("1 year ago"),
|
publish_date_txt: Some("1 year ago"),
|
||||||
view_count: 14056843,
|
view_count: Some(14056843),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Coming up are some crazy Soviet-era machines you won\'t believe exist!\nPart 2: https://youtu.be/MBZVOJrhuHY\nSuggest a topic here to be turned into a video: http://bit.ly/2kwqhuh\nSubscribe for...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Coming up are some crazy Soviet-era machines you won\'t believe exist!\nPart 2: https://youtu.be/MBZVOJrhuHY\nSuggest a topic here to be turned into a video: http://bit.ly/2kwqhuh\nSubscribe for..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "eu7ubm7g59E",
|
id: "eu7ubm7g59E",
|
||||||
title: "People Hated Me For Using This Slab",
|
title: "People Hated Me For Using This Slab",
|
||||||
length: Some(1264),
|
length: Some(1264),
|
||||||
|
@ -402,7 +413,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UC6I0KzAD7uFTL1qzxyunkvA",
|
id: "UC6I0KzAD7uFTL1qzxyunkvA",
|
||||||
name: "Blacktail Studio",
|
name: "Blacktail Studio",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -414,15 +425,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("3 months ago"),
|
publish_date_txt: Some("3 months ago"),
|
||||||
view_count: 2845035,
|
view_count: Some(2845035),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Some people were furious I used this slab, and I actually understand why. \nBlacktail bow tie jig (limited first run): https://www.blacktailstudio.com/bowtie-jig\nBlacktail epoxy table workshop:...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Some people were furious I used this slab, and I actually understand why. \nBlacktail bow tie jig (limited first run): https://www.blacktailstudio.com/bowtie-jig\nBlacktail epoxy table workshop:..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "TRGHIN2PGIA",
|
id: "TRGHIN2PGIA",
|
||||||
title: "Christian Bale Breaks Down His Most Iconic Characters | GQ",
|
title: "Christian Bale Breaks Down His Most Iconic Characters | GQ",
|
||||||
length: Some(1381),
|
length: Some(1381),
|
||||||
|
@ -438,7 +450,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCsEukrAd64fqA7FjwkmZ_Dw",
|
id: "UCsEukrAd64fqA7FjwkmZ_Dw",
|
||||||
name: "GQ",
|
name: "GQ",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -450,15 +462,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("9 days ago"),
|
publish_date_txt: Some("9 days ago"),
|
||||||
view_count: 8044465,
|
view_count: Some(8044465),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Christian Bale breaks down a few of his most iconic characters from \'American Psycho,\' \'The Dark Knight\' Trilogy, \'The Fighter,\' \'The Machinist,\' \'The Big Short,\' \'Vice,\' \'Empire of the Sun,\'...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Christian Bale breaks down a few of his most iconic characters from \'American Psycho,\' \'The Dark Knight\' Trilogy, \'The Fighter,\' \'The Machinist,\' \'The Big Short,\' \'Vice,\' \'Empire of the Sun,\'..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "w3tENzcssDU",
|
id: "w3tENzcssDU",
|
||||||
title: "NFL Trick Plays But They Get Increasingly Higher IQ",
|
title: "NFL Trick Plays But They Get Increasingly Higher IQ",
|
||||||
length: Some(599),
|
length: Some(599),
|
||||||
|
@ -474,7 +487,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCJka5SDh36_N4pjJd69efkg",
|
id: "UCJka5SDh36_N4pjJd69efkg",
|
||||||
name: "Savage Brick Sports",
|
name: "Savage Brick Sports",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -486,15 +499,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("3 months ago"),
|
publish_date_txt: Some("3 months ago"),
|
||||||
view_count: 1172372,
|
view_count: Some(1172372),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "NFL Trick Plays But They Get Increasingly Higher IQ\nCredit to CoshReport for starting this trend.\n\n(if any of the links don\'t work, check most recent video)\nTalkSports Discord: https://discord.gg/n...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("NFL Trick Plays But They Get Increasingly Higher IQ\nCredit to CoshReport for starting this trend.\n\n(if any of the links don\'t work, check most recent video)\nTalkSports Discord: https://discord.gg/n..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "gUAd2XXzH7w",
|
id: "gUAd2XXzH7w",
|
||||||
title: "⚓\u{fe0f}Found ABANDONED SHIP!!! Big CRUISE SHIP on a desert island☠\u{fe0f} Where did the people go?!?",
|
title: "⚓\u{fe0f}Found ABANDONED SHIP!!! Big CRUISE SHIP on a desert island☠\u{fe0f} Where did the people go?!?",
|
||||||
length: Some(2949),
|
length: Some(2949),
|
||||||
|
@ -510,7 +524,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UClUZos7yKYtrmr0-azaD8pw",
|
id: "UClUZos7yKYtrmr0-azaD8pw",
|
||||||
name: "Kreosan English",
|
name: "Kreosan English",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -522,15 +536,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("1 month ago"),
|
publish_date_txt: Some("1 month ago"),
|
||||||
view_count: 1883533,
|
view_count: Some(1883533),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "We are preparing a continuation of the cruise ship for you! Very soon you will be able to see the next part. If you would like to help us make a video:\n\n► Support us - https://www.patreon.com/k...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("We are preparing a continuation of the cruise ship for you! Very soon you will be able to see the next part. If you would like to help us make a video:\n\n► Support us - https://www.patreon.com/k..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "YpGjaJ1ettI",
|
id: "YpGjaJ1ettI",
|
||||||
title: "[Working BGM] Comfortable music that makes you feel positive -- Morning Mood -- Daily Routine",
|
title: "[Working BGM] Comfortable music that makes you feel positive -- Morning Mood -- Daily Routine",
|
||||||
length: Some(3651),
|
length: Some(3651),
|
||||||
|
@ -546,7 +561,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCpxY9-3iB5Hyho31uBgzh7w",
|
id: "UCpxY9-3iB5Hyho31uBgzh7w",
|
||||||
name: "Daily Routine",
|
name: "Daily Routine",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -558,15 +573,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("2 months ago"),
|
publish_date_txt: Some("2 months ago"),
|
||||||
view_count: 1465389,
|
view_count: Some(1465389),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Hello everyone. It\'s me again. I will stay at home and study . It\'s full of fun energy today, so it\'s ready to spread to everyone with hilarious music. 🔥🔥🔥\nHave fun together 😊😊😊...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Hello everyone. It\'s me again. I will stay at home and study . It\'s full of fun energy today, so it\'s ready to spread to everyone with hilarious music. 🔥🔥🔥\nHave fun together 😊😊😊..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "rPAhFD8hKxQ",
|
id: "rPAhFD8hKxQ",
|
||||||
title: "Survival Camping 9ft/3m Under Snow - Giant Winter Bushcraft Shelter and Quinzee",
|
title: "Survival Camping 9ft/3m Under Snow - Giant Winter Bushcraft Shelter and Quinzee",
|
||||||
length: Some(1301),
|
length: Some(1301),
|
||||||
|
@ -582,7 +598,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCfpCQ89W9wjkHc8J_6eTbBg",
|
id: "UCfpCQ89W9wjkHc8J_6eTbBg",
|
||||||
name: "Outdoor Boys",
|
name: "Outdoor Boys",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -594,15 +610,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("6 months ago"),
|
publish_date_txt: Some("6 months ago"),
|
||||||
view_count: 20488431,
|
view_count: Some(20488431),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Solo winter camping and bushcraft 9 feet (3 meters) under the snow. I hiked high up into the mountains during a snow storm with 30 mph/48 kmh winds to build a deep snow bushcraft survival shelter...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Solo winter camping and bushcraft 9 feet (3 meters) under the snow. I hiked high up into the mountains during a snow storm with 30 mph/48 kmh winds to build a deep snow bushcraft survival shelter..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "2rye4u-cCNk",
|
id: "2rye4u-cCNk",
|
||||||
title: "Pink Panther Fights Off Pests | 54 Minute Compilation | The Pink Panther Show",
|
title: "Pink Panther Fights Off Pests | 54 Minute Compilation | The Pink Panther Show",
|
||||||
length: Some(3158),
|
length: Some(3158),
|
||||||
|
@ -618,7 +635,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCFeUyPY6W8qX8w2o6oSiRmw",
|
id: "UCFeUyPY6W8qX8w2o6oSiRmw",
|
||||||
name: "Official Pink Panther",
|
name: "Official Pink Panther",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -630,15 +647,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("11 months ago"),
|
publish_date_txt: Some("11 months ago"),
|
||||||
view_count: 27357653,
|
view_count: Some(27357653),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "(1) Pink Pest Control\n(2) Pink-a-Boo\n(3) Little Beaux Pink\n(4) The Pink Package Plot\n(5) Come On In! The Water\'s Pink\n(6) Psychedelic Pink\n(7) Pink Posies\n(8) G.I. Pink\n\nThe Pink Panther is...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("(1) Pink Pest Control\n(2) Pink-a-Boo\n(3) Little Beaux Pink\n(4) The Pink Package Plot\n(5) Come On In! The Water\'s Pink\n(6) Psychedelic Pink\n(7) Pink Posies\n(8) G.I. Pink\n\nThe Pink Panther is..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "O0xAlfSaBNQ",
|
id: "O0xAlfSaBNQ",
|
||||||
title: "FC Nantes vs. SC Freiburg – Highlights & Tore | UEFA Europa League",
|
title: "FC Nantes vs. SC Freiburg – Highlights & Tore | UEFA Europa League",
|
||||||
length: Some(326),
|
length: Some(326),
|
||||||
|
@ -654,7 +672,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UC8WYi3XQXsf-6FNvqoEvxag",
|
id: "UC8WYi3XQXsf-6FNvqoEvxag",
|
||||||
name: "RTL Sport",
|
name: "RTL Sport",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -666,15 +684,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("11 hours ago"),
|
publish_date_txt: Some("11 hours ago"),
|
||||||
view_count: 117395,
|
view_count: Some(117395),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "UEFA Europa League: https://www.rtlplus.com/shows/uefa-europa-league-19818?utm_source=youtube&utm_medium=editorial&utm_campaign=beschreibung&utm_term=rtlsport \nFC Nantes vs. SC Freiburg –...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("UEFA Europa League: https://www.rtlplus.com/shows/uefa-europa-league-19818?utm_source=youtube&utm_medium=editorial&utm_campaign=beschreibung&utm_term=rtlsport \nFC Nantes vs. SC Freiburg –..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "Mhs9Sbnw19o",
|
id: "Mhs9Sbnw19o",
|
||||||
title: "Dramatisches Duell: 400 Jahre altes Kästchen erzielt zig-fachen Wunschpreis! | Bares für Rares XXL",
|
title: "Dramatisches Duell: 400 Jahre altes Kästchen erzielt zig-fachen Wunschpreis! | Bares für Rares XXL",
|
||||||
length: Some(744),
|
length: Some(744),
|
||||||
|
@ -690,7 +709,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UC53bIpnef1pwAx69ERmmOLA",
|
id: "UC53bIpnef1pwAx69ERmmOLA",
|
||||||
name: "Bares für Rares",
|
name: "Bares für Rares",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -702,15 +721,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("11 days ago"),
|
publish_date_txt: Some("11 days ago"),
|
||||||
view_count: 836333,
|
view_count: Some(836333),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Du hast Schätze im Keller, die du unseren Expert*innen präsentieren möchtest? Hier geht\'s zum Bewerbungsformular: kurz.zdf.de/lSJ/\n\nEin einmaliges Bieterduell treibt den Preis für dieses...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Du hast Schätze im Keller, die du unseren Expert*innen präsentieren möchtest? Hier geht\'s zum Bewerbungsformular: kurz.zdf.de/lSJ/\n\nEin einmaliges Bieterduell treibt den Preis für dieses..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "Bzzp5Cay7DI",
|
id: "Bzzp5Cay7DI",
|
||||||
title: "Sweet Jazz - Cool autumn Bossa Nova & October Jazz Positive Mood",
|
title: "Sweet Jazz - Cool autumn Bossa Nova & October Jazz Positive Mood",
|
||||||
length: None,
|
length: None,
|
||||||
|
@ -726,7 +746,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCoGlllJE7aYe_VzIGP3s_wA",
|
id: "UCoGlllJE7aYe_VzIGP3s_wA",
|
||||||
name: "Smooth Jazz Music",
|
name: "Smooth Jazz Music",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -738,15 +758,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: None,
|
publish_date_txt: None,
|
||||||
view_count: 1216,
|
view_count: Some(1216),
|
||||||
is_live: false,
|
is_live: true,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Sweet Jazz - Cool autumn Bossa Nova & October Jazz Positive Mood\nhttps://youtu.be/Bzzp5Cay7DI\n********************************************\nSounds available on: Jazz Bossa Nova\nOFFICIAL VIDEO:...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Sweet Jazz - Cool autumn Bossa Nova & October Jazz Positive Mood\nhttps://youtu.be/Bzzp5Cay7DI\n********************************************\nSounds available on: Jazz Bossa Nova\nOFFICIAL VIDEO:..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "SlskTqc9CEc",
|
id: "SlskTqc9CEc",
|
||||||
title: "The Chick-Fil-A Full Menu Challenge",
|
title: "The Chick-Fil-A Full Menu Challenge",
|
||||||
length: Some(613),
|
length: Some(613),
|
||||||
|
@ -762,7 +783,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCd1fLoVFooPeWqCEYVUJZqg",
|
id: "UCd1fLoVFooPeWqCEYVUJZqg",
|
||||||
name: "Matt Stonie",
|
name: "Matt Stonie",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -774,15 +795,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("3 years ago"),
|
publish_date_txt: Some("3 years ago"),
|
||||||
view_count: 39286403,
|
view_count: Some(39286403),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Good Video? Like/Fav & Share!!\n\nTBH this is really my 1st time trying Chick-Fil-A, legitimately. My verdict is torn, but that sauce is BOMB!\n\nChallenge\n+ Chick-Fil-A Deluxe\n+ Spicy Deluxe\n+...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("Good Video? Like/Fav & Share!!\n\nTBH this is really my 1st time trying Chick-Fil-A, legitimately. My verdict is torn, but that sauce is BOMB!\n\nChallenge\n+ Chick-Fil-A Deluxe\n+ Spicy Deluxe\n+..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "CwRvM2TfYbs",
|
id: "CwRvM2TfYbs",
|
||||||
title: "Gentle healing music of health and to calm the nervous system, deep relaxation! Say Life Yes",
|
title: "Gentle healing music of health and to calm the nervous system, deep relaxation! Say Life Yes",
|
||||||
length: None,
|
length: None,
|
||||||
|
@ -798,7 +820,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UC6jH5GNi0iOR17opA1Vowhw",
|
id: "UC6jH5GNi0iOR17opA1Vowhw",
|
||||||
name: "Lucid Dream",
|
name: "Lucid Dream",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -810,15 +832,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: None,
|
publish_date_txt: None,
|
||||||
view_count: 1416,
|
view_count: Some(1416),
|
||||||
is_live: false,
|
is_live: true,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "🌿 Music for relaxation, meditation, study, reading, massage, spa or sleep. This music is ideal for dealing with anxiety, stress or insomnia as it promotes relaxation and helps eliminate...",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("🌿 Music for relaxation, meditation, study, reading, massage, spa or sleep. This music is ideal for dealing with anxiety, stress or insomnia as it promotes relaxation and helps eliminate..."),
|
||||||
SearchVideo(
|
)),
|
||||||
|
Video(VideoItem(
|
||||||
id: "7jz0pXSe_kI",
|
id: "7jz0pXSe_kI",
|
||||||
title: "Craziest \"Fine...I\'ll Do it Myself\" Moments in Sports History (PART 2)",
|
title: "Craziest \"Fine...I\'ll Do it Myself\" Moments in Sports History (PART 2)",
|
||||||
length: Some(1822),
|
length: Some(1822),
|
||||||
|
@ -834,7 +857,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCd5hdemikI6GxwGKhJCwzww",
|
id: "UCd5hdemikI6GxwGKhJCwzww",
|
||||||
name: "Highlight Reel",
|
name: "Highlight Reel",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -846,14 +869,15 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("10 months ago"),
|
publish_date_txt: Some("10 months ago"),
|
||||||
view_count: 11601863,
|
view_count: Some(11601863),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "(PART 2) of 👉🏼 Craziest \"Fine...I\'ll Do It Myself\" Moments in Sports History \n\nBIBLE VERSE OF THE DAY: Luke 12:40",
|
is_upcoming: false,
|
||||||
),
|
short_description: Some("(PART 2) of 👉🏼 Craziest \"Fine...I\'ll Do It Myself\" Moments in Sports History \n\nBIBLE VERSE OF THE DAY: Luke 12:40"),
|
||||||
|
)),
|
||||||
],
|
],
|
||||||
ctoken: Some("4qmFsgKxAxIPRkV3aGF0X3RvX3dhdGNoGoADQ0RCNmxnSkhUWFpRYzJOVU1UUm1iME5OWjNOSmQzWjZOM0JPWlZWMldqZDFRVlp3ZEVOdGMwdEhXR3d3V0ROQ2FGb3lWbVpqTWpWb1kwaE9iMkl6VW1aamJWWnVZVmM1ZFZsWGQxTklNVlUwVDFSU1dXUXhUbXhXTTBaeVdsaGtSRkpGYkZCWk0yaDZWbXMxTlV4VmVGbE1XRnBSVlcxallVeFJRVUZhVnpSQlFWWldWRUZCUmtWU1VVRkNRVVZhUm1ReWFHaGtSamt3WWpFNU0xbFlVbXBoUVVGQ1FVRkZRa0ZCUVVKQlFVVkJRVUZGUWtGSFNrSkRRVUZUUlROQ2FGb3lWbVpqTWpWb1kwaE9iMkl6VW1aa1J6bHlXbGMwWVVWM2Ftb3hPRkJGT1dWSU5rRm9WVlpZWlVGTFNGaHVSMEp2ZDJsRmQycERObkZmUlRsbFNEWkJhRmRIZG1RMFMwaGxaMGhDTlZnMmJrMWxPVU5SU1VsTlVRJTNEJTNEmgIaYnJvd3NlLWZlZWRGRXdoYXRfdG9fd2F0Y2g%3D"),
|
ctoken: Some("4qmFsgKxAxIPRkV3aGF0X3RvX3dhdGNoGoADQ0RCNmxnSkhUWFpRYzJOVU1UUm1iME5OWjNOSmQzWjZOM0JPWlZWMldqZDFRVlp3ZEVOdGMwdEhXR3d3V0ROQ2FGb3lWbVpqTWpWb1kwaE9iMkl6VW1aamJWWnVZVmM1ZFZsWGQxTklNVlUwVDFSU1dXUXhUbXhXTTBaeVdsaGtSRkpGYkZCWk0yaDZWbXMxTlV4VmVGbE1XRnBSVlcxallVeFJRVUZhVnpSQlFWWldWRUZCUmtWU1VVRkNRVVZhUm1ReWFHaGtSamt3WWpFNU0xbFlVbXBoUVVGQ1FVRkZRa0ZCUVVKQlFVVkJRVUZGUWtGSFNrSkRRVUZUUlROQ2FGb3lWbVpqTWpWb1kwaE9iMkl6VW1aa1J6bHlXbGMwWVVWM2Ftb3hPRkJGT1dWSU5rRm9WVlpZWlVGTFNGaHVSMEp2ZDJsRmQycERObkZmUlRsbFNEWkJhRmRIZG1RMFMwaGxaMGhDTlZnMmJrMWxPVU5SU1VsTlVRJTNEJTNEmgIaYnJvd3NlLWZlZWRGRXdoYXRfdG9fd2F0Y2g%3D"),
|
||||||
endpoint: browse,
|
endpoint: browse,
|
|
@ -5,7 +5,7 @@ expression: map_res.c
|
||||||
Paginator(
|
Paginator(
|
||||||
count: None,
|
count: None,
|
||||||
items: [
|
items: [
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "_cyJhGsXDDM",
|
id: "_cyJhGsXDDM",
|
||||||
title: "Ultimate Criminal Canal Found Magnet Fishing! Police on the Hunt",
|
title: "Ultimate Criminal Canal Found Magnet Fishing! Police on the Hunt",
|
||||||
length: Some(1096),
|
length: Some(1096),
|
||||||
|
@ -21,7 +21,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCMLXec9-wpON8tZegnDsYLw",
|
id: "UCMLXec9-wpON8tZegnDsYLw",
|
||||||
name: "Bondi Treasure Hunter",
|
name: "Bondi Treasure Hunter",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -33,15 +33,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("1 day ago"),
|
publish_date_txt: Some("1 day ago"),
|
||||||
view_count: 700385,
|
view_count: Some(700385),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Subscribe for more Treasure Hunting videos: https://tinyurl.com/yyl3zerk\n\nMy Magnet! (Use Discount code \'BONDI\'): https://magnetarmagnets.com/\nMy Dive System! (Use Bonus code \'BONDI\'): https://lddy...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("Subscribe for more Treasure Hunting videos: https://tinyurl.com/yyl3zerk\n\nMy Magnet! (Use Discount code \'BONDI\'): https://magnetarmagnets.com/\nMy Dive System! (Use Bonus code \'BONDI\'): https://lddy..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "36YnV9STBqc",
|
id: "36YnV9STBqc",
|
||||||
title: "The Good Life Radio\u{a0}•\u{a0}24/7 Live Radio | Best Relax House, Chillout, Study, Running, Gym, Happy Music",
|
title: "The Good Life Radio\u{a0}•\u{a0}24/7 Live Radio | Best Relax House, Chillout, Study, Running, Gym, Happy Music",
|
||||||
length: None,
|
length: None,
|
||||||
|
@ -57,7 +58,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UChs0pSaEoNLV4mevBFGaoKA",
|
id: "UChs0pSaEoNLV4mevBFGaoKA",
|
||||||
name: "The Good Life Radio x Sensual Musique",
|
name: "The Good Life Radio x Sensual Musique",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -69,15 +70,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: None,
|
publish_date_txt: None,
|
||||||
view_count: 7202,
|
view_count: Some(7202),
|
||||||
is_live: false,
|
is_live: true,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "The Good Life is live streaming the best of Relaxing & Chill House Music, Deep House, Tropical House, EDM, Dance & Pop as well as Music for Sleep, Focus, Study, Workout, Gym, Running etc. in...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("The Good Life is live streaming the best of Relaxing & Chill House Music, Deep House, Tropical House, EDM, Dance & Pop as well as Music for Sleep, Focus, Study, Workout, Gym, Running etc. in..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "YYD1qgH5qC4",
|
id: "YYD1qgH5qC4",
|
||||||
title: "چند شنبه با سینــا | فصل چهـارم | قسمت 5 | با حضور نازنین انصاری مدیر روزنامه کیهان لندن",
|
title: "چند شنبه با سینــا | فصل چهـارم | قسمت 5 | با حضور نازنین انصاری مدیر روزنامه کیهان لندن",
|
||||||
length: Some(3261),
|
length: Some(3261),
|
||||||
|
@ -93,7 +95,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCzH_7hfL6Jd1H0WpNO_eryQ",
|
id: "UCzH_7hfL6Jd1H0WpNO_eryQ",
|
||||||
name: "MBC PERSIA",
|
name: "MBC PERSIA",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -105,15 +107,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("14 hours ago"),
|
publish_date_txt: Some("14 hours ago"),
|
||||||
view_count: 104344,
|
view_count: Some(104344),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "#mbcpersia\n#chandshanbeh\n#چندشنبه\n\nشبكه ام بى سى پرشيا را از حساب هاى مختلف در شبكه هاى اجتماعى دنبال كنيد\n►MBCPERSIA on Facebook:...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("#mbcpersia\n#chandshanbeh\n#چندشنبه\n\nشبكه ام بى سى پرشيا را از حساب هاى مختلف در شبكه هاى اجتماعى دنبال كنيد\n►MBCPERSIA on Facebook:..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "BeJqgI6rw9k",
|
id: "BeJqgI6rw9k",
|
||||||
title: "your city is full of fake buildings, here\'s why",
|
title: "your city is full of fake buildings, here\'s why",
|
||||||
length: Some(725),
|
length: Some(725),
|
||||||
|
@ -129,7 +132,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCqVEHtQoXHmUCfJ-9smpTSg",
|
id: "UCqVEHtQoXHmUCfJ-9smpTSg",
|
||||||
name: "Answer in Progress",
|
name: "Answer in Progress",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -141,15 +144,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("7 days ago"),
|
publish_date_txt: Some("7 days ago"),
|
||||||
view_count: 1447008,
|
view_count: Some(1447008),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Save 33% on your first Native Deodorant Pack - normally $39, you’ll get it for $26! Click here https://bit.ly/nativeanswer1 and use my code ANSWER #AD\n\nSomewhere on your street there may...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("Save 33% on your first Native Deodorant Pack - normally $39, you’ll get it for $26! Click here https://bit.ly/nativeanswer1 and use my code ANSWER #AD\n\nSomewhere on your street there may..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "ma28eWd1oyA",
|
id: "ma28eWd1oyA",
|
||||||
title: "Post Malone, Maroon 5, Adele, Taylor Swift, Ed Sheeran, Shawn Mendes, Pop Hits 2020 Part 6",
|
title: "Post Malone, Maroon 5, Adele, Taylor Swift, Ed Sheeran, Shawn Mendes, Pop Hits 2020 Part 6",
|
||||||
length: Some(29989),
|
length: Some(29989),
|
||||||
|
@ -160,7 +164,7 @@ Paginator(
|
||||||
height: 270,
|
height: 270,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCldQuUMYTUGrjvcU2vaPSFQ",
|
id: "UCldQuUMYTUGrjvcU2vaPSFQ",
|
||||||
name: "Music Library",
|
name: "Music Library",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -172,15 +176,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("Streamed 2 years ago"),
|
publish_date_txt: Some("Streamed 2 years ago"),
|
||||||
view_count: 1861814,
|
view_count: Some(1861814),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Post Malone, Maroon 5, Adele, Taylor Swift, Ed Sheeran, Shawn Mendes, Charlie Puth Pop Hits 2020\nPost Malone, Maroon 5, Adele, Taylor Swift, Ed Sheeran, Shawn Mendes, Charlie Puth Pop Hits...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("Post Malone, Maroon 5, Adele, Taylor Swift, Ed Sheeran, Shawn Mendes, Charlie Puth Pop Hits 2020\nPost Malone, Maroon 5, Adele, Taylor Swift, Ed Sheeran, Shawn Mendes, Charlie Puth Pop Hits..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "mL2LBRM5GBI",
|
id: "mL2LBRM5GBI",
|
||||||
title: "Salahs 6-Minuten-Hattrick & Firmino-Gala: Rangers - FC Liverpool 1:7 | UEFA Champions League | DAZN",
|
title: "Salahs 6-Minuten-Hattrick & Firmino-Gala: Rangers - FC Liverpool 1:7 | UEFA Champions League | DAZN",
|
||||||
length: Some(355),
|
length: Some(355),
|
||||||
|
@ -196,7 +201,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCB-GdMjyokO9lZkKU_oIK6g",
|
id: "UCB-GdMjyokO9lZkKU_oIK6g",
|
||||||
name: "DAZN UEFA Champions League",
|
name: "DAZN UEFA Champions League",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -208,15 +213,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("2 days ago"),
|
publish_date_txt: Some("2 days ago"),
|
||||||
view_count: 1471667,
|
view_count: Some(1471667),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "In der Liga läuft es für die Reds weiterhin nicht rund. Am vergangenen Spieltag gab es gegen Arsenal eine 2:3-Niederlage, am Sonntag trifft man auf Man City. Die Champions League soll für...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("In der Liga läuft es für die Reds weiterhin nicht rund. Am vergangenen Spieltag gab es gegen Arsenal eine 2:3-Niederlage, am Sonntag trifft man auf Man City. Die Champions League soll für..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "Ang18qz2IeQ",
|
id: "Ang18qz2IeQ",
|
||||||
title: "Satisfying Videos of Workers Doing Their Job Perfectly",
|
title: "Satisfying Videos of Workers Doing Their Job Perfectly",
|
||||||
length: Some(1186),
|
length: Some(1186),
|
||||||
|
@ -232,7 +238,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCYenDLnIHsoqQ6smwKXQ7Hg",
|
id: "UCYenDLnIHsoqQ6smwKXQ7Hg",
|
||||||
name: "#Mind Warehouse",
|
name: "#Mind Warehouse",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -244,15 +250,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("2 days ago"),
|
publish_date_txt: Some("2 days ago"),
|
||||||
view_count: 173121,
|
view_count: Some(173121),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "TechZone ► https://goo.gl/Gj3wZs \n\n #incrediblemoments #mindwarehouse #IncredibleMoments #CaughtOnCamera #InterestingFacts \n\nYou can endlessly watch how others work, but in this selection,...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("TechZone ► https://goo.gl/Gj3wZs \n\n #incrediblemoments #mindwarehouse #IncredibleMoments #CaughtOnCamera #InterestingFacts \n\nYou can endlessly watch how others work, but in this selection,..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "fjHN4jsJnEU",
|
id: "fjHN4jsJnEU",
|
||||||
title: "I Made 200 Players Simulate Survival Island in Minecraft...",
|
title: "I Made 200 Players Simulate Survival Island in Minecraft...",
|
||||||
length: Some(2361),
|
length: Some(2361),
|
||||||
|
@ -268,7 +275,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCqt4mmAqLmH-AwXz31URJsw",
|
id: "UCqt4mmAqLmH-AwXz31URJsw",
|
||||||
name: "Sword4000",
|
name: "Sword4000",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -280,15 +287,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("7 days ago"),
|
publish_date_txt: Some("7 days ago"),
|
||||||
view_count: 751909,
|
view_count: Some(751909),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "200 Players Simulate Survival Island Civilizations in Minecraft...\n-------------------------------------------------------------------\nI invited 200 Players to a Survival Island and let them...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("200 Players Simulate Survival Island Civilizations in Minecraft...\n-------------------------------------------------------------------\nI invited 200 Players to a Survival Island and let them..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "FI1XrdBJIUI",
|
id: "FI1XrdBJIUI",
|
||||||
title: "Epic Construction Fails | Expensive Fails Compilation | FailArmy",
|
title: "Epic Construction Fails | Expensive Fails Compilation | FailArmy",
|
||||||
length: Some(631),
|
length: Some(631),
|
||||||
|
@ -304,7 +312,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCPDis9pjXuqyI7RYLJ-TTSA",
|
id: "UCPDis9pjXuqyI7RYLJ-TTSA",
|
||||||
name: "FailArmy",
|
name: "FailArmy",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -316,15 +324,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("2 days ago"),
|
publish_date_txt: Some("2 days ago"),
|
||||||
view_count: 2226471,
|
view_count: Some(2226471),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "I don\'t think so, Tim. ►►► Submit your videos for the chance to be featured 🔗 https://www.failarmy.com/pages/submit-video ▼ Follow us for more fails! https://linktr.ee/failarmy\n#fails...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("I don\'t think so, Tim. ►►► Submit your videos for the chance to be featured 🔗 https://www.failarmy.com/pages/submit-video ▼ Follow us for more fails! https://linktr.ee/failarmy\n#fails..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "MXdplejK8vU",
|
id: "MXdplejK8vU",
|
||||||
title: "Chilly autumn Jazz ☕ Smooth September Jazz & Bossa Nova for a great relaxing weekend",
|
title: "Chilly autumn Jazz ☕ Smooth September Jazz & Bossa Nova for a great relaxing weekend",
|
||||||
length: Some(86403),
|
length: Some(86403),
|
||||||
|
@ -340,7 +349,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCeGJ6v6KQt0s88hGKMfybuw",
|
id: "UCeGJ6v6KQt0s88hGKMfybuw",
|
||||||
name: "Cozy Jazz Music",
|
name: "Cozy Jazz Music",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -352,15 +361,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("1 month ago"),
|
publish_date_txt: Some("1 month ago"),
|
||||||
view_count: 148743,
|
view_count: Some(148743),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Chilly autumn Jazz ☕ Smooth September Jazz & Bossa Nova for a great relaxing weekend\nhttps://youtu.be/MXdplejK8vU\n*******************************************\nSounds available on: Jazz Bossa...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("Chilly autumn Jazz ☕ Smooth September Jazz & Bossa Nova for a great relaxing weekend\nhttps://youtu.be/MXdplejK8vU\n*******************************************\nSounds available on: Jazz Bossa..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "Jri4_9vBFiQ",
|
id: "Jri4_9vBFiQ",
|
||||||
title: "Top 100 Best Classic Rock Songs Of All Time 🔥 R.E.M, Queen, Metallica,Guns N’ Roses,Bon Jovi, U2,CCR",
|
title: "Top 100 Best Classic Rock Songs Of All Time 🔥 R.E.M, Queen, Metallica,Guns N’ Roses,Bon Jovi, U2,CCR",
|
||||||
length: None,
|
length: None,
|
||||||
|
@ -376,7 +386,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCiIWdzEVNH8okhlapR9a-xA",
|
id: "UCiIWdzEVNH8okhlapR9a-xA",
|
||||||
name: "Rock Music",
|
name: "Rock Music",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -388,15 +398,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: None,
|
publish_date_txt: None,
|
||||||
view_count: 192,
|
view_count: Some(192),
|
||||||
is_live: false,
|
is_live: true,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Top 100 Best Classic Rock Songs Of All Time 🔥 R.E.M, Queen, Metallica,Guns N’ Roses,Bon Jovi, U2,CCR\nTop 100 Best Classic Rock Songs Of All Time 🔥 R.E.M, Queen, Metallica,Guns N’...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("Top 100 Best Classic Rock Songs Of All Time 🔥 R.E.M, Queen, Metallica,Guns N’ Roses,Bon Jovi, U2,CCR\nTop 100 Best Classic Rock Songs Of All Time 🔥 R.E.M, Queen, Metallica,Guns N’..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "ll4d5Lt-Ie8",
|
id: "ll4d5Lt-Ie8",
|
||||||
title: "Relaxing Music Healing Stress, Anxiety and Depressive States Heal Mind, Body and Soul | Sleep music",
|
title: "Relaxing Music Healing Stress, Anxiety and Depressive States Heal Mind, Body and Soul | Sleep music",
|
||||||
length: Some(42896),
|
length: Some(42896),
|
||||||
|
@ -412,7 +423,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCNS3dqFGBPhxHmOigehpBeg",
|
id: "UCNS3dqFGBPhxHmOigehpBeg",
|
||||||
name: "Love YourSelf",
|
name: "Love YourSelf",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -424,15 +435,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("Streamed 5 months ago"),
|
publish_date_txt: Some("Streamed 5 months ago"),
|
||||||
view_count: 5363904,
|
view_count: Some(5363904),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "The study found that listening to relaxing music of the patient\'s choice resulted in \"significant pain relief and increased mobility.\" Researchers believe that music relieves pain because listening...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("The study found that listening to relaxing music of the patient\'s choice resulted in \"significant pain relief and increased mobility.\" Researchers believe that music relieves pain because listening..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "Dx2wbKLokuQ",
|
id: "Dx2wbKLokuQ",
|
||||||
title: "W. Putin: Die Sehnsucht nach dem Imperium | Mit offenen Karten | ARTE",
|
title: "W. Putin: Die Sehnsucht nach dem Imperium | Mit offenen Karten | ARTE",
|
||||||
length: Some(729),
|
length: Some(729),
|
||||||
|
@ -448,7 +460,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCLLibJTCy3sXjHLVaDimnpQ",
|
id: "UCLLibJTCy3sXjHLVaDimnpQ",
|
||||||
name: "ARTEde",
|
name: "ARTEde",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -460,15 +472,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("2 weeks ago"),
|
publish_date_txt: Some("2 weeks ago"),
|
||||||
view_count: 539838,
|
view_count: Some(539838),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Jede Woche untersucht „Mit offenen Karten“ die politischen Kräfteverhältnisse in der ganzen Welt anhand detaillierter geografischer Karten \n\nIm Februar 2022 rechtfertigte Wladimir Putin...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("Jede Woche untersucht „Mit offenen Karten“ die politischen Kräfteverhältnisse in der ganzen Welt anhand detaillierter geografischer Karten \n\nIm Februar 2022 rechtfertigte Wladimir Putin..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "jfKfPfyJRdk",
|
id: "jfKfPfyJRdk",
|
||||||
title: "lofi hip hop radio - beats to relax/study to",
|
title: "lofi hip hop radio - beats to relax/study to",
|
||||||
length: None,
|
length: None,
|
||||||
|
@ -484,7 +497,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCSJ4gkVC6NrvII8umztf0Ow",
|
id: "UCSJ4gkVC6NrvII8umztf0Ow",
|
||||||
name: "Lofi Girl",
|
name: "Lofi Girl",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -496,15 +509,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: None,
|
publish_date_txt: None,
|
||||||
view_count: 21262,
|
view_count: Some(21262),
|
||||||
is_live: false,
|
is_live: true,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "🤗 Thank you for listening, I hope you will have a good time here\n\n💽 | Get the latest vinyl (limited edition)\n→ https://vinyl-lofirecords.com/\n\n🎼 | Listen on Spotify, Apple music...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("🤗 Thank you for listening, I hope you will have a good time here\n\n💽 | Get the latest vinyl (limited edition)\n→ https://vinyl-lofirecords.com/\n\n🎼 | Listen on Spotify, Apple music..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "qmrzTUmZ4UU",
|
id: "qmrzTUmZ4UU",
|
||||||
title: "850€ für den Verrat am System - UCS AT-AT LEGO® Star Wars 75313",
|
title: "850€ für den Verrat am System - UCS AT-AT LEGO® Star Wars 75313",
|
||||||
length: Some(2043),
|
length: Some(2043),
|
||||||
|
@ -520,7 +534,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UC_EZd3lsmxudu3IQzpTzOgw",
|
id: "UC_EZd3lsmxudu3IQzpTzOgw",
|
||||||
name: "Held der Steine Inh. Thomas Panke",
|
name: "Held der Steine Inh. Thomas Panke",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -532,15 +546,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("6 days ago"),
|
publish_date_txt: Some("6 days ago"),
|
||||||
view_count: 600150,
|
view_count: Some(600150),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Star Wars - erschienen 2021 - 6749 Teile\n\nDieses Set bei Amazon*:\nhttps://amzn.to/3yu9dHX\n\nErwähnt im Video*:\nTassen https://bit.ly/HdSBausteinecke\nBig Boy https://bit.ly/BBLokBigBoy\nBurg...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("Star Wars - erschienen 2021 - 6749 Teile\n\nDieses Set bei Amazon*:\nhttps://amzn.to/3yu9dHX\n\nErwähnt im Video*:\nTassen https://bit.ly/HdSBausteinecke\nBig Boy https://bit.ly/BBLokBigBoy\nBurg..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "t0Q2otsqC4I",
|
id: "t0Q2otsqC4I",
|
||||||
title: "Tom & Jerry | Tom & Jerry in Full Screen | Classic Cartoon Compilation | WB Kids",
|
title: "Tom & Jerry | Tom & Jerry in Full Screen | Classic Cartoon Compilation | WB Kids",
|
||||||
length: Some(1298),
|
length: Some(1298),
|
||||||
|
@ -556,7 +571,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UC9trsD1jCTXXtN3xIOIU8gg",
|
id: "UC9trsD1jCTXXtN3xIOIU8gg",
|
||||||
name: "WB Kids",
|
name: "WB Kids",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -568,15 +583,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: verified,
|
verification: verified,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("10 months ago"),
|
publish_date_txt: Some("10 months ago"),
|
||||||
view_count: 252381571,
|
view_count: Some(252381571),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Did you know that there are only 25 classic Tom & Jerry episodes that were displayed in a widescreen CinemaScope from the 1950s? Enjoy a compilation filled with some of the best moments from...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("Did you know that there are only 25 classic Tom & Jerry episodes that were displayed in a widescreen CinemaScope from the 1950s? Enjoy a compilation filled with some of the best moments from..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "zE-a5eqvlv8",
|
id: "zE-a5eqvlv8",
|
||||||
title: "Dua Lipa, Coldplay, Martin Garrix & Kygo, The Chainsmokers Style - Feeling Me",
|
title: "Dua Lipa, Coldplay, Martin Garrix & Kygo, The Chainsmokers Style - Feeling Me",
|
||||||
length: None,
|
length: None,
|
||||||
|
@ -592,7 +608,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCX-USfenzQlhrEJR1zD5IYw",
|
id: "UCX-USfenzQlhrEJR1zD5IYw",
|
||||||
name: "Deep Mood.",
|
name: "Deep Mood.",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -604,15 +620,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: None,
|
publish_date_txt: None,
|
||||||
view_count: 955,
|
view_count: Some(955),
|
||||||
is_live: false,
|
is_live: true,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "#Summermix #DeepHouse #DeepHouseSummerMix\nDua Lipa, Coldplay, Martin Garrix & Kygo, The Chainsmokers Style - Feeling Me\n\n🎵 All songs in this spotify playlist: https://spoti.fi/2TJ4Dyj\nSubmit...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("#Summermix #DeepHouse #DeepHouseSummerMix\nDua Lipa, Coldplay, Martin Garrix & Kygo, The Chainsmokers Style - Feeling Me\n\n🎵 All songs in this spotify playlist: https://spoti.fi/2TJ4Dyj\nSubmit..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "HxCcKzRAGWk",
|
id: "HxCcKzRAGWk",
|
||||||
title: "(Music for Man ) Relaxing Whiskey Blues Music - Modern Electric Guitar Blues - JAZZ & BLUES",
|
title: "(Music for Man ) Relaxing Whiskey Blues Music - Modern Electric Guitar Blues - JAZZ & BLUES",
|
||||||
length: Some(42899),
|
length: Some(42899),
|
||||||
|
@ -628,7 +645,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCGr-rTYtP1m-r_-ncspdVQQ",
|
id: "UCGr-rTYtP1m-r_-ncspdVQQ",
|
||||||
name: "JAZZ & BLUES",
|
name: "JAZZ & BLUES",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -640,15 +657,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("Streamed 3 months ago"),
|
publish_date_txt: Some("Streamed 3 months ago"),
|
||||||
view_count: 3156236,
|
view_count: Some(3156236),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "-----------------------------------------------------------------------------------\n✔Thanks for watching! Have a nice day!\n✔Don\'t forget LIKE - SHARE - COMMENT\n#bluesmusic#slowblues#bluesrock...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("-----------------------------------------------------------------------------------\n✔Thanks for watching! Have a nice day!\n✔Don\'t forget LIKE - SHARE - COMMENT\n#bluesmusic#slowblues#bluesrock..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "HlHYOdZePSE",
|
id: "HlHYOdZePSE",
|
||||||
title: "Healing Music for Anxiety Disorders, Fears, Depression and Eliminate Negative Thoughts",
|
title: "Healing Music for Anxiety Disorders, Fears, Depression and Eliminate Negative Thoughts",
|
||||||
length: None,
|
length: None,
|
||||||
|
@ -664,7 +682,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCqNYK5QArQRZSIR8v6_FCfA",
|
id: "UCqNYK5QArQRZSIR8v6_FCfA",
|
||||||
name: "Tranquil Music",
|
name: "Tranquil Music",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -676,15 +694,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: None,
|
publish_date_txt: None,
|
||||||
view_count: 1585,
|
view_count: Some(1585),
|
||||||
is_live: false,
|
is_live: true,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "Healing Music for Anxiety Disorders, Fears, Depression and Eliminate Negative Thoughts\n#HealingMusic #RelaxingMusic #TranquilMusic\n__________________________________\nMusic for:\nChakra healing....",
|
is_upcoming: false,
|
||||||
|
short_description: Some("Healing Music for Anxiety Disorders, Fears, Depression and Eliminate Negative Thoughts\n#HealingMusic #RelaxingMusic #TranquilMusic\n__________________________________\nMusic for:\nChakra healing...."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "CJ2AH3LJeic",
|
id: "CJ2AH3LJeic",
|
||||||
title: "Coldplay Greatest Hits Full Album 2022 New Songs of Coldplay 2022",
|
title: "Coldplay Greatest Hits Full Album 2022 New Songs of Coldplay 2022",
|
||||||
length: Some(7781),
|
length: Some(7781),
|
||||||
|
@ -700,7 +719,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCdK2lzwelugXGhR9SCWuEew",
|
id: "UCdK2lzwelugXGhR9SCWuEew",
|
||||||
name: "PLAY MUSIC",
|
name: "PLAY MUSIC",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -712,15 +731,16 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("7 months ago"),
|
publish_date_txt: Some("7 months ago"),
|
||||||
view_count: 5595965,
|
view_count: Some(5595965),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\nSubscribe channel for more videos:\n🔔Subscribe: https://bit.ly/2UbIZFv\n⚡Facebook: https://bitly.com.vn/gXDsC...",
|
is_upcoming: false,
|
||||||
|
short_description: Some("▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\nSubscribe channel for more videos:\n🔔Subscribe: https://bit.ly/2UbIZFv\n⚡Facebook: https://bitly.com.vn/gXDsC..."),
|
||||||
),
|
),
|
||||||
SearchVideo(
|
VideoItem(
|
||||||
id: "KJwzKxQ81iA",
|
id: "KJwzKxQ81iA",
|
||||||
title: "Handmade Candy Making Collection / 수제 사탕 만들기 모음 / Korean Candy Store",
|
title: "Handmade Candy Making Collection / 수제 사탕 만들기 모음 / Korean Candy Store",
|
||||||
length: Some(3152),
|
length: Some(3152),
|
||||||
|
@ -736,7 +756,7 @@ Paginator(
|
||||||
height: 404,
|
height: 404,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
channel: ChannelTag(
|
channel: Some(ChannelTag(
|
||||||
id: "UCdGwDjTgbSwQDZ8dYOdrplg",
|
id: "UCdGwDjTgbSwQDZ8dYOdrplg",
|
||||||
name: "Soon Films 순필름",
|
name: "Soon Films 순필름",
|
||||||
avatar: [
|
avatar: [
|
||||||
|
@ -748,13 +768,14 @@ Paginator(
|
||||||
],
|
],
|
||||||
verification: none,
|
verification: none,
|
||||||
subscriber_count: None,
|
subscriber_count: None,
|
||||||
),
|
)),
|
||||||
publish_date: "[date]",
|
publish_date: "[date]",
|
||||||
publish_date_txt: Some("1 month ago"),
|
publish_date_txt: Some("1 month ago"),
|
||||||
view_count: 3127238,
|
view_count: Some(3127238),
|
||||||
is_live: false,
|
is_live: false,
|
||||||
is_short: false,
|
is_short: false,
|
||||||
short_description: "00:00 Handmade Candy Making\n13:43 Delicate Handmade Candy Making\n28:33 Rainbow Lollipop Handmade Candy Making\n39:10 Cute Handmade Candy Making",
|
is_upcoming: false,
|
||||||
|
short_description: Some("00:00 Handmade Candy Making\n13:43 Delicate Handmade Candy Making\n28:33 Rainbow Lollipop Handmade Candy Making\n39:10 Cute Handmade Candy Making"),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
ctoken: Some("4qmFsgKbAxIPRkV3aGF0X3RvX3dhdGNoGuoCQ0JoNmlBSk5aMjlKYjB0NmVtOWlTR3hxVFRSdlYyMHdTMkYzYjFwbFdGSm1ZMGRHYmxwV09YcGliVVozWXpKb2RtUkdPWGxhVjJSd1lqSTFhR0pDU1daWFZFSXhUbFpuZDFSV09YSldNRlp0WkRCT1JWTlZPV3BsU0U1WFZHNWtiRXhWY0ZSa1ZrSlRXbmh2ZEVGQlFteGlaMEZDVmxaTlFVRlZVa1pCUVVWQlVtdFdNMkZIUmpCWU0xSjJXRE5rYUdSSFRtOUJRVVZCUVZGRlFVRkJSVUZCVVVGQlFWRkZRVmxyUlVsQlFrbFVZMGRHYmxwV09YcGliVVozWXpKb2RtUkdPVEJpTW5Sc1ltaHZWRU5MVDNJeFpuSjROR1p2UTBaU1YwSm1RVzlrVkZWSlN6RnBTVlJEUzA5eU1XWnllRFJtYjBOR1VsZENaa0Z2WkZSVlNVc3hkbkZqZURjd1NrRm5aMW8lM0SaAhpicm93c2UtZmVlZEZFd2hhdF90b193YXRjaA%3D%3D"),
|
ctoken: Some("4qmFsgKbAxIPRkV3aGF0X3RvX3dhdGNoGuoCQ0JoNmlBSk5aMjlKYjB0NmVtOWlTR3hxVFRSdlYyMHdTMkYzYjFwbFdGSm1ZMGRHYmxwV09YcGliVVozWXpKb2RtUkdPWGxhVjJSd1lqSTFhR0pDU1daWFZFSXhUbFpuZDFSV09YSldNRlp0WkRCT1JWTlZPV3BsU0U1WFZHNWtiRXhWY0ZSa1ZrSlRXbmh2ZEVGQlFteGlaMEZDVmxaTlFVRlZVa1pCUVVWQlVtdFdNMkZIUmpCWU0xSjJXRE5rYUdSSFRtOUJRVVZCUVZGRlFVRkJSVUZCVVVGQlFWRkZRVmxyUlVsQlFrbFVZMGRHYmxwV09YcGliVVozWXpKb2RtUkdPVEJpTW5Sc1ltaHZWRU5MVDNJeFpuSjROR1p2UTBaU1YwSm1RVzlrVkZWSlN6RnBTVlJEUzA5eU1XWnllRFJtYjBOR1VsZENaa0Z2WkZSVlNVc3hkbkZqZURjd1NrRm5aMW8lM0SaAhpicm93c2UtZmVlZEZFd2hhdF90b193YXRjaA%3D%3D"),
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,18 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, ExtractionError},
|
error::{Error, ExtractionError},
|
||||||
model::{Paginator, SearchVideo},
|
model::{Paginator, VideoItem},
|
||||||
param::Language,
|
param::Language,
|
||||||
serializer::MapResult,
|
serializer::MapResult,
|
||||||
util::TryRemove,
|
util::TryRemove,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{response, ClientType, MapResponse, QBrowse, RustyPipeQuery};
|
||||||
response::{self, TryFromWLang},
|
|
||||||
ClientType, MapResponse, QBrowse, QContinuation, RustyPipeQuery,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl 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 context = self.get_context(ClientType::Desktop, true).await;
|
||||||
let request_body = QBrowse {
|
let request_body = QBrowse {
|
||||||
context,
|
context,
|
||||||
|
@ -29,33 +26,7 @@ impl RustyPipeQuery {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn startpage_continuation(
|
pub async fn trending(self) -> Result<Vec<VideoItem>, Error> {
|
||||||
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> {
|
|
||||||
let context = self.get_context(ClientType::Desktop, true).await;
|
let context = self.get_context(ClientType::Desktop, true).await;
|
||||||
let request_body = QBrowse {
|
let request_body = QBrowse {
|
||||||
context,
|
context,
|
||||||
|
@ -73,20 +44,20 @@ impl RustyPipeQuery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapResponse<Paginator<SearchVideo>> for response::Startpage {
|
impl MapResponse<Paginator<VideoItem>> for response::Startpage {
|
||||||
fn map_response(
|
fn map_response(
|
||||||
self,
|
self,
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::Deobfuscator>,
|
_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 mut contents = self.contents.two_column_browse_results_renderer.tabs;
|
||||||
let grid = contents
|
let grid = contents
|
||||||
.try_swap_remove(0)
|
.try_swap_remove(0)
|
||||||
.ok_or_else(|| ExtractionError::InvalidData("no contents".into()))?
|
.ok_or_else(|| ExtractionError::InvalidData("no contents".into()))?
|
||||||
.tab_renderer
|
.tab_renderer
|
||||||
.content
|
.content
|
||||||
.rich_grid_renderer
|
.section_list_renderer
|
||||||
.contents;
|
.contents;
|
||||||
|
|
||||||
Ok(map_startpage_videos(
|
Ok(map_startpage_videos(
|
||||||
|
@ -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(
|
fn map_response(
|
||||||
self,
|
self,
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::Deobfuscator>,
|
_deobf: Option<&crate::deobfuscate::Deobfuscator>,
|
||||||
) -> Result<MapResult<Paginator<SearchVideo>>, ExtractionError> {
|
) -> Result<MapResult<Vec<VideoItem>>, 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> {
|
|
||||||
let mut contents = self.contents.two_column_browse_results_renderer.tabs;
|
let mut contents = self.contents.two_column_browse_results_renderer.tabs;
|
||||||
let sections = contents
|
let items = contents
|
||||||
.try_swap_remove(0)
|
.try_swap_remove(0)
|
||||||
.ok_or_else(|| ExtractionError::InvalidData("no contents".into()))?
|
.ok_or_else(|| ExtractionError::InvalidData("no contents".into()))?
|
||||||
.tab_renderer
|
.tab_renderer
|
||||||
|
@ -131,76 +84,27 @@ impl MapResponse<Vec<SearchVideo>> for response::Trending {
|
||||||
.section_list_renderer
|
.section_list_renderer
|
||||||
.contents;
|
.contents;
|
||||||
|
|
||||||
let mut items = Vec::new();
|
let mut mapper = response::YouTubeListMapper::<VideoItem>::new(lang);
|
||||||
let mut warnings = Vec::new();
|
mapper.map_response(items);
|
||||||
|
|
||||||
for mut section in sections {
|
Ok(MapResult {
|
||||||
let shelf = section
|
c: mapper.items,
|
||||||
.item_section_renderer
|
warnings: mapper.warnings,
|
||||||
.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 })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_startpage_videos(
|
fn map_startpage_videos(
|
||||||
videos: MapResult<Vec<response::VideoListItem>>,
|
videos: MapResult<Vec<response::YouTubeListItem>>,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
visitor_data: Option<String>,
|
visitor_data: Option<String>,
|
||||||
) -> MapResult<Paginator<SearchVideo>> {
|
) -> MapResult<Paginator<VideoItem>> {
|
||||||
let mut warnings = videos.warnings;
|
let mut mapper = response::YouTubeListMapper::<VideoItem>::new(lang);
|
||||||
let mut ctoken = None;
|
mapper.map_response(videos);
|
||||||
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 {
|
MapResult {
|
||||||
c: Paginator::new_with_vdata(None, items, ctoken, visitor_data),
|
c: Paginator::new_with_vdata(None, mapper.items, mapper.ctoken, visitor_data),
|
||||||
warnings,
|
warnings: mapper.warnings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +114,7 @@ mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::{response, MapResponse},
|
client::{response, MapResponse},
|
||||||
model::{Paginator, SearchVideo},
|
model::{Paginator, VideoItem},
|
||||||
param::Language,
|
param::Language,
|
||||||
serializer::MapResult,
|
serializer::MapResult,
|
||||||
};
|
};
|
||||||
|
@ -223,7 +127,7 @@ mod tests {
|
||||||
|
|
||||||
let startpage: response::Startpage =
|
let startpage: response::Startpage =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
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();
|
startpage.map_response("", Language::En, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
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]
|
#[test]
|
||||||
fn map_trending() {
|
fn map_trending() {
|
||||||
let filename = "testfiles/trends/trending.json";
|
let filename = "testfiles/trends/trending.json";
|
||||||
|
@ -267,7 +149,7 @@ mod tests {
|
||||||
|
|
||||||
let startpage: response::Trending =
|
let startpage: response::Trending =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
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();
|
startpage.map_response("", Language::En, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
|
Loading…
Add table
Reference in a new issue