Compare commits
No commits in common. "f748b98ccc9e48f49bd7732552071f0db3bdee0a" and "6e2ba71f33a828d3dc6c66a0a942b329ecfef857" have entirely different histories.
f748b98ccc
...
6e2ba71f33
6 changed files with 47 additions and 45 deletions
|
@ -49,7 +49,8 @@ async fn download_single_video(
|
||||||
main: Option<ProgressBar>,
|
main: Option<ProgressBar>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let pb = multi.add(ProgressBar::new(1));
|
let pb = multi.add(ProgressBar::new(1));
|
||||||
pb.set_style(ProgressStyle::with_template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})").unwrap()
|
pb.set_style(ProgressStyle::default_bar()
|
||||||
|
.template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})").unwrap()
|
||||||
.progress_chars("#>-"));
|
.progress_chars("#>-"));
|
||||||
pb.set_message(format!("Fetching player data for {}", video_title));
|
pb.set_message(format!("Fetching player data for {}", video_title));
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@ use crate::{
|
||||||
deobfuscate::Deobfuscator,
|
deobfuscate::Deobfuscator,
|
||||||
error::{DeobfError, Error, ExtractionError},
|
error::{DeobfError, Error, ExtractionError},
|
||||||
model::{
|
model::{
|
||||||
AudioCodec, AudioFormat, AudioStream, AudioTrack, ChannelId, QualityOrd, Subtitle,
|
AudioCodec, AudioFormat, AudioStream, AudioTrack, ChannelId, Subtitle, VideoCodec,
|
||||||
VideoCodec, VideoFormat, VideoPlayer, VideoPlayerDetails, VideoStream,
|
VideoFormat, VideoPlayer, VideoPlayerDetails, VideoStream,
|
||||||
},
|
},
|
||||||
param::Language,
|
param::Language,
|
||||||
util,
|
util,
|
||||||
|
@ -244,9 +244,9 @@ impl MapResponse<VideoPlayer> for response::Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
video_streams.sort_by(QualityOrd::quality_cmp);
|
video_streams.sort();
|
||||||
video_only_streams.sort_by(QualityOrd::quality_cmp);
|
video_only_streams.sort();
|
||||||
audio_streams.sort_by(QualityOrd::quality_cmp);
|
audio_streams.sort();
|
||||||
|
|
||||||
let subtitles = self.captions.map_or(Vec::new(), |captions| {
|
let subtitles = self.captions.map_or(Vec::new(), |captions| {
|
||||||
captions
|
captions
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
//! YouTube audio/video downloader
|
//! YouTube audio/video downloader
|
||||||
|
|
||||||
use std::{borrow::Cow, cmp::Ordering, ffi::OsString, ops::Range, path::PathBuf, time::Duration};
|
use std::{borrow::Cow, cmp::Ordering, ffi::OsString, ops::Range, path::PathBuf};
|
||||||
|
|
||||||
use fancy_regex::Regex;
|
use fancy_regex::Regex;
|
||||||
use futures::stream::{self, StreamExt};
|
use futures::stream::{self, StreamExt};
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::ProgressBar;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
@ -150,7 +150,7 @@ async fn download_single_file<P: Into<PathBuf>>(
|
||||||
let mut file = fs::OpenOptions::new()
|
let mut file = fs::OpenOptions::new()
|
||||||
.append(true)
|
.append(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.open(&output_path_tmp)
|
.open(output_path_tmp.to_owned())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if is_gvideo && size.is_some() {
|
if is_gvideo && size.is_some() {
|
||||||
|
@ -159,7 +159,7 @@ async fn download_single_file<P: Into<PathBuf>>(
|
||||||
download_chunks_by_header(http, &mut file, url, size, offset, pb).await?;
|
download_chunks_by_header(http, &mut file, url, size, offset, pb).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::rename(&output_path_tmp, &output_path).await?;
|
fs::rename(output_path_tmp, output_path).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,13 +391,7 @@ pub async fn download_video(
|
||||||
download_streams(&downloads, http, pb.clone()).await?;
|
download_streams(&downloads, http, pb.clone()).await?;
|
||||||
|
|
||||||
pb.set_message(format!("Converting {}", title));
|
pb.set_message(format!("Converting {}", title));
|
||||||
pb.set_style(
|
|
||||||
ProgressStyle::with_template("{msg}\n{spinner:.green} [{elapsed_precise}]")
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
pb.enable_steady_tick(Duration::from_millis(100));
|
|
||||||
convert_streams(&downloads, output_path, ffmpeg).await?;
|
convert_streams(&downloads, output_path, ffmpeg).await?;
|
||||||
pb.disable_steady_tick();
|
|
||||||
|
|
||||||
// Delete original files
|
// Delete original files
|
||||||
stream::iter(&downloads)
|
stream::iter(&downloads)
|
||||||
|
|
|
@ -6,7 +6,6 @@ mod paginator;
|
||||||
pub mod richtext;
|
pub mod richtext;
|
||||||
|
|
||||||
pub use convert::FromYtItem;
|
pub use convert::FromYtItem;
|
||||||
pub use ordering::QualityOrd;
|
|
||||||
pub use paginator::Paginator;
|
pub use paginator::Paginator;
|
||||||
use serde_with::serde_as;
|
use serde_with::serde_as;
|
||||||
|
|
||||||
|
@ -192,7 +191,7 @@ pub struct VideoStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Audio stream
|
/// Audio stream
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct AudioStream {
|
pub struct AudioStream {
|
||||||
/// Audio stream URL
|
/// Audio stream URL
|
||||||
|
|
|
@ -4,26 +4,30 @@ use crate::model::AudioCodec;
|
||||||
|
|
||||||
use super::{AudioStream, VideoStream};
|
use super::{AudioStream, VideoStream};
|
||||||
|
|
||||||
pub trait QualityOrd {
|
impl PartialOrd for VideoStream {
|
||||||
fn quality_cmp(&self, other: &Self) -> Ordering;
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
}
|
Some(
|
||||||
|
match (self.width * self.height).cmp(&(other.width * other.height)) {
|
||||||
impl QualityOrd for VideoStream {
|
|
||||||
fn quality_cmp(&self, other: &Self) -> Ordering {
|
|
||||||
match (self.width * self.height).cmp(&(other.width * other.height)) {
|
|
||||||
Ordering::Less => Ordering::Less,
|
|
||||||
Ordering::Greater => Ordering::Greater,
|
|
||||||
Ordering::Equal => match self.codec.cmp(&other.codec) {
|
|
||||||
Ordering::Less => Ordering::Less,
|
Ordering::Less => Ordering::Less,
|
||||||
Ordering::Greater => Ordering::Greater,
|
Ordering::Greater => Ordering::Greater,
|
||||||
Ordering::Equal => self.average_bitrate.cmp(&other.average_bitrate),
|
Ordering::Equal => match self.codec.cmp(&other.codec) {
|
||||||
|
Ordering::Less => Ordering::Less,
|
||||||
|
Ordering::Greater => Ordering::Greater,
|
||||||
|
Ordering::Equal => self.average_bitrate.cmp(&other.average_bitrate),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QualityOrd for AudioStream {
|
impl Ord for VideoStream {
|
||||||
fn quality_cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.partial_cmp(other).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for AudioStream {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
fn cmp_bitrate(s: &AudioStream) -> u32 {
|
fn cmp_bitrate(s: &AudioStream) -> u32 {
|
||||||
match s.codec {
|
match s.codec {
|
||||||
// Opus is more efficient
|
// Opus is more efficient
|
||||||
|
@ -32,6 +36,12 @@ impl QualityOrd for AudioStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmp_bitrate(self).cmp(&cmp_bitrate(other))
|
Some(cmp_bitrate(self).cmp(&cmp_bitrate(other)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for AudioStream {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.partial_cmp(other).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
//! Filters for selecting audio/video streams
|
//! Filters for selecting audio/video streams
|
||||||
|
|
||||||
use std::{cmp::Ordering, collections::HashSet};
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::model::{
|
use crate::model::{
|
||||||
AudioCodec, AudioFormat, AudioStream, QualityOrd, VideoCodec, VideoFormat, VideoPlayer,
|
AudioCodec, AudioFormat, AudioStream, VideoCodec, VideoFormat, VideoPlayer, VideoStream,
|
||||||
VideoStream,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
|
@ -303,15 +302,14 @@ impl VideoPlayer {
|
||||||
(Some(video_only_stream), self.select_audio_stream(filter))
|
(Some(video_only_stream), self.select_audio_stream(filter))
|
||||||
}
|
}
|
||||||
(Some(video_stream), None) => (Some(video_stream), None),
|
(Some(video_stream), None) => (Some(video_stream), None),
|
||||||
(Some(video_stream), Some(video_only_stream)) => {
|
(Some(video_stream), Some(video_only_stream)) => match video_only_stream > video_stream
|
||||||
match video_only_stream.quality_cmp(video_stream) {
|
{
|
||||||
Ordering::Greater => match self.select_audio_stream(filter) {
|
true => match self.select_audio_stream(filter) {
|
||||||
Some(audio_stream) => (Some(video_only_stream), Some(audio_stream)),
|
Some(audio_stream) => (Some(video_only_stream), Some(audio_stream)),
|
||||||
None => (Some(video_stream), None),
|
None => (Some(video_stream), None),
|
||||||
},
|
},
|
||||||
_ => (Some(video_stream), None),
|
false => (Some(video_stream), None),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue