diff --git a/cli/src/main.rs b/cli/src/main.rs index 6ab09a9..6c21cde 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -49,8 +49,7 @@ async fn download_single_video( main: Option, ) -> Result<()> { let pb = multi.add(ProgressBar::new(1)); - 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() + pb.set_style(ProgressStyle::with_template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})").unwrap() .progress_chars("#>-")); pb.set_message(format!("Fetching player data for {}", video_title)); diff --git a/src/client/player.rs b/src/client/player.rs index 88f3d90..129a9fb 100644 --- a/src/client/player.rs +++ b/src/client/player.rs @@ -12,8 +12,8 @@ use crate::{ deobfuscate::Deobfuscator, error::{DeobfError, Error, ExtractionError}, model::{ - AudioCodec, AudioFormat, AudioStream, AudioTrack, ChannelId, Subtitle, VideoCodec, - VideoFormat, VideoPlayer, VideoPlayerDetails, VideoStream, + AudioCodec, AudioFormat, AudioStream, AudioTrack, ChannelId, QualityOrd, Subtitle, + VideoCodec, VideoFormat, VideoPlayer, VideoPlayerDetails, VideoStream, }, param::Language, util, @@ -244,9 +244,9 @@ impl MapResponse for response::Player { } } - video_streams.sort(); - video_only_streams.sort(); - audio_streams.sort(); + video_streams.sort_by(QualityOrd::quality_cmp); + video_only_streams.sort_by(QualityOrd::quality_cmp); + audio_streams.sort_by(QualityOrd::quality_cmp); let subtitles = self.captions.map_or(Vec::new(), |captions| { captions diff --git a/src/download.rs b/src/download.rs index 4dc144e..00738c9 100644 --- a/src/download.rs +++ b/src/download.rs @@ -1,10 +1,10 @@ //! YouTube audio/video downloader -use std::{borrow::Cow, cmp::Ordering, ffi::OsString, ops::Range, path::PathBuf}; +use std::{borrow::Cow, cmp::Ordering, ffi::OsString, ops::Range, path::PathBuf, time::Duration}; use fancy_regex::Regex; use futures::stream::{self, StreamExt}; -use indicatif::ProgressBar; +use indicatif::{ProgressBar, ProgressStyle}; use log::{debug, info}; use once_cell::sync::Lazy; use rand::Rng; @@ -150,7 +150,7 @@ async fn download_single_file>( let mut file = fs::OpenOptions::new() .append(true) .create(true) - .open(output_path_tmp.to_owned()) + .open(&output_path_tmp) .await?; if is_gvideo && size.is_some() { @@ -159,7 +159,7 @@ async fn download_single_file>( 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(()) } @@ -391,7 +391,13 @@ pub async fn download_video( download_streams(&downloads, http, pb.clone()).await?; 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?; + pb.disable_steady_tick(); // Delete original files stream::iter(&downloads) diff --git a/src/model/mod.rs b/src/model/mod.rs index 31d2291..db0a4b0 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -6,6 +6,7 @@ mod paginator; pub mod richtext; pub use convert::FromYtItem; +pub use ordering::QualityOrd; pub use paginator::Paginator; use serde_with::serde_as; @@ -191,7 +192,7 @@ pub struct VideoStream { } /// Audio stream -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[non_exhaustive] pub struct AudioStream { /// Audio stream URL diff --git a/src/model/ordering.rs b/src/model/ordering.rs index e7df9af..012f35b 100644 --- a/src/model/ordering.rs +++ b/src/model/ordering.rs @@ -4,30 +4,26 @@ use crate::model::AudioCodec; use super::{AudioStream, VideoStream}; -impl PartialOrd for VideoStream { - fn partial_cmp(&self, other: &Self) -> Option { - Some( - match (self.width * self.height).cmp(&(other.width * other.height)) { +pub trait QualityOrd { + fn quality_cmp(&self, other: &Self) -> Ordering; +} + +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::Greater => Ordering::Greater, - 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), - }, + Ordering::Equal => self.average_bitrate.cmp(&other.average_bitrate), }, - ) + } } } -impl Ord for VideoStream { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap() - } -} - -impl PartialOrd for AudioStream { - fn partial_cmp(&self, other: &Self) -> Option { +impl QualityOrd for AudioStream { + fn quality_cmp(&self, other: &Self) -> Ordering { fn cmp_bitrate(s: &AudioStream) -> u32 { match s.codec { // Opus is more efficient @@ -36,12 +32,6 @@ impl PartialOrd for AudioStream { } } - Some(cmp_bitrate(self).cmp(&cmp_bitrate(other))) - } -} - -impl Ord for AudioStream { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap() + cmp_bitrate(self).cmp(&cmp_bitrate(other)) } } diff --git a/src/param/stream_filter.rs b/src/param/stream_filter.rs index ce14c3e..64d32c5 100644 --- a/src/param/stream_filter.rs +++ b/src/param/stream_filter.rs @@ -1,9 +1,10 @@ //! Filters for selecting audio/video streams -use std::collections::HashSet; +use std::{cmp::Ordering, collections::HashSet}; use crate::model::{ - AudioCodec, AudioFormat, AudioStream, VideoCodec, VideoFormat, VideoPlayer, VideoStream, + AudioCodec, AudioFormat, AudioStream, QualityOrd, VideoCodec, VideoFormat, VideoPlayer, + VideoStream, }; #[derive(Debug, Default, Clone)] @@ -302,14 +303,15 @@ impl VideoPlayer { (Some(video_only_stream), self.select_audio_stream(filter)) } (Some(video_stream), None) => (Some(video_stream), None), - (Some(video_stream), Some(video_only_stream)) => match video_only_stream > video_stream - { - true => match self.select_audio_stream(filter) { - Some(audio_stream) => (Some(video_only_stream), Some(audio_stream)), - None => (Some(video_stream), None), - }, - false => (Some(video_stream), None), - }, + (Some(video_stream), Some(video_only_stream)) => { + match video_only_stream.quality_cmp(video_stream) { + Ordering::Greater => match self.select_audio_stream(filter) { + Some(audio_stream) => (Some(video_only_stream), Some(audio_stream)), + None => (Some(video_stream), None), + }, + _ => (Some(video_stream), None), + } + } } } }