use std::{path::Path, process::Command};
use crate::{
config::common::common_config, ffmpeg::loudnorm::LoudnormAnalysis,
library::metadata::canonicalize_metadata_key,
};
pub trait FfmpegPresets {
fn input_file(&mut self, input: impl AsRef<Path>);
fn output_file(&mut self, output: &Path);
fn cover_art_from(&mut self, input_index: usize);
fn drop_metadata(&mut self);
fn copy_all(&mut self);
fn add_metadata<K, V>(&mut self, key: K, value: V)
where
K: AsRef<str>,
V: AsRef<str>;
fn add_metadata_group<'a, I, K, V>(&mut self, metadata: I)
where
I: IntoIterator<Item = (&'a K, &'a V)>,
K: AsRef<str> + 'a,
V: AsRef<str> + 'a;
fn apply_loudnorm_filter(&mut self, measured: LoudnormAnalysis);
fn set_codec(&mut self, codec: impl AsRef<str>);
fn set_container(&mut self, container: impl AsRef<str>);
fn map_audio_from(&mut self, input_index: usize);
fn drop_subtitles(&mut self);
}
impl FfmpegPresets for Command {
fn input_file(&mut self, file: impl AsRef<Path>) {
self.arg("-i").arg(file.as_ref());
}
fn output_file(&mut self, output: &Path) {
self.arg("-y").arg(output);
}
fn cover_art_from(&mut self, input_index: usize) {
self.args([
"-map",
&format!("{input_index}:v:0"),
"-disposition:v",
"attached_pic",
"-metadata:s:v",
"title=cover",
"-metadata:s:v",
"comment=Cover (front)",
]);
}
fn drop_metadata(&mut self) {
self.args(["-map_metadata", "-1"]);
}
fn add_metadata<K, V>(&mut self, key: K, value: V)
where
K: AsRef<str>,
V: AsRef<str>,
{
let key = canonicalize_metadata_key(key);
let value = value.as_ref();
self.args(["-metadata", format!("{key}={value}").as_str()]);
}
fn add_metadata_group<'a, I, K, V>(&mut self, metadata: I)
where
I: IntoIterator<Item = (&'a K, &'a V)>,
K: AsRef<str> + 'a,
V: AsRef<str> + 'a,
{
for (key, value) in metadata {
self.add_metadata(key.as_ref(), value.as_ref());
}
}
fn apply_loudnorm_filter(&mut self, measured: LoudnormAnalysis) {
let loudnorm_config = &common_config().loudnorm_config;
let loudnorm_filter = format!(
"loudnorm=linear={linear}:measured_i={measured_i}:measured_tp={measured_tp}:measured_lra={measured_lra}:measured_thresh={measured_thresh}:i={target_i}:tp={target_tp}:lra={target_lra}:offset={target_offset}",
linear = loudnorm_config.linear,
measured_i = measured.input_i,
measured_tp = measured.input_tp,
measured_lra = measured.input_lra,
measured_thresh = measured.input_thresh,
target_i = loudnorm_config.target_i,
target_tp = loudnorm_config.target_tp,
target_lra = loudnorm_config.target_lra,
target_offset = loudnorm_config.target_offset,
);
self.args(["-filter:a".to_string(), loudnorm_filter]);
}
fn set_codec(&mut self, codec: impl AsRef<str>) {
self.args(["-c:a", codec.as_ref()]);
}
fn set_container(&mut self, container: impl AsRef<str>) {
self.args(["-f", container.as_ref()]);
}
fn map_audio_from(&mut self, input_index: usize) {
self.args(["-map", &format!("{input_index}:a:0")]);
}
fn drop_subtitles(&mut self) {
self.arg("-sn");
}
fn copy_all(&mut self) {
self.args(["-c", "copy"]);
}
}