fix: add support for A/B test 7 (short date format)
This commit is contained in:
parent
cca9838b7e
commit
cc2cadc309
21 changed files with 184 additions and 71 deletions
|
|
@ -4,6 +4,8 @@ use anyhow::{bail, Result};
|
||||||
use futures::{stream, StreamExt};
|
use futures::{stream, StreamExt};
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use num_enum::TryFromPrimitive;
|
use num_enum::TryFromPrimitive;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use regex::Regex;
|
||||||
use rustypipe::client::{ClientType, RustyPipe, RustyPipeQuery, YTContext};
|
use rustypipe::client::{ClientType, RustyPipe, RustyPipeQuery, YTContext};
|
||||||
use rustypipe::model::YouTubeItem;
|
use rustypipe::model::YouTubeItem;
|
||||||
use rustypipe::param::search_filter::{ItemType, SearchFilter};
|
use rustypipe::param::search_filter::{ItemType, SearchFilter};
|
||||||
|
|
@ -21,6 +23,7 @@ pub enum ABTest {
|
||||||
TrendsVideoTab = 4,
|
TrendsVideoTab = 4,
|
||||||
TrendsPageHeaderRenderer = 5,
|
TrendsPageHeaderRenderer = 5,
|
||||||
DiscographyPage = 6,
|
DiscographyPage = 6,
|
||||||
|
ShortDateFormat = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TESTS_TO_RUN: [ABTest; 3] = [
|
const TESTS_TO_RUN: [ABTest; 3] = [
|
||||||
|
|
@ -90,6 +93,7 @@ pub async fn run_test(
|
||||||
ABTest::TrendsVideoTab => trends_video_tab(&query).await,
|
ABTest::TrendsVideoTab => trends_video_tab(&query).await,
|
||||||
ABTest::TrendsPageHeaderRenderer => trends_page_header_renderer(&query).await,
|
ABTest::TrendsPageHeaderRenderer => trends_page_header_renderer(&query).await,
|
||||||
ABTest::DiscographyPage => discography_page(&query).await,
|
ABTest::DiscographyPage => discography_page(&query).await,
|
||||||
|
ABTest::ShortDateFormat => short_date_format(&query).await,
|
||||||
}
|
}
|
||||||
.unwrap();
|
.unwrap();
|
||||||
pb.inc(1);
|
pb.inc(1);
|
||||||
|
|
@ -223,10 +227,19 @@ pub async fn trends_page_header_renderer(rp: &RustyPipeQuery) -> Result<bool> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn discography_page(rp: &RustyPipeQuery) -> Result<bool> {
|
pub async fn discography_page(rp: &RustyPipeQuery) -> Result<bool> {
|
||||||
let artist = rp
|
let artist = rp.music_artist("UC7cl4MmM6ZZ2TcFyMk_b4pg", false).await?;
|
||||||
.music_artist("UC7cl4MmM6ZZ2TcFyMk_b4pg", false)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Ok(artist.albums.len() <= 10)
|
Ok(artist.albums.len() <= 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn short_date_format(rp: &RustyPipeQuery) -> Result<bool> {
|
||||||
|
static SHORT_DATE: Lazy<Regex> = Lazy::new(|| Regex::new("\\d(?:y|mo|w|d|h|min) ").unwrap());
|
||||||
|
let channel = rp.channel_videos("UC2DjFE7Xf11URZqWBigcVOQ").await?;
|
||||||
|
|
||||||
|
Ok(channel.content.items.iter().any(|itm| {
|
||||||
|
itm.publish_date_txt
|
||||||
|
.as_deref()
|
||||||
|
.map(|d| SHORT_DATE.is_match(d))
|
||||||
|
.unwrap_or_default()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -376,3 +376,11 @@ visitor data cookie to be set, as it was the case with the old system.
|
||||||
**NEW**
|
**NEW**
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## [7] Short timeago format
|
||||||
|
|
||||||
|
- **Encountered on:** 28.05.2023
|
||||||
|
- **Impact:** 🟡 Medium
|
||||||
|
|
||||||
|
YouTube changed their date format from the long format (*21 hours ago*, *3 days ago*) to
|
||||||
|
a short format (*21h ago*, *3d ago*).
|
||||||
|
|
|
||||||
|
|
@ -200,15 +200,20 @@ impl MapResponse<Channel<Paginator<VideoItem>>> for response::Channel {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Channel<Paginator<VideoItem>>>, ExtractionError> {
|
) -> Result<MapResult<Channel<Paginator<VideoItem>>>, ExtractionError> {
|
||||||
let content = map_channel_content(id, self.contents, self.alerts)?;
|
let content = map_channel_content(id, self.contents, self.alerts)?;
|
||||||
|
let visitor_data = self
|
||||||
|
.response_context
|
||||||
|
.visitor_data
|
||||||
|
.or_else(|| vdata.map(str::to_owned));
|
||||||
|
|
||||||
let channel_data = map_channel(
|
let channel_data = map_channel(
|
||||||
MapChannelData {
|
MapChannelData {
|
||||||
header: self.header,
|
header: self.header,
|
||||||
metadata: self.metadata,
|
metadata: self.metadata,
|
||||||
microformat: self.microformat,
|
microformat: self.microformat,
|
||||||
visitor_data: self.response_context.visitor_data.clone(),
|
visitor_data: visitor_data.clone(),
|
||||||
has_shorts: content.has_shorts,
|
has_shorts: content.has_shorts,
|
||||||
has_live: content.has_live,
|
has_live: content.has_live,
|
||||||
},
|
},
|
||||||
|
|
@ -226,7 +231,7 @@ impl MapResponse<Channel<Paginator<VideoItem>>> for response::Channel {
|
||||||
None,
|
None,
|
||||||
mapper.items,
|
mapper.items,
|
||||||
mapper.ctoken,
|
mapper.ctoken,
|
||||||
self.response_context.visitor_data,
|
visitor_data,
|
||||||
crate::model::paginator::ContinuationEndpoint::Browse,
|
crate::model::paginator::ContinuationEndpoint::Browse,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -243,15 +248,20 @@ impl MapResponse<Channel<Paginator<PlaylistItem>>> for response::Channel {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Channel<Paginator<PlaylistItem>>>, ExtractionError> {
|
) -> Result<MapResult<Channel<Paginator<PlaylistItem>>>, ExtractionError> {
|
||||||
let content = map_channel_content(id, self.contents, self.alerts)?;
|
let content = map_channel_content(id, self.contents, self.alerts)?;
|
||||||
|
let visitor_data = self
|
||||||
|
.response_context
|
||||||
|
.visitor_data
|
||||||
|
.or_else(|| vdata.map(str::to_owned));
|
||||||
|
|
||||||
let channel_data = map_channel(
|
let channel_data = map_channel(
|
||||||
MapChannelData {
|
MapChannelData {
|
||||||
header: self.header,
|
header: self.header,
|
||||||
metadata: self.metadata,
|
metadata: self.metadata,
|
||||||
microformat: self.microformat,
|
microformat: self.microformat,
|
||||||
visitor_data: self.response_context.visitor_data,
|
visitor_data,
|
||||||
has_shorts: content.has_shorts,
|
has_shorts: content.has_shorts,
|
||||||
has_live: content.has_live,
|
has_live: content.has_live,
|
||||||
},
|
},
|
||||||
|
|
@ -280,6 +290,7 @@ impl MapResponse<Channel<ChannelInfo>> for response::Channel {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Channel<ChannelInfo>>, ExtractionError> {
|
) -> Result<MapResult<Channel<ChannelInfo>>, ExtractionError> {
|
||||||
let content = map_channel_content(id, self.contents, self.alerts)?;
|
let content = map_channel_content(id, self.contents, self.alerts)?;
|
||||||
let channel_data = map_channel(
|
let channel_data = map_channel(
|
||||||
|
|
@ -287,7 +298,10 @@ impl MapResponse<Channel<ChannelInfo>> for response::Channel {
|
||||||
header: self.header,
|
header: self.header,
|
||||||
metadata: self.metadata,
|
metadata: self.metadata,
|
||||||
microformat: self.microformat,
|
microformat: self.microformat,
|
||||||
visitor_data: self.response_context.visitor_data,
|
visitor_data: self
|
||||||
|
.response_context
|
||||||
|
.visitor_data
|
||||||
|
.or_else(|| vdata.map(str::to_owned)),
|
||||||
has_shorts: content.has_shorts,
|
has_shorts: content.has_shorts,
|
||||||
has_live: content.has_live,
|
has_live: content.has_live,
|
||||||
},
|
},
|
||||||
|
|
@ -605,7 +619,7 @@ mod tests {
|
||||||
let channel: response::Channel =
|
let channel: response::Channel =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Channel<Paginator<VideoItem>>> =
|
let map_res: MapResult<Channel<Paginator<VideoItem>>> =
|
||||||
channel.map_response(id, Language::En, None).unwrap();
|
channel.map_response(id, Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -632,7 +646,7 @@ mod tests {
|
||||||
let channel: response::Channel =
|
let channel: response::Channel =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Channel<Paginator<PlaylistItem>>> = channel
|
let map_res: MapResult<Channel<Paginator<PlaylistItem>>> = channel
|
||||||
.map_response("UC2DjFE7Xf11URZqWBigcVOQ", Language::En, None)
|
.map_response("UC2DjFE7Xf11URZqWBigcVOQ", Language::En, None, None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
|
@ -651,7 +665,7 @@ mod tests {
|
||||||
let channel: response::Channel =
|
let channel: response::Channel =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Channel<ChannelInfo>> = channel
|
let map_res: MapResult<Channel<ChannelInfo>> = channel
|
||||||
.map_response("UC2DjFE7Xf11URZqWBigcVOQ", Language::En, None)
|
.map_response("UC2DjFE7Xf11URZqWBigcVOQ", Language::En, None, None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
||||||
|
|
@ -1247,7 +1247,12 @@ impl RustyPipeQuery {
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
match serde_json::from_str::<R>(&body) {
|
match serde_json::from_str::<R>(&body) {
|
||||||
Ok(deserialized) => match deserialized.map_response(id, self.opts.lang, deobf) {
|
Ok(deserialized) => match deserialized.map_response(
|
||||||
|
id,
|
||||||
|
self.opts.lang,
|
||||||
|
deobf,
|
||||||
|
self.opts.visitor_data.as_deref(),
|
||||||
|
) {
|
||||||
Ok(mapres) => Ok(mapres),
|
Ok(mapres) => Ok(mapres),
|
||||||
Err(e) => Err(e.into()),
|
Err(e) => Err(e.into()),
|
||||||
},
|
},
|
||||||
|
|
@ -1453,11 +1458,13 @@ trait MapResponse<T> {
|
||||||
/// that the returned entity matches this ID and return an error instead.
|
/// that the returned entity matches this ID and return an error instead.
|
||||||
/// - `lang`: Language of the request. Used for mapping localized information like dates.
|
/// - `lang`: Language of the request. Used for mapping localized information like dates.
|
||||||
/// - `deobf`: Deobfuscator (if passed to the `execute_request_deobf` method)
|
/// - `deobf`: Deobfuscator (if passed to the `execute_request_deobf` method)
|
||||||
|
/// - `vdata`: Visitor data option of the client
|
||||||
fn map_response(
|
fn map_response(
|
||||||
self,
|
self,
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
deobf: Option<&DeobfData>,
|
deobf: Option<&DeobfData>,
|
||||||
|
vdata: Option<&str>,
|
||||||
) -> Result<MapResult<T>, ExtractionError>;
|
) -> Result<MapResult<T>, ExtractionError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ impl MapResponse<MusicArtist> for response::MusicArtist {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<MusicArtist>, ExtractionError> {
|
) -> Result<MapResult<MusicArtist>, ExtractionError> {
|
||||||
let mapped = map_artist_page(self, id, lang, false)?;
|
let mapped = map_artist_page(self, id, lang, false)?;
|
||||||
Ok(MapResult {
|
Ok(MapResult {
|
||||||
|
|
@ -111,6 +112,7 @@ impl MapResponse<(MusicArtist, bool)> for response::MusicArtist {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<(MusicArtist, bool)>, ExtractionError> {
|
) -> Result<MapResult<(MusicArtist, bool)>, ExtractionError> {
|
||||||
map_artist_page(self, id, lang, true)
|
map_artist_page(self, id, lang, true)
|
||||||
}
|
}
|
||||||
|
|
@ -286,6 +288,7 @@ impl MapResponse<Vec<AlbumItem>> for response::MusicArtistAlbums {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Vec<AlbumItem>>, ExtractionError> {
|
) -> Result<MapResult<Vec<AlbumItem>>, ExtractionError> {
|
||||||
// dbg!(&self);
|
// dbg!(&self);
|
||||||
|
|
||||||
|
|
@ -356,7 +359,7 @@ mod tests {
|
||||||
let resp: response::MusicArtist =
|
let resp: response::MusicArtist =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<(MusicArtist, bool)> =
|
let map_res: MapResult<(MusicArtist, bool)> =
|
||||||
resp.map_response(id, Language::En, None).unwrap();
|
resp.map_response(id, Language::En, None, None).unwrap();
|
||||||
let (mut artist, can_fetch_more) = map_res.c;
|
let (mut artist, can_fetch_more) = map_res.c;
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
|
@ -371,7 +374,7 @@ mod tests {
|
||||||
let resp: response::MusicArtistAlbums =
|
let resp: response::MusicArtistAlbums =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let mut map_res: MapResult<Vec<AlbumItem>> =
|
let mut map_res: MapResult<Vec<AlbumItem>> =
|
||||||
resp.map_response(id, Language::En, None).unwrap();
|
resp.map_response(id, Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -392,7 +395,7 @@ mod tests {
|
||||||
let artist: response::MusicArtist =
|
let artist: response::MusicArtist =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<MusicArtist> = artist
|
let map_res: MapResult<MusicArtist> = artist
|
||||||
.map_response("UClmXPfaYhXOYsNn_QUyheWQ", Language::En, None)
|
.map_response("UClmXPfaYhXOYsNn_QUyheWQ", Language::En, None, None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
|
@ -411,7 +414,7 @@ mod tests {
|
||||||
let artist: response::MusicArtist =
|
let artist: response::MusicArtist =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let res: Result<MapResult<MusicArtist>, ExtractionError> =
|
let res: Result<MapResult<MusicArtist>, ExtractionError> =
|
||||||
artist.map_response("UCLkAepWjdylmXSltofFvsYQ", Language::En, None);
|
artist.map_response("UCLkAepWjdylmXSltofFvsYQ", Language::En, None, None);
|
||||||
let e = res.unwrap_err();
|
let e = res.unwrap_err();
|
||||||
|
|
||||||
match e {
|
match e {
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ impl MapResponse<MusicCharts> for response::MusicCharts {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<crate::serializer::MapResult<MusicCharts>, crate::error::ExtractionError> {
|
) -> Result<crate::serializer::MapResult<MusicCharts>, crate::error::ExtractionError> {
|
||||||
let countries = self
|
let countries = self
|
||||||
.framework_updates
|
.framework_updates
|
||||||
|
|
@ -164,7 +165,8 @@ mod tests {
|
||||||
|
|
||||||
let charts: response::MusicCharts =
|
let charts: response::MusicCharts =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<MusicCharts> = charts.map_response("", Language::En, None).unwrap();
|
let map_res: MapResult<MusicCharts> =
|
||||||
|
charts.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,7 @@ impl MapResponse<TrackDetails> for response::MusicDetails {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<TrackDetails>, ExtractionError> {
|
) -> Result<MapResult<TrackDetails>, ExtractionError> {
|
||||||
let tabs = self
|
let tabs = self
|
||||||
.contents
|
.contents
|
||||||
|
|
@ -237,6 +238,7 @@ impl MapResponse<Paginator<TrackItem>> for response::MusicDetails {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Paginator<TrackItem>>, ExtractionError> {
|
) -> Result<MapResult<Paginator<TrackItem>>, ExtractionError> {
|
||||||
let tabs = self
|
let tabs = self
|
||||||
.contents
|
.contents
|
||||||
|
|
@ -297,6 +299,7 @@ impl MapResponse<Lyrics> for response::MusicLyrics {
|
||||||
id: &str,
|
id: &str,
|
||||||
_lang: Language,
|
_lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Lyrics>, ExtractionError> {
|
) -> Result<MapResult<Lyrics>, ExtractionError> {
|
||||||
let lyrics = self
|
let lyrics = self
|
||||||
.contents
|
.contents
|
||||||
|
|
@ -330,6 +333,7 @@ impl MapResponse<MusicRelated> for response::MusicRelated {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<MusicRelated>, ExtractionError> {
|
) -> Result<MapResult<MusicRelated>, ExtractionError> {
|
||||||
// Find artist
|
// Find artist
|
||||||
let artist_id = self
|
let artist_id = self
|
||||||
|
|
@ -422,7 +426,7 @@ mod tests {
|
||||||
let details: response::MusicDetails =
|
let details: response::MusicDetails =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<model::TrackDetails> =
|
let map_res: MapResult<model::TrackDetails> =
|
||||||
details.map_response(id, Language::En, None).unwrap();
|
details.map_response(id, Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -442,7 +446,7 @@ mod tests {
|
||||||
let radio: response::MusicDetails =
|
let radio: response::MusicDetails =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Paginator<TrackItem>> =
|
let map_res: MapResult<Paginator<TrackItem>> =
|
||||||
radio.map_response(id, Language::En, None).unwrap();
|
radio.map_response(id, Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -459,7 +463,7 @@ mod tests {
|
||||||
|
|
||||||
let lyrics: response::MusicLyrics =
|
let lyrics: response::MusicLyrics =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Lyrics> = lyrics.map_response("", Language::En, None).unwrap();
|
let map_res: MapResult<Lyrics> = lyrics.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -476,7 +480,8 @@ mod tests {
|
||||||
|
|
||||||
let lyrics: response::MusicRelated =
|
let lyrics: response::MusicRelated =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<MusicRelated> = lyrics.map_response("", Language::En, None).unwrap();
|
let map_res: MapResult<MusicRelated> =
|
||||||
|
lyrics.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ impl MapResponse<Vec<MusicGenreItem>> for response::MusicGenres {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
_lang: crate::param::Language,
|
_lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<crate::serializer::MapResult<Vec<MusicGenreItem>>, ExtractionError> {
|
) -> Result<crate::serializer::MapResult<Vec<MusicGenreItem>>, ExtractionError> {
|
||||||
let content = self
|
let content = self
|
||||||
.contents
|
.contents
|
||||||
|
|
@ -110,6 +111,7 @@ impl MapResponse<MusicGenre> for response::MusicGenre {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<crate::serializer::MapResult<MusicGenre>, ExtractionError> {
|
) -> Result<crate::serializer::MapResult<MusicGenre>, ExtractionError> {
|
||||||
// dbg!(&self);
|
// dbg!(&self);
|
||||||
|
|
||||||
|
|
@ -214,7 +216,7 @@ mod tests {
|
||||||
let playlist: response::MusicGenres =
|
let playlist: response::MusicGenres =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Vec<model::MusicGenreItem>> =
|
let map_res: MapResult<Vec<model::MusicGenreItem>> =
|
||||||
playlist.map_response("", Language::En, None).unwrap();
|
playlist.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -234,7 +236,7 @@ mod tests {
|
||||||
let playlist: response::MusicGenre =
|
let playlist: response::MusicGenre =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<model::MusicGenre> =
|
let map_res: MapResult<model::MusicGenre> =
|
||||||
playlist.map_response(id, Language::En, None).unwrap();
|
playlist.map_response(id, Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ impl<T: FromYtItem> MapResponse<Vec<T>> for response::MusicNew {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<crate::serializer::MapResult<Vec<T>>, ExtractionError> {
|
) -> Result<crate::serializer::MapResult<Vec<T>>, ExtractionError> {
|
||||||
let items = self
|
let items = self
|
||||||
.contents
|
.contents
|
||||||
|
|
@ -96,8 +97,9 @@ mod tests {
|
||||||
|
|
||||||
let new_albums: response::MusicNew =
|
let new_albums: response::MusicNew =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Vec<AlbumItem>> =
|
let map_res: MapResult<Vec<AlbumItem>> = new_albums
|
||||||
new_albums.map_response("", Language::En, None).unwrap();
|
.map_response("", Language::En, None, None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -115,8 +117,9 @@ mod tests {
|
||||||
|
|
||||||
let new_albums: response::MusicNew =
|
let new_albums: response::MusicNew =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Vec<TrackItem>> =
|
let map_res: MapResult<Vec<TrackItem>> = new_albums
|
||||||
new_albums.map_response("", Language::En, None).unwrap();
|
.map_response("", Language::En, None, None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ impl MapResponse<MusicPlaylist> for response::MusicPlaylist {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<MusicPlaylist>, ExtractionError> {
|
) -> Result<MapResult<MusicPlaylist>, ExtractionError> {
|
||||||
// dbg!(&self);
|
// dbg!(&self);
|
||||||
|
|
||||||
|
|
@ -267,6 +268,7 @@ impl MapResponse<MusicAlbum> for response::MusicPlaylist {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<MusicAlbum>, ExtractionError> {
|
) -> Result<MapResult<MusicAlbum>, ExtractionError> {
|
||||||
// dbg!(&self);
|
// dbg!(&self);
|
||||||
|
|
||||||
|
|
@ -418,7 +420,7 @@ mod tests {
|
||||||
let playlist: response::MusicPlaylist =
|
let playlist: response::MusicPlaylist =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<model::MusicPlaylist> =
|
let map_res: MapResult<model::MusicPlaylist> =
|
||||||
playlist.map_response(id, Language::En, None).unwrap();
|
playlist.map_response(id, Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -443,7 +445,7 @@ mod tests {
|
||||||
let playlist: response::MusicPlaylist =
|
let playlist: response::MusicPlaylist =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<model::MusicAlbum> =
|
let map_res: MapResult<model::MusicAlbum> =
|
||||||
playlist.map_response(id, Language::En, None).unwrap();
|
playlist.map_response(id, Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,7 @@ impl MapResponse<MusicSearchResult> for response::MusicSearch {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<MusicSearchResult>, crate::error::ExtractionError> {
|
) -> Result<MapResult<MusicSearchResult>, crate::error::ExtractionError> {
|
||||||
// dbg!(&self);
|
// dbg!(&self);
|
||||||
|
|
||||||
|
|
@ -296,6 +297,7 @@ impl<T: FromYtItem> MapResponse<MusicSearchFiltered<T>> for response::MusicSearc
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<MusicSearchFiltered<T>>, ExtractionError> {
|
) -> Result<MapResult<MusicSearchFiltered<T>>, ExtractionError> {
|
||||||
// dbg!(&self);
|
// dbg!(&self);
|
||||||
|
|
||||||
|
|
@ -356,6 +358,7 @@ impl MapResponse<MusicSearchSuggestion> for response::MusicSearchSuggestion {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<MusicSearchSuggestion>, ExtractionError> {
|
) -> Result<MapResult<MusicSearchSuggestion>, ExtractionError> {
|
||||||
let mut mapper = MusicListMapper::new(lang);
|
let mut mapper = MusicListMapper::new(lang);
|
||||||
let mut terms = Vec::new();
|
let mut terms = Vec::new();
|
||||||
|
|
@ -419,7 +422,7 @@ mod tests {
|
||||||
let search: response::MusicSearch =
|
let search: response::MusicSearch =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<MusicSearchResult> =
|
let map_res: MapResult<MusicSearchResult> =
|
||||||
search.map_response("", Language::En, None).unwrap();
|
search.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -442,7 +445,7 @@ mod tests {
|
||||||
let search: response::MusicSearch =
|
let search: response::MusicSearch =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<MusicSearchFiltered<TrackItem>> =
|
let map_res: MapResult<MusicSearchFiltered<TrackItem>> =
|
||||||
search.map_response("", Language::En, None).unwrap();
|
search.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -461,7 +464,7 @@ mod tests {
|
||||||
let search: response::MusicSearch =
|
let search: response::MusicSearch =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<MusicSearchFiltered<AlbumItem>> =
|
let map_res: MapResult<MusicSearchFiltered<AlbumItem>> =
|
||||||
search.map_response("", Language::En, None).unwrap();
|
search.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -480,7 +483,7 @@ mod tests {
|
||||||
let search: response::MusicSearch =
|
let search: response::MusicSearch =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<MusicSearchFiltered<ArtistItem>> =
|
let map_res: MapResult<MusicSearchFiltered<ArtistItem>> =
|
||||||
search.map_response("", Language::En, None).unwrap();
|
search.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -501,7 +504,7 @@ mod tests {
|
||||||
let search: response::MusicSearch =
|
let search: response::MusicSearch =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<MusicSearchFiltered<MusicPlaylistItem>> =
|
let map_res: MapResult<MusicSearchFiltered<MusicPlaylistItem>> =
|
||||||
search.map_response("", Language::En, None).unwrap();
|
search.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -521,8 +524,9 @@ mod tests {
|
||||||
|
|
||||||
let suggestion: response::MusicSearchSuggestion =
|
let suggestion: response::MusicSearchSuggestion =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<MusicSearchSuggestion> =
|
let map_res: MapResult<MusicSearchSuggestion> = suggestion
|
||||||
suggestion.map_response("", Language::En, None).unwrap();
|
.map_response("", Language::En, None, None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ impl MapResponse<Paginator<YouTubeItem>> for response::Continuation {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Paginator<YouTubeItem>>, ExtractionError> {
|
) -> Result<MapResult<Paginator<YouTubeItem>>, ExtractionError> {
|
||||||
let items = self
|
let items = self
|
||||||
.on_response_received_actions
|
.on_response_received_actions
|
||||||
|
|
@ -131,6 +132,7 @@ impl MapResponse<Paginator<MusicItem>> for response::MusicContinuation {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Paginator<MusicItem>>, ExtractionError> {
|
) -> Result<MapResult<Paginator<MusicItem>>, ExtractionError> {
|
||||||
let mut mapper = MusicListMapper::new(lang);
|
let mut mapper = MusicListMapper::new(lang);
|
||||||
let mut continuations = Vec::new();
|
let mut continuations = Vec::new();
|
||||||
|
|
@ -353,7 +355,7 @@ mod tests {
|
||||||
let items: response::Continuation =
|
let items: response::Continuation =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Paginator<YouTubeItem>> =
|
let map_res: MapResult<Paginator<YouTubeItem>> =
|
||||||
items.map_response("", Language::En, None).unwrap();
|
items.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -375,7 +377,7 @@ mod tests {
|
||||||
let items: response::Continuation =
|
let items: response::Continuation =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Paginator<YouTubeItem>> =
|
let map_res: MapResult<Paginator<YouTubeItem>> =
|
||||||
items.map_response("", Language::En, None).unwrap();
|
items.map_response("", Language::En, None, None).unwrap();
|
||||||
let paginator: Paginator<VideoItem> =
|
let paginator: Paginator<VideoItem> =
|
||||||
map_yt_paginator(map_res.c, None, ContinuationEndpoint::Browse);
|
map_yt_paginator(map_res.c, None, ContinuationEndpoint::Browse);
|
||||||
|
|
||||||
|
|
@ -398,7 +400,7 @@ mod tests {
|
||||||
let items: response::Continuation =
|
let items: response::Continuation =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Paginator<YouTubeItem>> =
|
let map_res: MapResult<Paginator<YouTubeItem>> =
|
||||||
items.map_response("", Language::En, None).unwrap();
|
items.map_response("", Language::En, None, None).unwrap();
|
||||||
let paginator: Paginator<PlaylistItem> =
|
let paginator: Paginator<PlaylistItem> =
|
||||||
map_yt_paginator(map_res.c, None, ContinuationEndpoint::Browse);
|
map_yt_paginator(map_res.c, None, ContinuationEndpoint::Browse);
|
||||||
|
|
||||||
|
|
@ -421,7 +423,7 @@ mod tests {
|
||||||
let items: response::MusicContinuation =
|
let items: response::MusicContinuation =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Paginator<MusicItem>> =
|
let map_res: MapResult<Paginator<MusicItem>> =
|
||||||
items.map_response("", Language::En, None).unwrap();
|
items.map_response("", Language::En, None, None).unwrap();
|
||||||
let paginator: Paginator<TrackItem> =
|
let paginator: Paginator<TrackItem> =
|
||||||
map_ytm_paginator(map_res.c, None, ContinuationEndpoint::MusicBrowse);
|
map_ytm_paginator(map_res.c, None, ContinuationEndpoint::MusicBrowse);
|
||||||
|
|
||||||
|
|
@ -442,7 +444,7 @@ mod tests {
|
||||||
let items: response::MusicContinuation =
|
let items: response::MusicContinuation =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<Paginator<MusicItem>> =
|
let map_res: MapResult<Paginator<MusicItem>> =
|
||||||
items.map_response("", Language::En, None).unwrap();
|
items.map_response("", Language::En, None, None).unwrap();
|
||||||
let paginator: Paginator<MusicPlaylistItem> =
|
let paginator: Paginator<MusicPlaylistItem> =
|
||||||
map_ytm_paginator(map_res.c, None, ContinuationEndpoint::MusicBrowse);
|
map_ytm_paginator(map_res.c, None, ContinuationEndpoint::MusicBrowse);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,7 @@ impl MapResponse<VideoPlayer> for response::Player {
|
||||||
id: &str,
|
id: &str,
|
||||||
_lang: Language,
|
_lang: Language,
|
||||||
deobf: Option<&crate::deobfuscate::DeobfData>,
|
deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
vdata: Option<&str>,
|
||||||
) -> Result<super::MapResult<VideoPlayer>, ExtractionError> {
|
) -> Result<super::MapResult<VideoPlayer>, ExtractionError> {
|
||||||
let deobf = Deobfuscator::new(deobf.unwrap())?;
|
let deobf = Deobfuscator::new(deobf.unwrap())?;
|
||||||
let mut warnings = vec![];
|
let mut warnings = vec![];
|
||||||
|
|
@ -372,7 +373,10 @@ impl MapResponse<VideoPlayer> for response::Player {
|
||||||
hls_manifest_url: streaming_data.hls_manifest_url,
|
hls_manifest_url: streaming_data.hls_manifest_url,
|
||||||
dash_manifest_url: streaming_data.dash_manifest_url,
|
dash_manifest_url: streaming_data.dash_manifest_url,
|
||||||
preview_frames,
|
preview_frames,
|
||||||
visitor_data: self.response_context.visitor_data,
|
visitor_data: self
|
||||||
|
.response_context
|
||||||
|
.visitor_data
|
||||||
|
.or_else(|| vdata.map(str::to_owned)),
|
||||||
},
|
},
|
||||||
warnings,
|
warnings,
|
||||||
})
|
})
|
||||||
|
|
@ -717,7 +721,7 @@ mod tests {
|
||||||
|
|
||||||
let resp: response::Player = serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
let resp: response::Player = serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res = resp
|
let map_res = resp
|
||||||
.map_response("pPvd8UxmSbQ", Language::En, Some(&DEOBF_DATA))
|
.map_response("pPvd8UxmSbQ", Language::En, Some(&DEOBF_DATA), None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ impl MapResponse<Playlist> for response::Playlist {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Playlist>, ExtractionError> {
|
) -> Result<MapResult<Playlist>, ExtractionError> {
|
||||||
let (Some(contents), Some(header)) = (self.contents, self.header) else {
|
let (Some(contents), Some(header)) = (self.contents, self.header) else {
|
||||||
return Err(response::alerts_to_err(id, self.alerts));
|
return Err(response::alerts_to_err(id, self.alerts));
|
||||||
|
|
@ -152,7 +153,10 @@ impl MapResponse<Playlist> for response::Playlist {
|
||||||
channel,
|
channel,
|
||||||
last_update,
|
last_update,
|
||||||
last_update_txt,
|
last_update_txt,
|
||||||
visitor_data: self.response_context.visitor_data,
|
visitor_data: self
|
||||||
|
.response_context
|
||||||
|
.visitor_data
|
||||||
|
.or_else(|| vdata.map(str::to_owned)),
|
||||||
},
|
},
|
||||||
warnings: mapper.warnings,
|
warnings: mapper.warnings,
|
||||||
})
|
})
|
||||||
|
|
@ -181,7 +185,7 @@ mod tests {
|
||||||
|
|
||||||
let playlist: response::Playlist =
|
let playlist: response::Playlist =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res = playlist.map_response(id, Language::En, None).unwrap();
|
let map_res = playlist.map_response(id, Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@ impl MapResponse<SearchResult> for response::Search {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
vdata: Option<&str>,
|
||||||
) -> Result<MapResult<SearchResult>, ExtractionError> {
|
) -> Result<MapResult<SearchResult>, ExtractionError> {
|
||||||
let items = self
|
let items = self
|
||||||
.contents
|
.contents
|
||||||
|
|
@ -113,7 +114,10 @@ impl MapResponse<SearchResult> for response::Search {
|
||||||
crate::model::paginator::ContinuationEndpoint::Search,
|
crate::model::paginator::ContinuationEndpoint::Search,
|
||||||
),
|
),
|
||||||
corrected_query: mapper.corrected_query,
|
corrected_query: mapper.corrected_query,
|
||||||
visitor_data: self.response_context.visitor_data,
|
visitor_data: self
|
||||||
|
.response_context
|
||||||
|
.visitor_data
|
||||||
|
.or_else(|| vdata.map(str::to_owned)),
|
||||||
},
|
},
|
||||||
warnings: mapper.warnings,
|
warnings: mapper.warnings,
|
||||||
})
|
})
|
||||||
|
|
@ -145,7 +149,8 @@ mod tests {
|
||||||
let json_file = File::open(json_path).unwrap();
|
let json_file = File::open(json_path).unwrap();
|
||||||
|
|
||||||
let search: response::Search = serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
let search: response::Search = serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res: MapResult<SearchResult> = search.map_response("", Language::En, None).unwrap();
|
let map_res: MapResult<SearchResult> =
|
||||||
|
search.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ impl MapResponse<Paginator<VideoItem>> for response::Startpage {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Paginator<VideoItem>>, ExtractionError> {
|
) -> Result<MapResult<Paginator<VideoItem>>, ExtractionError> {
|
||||||
let grid = self
|
let grid = self
|
||||||
.contents
|
.contents
|
||||||
|
|
@ -70,7 +71,9 @@ impl MapResponse<Paginator<VideoItem>> for response::Startpage {
|
||||||
Ok(map_startpage_videos(
|
Ok(map_startpage_videos(
|
||||||
grid,
|
grid,
|
||||||
lang,
|
lang,
|
||||||
self.response_context.visitor_data,
|
self.response_context
|
||||||
|
.visitor_data
|
||||||
|
.or_else(|| vdata.map(str::to_owned)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -81,6 +84,7 @@ impl MapResponse<Vec<VideoItem>> for response::Trending {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: crate::param::Language,
|
lang: crate::param::Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Vec<VideoItem>>, ExtractionError> {
|
) -> Result<MapResult<Vec<VideoItem>>, ExtractionError> {
|
||||||
let items = self
|
let items = self
|
||||||
.contents
|
.contents
|
||||||
|
|
@ -146,8 +150,9 @@ 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<VideoItem>> =
|
let map_res: MapResult<Paginator<VideoItem>> = startpage
|
||||||
startpage.map_response("", Language::En, None).unwrap();
|
.map_response("", Language::En, None, None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -169,8 +174,9 @@ 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<VideoItem>> =
|
let map_res: MapResult<Vec<VideoItem>> = startpage
|
||||||
startpage.map_response("", Language::En, None).unwrap();
|
.map_response("", Language::En, None, None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -328,6 +328,7 @@ impl MapResponse<UrlTarget> for response::ResolvedUrl {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
_lang: Language,
|
_lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<UrlTarget>, ExtractionError> {
|
) -> Result<MapResult<UrlTarget>, ExtractionError> {
|
||||||
let pt = self.endpoint.page_type();
|
let pt = self.endpoint.page_type();
|
||||||
if let NavigationEndpoint::Browse {
|
if let NavigationEndpoint::Browse {
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
|
||||||
id: &str,
|
id: &str,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
vdata: Option<&str>,
|
||||||
) -> Result<MapResult<VideoDetails>, ExtractionError> {
|
) -> Result<MapResult<VideoDetails>, ExtractionError> {
|
||||||
let mut warnings = Vec::new();
|
let mut warnings = Vec::new();
|
||||||
|
|
||||||
|
|
@ -256,7 +257,10 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
|
||||||
_ => return Err(ExtractionError::InvalidData("invalid channel link".into())),
|
_ => return Err(ExtractionError::InvalidData("invalid channel link".into())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let visitor_data = self.response_context.visitor_data;
|
let visitor_data = self
|
||||||
|
.response_context
|
||||||
|
.visitor_data
|
||||||
|
.or_else(|| vdata.map(str::to_owned));
|
||||||
let recommended = contents
|
let recommended = contents
|
||||||
.two_column_watch_next_results
|
.two_column_watch_next_results
|
||||||
.secondary_results
|
.secondary_results
|
||||||
|
|
@ -369,6 +373,7 @@ impl MapResponse<Paginator<Comment>> for response::VideoComments {
|
||||||
_id: &str,
|
_id: &str,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||||
|
_vdata: Option<&str>,
|
||||||
) -> Result<MapResult<Paginator<Comment>>, ExtractionError> {
|
) -> Result<MapResult<Paginator<Comment>>, ExtractionError> {
|
||||||
let received_endpoints = self.on_response_received_endpoints;
|
let received_endpoints = self.on_response_received_endpoints;
|
||||||
let mut warnings = received_endpoints.warnings;
|
let mut warnings = received_endpoints.warnings;
|
||||||
|
|
@ -561,7 +566,7 @@ mod tests {
|
||||||
|
|
||||||
let details: response::VideoDetails =
|
let details: response::VideoDetails =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res = details.map_response(id, Language::En, None).unwrap();
|
let map_res = details.map_response(id, Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
@ -581,7 +586,9 @@ mod tests {
|
||||||
|
|
||||||
let details: response::VideoDetails =
|
let details: response::VideoDetails =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let err = details.map_response("", Language::En, None).unwrap_err();
|
let err = details
|
||||||
|
.map_response("", Language::En, None, None)
|
||||||
|
.unwrap_err();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
err,
|
err,
|
||||||
crate::error::ExtractionError::NotFound { .. }
|
crate::error::ExtractionError::NotFound { .. }
|
||||||
|
|
@ -597,7 +604,7 @@ mod tests {
|
||||||
|
|
||||||
let comments: response::VideoComments =
|
let comments: response::VideoComments =
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||||
let map_res = comments.map_response("", Language::En, None).unwrap();
|
let map_res = comments.map_response("", Language::En, None, None).unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
map_res.warnings.is_empty(),
|
map_res.warnings.is_empty(),
|
||||||
|
|
|
||||||
|
|
@ -1324,27 +1324,36 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
||||||
},
|
},
|
||||||
Language::En | Language::EnGb | Language::EnIn => Entry {
|
Language::En | Language::EnGb | Language::EnIn => Entry {
|
||||||
timeago_tokens: ::phf::Map {
|
timeago_tokens: ::phf::Map {
|
||||||
key: 7485420634051515786,
|
key: 12913932095322966823,
|
||||||
disps: &[
|
disps: &[
|
||||||
(0, 7),
|
(2, 0),
|
||||||
(8, 12),
|
(2, 0),
|
||||||
(5, 0),
|
(5, 18),
|
||||||
|
(4, 15),
|
||||||
|
(2, 17),
|
||||||
],
|
],
|
||||||
entries: &[
|
entries: &[
|
||||||
("months", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
|
|
||||||
("month", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
|
|
||||||
("hours", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
|
|
||||||
("days", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
|
|
||||||
("years", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
|
|
||||||
("week", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
|
|
||||||
("second", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
|
|
||||||
("day", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
|
("day", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
|
||||||
|
("month", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
|
||||||
|
("minutes", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
|
||||||
|
("min", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
|
||||||
|
("y", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
|
||||||
|
("days", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
|
||||||
("minute", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
|
("minute", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
|
||||||
("seconds", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
|
("seconds", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
|
||||||
|
("s", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
|
||||||
|
("mo", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
|
||||||
|
("hours", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
|
||||||
|
("w", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
|
||||||
|
("h", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
|
||||||
|
("d", TaToken { n: 1, unit: Some(TimeUnit::Day) }),
|
||||||
|
("second", TaToken { n: 1, unit: Some(TimeUnit::Second) }),
|
||||||
|
("years", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
|
||||||
|
("months", TaToken { n: 1, unit: Some(TimeUnit::Month) }),
|
||||||
|
("week", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
|
||||||
("weeks", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
|
("weeks", TaToken { n: 1, unit: Some(TimeUnit::Week) }),
|
||||||
("hour", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
|
|
||||||
("minutes", TaToken { n: 1, unit: Some(TimeUnit::Minute) }),
|
|
||||||
("year", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
|
("year", TaToken { n: 1, unit: Some(TimeUnit::Year) }),
|
||||||
|
("hour", TaToken { n: 1, unit: Some(TimeUnit::Hour) }),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
date_order: &[DateCmp::D, DateCmp::Y],
|
date_order: &[DateCmp::D, DateCmp::Y],
|
||||||
|
|
|
||||||
|
|
@ -754,7 +754,14 @@
|
||||||
"week": "W",
|
"week": "W",
|
||||||
"weeks": "W",
|
"weeks": "W",
|
||||||
"year": "Y",
|
"year": "Y",
|
||||||
"years": "Y"
|
"years": "Y",
|
||||||
|
"y": "Y",
|
||||||
|
"mo": "M",
|
||||||
|
"w": "W",
|
||||||
|
"d": "D",
|
||||||
|
"h": "h",
|
||||||
|
"min": "m",
|
||||||
|
"s": "s"
|
||||||
},
|
},
|
||||||
"date_order": "DY",
|
"date_order": "DY",
|
||||||
"months": {
|
"months": {
|
||||||
|
|
|
||||||
|
|
@ -2336,7 +2336,12 @@ fn lang() -> Language {
|
||||||
/// Get a new RustyPipe instance
|
/// Get a new RustyPipe instance
|
||||||
#[fixture]
|
#[fixture]
|
||||||
fn rp(lang: Language) -> RustyPipe {
|
fn rp(lang: Language) -> RustyPipe {
|
||||||
RustyPipe::builder().strict().lang(lang).build()
|
let vdata = std::env::var("YT_VDATA").ok();
|
||||||
|
RustyPipe::builder()
|
||||||
|
.strict()
|
||||||
|
.lang(lang)
|
||||||
|
.visitor_data_opt(vdata)
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a flag signaling if the language is set to English
|
/// Get a flag signaling if the language is set to English
|
||||||
|
|
|
||||||
Reference in a new issue