From 8624dd7a2f717a74aec482f486860e4e8ea174b3 Mon Sep 17 00:00:00 2001 From: chaos Date: Sun, 12 Nov 2023 14:25:37 +0000 Subject: [PATCH] improve progress_monitor using out_time_us instead of out_time; use ffprobe crate for duration analysis --- modules/ffprobe/src/ffprobe_output.rs | 1 + modules/ffprobe/src/lib.rs | 4 ++ modules/ffprobe/src/meta.rs | 0 modules/ffprobe/src/types.rs | 2 + src/commands/copy.rs | 8 +-- src/utils/transcoder/progress_monitor.rs | 71 +++++------------------- 6 files changed, 24 insertions(+), 62 deletions(-) delete mode 100644 modules/ffprobe/src/meta.rs diff --git a/modules/ffprobe/src/ffprobe_output.rs b/modules/ffprobe/src/ffprobe_output.rs index ef2ef60..a734d55 100644 --- a/modules/ffprobe/src/ffprobe_output.rs +++ b/modules/ffprobe/src/ffprobe_output.rs @@ -20,6 +20,7 @@ pub struct FFProbeOutputStream { #[derive(Debug, Clone, Deserialize)] pub struct FFProbeOutputFormat { pub tags: FFProbeOutputTags, + pub duration: String, } #[derive(Default, Debug, Clone, Deserialize)] diff --git a/modules/ffprobe/src/lib.rs b/modules/ffprobe/src/lib.rs index b1824e4..eea4cf6 100644 --- a/modules/ffprobe/src/lib.rs +++ b/modules/ffprobe/src/lib.rs @@ -50,6 +50,10 @@ pub fn analyze( let mut data = types::FFProbeData { tags: raw_data.format.tags.into(), + duration: match raw_data.format.duration.parse::() { + Ok(ts) => ts, + Err(_) => 0.0, + }, album_art: None, }; diff --git a/modules/ffprobe/src/meta.rs b/modules/ffprobe/src/meta.rs deleted file mode 100644 index e69de29..0000000 diff --git a/modules/ffprobe/src/types.rs b/modules/ffprobe/src/types.rs index 01f8fa6..fb4aad1 100644 --- a/modules/ffprobe/src/types.rs +++ b/modules/ffprobe/src/types.rs @@ -48,6 +48,8 @@ pub struct FFProbeAlbumArt { #[derive(Debug, Clone, Serialize)] pub struct FFProbeData { + // in seconds + pub duration: f64, pub tags: FFProbeTags, pub album_art: Option, } diff --git a/src/commands/copy.rs b/src/commands/copy.rs index dba7a02..b07eded 100644 --- a/src/commands/copy.rs +++ b/src/commands/copy.rs @@ -183,11 +183,9 @@ fn transcode_file( } }; - if copy_args.skip_same_extension { - if config.file_extension.as_ref().unwrap() == &file.extension().unwrap() { - return copy_file(file.as_relative_file(), copy_args); - } - } + if copy_args.skip_same_extension && config.file_extension.as_ref().unwrap() == &file.extension().unwrap() { + return copy_file(file.as_relative_file(), copy_args); + } let to_path_dest = PathBuf::from_str(copy_args.dest.as_str()).expect("invalid destination"); let to_path = match copy_args.single_directory { diff --git a/src/utils/transcoder/progress_monitor.rs b/src/utils/transcoder/progress_monitor.rs index b7e2405..920c0cd 100644 --- a/src/utils/transcoder/progress_monitor.rs +++ b/src/utils/transcoder/progress_monitor.rs @@ -2,67 +2,18 @@ use std::{ fs, io::{BufRead, BufReader, Seek, SeekFrom}, path::PathBuf, - process::Command, sync::mpsc::{self, Sender}, thread::{self, JoinHandle}, time::Duration, }; use notify::{EventKind, RecommendedWatcher, RecursiveMode, Watcher}; -use serde::Deserialize; -use string_error::static_err; -#[derive(Debug, Clone, Deserialize)] -struct FFProbeOutput { - pub format: FFProbeFormat, -} - -#[derive(Debug, Clone, Deserialize)] -struct FFProbeFormat { - pub duration: String, -} - -fn get_file_length_milliseconds( - source_filepath: PathBuf, -) -> Result> { - let output = Command::new(crate::meta::FFPROBE) - .args([ - "-v", - "quiet", - "-print_format", - "json", - "-show_format", - &source_filepath.to_string_lossy(), - ]) - .output()?; - - if !output.status.success() { - print!("{:?}", String::from_utf8(output.stderr).unwrap()); - return Err(static_err("FFprobe Crashed")); +fn get_file_length_milliseconds(path: PathBuf) -> Result> { + match ffprobe::analyze(&path, Some(crate::meta::FFPROBE)) { + Ok(data) => Ok((data.duration * 1000.0).round() as u64), + Err(e) => Err(Box::from(e)), } - - let output_str = String::from_utf8(output.stdout).unwrap(); - let ffprobe_out: FFProbeOutput = serde_json::from_str(output_str.as_str())?; - - let duration_seconds = ffprobe_out.format.duration.parse::()?; - - Ok((duration_seconds * 1000.0).round() as u64) -} - -fn ffprobe_duration_to_ms(duration: String) -> Result> { - let fields: Vec<&str> = duration.split(':').collect(); - let mut duration = Duration::from_nanos(0); - - let hours = fields[0].parse::()?; - duration += Duration::from_secs(hours * 60 * 60); - - let minutes = fields[1].parse::()?; - duration += Duration::from_secs(minutes * 60); - - let seconds = fields[1].parse::()?; - duration += Duration::from_millis((seconds * 1000.0) as u64); - - Ok(duration.as_millis() as u64) } pub fn progress_monitor( @@ -121,13 +72,19 @@ pub fn progress_monitor( break 'outer; } - if ln.starts_with("out_time=") { - let out_time = ln.strip_prefix("out_time=").unwrap().to_string(); - let out_time_ms = ffprobe_duration_to_ms(out_time).unwrap(); + // there is a out_time_ms however it seems to be the same value as out_time_us + // https://trac.ffmpeg.org/ticket/7345 + // it has not yet been actually fixed + if ln.starts_with("out_time_us=") { + let out_time = ln.strip_prefix("out_time_us=").unwrap().to_string(); + let out_time_ms = match out_time.parse::() { + Ok(ts) => ((ts as f64) / 1000.0).round(), + Err(_) => 0.0, + }; if sender .send(format!( "{:.2}%", - ((out_time_ms as f64 / total_length_millis as f64) * 100.0) + ((out_time_ms / total_length_millis as f64) * 100.0) )) .is_err() {