From a4abb14ae357657132cf8e4e1d0edb7e92d5379b Mon Sep 17 00:00:00 2001 From: kralverde <80051564+kralverde@users.noreply.github.com> Date: Mon, 29 Jan 2024 02:18:42 -0500 Subject: [PATCH] use a 'close enough' method to audio auto merge (#286) (#320) * use a 'close enough' method to audio merge * change default, rename flag, and use more gooder words --- crunchy-cli-core/src/archive/command.rs | 62 ++++++++++++++++++------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/crunchy-cli-core/src/archive/command.rs b/crunchy-cli-core/src/archive/command.rs index 065b3da..b045cce 100644 --- a/crunchy-cli-core/src/archive/command.rs +++ b/crunchy-cli-core/src/archive/command.rs @@ -16,7 +16,7 @@ use chrono::Duration; use crunchyroll_rs::media::{Resolution, Subtitle}; use crunchyroll_rs::Locale; use log::{debug, warn}; -use std::collections::HashMap; +use std::ops::Sub; use std::path::PathBuf; #[derive(Clone, Debug, clap::Parser)] @@ -86,6 +86,12 @@ pub struct Archive { #[arg(value_parser = MergeBehavior::parse)] pub(crate) merge: MergeBehavior, + #[arg( + help = "If the merge behavior is 'auto', only download multiple video tracks if their length difference is higher than the given milliseconds" + )] + #[arg(long, default_value_t = 200)] + pub(crate) merge_auto_tolerance: u32, + #[arg(help = format!("Presets for converting the video to a specific coding format. \ Available presets: \n {}", FFmpegPreset::available_matches_human_readable().join("\n ")))] #[arg(long_help = format!("Presets for converting the video to a specific coding format. \ @@ -356,26 +362,46 @@ async fn get_format( .collect(), }), MergeBehavior::Auto => { - let mut d_formats: HashMap = HashMap::new(); - + let mut d_formats: Vec<(Duration, DownloadFormat)> = vec![]; + for (single_format, video, audio, subtitles) in format_pairs { - if let Some(d_format) = d_formats.get_mut(&single_format.duration) { - d_format.audios.push((audio, single_format.audio.clone())); - d_format.subtitles.extend(subtitles) - } else { - d_formats.insert( - single_format.duration, - DownloadFormat { - video: (video, single_format.audio.clone()), - audios: vec![(audio, single_format.audio.clone())], - subtitles, - }, - ); - } + let closest_format = d_formats.iter_mut().min_by(|(x, _), (y, _)| { + x.sub(single_format.duration) + .abs() + .cmp(&y.sub(single_format.duration).abs()) + }); + + match closest_format { + Some(closest_format) + if closest_format + .0 + .sub(single_format.duration) + .abs() + .num_milliseconds() + < archive.merge_auto_tolerance.into() => + { + // If less than `audio_error` apart, use same audio. + closest_format + .1 + .audios + .push((audio, single_format.audio.clone())); + closest_format.1.subtitles.extend(subtitles); + } + _ => { + d_formats.push(( + single_format.duration, + DownloadFormat { + video: (video, single_format.audio.clone()), + audios: vec![(audio, single_format.audio.clone())], + subtitles, + }, + )); + } + }; } - for d_format in d_formats.into_values() { - download_formats.push(d_format) + for (_, d_format) in d_formats.into_iter() { + download_formats.push(d_format); } } }