fix: accept video streams without content length/average bitrate
This commit is contained in:
parent
b52fd7349b
commit
63d2a0fb36
6 changed files with 42 additions and 50 deletions
|
|
@ -59,6 +59,7 @@ async fn download_single_video(
|
||||||
|
|
||||||
let res = async {
|
let res = async {
|
||||||
let player_data = rp
|
let player_data = rp
|
||||||
|
.query()
|
||||||
.get_player(video_id.as_str(), ClientType::TvHtml5Embed)
|
.get_player(video_id.as_str(), ClientType::TvHtml5Embed)
|
||||||
.await
|
.await
|
||||||
.context(format!(
|
.context(format!(
|
||||||
|
|
@ -148,7 +149,7 @@ async fn download_playlist(
|
||||||
.expect("unable to build the HTTP client");
|
.expect("unable to build the HTTP client");
|
||||||
|
|
||||||
let rp = RustyPipe::default();
|
let rp = RustyPipe::default();
|
||||||
let playlist = rp.get_playlist(id).await.unwrap();
|
let playlist = rp.query().get_playlist(id).await.unwrap();
|
||||||
|
|
||||||
// Indicatif setup
|
// Indicatif setup
|
||||||
let multi = MultiProgress::new();
|
let multi = MultiProgress::new();
|
||||||
|
|
|
||||||
|
|
@ -59,15 +59,10 @@ struct QContentPlaybackContext {
|
||||||
|
|
||||||
impl RustyPipeQuery {
|
impl RustyPipeQuery {
|
||||||
pub async fn get_player(self, video_id: &str, client_type: ClientType) -> Result<VideoPlayer> {
|
pub async fn get_player(self, video_id: &str, client_type: ClientType) -> Result<VideoPlayer> {
|
||||||
// let (context, deobf) = tokio::join!(self.get_context(client_type, false), self.get_deobf());
|
|
||||||
// let deobf = deobf?;
|
|
||||||
|
|
||||||
let q1 = self.clone();
|
let q1 = self.clone();
|
||||||
let t_context = tokio::spawn(async move { q1.get_context(client_type, false).await });
|
let t_context = tokio::spawn(async move { q1.get_context(client_type, false).await });
|
||||||
let q2 = self.clone();
|
let q2 = self.clone();
|
||||||
let t_deobf = tokio::spawn(async move { q2.get_deobf().await });
|
let t_deobf = tokio::spawn(async move { q2.get_deobf().await });
|
||||||
// let context = t_context.await.unwrap();
|
|
||||||
// let deobf = t_deobf.await.unwrap()?;
|
|
||||||
|
|
||||||
let (context, deobf) = tokio::join!(t_context, t_deobf);
|
let (context, deobf) = tokio::join!(t_context, t_deobf);
|
||||||
let context = context.unwrap();
|
let context = context.unwrap();
|
||||||
|
|
@ -234,7 +229,7 @@ impl MapResponse<VideoPlayer> for response::Player {
|
||||||
audio_streams.push(c);
|
audio_streams.push(c);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(false, false) => warnings.push(format!("invalid format: {}", f.itag)),
|
(false, false) => warnings.push(format!("invalid stream: itag {}", f.itag)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,38 +401,16 @@ fn map_video_stream(
|
||||||
url,
|
url,
|
||||||
itag: f.itag,
|
itag: f.itag,
|
||||||
bitrate: f.bitrate,
|
bitrate: f.bitrate,
|
||||||
average_bitrate: f.average_bitrate,
|
average_bitrate: f.average_bitrate.unwrap_or(f.bitrate),
|
||||||
size: f.content_length,
|
size: f.content_length,
|
||||||
index_range: f.index_range,
|
index_range: f.index_range,
|
||||||
init_range: f.init_range,
|
init_range: f.init_range,
|
||||||
width: some_or_bail!(
|
// Note that the format has already been verified using
|
||||||
f.width,
|
// is_video(), so these unwraps are safe
|
||||||
MapResult {
|
width: f.width.unwrap(),
|
||||||
c: None,
|
height: f.height.unwrap(),
|
||||||
warnings: map_res.warnings
|
fps: f.fps.unwrap(),
|
||||||
}
|
quality: f.quality_label.unwrap(),
|
||||||
),
|
|
||||||
height: some_or_bail!(
|
|
||||||
f.height,
|
|
||||||
MapResult {
|
|
||||||
c: None,
|
|
||||||
warnings: map_res.warnings
|
|
||||||
}
|
|
||||||
),
|
|
||||||
fps: some_or_bail!(
|
|
||||||
f.fps,
|
|
||||||
MapResult {
|
|
||||||
c: None,
|
|
||||||
warnings: map_res.warnings
|
|
||||||
}
|
|
||||||
),
|
|
||||||
quality: some_or_bail!(
|
|
||||||
f.quality_label,
|
|
||||||
MapResult {
|
|
||||||
c: None,
|
|
||||||
warnings: map_res.warnings
|
|
||||||
}
|
|
||||||
),
|
|
||||||
hdr: f.color_info.unwrap_or_default().primaries
|
hdr: f.color_info.unwrap_or_default().primaries
|
||||||
== player::Primaries::ColorPrimariesBt2020,
|
== player::Primaries::ColorPrimariesBt2020,
|
||||||
mime: f.mime_type.to_owned(),
|
mime: f.mime_type.to_owned(),
|
||||||
|
|
@ -445,7 +418,7 @@ fn map_video_stream(
|
||||||
get_video_format(mtype),
|
get_video_format(mtype),
|
||||||
MapResult {
|
MapResult {
|
||||||
c: None,
|
c: None,
|
||||||
warnings: vec![format!("no valid format in video format")]
|
warnings: vec![format!("invalid video format. itag: {}", f.itag)]
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
codec: get_video_codec(codecs),
|
codec: get_video_codec(codecs),
|
||||||
|
|
@ -485,8 +458,8 @@ fn map_audio_stream(
|
||||||
url,
|
url,
|
||||||
itag: f.itag,
|
itag: f.itag,
|
||||||
bitrate: f.bitrate,
|
bitrate: f.bitrate,
|
||||||
average_bitrate: f.average_bitrate,
|
average_bitrate: f.average_bitrate.unwrap_or(f.bitrate),
|
||||||
size: f.content_length,
|
size: f.content_length.unwrap(),
|
||||||
index_range: f.index_range,
|
index_range: f.index_range,
|
||||||
init_range: f.init_range,
|
init_range: f.init_range,
|
||||||
mime: f.mime_type.to_owned(),
|
mime: f.mime_type.to_owned(),
|
||||||
|
|
@ -494,7 +467,7 @@ fn map_audio_stream(
|
||||||
get_audio_format(mtype),
|
get_audio_format(mtype),
|
||||||
MapResult {
|
MapResult {
|
||||||
c: None,
|
c: None,
|
||||||
warnings: vec![format!("invalid format in audio format {}", f.itag)]
|
warnings: vec![format!("invalid audio format. itag: {}", f.itag)]
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
codec: get_audio_codec(codecs),
|
codec: get_audio_codec(codecs),
|
||||||
|
|
@ -759,7 +732,7 @@ mod tests {
|
||||||
// Bitrates may change between requests
|
// Bitrates may change between requests
|
||||||
assert_approx(video.bitrate as f64, 1507068.0);
|
assert_approx(video.bitrate as f64, 1507068.0);
|
||||||
assert_eq!(video.average_bitrate, 1345149);
|
assert_eq!(video.average_bitrate, 1345149);
|
||||||
assert_eq!(video.size, 43553412);
|
assert_eq!(video.size.unwrap(), 43553412);
|
||||||
assert_eq!(video.width, 1280);
|
assert_eq!(video.width, 1280);
|
||||||
assert_eq!(video.height, 720);
|
assert_eq!(video.height, 720);
|
||||||
assert_eq!(video.fps, 30);
|
assert_eq!(video.fps, 30);
|
||||||
|
|
@ -789,7 +762,7 @@ mod tests {
|
||||||
|
|
||||||
assert_approx(video.bitrate as f64, 1340829.0);
|
assert_approx(video.bitrate as f64, 1340829.0);
|
||||||
assert_approx(video.average_bitrate as f64, 1233444.0);
|
assert_approx(video.average_bitrate as f64, 1233444.0);
|
||||||
assert_approx(video.size as f64, 39936630.0);
|
assert_approx(video.size.unwrap() as f64, 39936630.0);
|
||||||
assert_eq!(video.width, 1280);
|
assert_eq!(video.width, 1280);
|
||||||
assert_eq!(video.height, 720);
|
assert_eq!(video.height, 720);
|
||||||
assert_eq!(video.fps, 30);
|
assert_eq!(video.fps, 30);
|
||||||
|
|
|
||||||
|
|
@ -80,15 +80,15 @@ pub struct Format {
|
||||||
#[serde_as(as = "Option<crate::serializer::Range>")]
|
#[serde_as(as = "Option<crate::serializer::Range>")]
|
||||||
pub init_range: Option<Range<u32>>,
|
pub init_range: Option<Range<u32>>,
|
||||||
|
|
||||||
#[serde_as(as = "JsonString")]
|
#[serde_as(as = "Option<JsonString>")]
|
||||||
pub content_length: u64,
|
pub content_length: Option<u64>,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
#[serde_as(deserialize_as = "DefaultOnError")]
|
#[serde_as(deserialize_as = "DefaultOnError")]
|
||||||
pub quality: Option<Quality>,
|
pub quality: Option<Quality>,
|
||||||
pub fps: Option<u8>,
|
pub fps: Option<u8>,
|
||||||
pub quality_label: Option<String>,
|
pub quality_label: Option<String>,
|
||||||
pub average_bitrate: u32,
|
pub average_bitrate: Option<u32>,
|
||||||
pub color_info: Option<ColorInfo>,
|
pub color_info: Option<ColorInfo>,
|
||||||
|
|
||||||
// Audio only
|
// Audio only
|
||||||
|
|
@ -106,7 +106,9 @@ pub struct Format {
|
||||||
|
|
||||||
impl Format {
|
impl Format {
|
||||||
pub fn is_audio(&self) -> bool {
|
pub fn is_audio(&self) -> bool {
|
||||||
self.audio_quality.is_some() && self.audio_sample_rate.is_some()
|
self.content_length.is_some()
|
||||||
|
&& self.audio_quality.is_some()
|
||||||
|
&& self.audio_sample_rate.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_video(&self) -> bool {
|
pub fn is_video(&self) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: src/client/player.rs
|
source: src/client2/player.rs
|
||||||
expression: player_data
|
expression: map_res.c
|
||||||
---
|
---
|
||||||
info:
|
info:
|
||||||
id: pPvd8UxmSbQ
|
id: pPvd8UxmSbQ
|
||||||
|
|
@ -184,6 +184,22 @@ video_only_streams:
|
||||||
format: mp4
|
format: mp4
|
||||||
codec: av01
|
codec: av01
|
||||||
throttled: false
|
throttled: false
|
||||||
|
- url: "https://rr5---sn-h0jeenek.googlevideo.com/videoplayback?c=ANDROID&dur=163.096&ei=q1jpYtOPEYSBgQeHmqbwAQ&expire=1659481355&fexp=24001373%2C24007246&fvip=4&id=o-AEDMTCojVtwpIKOdhBaxEHE5s322qnAJHGqa2r1F46BM&initcwndbps=1527500&ip=2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e&itag=22&lmt=1580005750956837&lsig=AG3C_xAwRgIhAOiL-qJ04sA8FSOkEJfOYl3gFe4SzwYu_rAf3DMLHYigAiEA0Upi1HqqIu7NH_LTDL0jT1R5TTozQypL5FiSP9RoqtU%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&mh=mQ&mime=video%2Fmp4&mm=31%2C29&mn=sn-h0jeenek%2Csn-h0jelnez&ms=au%2Crdu&mt=1659459429&mv=m&mvi=5&pl=37&ratebypass=yes&rbqsm=fr&requiressl=yes&sig=AOq0QJ8wRAIgFlQZgR63Yz9UgY9gVqiyGDVkZmSmACRP3-MmKN7CRzQCIAMHAwZbHmWL1qNH4Nu3A0pXZwErXMVPzMIt-PyxeZqa&source=youtube&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cvprv%2Cmime%2Cratebypass%2Cdur%2Clmt&txp=2211222&vprv=1"
|
||||||
|
itag: 22
|
||||||
|
bitrate: 1574434
|
||||||
|
average_bitrate: 1574434
|
||||||
|
size: ~
|
||||||
|
index_range: ~
|
||||||
|
init_range: ~
|
||||||
|
width: 1280
|
||||||
|
height: 720
|
||||||
|
fps: 30
|
||||||
|
quality: 720p
|
||||||
|
hdr: false
|
||||||
|
mime: "video/mp4; codecs=\"avc1.64001F, mp4a.40.2\""
|
||||||
|
format: mp4
|
||||||
|
codec: avc1
|
||||||
|
throttled: false
|
||||||
- url: "https://rr5---sn-h0jeenek.googlevideo.com/videoplayback?c=ANDROID&clen=22365208&dur=163.046&ei=q1jpYtOPEYSBgQeHmqbwAQ&expire=1659481355&fexp=24001373%2C24007246&fvip=4&gir=yes&id=o-AEDMTCojVtwpIKOdhBaxEHE5s322qnAJHGqa2r1F46BM&initcwndbps=1527500&ip=2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e&itag=398&keepalive=yes&lmt=1608048380553749&lsig=AG3C_xAwRgIhAOiL-qJ04sA8FSOkEJfOYl3gFe4SzwYu_rAf3DMLHYigAiEA0Upi1HqqIu7NH_LTDL0jT1R5TTozQypL5FiSP9RoqtU%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&mh=mQ&mime=video%2Fmp4&mm=31%2C29&mn=sn-h0jeenek%2Csn-h0jelnez&ms=au%2Crdu&mt=1659459429&mv=m&mvi=5&otfp=1&pl=37&rbqsm=fr&requiressl=yes&sig=AOq0QJ8wRAIgR6KqCOoig_FMl2tWKa7qHSmCjIZa9S7ABzEI16qdO2sCIFXccwql4bqV9CHlqXY4tgxyMFUsp7vW4XUjxs3AyG6H&source=youtube&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cvprv%2Cmime%2Cgir%2Cclen%2Cotfp%2Cdur%2Clmt&txp=1311222&vprv=1"
|
- url: "https://rr5---sn-h0jeenek.googlevideo.com/videoplayback?c=ANDROID&clen=22365208&dur=163.046&ei=q1jpYtOPEYSBgQeHmqbwAQ&expire=1659481355&fexp=24001373%2C24007246&fvip=4&gir=yes&id=o-AEDMTCojVtwpIKOdhBaxEHE5s322qnAJHGqa2r1F46BM&initcwndbps=1527500&ip=2003%3Ade%3Aaf0e%3A2f00%3Ade47%3A297%3Aa6db%3A774e&itag=398&keepalive=yes&lmt=1608048380553749&lsig=AG3C_xAwRgIhAOiL-qJ04sA8FSOkEJfOYl3gFe4SzwYu_rAf3DMLHYigAiEA0Upi1HqqIu7NH_LTDL0jT1R5TTozQypL5FiSP9RoqtU%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&mh=mQ&mime=video%2Fmp4&mm=31%2C29&mn=sn-h0jeenek%2Csn-h0jelnez&ms=au%2Crdu&mt=1659459429&mv=m&mvi=5&otfp=1&pl=37&rbqsm=fr&requiressl=yes&sig=AOq0QJ8wRAIgR6KqCOoig_FMl2tWKa7qHSmCjIZa9S7ABzEI16qdO2sCIFXccwql4bqV9CHlqXY4tgxyMFUsp7vW4XUjxs3AyG6H&source=youtube&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cvprv%2Cmime%2Cgir%2Cclen%2Cotfp%2Cdur%2Clmt&txp=1311222&vprv=1"
|
||||||
itag: 398
|
itag: 398
|
||||||
bitrate: 1348419
|
bitrate: 1348419
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ pub struct VideoStream {
|
||||||
pub itag: u32,
|
pub itag: u32,
|
||||||
pub bitrate: u32,
|
pub bitrate: u32,
|
||||||
pub average_bitrate: u32,
|
pub average_bitrate: u32,
|
||||||
pub size: u64,
|
pub size: Option<u64>,
|
||||||
pub index_range: Option<Range<u32>>,
|
pub index_range: Option<Range<u32>>,
|
||||||
pub init_range: Option<Range<u32>>,
|
pub init_range: Option<Range<u32>>,
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ impl YamlFileReporter {
|
||||||
impl Default for YamlFileReporter {
|
impl Default for YamlFileReporter {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
path: Path::new("RustyPipeReports").to_path_buf(),
|
path: Path::new("rustypipe_reports").to_path_buf(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue