76 lines
2.5 KiB
Rust
76 lines
2.5 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 VideoPath<'a>(pub &'a Path);
|
|
|
|
impl<'a> Previewable for VideoPath<'a> {
|
|
fn get_thumbnail(&self, options: HashMap<String, String>) -> Result<Option<Vec<u8>>> {
|
|
let mut ffprobe = Command::new("ffprobe");
|
|
let command = ffprobe
|
|
.args(["-threads", "1"])
|
|
.args(["-v", "error"])
|
|
.args(["-show_entries", "format=duration"])
|
|
.args(["-of", "default=noprint_wrappers=1:nokey=1"])
|
|
.arg(self.0);
|
|
|
|
trace!("Running `{:?}`", command);
|
|
let now = std::time::Instant::now();
|
|
let duration_cmd = command.output()?;
|
|
debug!("Ran `{:?}`, took {}s", command, now.elapsed().as_secs_f32());
|
|
|
|
if !duration_cmd.status.success() {
|
|
return Err(anyhow!(
|
|
"Failed to retrieve file duration: {:?}",
|
|
String::from_utf8_lossy(&duration_cmd.stderr)
|
|
));
|
|
}
|
|
|
|
let duration = String::from_utf8_lossy(&duration_cmd.stdout)
|
|
.trim()
|
|
.parse::<f64>()?;
|
|
let position = {
|
|
if let Some(str_position) = options.get("position") {
|
|
str_position.parse()?
|
|
} else {
|
|
90.0f64
|
|
}
|
|
};
|
|
|
|
let outfile = tempfile::Builder::new().suffix(".webp").tempfile()?;
|
|
let mut ffmpeg = Command::new("ffmpeg");
|
|
let command = ffmpeg
|
|
.args(["-threads", "1"])
|
|
.args(["-discard", "nokey"])
|
|
.args(["-noaccurate_seek"])
|
|
.args(["-ss", &(position.min(duration / 2.0)).to_string()])
|
|
.args(["-i", &self.0.to_string_lossy()])
|
|
.args(["-vframes", "1"])
|
|
.args(["-vsync", "passthrough"])
|
|
.arg(&*outfile.path().to_string_lossy())
|
|
.arg("-y");
|
|
|
|
trace!("Running `{:?}`", command);
|
|
let now = std::time::Instant::now();
|
|
let thumbnail_cmd = command.output()?;
|
|
debug!("Ran `{:?}`, took {}s", command, now.elapsed().as_secs_f32());
|
|
|
|
if !thumbnail_cmd.status.success() {
|
|
return Err(anyhow!(
|
|
"Failed to render thumbnail: {:?}",
|
|
String::from_utf8_lossy(&thumbnail_cmd.stderr)
|
|
));
|
|
}
|
|
|
|
let mut buffer = Vec::new();
|
|
outfile.as_file().read_to_end(&mut buffer)?;
|
|
Ok(Some(buffer))
|
|
}
|
|
}
|