feat: argparse and dry-run.
This commit is contained in:
+148
@@ -0,0 +1,148 @@
|
||||
use crate::dry_run::ShellScript;
|
||||
use std::io::Result;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::io;
|
||||
|
||||
pub struct FFmpegCommand {
|
||||
inputs: Vec<String>,
|
||||
output: Option<String>,
|
||||
codec: Option<String>,
|
||||
overwrite: bool,
|
||||
}
|
||||
|
||||
impl FFmpegCommand {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inputs: Vec::new(),
|
||||
output: None,
|
||||
codec: None,
|
||||
overwrite: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input(mut self, path: &Path) -> Self {
|
||||
self.inputs.push(path.display().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn input_var(mut self, var: &str) -> Self {
|
||||
self.inputs.push(format!("${}", var));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn output(mut self, path: &Path) -> Self {
|
||||
self.output = Some(path.display().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn output_var(mut self, var: &str) -> Self {
|
||||
self.output = Some(format!("${}", var));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn codec(mut self, codec: &str) -> Self {
|
||||
self.codec = Some(codec.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overwrite(mut self, overwrite: bool) -> Self {
|
||||
self.overwrite = overwrite;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn execute(self, dry_run: bool) -> Result<()> {
|
||||
if dry_run {
|
||||
self.execute_dry_run()
|
||||
} else {
|
||||
self.execute_real()
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_dry_run(self) -> Result<()> {
|
||||
let mut script = ShellScript::new();
|
||||
let mut cmd_parts = vec!["ffmpeg".to_string()];
|
||||
|
||||
if self.overwrite {
|
||||
cmd_parts.push("-y".to_string());
|
||||
}
|
||||
cmd_parts.push("-hide_banner".to_string());
|
||||
|
||||
for input in &self.inputs {
|
||||
cmd_parts.push("-i".to_string());
|
||||
cmd_parts.push(input.clone());
|
||||
}
|
||||
|
||||
if let Some(ref codec) = self.codec {
|
||||
cmd_parts.push("-c".to_string());
|
||||
cmd_parts.push(codec.clone());
|
||||
}
|
||||
|
||||
if let Some(ref output) = self.output {
|
||||
cmd_parts.push(output.clone());
|
||||
}
|
||||
|
||||
let cmd_str = cmd_parts.iter()
|
||||
.map(|arg| {
|
||||
if arg.starts_with('$') {
|
||||
format!("\"{}\"", arg)
|
||||
} else if arg.contains(' ') || arg.contains('$') {
|
||||
format!("\"{}\"", arg.replace('"', r#"\""#))
|
||||
} else {
|
||||
arg.clone()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
script.add_command(&cmd_str);
|
||||
crate::dry_run::print_shell_script(&script);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_real(self) -> Result<()> {
|
||||
let mut cmd = Command::new("ffmpeg");
|
||||
|
||||
if self.overwrite {
|
||||
cmd.arg("-y");
|
||||
}
|
||||
cmd.arg("-hide_banner");
|
||||
|
||||
for input in &self.inputs {
|
||||
cmd.arg("-i");
|
||||
if input.starts_with('$') {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!("Cannot execute with variable input: {}", input)
|
||||
));
|
||||
}
|
||||
cmd.arg(input);
|
||||
}
|
||||
|
||||
if let Some(ref codec) = self.codec {
|
||||
cmd.arg("-c");
|
||||
cmd.arg(codec);
|
||||
}
|
||||
|
||||
if let Some(ref output) = self.output {
|
||||
if output.starts_with('$') {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!("Cannot execute with variable output: {}", output)
|
||||
));
|
||||
}
|
||||
cmd.arg(output);
|
||||
}
|
||||
|
||||
let output = cmd.spawn()?.wait_with_output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("ffmpeg exited with status {}", output.status)
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user