upend/cli/src/previews/audio.rs

83 lines
3.1 KiB
Rust

use anyhow::anyhow;
use anyhow::Result;
use std::collections::HashMap;
use std::io::Read;
use std::path::Path;
use std::process::Command;
use tracing::{debug, trace};
use super::Previewable;
pub struct AudioPath<'a>(pub &'a Path);
const COLOR: &str = "dc322f"; // solarized red
impl<'a> Previewable for AudioPath<'a> {
fn get_thumbnail(&self, options: HashMap<String, String>) -> Result<Option<Vec<u8>>> {
match options.get("type").map(|x| x.as_str()) {
Some("json") => {
let outfile = tempfile::Builder::new().suffix(".json").tempfile()?;
// -i long_clip.mp3 -o long_clip.json --pixels-per-second 20 --bits 8
let audiowaveform_cmd = Command::new("audiowaveform")
.args(["-i", &self.0.to_string_lossy()])
.args(["-o", &*outfile.path().to_string_lossy()])
.args(["--pixels-per-second", "20"])
.args(["--bits", "8"])
.output()?;
if !audiowaveform_cmd.status.success() {
return Err(anyhow!(
"Failed to retrieve audiofile peaks: {:?}",
String::from_utf8_lossy(&audiowaveform_cmd.stderr)
));
}
let mut buffer = Vec::new();
outfile.as_file().read_to_end(&mut buffer)?;
Ok(Some(buffer))
}
Some("image") | None => {
let outfile = tempfile::Builder::new().suffix(".png").tempfile()?;
let color = options
.get("color")
.map(String::to_owned)
.unwrap_or_else(|| COLOR.into());
let mut audiowaveform = Command::new("audiowaveform");
let command = audiowaveform
.args(["-i", &self.0.to_string_lossy()])
.args([
"--border-color",
"00000000",
"--background-color",
"00000000",
"--waveform-color",
&color,
"--no-axis-label",
])
.args(["--width", "860", "--height", "256"])
.args(["-o", &*outfile.path().to_string_lossy()]);
trace!("Running `{:?}`", command);
let now = std::time::Instant::now();
let cmd_output = command.output()?;
debug!("Ran `{:?}`, took {}s", command, now.elapsed().as_secs_f32());
if !cmd_output.status.success() {
return Err(anyhow!(
"Failed to render thumbnail: {:?}",
String::from_utf8_lossy(&cmd_output.stderr)
));
}
let mut buffer = Vec::new();
outfile.as_file().read_to_end(&mut buffer)?;
Ok(Some(buffer))
}
Some(_) => Err(anyhow!("type has to be one of: image, json")),
}
}
}