feat: add frameset
This commit is contained in:
parent
e184341625
commit
aa5cd47dcd
12 changed files with 339 additions and 10 deletions
|
|
@ -12,8 +12,8 @@ use crate::{
|
||||||
deobfuscate::Deobfuscator,
|
deobfuscate::Deobfuscator,
|
||||||
error::{internal::DeobfError, Error, ExtractionError, UnavailabilityReason},
|
error::{internal::DeobfError, Error, ExtractionError, UnavailabilityReason},
|
||||||
model::{
|
model::{
|
||||||
traits::QualityOrd, AudioCodec, AudioFormat, AudioStream, AudioTrack, ChannelId, Subtitle,
|
traits::QualityOrd, AudioCodec, AudioFormat, AudioStream, AudioTrack, ChannelId, Frameset,
|
||||||
VideoCodec, VideoFormat, VideoPlayer, VideoPlayerDetails, VideoStream,
|
Subtitle, VideoCodec, VideoFormat, VideoPlayer, VideoPlayerDetails, VideoStream,
|
||||||
},
|
},
|
||||||
param::Language,
|
param::Language,
|
||||||
util,
|
util,
|
||||||
|
|
@ -313,6 +313,54 @@ impl MapResponse<VideoPlayer> for response::Player {
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let preview_frames = self
|
||||||
|
.storyboards
|
||||||
|
.and_then(|sb| {
|
||||||
|
let spec = sb.player_storyboard_spec_renderer.spec;
|
||||||
|
let mut spec_parts = spec.split('|');
|
||||||
|
let url_tmpl = spec_parts.next()?;
|
||||||
|
|
||||||
|
Some(
|
||||||
|
spec_parts
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, fs_spec)| {
|
||||||
|
// Example: 160#90#131#5#5#2000#M$M#rs$AOn4CLCV3TJ2Nty5fbw2r-Lqg4VDOZcVvQ
|
||||||
|
let mut parts = fs_spec.split('#');
|
||||||
|
|
||||||
|
let frame_width = parts.next()?.parse().ok()?;
|
||||||
|
let frame_height = parts.next()?.parse().ok()?;
|
||||||
|
let total_count = parts.next()?.parse().ok()?;
|
||||||
|
let frames_per_page_x = parts.next()?.parse().ok()?;
|
||||||
|
let frames_per_page_y = parts.next()?.parse().ok()?;
|
||||||
|
let duration_per_frame = parts.next()?.parse().ok()?;
|
||||||
|
|
||||||
|
let n = parts.next()?;
|
||||||
|
let sigh = parts.next()?;
|
||||||
|
|
||||||
|
let url = url_tmpl.replace("$L", &i.to_string()).replace("$N", n)
|
||||||
|
+ "&sigh="
|
||||||
|
+ sigh;
|
||||||
|
|
||||||
|
let sprite_count = ((total_count as f64)
|
||||||
|
/ (frames_per_page_x * frames_per_page_y) as f64)
|
||||||
|
.ceil() as u32;
|
||||||
|
|
||||||
|
Some(Frameset {
|
||||||
|
url_template: url,
|
||||||
|
frame_width,
|
||||||
|
frame_height,
|
||||||
|
page_count: sprite_count,
|
||||||
|
total_count,
|
||||||
|
duration_per_frame,
|
||||||
|
frames_per_page_x,
|
||||||
|
frames_per_page_y,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
Ok(MapResult {
|
Ok(MapResult {
|
||||||
c: VideoPlayer {
|
c: VideoPlayer {
|
||||||
details: video_info,
|
details: video_info,
|
||||||
|
|
@ -323,6 +371,7 @@ impl MapResponse<VideoPlayer> for response::Player {
|
||||||
expires_in_seconds: streaming_data.expires_in_seconds,
|
expires_in_seconds: streaming_data.expires_in_seconds,
|
||||||
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,
|
||||||
visitor_data: self.response_context.visitor_data,
|
visitor_data: self.response_context.visitor_data,
|
||||||
},
|
},
|
||||||
warnings,
|
warnings,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use serde_with::{json::JsonString, DefaultOnError};
|
||||||
use super::{ResponseContext, Thumbnails};
|
use super::{ResponseContext, Thumbnails};
|
||||||
use crate::serializer::{text::Text, MapResult};
|
use crate::serializer::{text::Text, MapResult};
|
||||||
|
|
||||||
|
#[serde_as]
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub(crate) struct Player {
|
pub(crate) struct Player {
|
||||||
|
|
@ -14,6 +15,9 @@ pub(crate) struct Player {
|
||||||
pub streaming_data: Option<StreamingData>,
|
pub streaming_data: Option<StreamingData>,
|
||||||
pub captions: Option<Captions>,
|
pub captions: Option<Captions>,
|
||||||
pub video_details: Option<VideoDetails>,
|
pub video_details: Option<VideoDetails>,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde_as(deserialize_as = "DefaultOnError")]
|
||||||
|
pub storyboards: Option<Storyboards>,
|
||||||
pub response_context: ResponseContext,
|
pub response_context: ResponseContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,3 +250,15 @@ pub(crate) struct VideoDetails {
|
||||||
pub author: String,
|
pub author: String,
|
||||||
pub is_live_content: bool,
|
pub is_live_content: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub(crate) struct Storyboards {
|
||||||
|
pub player_storyboard_spec_renderer: StoryboardRenderer,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub(crate) struct StoryboardRenderer {
|
||||||
|
pub spec: String,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -450,5 +450,37 @@ VideoPlayer(
|
||||||
expires_in_seconds: 21540,
|
expires_in_seconds: 21540,
|
||||||
hls_manifest_url: None,
|
hls_manifest_url: None,
|
||||||
dash_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/dash/expire/1659481355/ei/q1jpYtOPEYSBgQeHmqbwAQ/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr5---sn-h0jeenek.googlevideo.com/mh/mQ/mm/31%2C29/mn/sn-h0jeenek%2Csn-h0jelnez/ms/au%2Crdu/mv/m/mvi/5/pl/37/hfr/1/as/fmp4_audio_clear%2Cfmp4_sd_hd_clear/initcwndbps/1527500/vprv/1/mt/1659459429/fvip/4/itag_bl/376%2C377%2C384%2C385%2C612%2C613%2C617%2C619%2C623%2C628%2C655%2C656%2C660%2C662%2C666%2C671/keepalive/yes/fexp/24001373%2C24007246/itag/0/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cas%2Cvprv%2Citag/sig/AOq0QJ8wRAIgMm4a_MIHA3YUszKeruSy3exs5JwNjJAyLAwxL0yPdNMCIANb9GDMSTp_NT-PPhbvYMwRULJ5a9BO6MYD9FuWprC1/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRQIgETSOwhwWVMy7gmrFXZlJu655ToLzSwOEsT16oRyrWhACIQDkvOEw1fImz5omu4iVIRNFe-z-JC9v8WUyx281dW2NOw%3D%3D"),
|
dash_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/dash/expire/1659481355/ei/q1jpYtOPEYSBgQeHmqbwAQ/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr5---sn-h0jeenek.googlevideo.com/mh/mQ/mm/31%2C29/mn/sn-h0jeenek%2Csn-h0jelnez/ms/au%2Crdu/mv/m/mvi/5/pl/37/hfr/1/as/fmp4_audio_clear%2Cfmp4_sd_hd_clear/initcwndbps/1527500/vprv/1/mt/1659459429/fvip/4/itag_bl/376%2C377%2C384%2C385%2C612%2C613%2C617%2C619%2C623%2C628%2C655%2C656%2C660%2C662%2C666%2C671/keepalive/yes/fexp/24001373%2C24007246/itag/0/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cas%2Cvprv%2Citag/sig/AOq0QJ8wRAIgMm4a_MIHA3YUszKeruSy3exs5JwNjJAyLAwxL0yPdNMCIANb9GDMSTp_NT-PPhbvYMwRULJ5a9BO6MYD9FuWprC1/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRQIgETSOwhwWVMy7gmrFXZlJu655ToLzSwOEsT16oRyrWhACIQDkvOEw1fImz5omu4iVIRNFe-z-JC9v8WUyx281dW2NOw%3D%3D"),
|
||||||
|
preview_frames: [
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L0/default.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLAXobPyrylgm8IEvjlZzqYTiPe1Ow",
|
||||||
|
frame_width: 48,
|
||||||
|
frame_height: 27,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 100,
|
||||||
|
duration_per_frame: 0,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L1/M$M.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLCWd3ylPF7ViQFBu5RUODMcusr_5g",
|
||||||
|
frame_width: 80,
|
||||||
|
frame_height: 45,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L2/M$M.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLA6xat5cfw0e3EX_5SW-TPwkmExxA",
|
||||||
|
frame_width: 160,
|
||||||
|
frame_height: 90,
|
||||||
|
page_count: 4,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 5,
|
||||||
|
frames_per_page_y: 5,
|
||||||
|
),
|
||||||
|
],
|
||||||
visitor_data: Some("Cgt2aHFtQU5YZFBvYyirsaWXBg%3D%3D"),
|
visitor_data: Some("Cgt2aHFtQU5YZFBvYyirsaWXBg%3D%3D"),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -569,5 +569,37 @@ VideoPlayer(
|
||||||
expires_in_seconds: 21540,
|
expires_in_seconds: 21540,
|
||||||
hls_manifest_url: None,
|
hls_manifest_url: None,
|
||||||
dash_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/dash/expire/1659481355/ei/q1jpYtq3BJCX1gKVyJGQDg/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr4---sn-h0jelnez.googlevideo.com/mh/mQ/mm/31%2C26/mn/sn-h0jelnez%2Csn-4g5edn6k/ms/au%2Conr/mv/m/mvi/4/pl/37/hfr/all/as/fmp4_audio_clear%2Cwebm_audio_clear%2Cwebm2_audio_clear%2Cfmp4_sd_hd_clear%2Cwebm2_sd_hd_clear/initcwndbps/1513750/spc/lT-KhrZGE2opztWyVdAtyUNlb8dXPDs/vprv/1/mt/1659459429/fvip/4/keepalive/yes/fexp/24001373%2C24007246/itag/0/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cas%2Cspc%2Cvprv%2Citag/sig/AOq0QJ8wRgIhAPEjHK19PKVHqQeia6WF4qubuMYk74LGi8F8lk5ZMPkFAiEAsaB2pKQWBvuPnNUnbdQXHc-izgsHJUP793woC2xNJlg%3D/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRQIgOY4xu4H9wqPVZ7vF2i0hFcOnqrur1XGoA43a7ZEuuSUCIQCyPxBKXUQrKFmknNEGpX5GSWySKgMw_xHBikWpKpKwvg%3D%3D"),
|
dash_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/dash/expire/1659481355/ei/q1jpYtq3BJCX1gKVyJGQDg/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr4---sn-h0jelnez.googlevideo.com/mh/mQ/mm/31%2C26/mn/sn-h0jelnez%2Csn-4g5edn6k/ms/au%2Conr/mv/m/mvi/4/pl/37/hfr/all/as/fmp4_audio_clear%2Cwebm_audio_clear%2Cwebm2_audio_clear%2Cfmp4_sd_hd_clear%2Cwebm2_sd_hd_clear/initcwndbps/1513750/spc/lT-KhrZGE2opztWyVdAtyUNlb8dXPDs/vprv/1/mt/1659459429/fvip/4/keepalive/yes/fexp/24001373%2C24007246/itag/0/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cas%2Cspc%2Cvprv%2Citag/sig/AOq0QJ8wRgIhAPEjHK19PKVHqQeia6WF4qubuMYk74LGi8F8lk5ZMPkFAiEAsaB2pKQWBvuPnNUnbdQXHc-izgsHJUP793woC2xNJlg%3D/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRQIgOY4xu4H9wqPVZ7vF2i0hFcOnqrur1XGoA43a7ZEuuSUCIQCyPxBKXUQrKFmknNEGpX5GSWySKgMw_xHBikWpKpKwvg%3D%3D"),
|
||||||
|
preview_frames: [
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L0/default.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLAXobPyrylgm8IEvjlZzqYTiPe1Ow",
|
||||||
|
frame_width: 48,
|
||||||
|
frame_height: 27,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 100,
|
||||||
|
duration_per_frame: 0,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L1/M$M.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLCWd3ylPF7ViQFBu5RUODMcusr_5g",
|
||||||
|
frame_width: 80,
|
||||||
|
frame_height: 45,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L2/M$M.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLA6xat5cfw0e3EX_5SW-TPwkmExxA",
|
||||||
|
frame_width: 160,
|
||||||
|
frame_height: 90,
|
||||||
|
page_count: 4,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 5,
|
||||||
|
frames_per_page_y: 5,
|
||||||
|
),
|
||||||
|
],
|
||||||
visitor_data: Some("CgtoS1pCMVJTNUJISSirsaWXBg%3D%3D"),
|
visitor_data: Some("CgtoS1pCMVJTNUJISSirsaWXBg%3D%3D"),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -387,5 +387,37 @@ VideoPlayer(
|
||||||
expires_in_seconds: 21540,
|
expires_in_seconds: 21540,
|
||||||
hls_manifest_url: None,
|
hls_manifest_url: None,
|
||||||
dash_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/dash/expire/1659487474/ei/knDpYub6BojEgAf6jbLgDw/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr5---sn-h0jeenek.googlevideo.com/mh/mQ/mm/31%2C29/mn/sn-h0jeenek%2Csn-h0jelnez/ms/au%2Crdu/mv/m/mvi/5/pl/37/hfr/all/as/fmp4_audio_clear%2Cwebm_audio_clear%2Cwebm2_audio_clear%2Cfmp4_sd_hd_clear%2Cwebm2_sd_hd_clear/initcwndbps/1418750/spc/lT-Khox4YuJQ2wmH79zYALRvsWTPCUc/vprv/1/mt/1659465669/fvip/4/keepalive/yes/fexp/24001373%2C24007246/itag/0/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cas%2Cspc%2Cvprv%2Citag/sig/AOq0QJ8wRAIgErABhAEaoKHUDu9dDbpxE_8gR4b8WWAi61fnu8UKnuICIEYrEKcHvqHdO4V3R7cvSGwi_HGH34IlQsKbziOfMBov/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRQIgJxHmH0Sxo3cY_pW_ZzQ3hW9-7oz6K_pZWcUdrDDQ2sQCIQDJYNINQwLgKelgbO3CZYx7sMxdUAFpWdokmRBQ77vwvw%3D%3D"),
|
dash_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/dash/expire/1659487474/ei/knDpYub6BojEgAf6jbLgDw/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr5---sn-h0jeenek.googlevideo.com/mh/mQ/mm/31%2C29/mn/sn-h0jeenek%2Csn-h0jelnez/ms/au%2Crdu/mv/m/mvi/5/pl/37/hfr/all/as/fmp4_audio_clear%2Cwebm_audio_clear%2Cwebm2_audio_clear%2Cfmp4_sd_hd_clear%2Cwebm2_sd_hd_clear/initcwndbps/1418750/spc/lT-Khox4YuJQ2wmH79zYALRvsWTPCUc/vprv/1/mt/1659465669/fvip/4/keepalive/yes/fexp/24001373%2C24007246/itag/0/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cas%2Cspc%2Cvprv%2Citag/sig/AOq0QJ8wRAIgErABhAEaoKHUDu9dDbpxE_8gR4b8WWAi61fnu8UKnuICIEYrEKcHvqHdO4V3R7cvSGwi_HGH34IlQsKbziOfMBov/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRQIgJxHmH0Sxo3cY_pW_ZzQ3hW9-7oz6K_pZWcUdrDDQ2sQCIQDJYNINQwLgKelgbO3CZYx7sMxdUAFpWdokmRBQ77vwvw%3D%3D"),
|
||||||
|
preview_frames: [
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L0/default.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLAXobPyrylgm8IEvjlZzqYTiPe1Ow",
|
||||||
|
frame_width: 48,
|
||||||
|
frame_height: 27,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 100,
|
||||||
|
duration_per_frame: 0,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L1/M$M.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLCWd3ylPF7ViQFBu5RUODMcusr_5g",
|
||||||
|
frame_width: 80,
|
||||||
|
frame_height: 45,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L2/M$M.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLA6xat5cfw0e3EX_5SW-TPwkmExxA",
|
||||||
|
frame_width: 160,
|
||||||
|
frame_height: 90,
|
||||||
|
page_count: 4,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 5,
|
||||||
|
frames_per_page_y: 5,
|
||||||
|
),
|
||||||
|
],
|
||||||
visitor_data: Some("CgszSHZWNWs0SDhpTSiS4aWXBg%3D%3D"),
|
visitor_data: Some("CgszSHZWNWs0SDhpTSiS4aWXBg%3D%3D"),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -168,5 +168,37 @@ VideoPlayer(
|
||||||
expires_in_seconds: 21540,
|
expires_in_seconds: 21540,
|
||||||
hls_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/hls_variant/expire/1659481355/ei/q1jpYq-xHs7NgQev0bfwAQ/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr4---sn-h0jelnez.googlevideo.com/mh/mQ/mm/31%2C29/mn/sn-h0jelnez%2Csn-h0jeenek/ms/au%2Crdu/mv/m/mvi/4/pl/37/hfr/1/demuxed/1/tts_caps/1/maudio/1/initcwndbps/1513750/vprv/1/go/1/mt/1659459429/fvip/5/nvgoi/1/short_key/1/ncsapi/1/keepalive/yes/fexp/24001373%2C24007246/dover/13/itag/0/playlist_type/DVR/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cdemuxed%2Ctts_caps%2Cmaudio%2Cvprv%2Cgo%2Citag%2Cplaylist_type/sig/AOq0QJ8wRQIhAIYnEHvIgJtJ8hehAXNtVY3qsgsq_GdOhWf2hkJZe6lCAiBxaRY_nubYp6hBizcAg_KFkKnkG-t2XYLRQ5wGdM3AjA%3D%3D/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRgIhAM_91Kk_0VLuSsR6nLCY7LdtWojyRAzXSScd_X9ShRROAiEA1AF4VY04F71NsAI8_j3iqjuXnWL9s6NoXHq7P8-bHx8%3D/file/index.m3u8"),
|
hls_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/hls_variant/expire/1659481355/ei/q1jpYq-xHs7NgQev0bfwAQ/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr4---sn-h0jelnez.googlevideo.com/mh/mQ/mm/31%2C29/mn/sn-h0jelnez%2Csn-h0jeenek/ms/au%2Crdu/mv/m/mvi/4/pl/37/hfr/1/demuxed/1/tts_caps/1/maudio/1/initcwndbps/1513750/vprv/1/go/1/mt/1659459429/fvip/5/nvgoi/1/short_key/1/ncsapi/1/keepalive/yes/fexp/24001373%2C24007246/dover/13/itag/0/playlist_type/DVR/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cdemuxed%2Ctts_caps%2Cmaudio%2Cvprv%2Cgo%2Citag%2Cplaylist_type/sig/AOq0QJ8wRQIhAIYnEHvIgJtJ8hehAXNtVY3qsgsq_GdOhWf2hkJZe6lCAiBxaRY_nubYp6hBizcAg_KFkKnkG-t2XYLRQ5wGdM3AjA%3D%3D/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRgIhAM_91Kk_0VLuSsR6nLCY7LdtWojyRAzXSScd_X9ShRROAiEA1AF4VY04F71NsAI8_j3iqjuXnWL9s6NoXHq7P8-bHx8%3D/file/index.m3u8"),
|
||||||
dash_manifest_url: None,
|
dash_manifest_url: None,
|
||||||
|
preview_frames: [
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L0/default.jpg?sqp=-oaymwGbA0g48quKqQOSA4gBAZUBAAAEQpgBMqABPKgBBLABELABDbABDLABELABFbABH7ABJrABLbABDrABDrABD7ABErABF7ABK7ABLLABKbABD7ABDrABELABFbABH7ABKrABMrABKbABD7ABEbABFLABGLABJrABPbABOLABLbABEbABFLABHrABKrABMbABS7ABR7ABNrABFbABHLABKbABLrABObABR7ABTbABP7ABJbABLrABN7ABPbABR7ABUrABUbABRbABM7ABQLABQrABQ7ABTLABRLABRrABQ7gBEbgBEbgBFbgBI7gBRLgBQ7gBQ7gBQ7gBEbgBE7gBFrgBL7gBQ7gBQ7gBQ7gBQ7gBFbgBFrgBKbgBQ7gBQ7gBQ7gBQ7gBQ7gBI7gBL7gBQ7gBQ7gBQ7gBQ7gBQ7gBQ7gBRLgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLCsCT8Lprh2S0ptmCRsWH7VtDl3YQ",
|
||||||
|
frame_width: 48,
|
||||||
|
frame_height: 27,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 100,
|
||||||
|
duration_per_frame: 0,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L1/M$M.jpg?sqp=-oaymwGbA0g48quKqQOSA4gBAZUBAAAEQpgBMqABPKgBBLABELABDbABDLABELABFbABH7ABJrABLbABDrABDrABD7ABErABF7ABK7ABLLABKbABD7ABDrABELABFbABH7ABKrABMrABKbABD7ABEbABFLABGLABJrABPbABOLABLbABEbABFLABHrABKrABMbABS7ABR7ABNrABFbABHLABKbABLrABObABR7ABTbABP7ABJbABLrABN7ABPbABR7ABUrABUbABRbABM7ABQLABQrABQ7ABTLABRLABRrABQ7gBEbgBEbgBFbgBI7gBRLgBQ7gBQ7gBQ7gBEbgBE7gBFrgBL7gBQ7gBQ7gBQ7gBQ7gBFbgBFrgBKbgBQ7gBQ7gBQ7gBQ7gBQ7gBI7gBL7gBQ7gBQ7gBQ7gBQ7gBQ7gBQ7gBRLgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLBXrdgfuYV1WLnTGXqZtSAUm8oZCA",
|
||||||
|
frame_width: 80,
|
||||||
|
frame_height: 45,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L2/M$M.jpg?sqp=-oaymwGbA0g48quKqQOSA4gBAZUBAAAEQpgBMqABPKgBBLABELABDbABDLABELABFbABH7ABJrABLbABDrABDrABD7ABErABF7ABK7ABLLABKbABD7ABDrABELABFbABH7ABKrABMrABKbABD7ABEbABFLABGLABJrABPbABOLABLbABEbABFLABHrABKrABMbABS7ABR7ABNrABFbABHLABKbABLrABObABR7ABTbABP7ABJbABLrABN7ABPbABR7ABUrABUbABRbABM7ABQLABQrABQ7ABTLABRLABRrABQ7gBEbgBEbgBFbgBI7gBRLgBQ7gBQ7gBQ7gBEbgBE7gBFrgBL7gBQ7gBQ7gBQ7gBQ7gBFbgBFrgBKbgBQ7gBQ7gBQ7gBQ7gBQ7gBI7gBL7gBQ7gBQ7gBQ7gBQ7gBQ7gBQ7gBRLgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLCRazj84zMuwJLaCCc_PiUakX_YdQ",
|
||||||
|
frame_width: 160,
|
||||||
|
frame_height: 90,
|
||||||
|
page_count: 4,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 5,
|
||||||
|
frames_per_page_y: 5,
|
||||||
|
),
|
||||||
|
],
|
||||||
visitor_data: Some("Cgs4TXV4dk13WVEyWSirsaWXBg%3D%3D"),
|
visitor_data: Some("Cgs4TXV4dk13WVEyWSirsaWXBg%3D%3D"),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -569,5 +569,37 @@ VideoPlayer(
|
||||||
expires_in_seconds: 21540,
|
expires_in_seconds: 21540,
|
||||||
hls_manifest_url: None,
|
hls_manifest_url: None,
|
||||||
dash_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/dash/expire/1659481355/ei/q1jpYv-eJ9uF6dsPhvyH8As/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr4---sn-h0jelnez.googlevideo.com/mh/mQ/mm/31%2C29/mn/sn-h0jelnez%2Csn-h0jeenek/ms/au%2Crdu/mv/m/mvi/4/pl/37/hfr/all/as/fmp4_audio_clear%2Cfmp4_sd_hd_clear/initcwndbps/1527500/vprv/1/mt/1659459429/fvip/5/keepalive/yes/fexp/24001373%2C24007246/itag/0/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cas%2Cvprv%2Citag/sig/AOq0QJ8wRQIhANKWS7GCN4pSoHIQ6BMZdOaHAD0I25nHwRj7ds4qrxdEAiBsd9l8WIceqF7-2xyR82DGecCiS9hgUIPJhdNhkwVpHg%3D%3D/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRQIgMbu-wTOcXGCwGh27y0YZHktumKM1sopgxfQf8LCcCnECIQDnhFbgddOxwiQbnMOIcCn6ncpN54UyALRNigUSCp9Deg%3D%3D"),
|
dash_manifest_url: Some("https://manifest.googlevideo.com/api/manifest/dash/expire/1659481355/ei/q1jpYv-eJ9uF6dsPhvyH8As/ip/2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e/id/a4fbddf14c6649b4/source/youtube/requiressl/yes/playback_host/rr4---sn-h0jelnez.googlevideo.com/mh/mQ/mm/31%2C29/mn/sn-h0jelnez%2Csn-h0jeenek/ms/au%2Crdu/mv/m/mvi/4/pl/37/hfr/all/as/fmp4_audio_clear%2Cfmp4_sd_hd_clear/initcwndbps/1527500/vprv/1/mt/1659459429/fvip/5/keepalive/yes/fexp/24001373%2C24007246/itag/0/sparams/expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Chfr%2Cas%2Cvprv%2Citag/sig/AOq0QJ8wRQIhANKWS7GCN4pSoHIQ6BMZdOaHAD0I25nHwRj7ds4qrxdEAiBsd9l8WIceqF7-2xyR82DGecCiS9hgUIPJhdNhkwVpHg%3D%3D/lsparams/playback_host%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps/lsig/AG3C_xAwRQIgMbu-wTOcXGCwGh27y0YZHktumKM1sopgxfQf8LCcCnECIQDnhFbgddOxwiQbnMOIcCn6ncpN54UyALRNigUSCp9Deg%3D%3D"),
|
||||||
|
preview_frames: [
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L0/default.jpg?sqp=-oaymwGbA0g48quKqQOSA4gBAZUBAAAEQpgBMqABPKgBBLABELABDbABDLABELABFbABH7ABJrABLbABDrABDrABD7ABErABF7ABK7ABLLABKbABD7ABDrABELABFbABH7ABKrABMrABKbABD7ABEbABFLABGLABJrABPbABOLABLbABEbABFLABHrABKrABMbABS7ABR7ABNrABFbABHLABKbABLrABObABR7ABTbABP7ABJbABLrABN7ABPbABR7ABUrABUbABRbABM7ABQLABQrABQ7ABTLABRLABRrABQ7gBEbgBEbgBFbgBI7gBRLgBQ7gBQ7gBQ7gBEbgBE7gBFrgBL7gBQ7gBQ7gBQ7gBQ7gBFbgBFrgBKbgBQ7gBQ7gBQ7gBQ7gBQ7gBI7gBL7gBQ7gBQ7gBQ7gBQ7gBQ7gBQ7gBRLgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLCsCT8Lprh2S0ptmCRsWH7VtDl3YQ",
|
||||||
|
frame_width: 48,
|
||||||
|
frame_height: 27,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 100,
|
||||||
|
duration_per_frame: 0,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L1/M$M.jpg?sqp=-oaymwGbA0g48quKqQOSA4gBAZUBAAAEQpgBMqABPKgBBLABELABDbABDLABELABFbABH7ABJrABLbABDrABDrABD7ABErABF7ABK7ABLLABKbABD7ABDrABELABFbABH7ABKrABMrABKbABD7ABEbABFLABGLABJrABPbABOLABLbABEbABFLABHrABKrABMbABS7ABR7ABNrABFbABHLABKbABLrABObABR7ABTbABP7ABJbABLrABN7ABPbABR7ABUrABUbABRbABM7ABQLABQrABQ7ABTLABRLABRrABQ7gBEbgBEbgBFbgBI7gBRLgBQ7gBQ7gBQ7gBEbgBE7gBFrgBL7gBQ7gBQ7gBQ7gBQ7gBFbgBFrgBKbgBQ7gBQ7gBQ7gBQ7gBQ7gBI7gBL7gBQ7gBQ7gBQ7gBQ7gBQ7gBQ7gBRLgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLBXrdgfuYV1WLnTGXqZtSAUm8oZCA",
|
||||||
|
frame_width: 80,
|
||||||
|
frame_height: 45,
|
||||||
|
page_count: 1,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 10,
|
||||||
|
frames_per_page_y: 10,
|
||||||
|
),
|
||||||
|
Frameset(
|
||||||
|
url_template: "https://i.ytimg.com/sb/pPvd8UxmSbQ/storyboard3_L2/M$M.jpg?sqp=-oaymwGbA0g48quKqQOSA4gBAZUBAAAEQpgBMqABPKgBBLABELABDbABDLABELABFbABH7ABJrABLbABDrABDrABD7ABErABF7ABK7ABLLABKbABD7ABDrABELABFbABH7ABKrABMrABKbABD7ABEbABFLABGLABJrABPbABOLABLbABEbABFLABHrABKrABMbABS7ABR7ABNrABFbABHLABKbABLrABObABR7ABTbABP7ABJbABLrABN7ABPbABR7ABUrABUbABRbABM7ABQLABQrABQ7ABTLABRLABRrABQ7gBEbgBEbgBFbgBI7gBRLgBQ7gBQ7gBQ7gBEbgBE7gBFrgBL7gBQ7gBQ7gBQ7gBQ7gBFbgBFrgBKbgBQ7gBQ7gBQ7gBQ7gBQ7gBI7gBL7gBQ7gBQ7gBQ7gBQ7gBQ7gBQ7gBRLgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQ7gBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQ7gBQ7gBQ7gBQrgBQrgBQrgBQrgBQqLzl_8DBgjf8LPxBQ==&sigh=rs$AOn4CLCRazj84zMuwJLaCCc_PiUakX_YdQ",
|
||||||
|
frame_width: 160,
|
||||||
|
frame_height: 90,
|
||||||
|
page_count: 4,
|
||||||
|
total_count: 83,
|
||||||
|
duration_per_frame: 2000,
|
||||||
|
frames_per_page_x: 5,
|
||||||
|
frames_per_page_y: 5,
|
||||||
|
),
|
||||||
|
],
|
||||||
visitor_data: Some("CgtacUJOMG81dTI3cyirsaWXBg%3D%3D"),
|
visitor_data: Some("CgtacUJOMG81dTI3cyirsaWXBg%3D%3D"),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
61
src/model/frameset.rs
Normal file
61
src/model/frameset.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Set of video frames for seek preview
|
||||||
|
///
|
||||||
|
/// YouTube generates a set of images containing a grid of frames for each video.
|
||||||
|
/// These images are used by the player for the seekbar preview.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct Frameset {
|
||||||
|
/// Url template of the frameset
|
||||||
|
///
|
||||||
|
/// The `$M` placeholder has to be replaced with the page index (starting from 0).
|
||||||
|
pub url_template: String,
|
||||||
|
/// Width of a single frame in pixels
|
||||||
|
pub frame_width: u32,
|
||||||
|
/// Height of a single frame in pixels
|
||||||
|
pub frame_height: u32,
|
||||||
|
/// Number of pages (individual images)
|
||||||
|
pub page_count: u32,
|
||||||
|
/// Total number of frames in the set
|
||||||
|
pub total_count: u32,
|
||||||
|
/// Duration per frame in milliseconds
|
||||||
|
pub duration_per_frame: u32,
|
||||||
|
/// Number of frames in the x direction
|
||||||
|
pub frames_per_page_x: u32,
|
||||||
|
/// Number of frames in the y direction.
|
||||||
|
pub frames_per_page_y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterator producing frameset page urls
|
||||||
|
pub struct FramesetUrls<'a> {
|
||||||
|
frameset: &'a Frameset,
|
||||||
|
i: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frameset {
|
||||||
|
/// Gets an iterator over the page URLs of the frameset
|
||||||
|
pub fn urls(&self) -> FramesetUrls {
|
||||||
|
FramesetUrls {
|
||||||
|
frameset: self,
|
||||||
|
i: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for FramesetUrls<'_> {
|
||||||
|
type Item = String;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.i < self.frameset.page_count {
|
||||||
|
let url = self
|
||||||
|
.frameset
|
||||||
|
.url_template
|
||||||
|
.replace("$M", &self.i.to_string());
|
||||||
|
self.i += 1;
|
||||||
|
Some(url)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,23 +1,22 @@
|
||||||
//! YouTube API response models
|
//! YouTube API response models
|
||||||
|
|
||||||
mod convert;
|
mod convert;
|
||||||
|
mod frameset;
|
||||||
mod ordering;
|
mod ordering;
|
||||||
|
|
||||||
pub mod paginator;
|
pub mod paginator;
|
||||||
pub mod richtext;
|
pub mod richtext;
|
||||||
|
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
|
pub use frameset::{Frameset, FramesetUrls};
|
||||||
use serde_with::serde_as;
|
|
||||||
|
|
||||||
use std::{collections::BTreeSet, ops::Range};
|
use std::{collections::BTreeSet, ops::Range};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::serde_as;
|
||||||
use time::{Date, OffsetDateTime};
|
use time::{Date, OffsetDateTime};
|
||||||
|
|
||||||
use crate::{error::Error, param::Country, serializer::DateYmd, util};
|
|
||||||
|
|
||||||
use self::{paginator::Paginator, richtext::RichText};
|
use self::{paginator::Paginator, richtext::RichText};
|
||||||
|
use crate::{error::Error, param::Country, serializer::DateYmd, util};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#COMMON
|
#COMMON
|
||||||
|
|
@ -155,6 +154,8 @@ pub struct VideoPlayer {
|
||||||
pub hls_manifest_url: Option<String>,
|
pub hls_manifest_url: Option<String>,
|
||||||
/// Dash manifest URL (for livestreams)
|
/// Dash manifest URL (for livestreams)
|
||||||
pub dash_manifest_url: Option<String>,
|
pub dash_manifest_url: Option<String>,
|
||||||
|
/// Video frames for seek preview
|
||||||
|
pub preview_frames: Vec<Frameset>,
|
||||||
/// YouTube visitor data cookie
|
/// YouTube visitor data cookie
|
||||||
pub visitor_data: Option<String>,
|
pub visitor_data: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1124,5 +1124,6 @@
|
||||||
"subtitles": [],
|
"subtitles": [],
|
||||||
"expires_in_seconds": 21540,
|
"expires_in_seconds": 21540,
|
||||||
"hls_manifest_url": null,
|
"hls_manifest_url": null,
|
||||||
"dash_manifest_url": null
|
"dash_manifest_url": null,
|
||||||
|
"preview_frames": []
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2119,5 +2119,6 @@
|
||||||
"expires_in_seconds": 21540,
|
"expires_in_seconds": 21540,
|
||||||
"hls_manifest_url": null,
|
"hls_manifest_url": null,
|
||||||
"dash_manifest_url": null,
|
"dash_manifest_url": null,
|
||||||
|
"preview_frames": [],
|
||||||
"visitor_data": "CgtGWDFCUllrcTdxayjo1_OiBg%3D%3D"
|
"visitor_data": "CgtGWDFCUllrcTdxayjo1_OiBg%3D%3D"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use reqwest::Client;
|
||||||
use rstest::{fixture, rstest};
|
use rstest::{fixture, rstest};
|
||||||
use rustypipe::model::paginator::ContinuationEndpoint;
|
use rustypipe::model::paginator::ContinuationEndpoint;
|
||||||
use rustypipe::param::{ChannelOrder, ChannelVideoTab, Language};
|
use rustypipe::param::{ChannelOrder, ChannelVideoTab, Language};
|
||||||
|
|
@ -15,8 +16,8 @@ use rustypipe::model::{
|
||||||
paginator::Paginator,
|
paginator::Paginator,
|
||||||
richtext::ToPlaintext,
|
richtext::ToPlaintext,
|
||||||
traits::{FromYtItem, YtStream},
|
traits::{FromYtItem, YtStream},
|
||||||
AlbumType, AudioCodec, AudioFormat, AudioTrackType, Channel, MusicGenre, MusicItemType,
|
AlbumType, AudioCodec, AudioFormat, AudioTrackType, Channel, Frameset, MusicGenre,
|
||||||
UrlTarget, Verification, VideoCodec, VideoFormat, YouTubeItem,
|
MusicItemType, UrlTarget, Verification, VideoCodec, VideoFormat, YouTubeItem,
|
||||||
};
|
};
|
||||||
use rustypipe::param::{
|
use rustypipe::param::{
|
||||||
search_filter::{self, SearchFilter},
|
search_filter::{self, SearchFilter},
|
||||||
|
|
@ -287,6 +288,11 @@ fn get_player(
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_gte(player_data.expires_in_seconds, 10_000, "expiry time");
|
assert_gte(player_data.expires_in_seconds, 10_000, "expiry time");
|
||||||
|
|
||||||
|
if !is_live {
|
||||||
|
assert_gte(player_data.preview_frames.len(), 3, "preview framesets");
|
||||||
|
player_data.preview_frames.iter().for_each(assert_frameset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
|
|
@ -2375,3 +2381,37 @@ fn assert_album_id(id: &str) {
|
||||||
fn assert_playlist_id(id: &str) {
|
fn assert_playlist_id(id: &str) {
|
||||||
assert!(validate::playlist_id(id), "invalid playlist id: `{id}`");
|
assert!(validate::playlist_id(id), "invalid playlist id: `{id}`");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn assert_image(client: &Client, url: &str) {
|
||||||
|
// let resp = tokio_test::block_on(client.get(url).send())
|
||||||
|
// .unwrap()
|
||||||
|
// .error_for_status()
|
||||||
|
// .unwrap();
|
||||||
|
// let ctype = resp
|
||||||
|
// .headers()
|
||||||
|
// .get(reqwest::header::CONTENT_TYPE)
|
||||||
|
// .unwrap()
|
||||||
|
// .to_str()
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
|
// assert!(ctype.starts_with("image/"), "content type: {ctype}");
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn assert_frameset(frameset: &Frameset) {
|
||||||
|
assert_gte(frameset.frame_height, 20, "frame height");
|
||||||
|
assert_gte(frameset.frame_height, 20, "frame width");
|
||||||
|
assert_gte(frameset.page_count, 1, "page count");
|
||||||
|
assert_gte(frameset.total_count, 50, "total count");
|
||||||
|
assert_gte(frameset.frames_per_page_x, 5, "frames per page x");
|
||||||
|
assert_gte(frameset.frames_per_page_y, 5, "frames per page y");
|
||||||
|
|
||||||
|
// let client = Client::new();
|
||||||
|
|
||||||
|
let n = frameset
|
||||||
|
.urls()
|
||||||
|
// .map(|url| {
|
||||||
|
// assert_image(&client, &url);
|
||||||
|
// })
|
||||||
|
.count() as u32;
|
||||||
|
assert_eq!(n, frameset.page_count);
|
||||||
|
}
|
||||||
|
|
|
||||||
Reference in a new issue