add video thumbnailing via ffmpeg

feat/vaults
Tomáš Mládek 2021-12-26 18:16:37 +01:00
parent aa67b93e4e
commit 3186b9ce6e
No known key found for this signature in database
GPG Key ID: ED21612889E75EC5
4 changed files with 97 additions and 47 deletions

89
Cargo.lock generated
View File

@ -883,12 +883,6 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
@ -1689,19 +1683,6 @@ dependencies = [
"scheduled-thread-pool",
]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi 0.3.9",
]
[[package]]
name = "rand"
version = "0.7.3"
@ -1710,9 +1691,21 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc",
"rand_hc 0.2.0",
]
[[package]]
name = "rand"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [
"libc",
"rand_chacha 0.3.1",
"rand_core 0.6.3",
"rand_hc 0.3.1",
]
[[package]]
@ -1726,20 +1719,15 @@ dependencies = [
]
[[package]]
name = "rand_core"
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"rand_core 0.4.2",
"ppv-lite86",
"rand_core 0.6.3",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.5.1"
@ -1749,6 +1737,15 @@ dependencies = [
"getrandom 0.1.16",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom 0.2.3",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
@ -1758,6 +1755,15 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_hc"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
dependencies = [
"rand_core 0.6.3",
]
[[package]]
name = "rayon"
version = "1.5.1"
@ -1783,15 +1789,6 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.2.10"
@ -2092,13 +2089,17 @@ dependencies = [
]
[[package]]
name = "tempdir"
version = "0.3.7"
name = "tempfile"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
"rand 0.4.6",
"cfg-if 1.0.0",
"libc",
"rand 0.8.4",
"redox_syscall",
"remove_dir_all",
"winapi 0.3.9",
]
[[package]]
@ -2441,7 +2442,7 @@ dependencies = [
"rayon",
"serde",
"serde_json",
"tempdir",
"tempfile",
"thiserror",
"tiny-keccak",
"tree_magic_mini",

View File

@ -48,6 +48,7 @@ filebuffer = "0.4.0"
tiny-keccak = { version = "2.0", features = ["k12"] }
unsigned-varint = { version = "^0", features = ["std"] }
uuid = { version = "0.8", features = ["v4"] }
tempfile = "^3.2.0"
walkdir = "2"
mime = "^0.3.16"
@ -62,9 +63,6 @@ webbrowser = { version = "^0.5.5", optional = true }
nonempty = "0.6.0"
[dev-dependencies]
tempdir = "0.3.7"
[features]
default = ["desktop", "thumbnails"]
desktop = ["webbrowser", "opener", "is_executable"]

View File

@ -10,8 +10,11 @@ use std::{
};
use self::text::TextPath;
use self::video::VideoPath;
pub mod text;
pub mod video;
pub trait Thumbnailable {
fn get_thumbnail(&self) -> Result<Vec<u8>>;
@ -56,6 +59,7 @@ impl ThumbnailStore {
let data = match tree_magic_mini::from_filepath(&file.path) {
Some(tm) if tm.starts_with("text") => Ok(TextPath(&file.path).get_thumbnail()?),
Some(tm) if tm.starts_with("video") => Ok(VideoPath(&file.path).get_thumbnail()?),
Some(unknown) => Err(anyhow!("No capability for {:?} thumbnails.", unknown)),
_ => Err(anyhow!("Unknown file type, or file doesn't exist."))
}?;

47
src/thumbnails/video.rs Normal file
View File

@ -0,0 +1,47 @@
use anyhow::anyhow;
use std::io::Read;
use std::path::Path;
use std::process::Command;
use anyhow::Result;
use super::Thumbnailable;
pub struct VideoPath<'a>(pub &'a Path);
impl<'a> Thumbnailable for VideoPath<'a> {
fn get_thumbnail(&self) -> Result<Vec<u8>> {
let duration_cmd = Command::new("ffprobe")
.args(["-v", "error"])
.args(["-show_entries", "format=duration"])
.args(["-of", "default=noprint_wrappers=1:nokey=1"])
.arg(self.0)
.output()?;
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 outfile = tempfile::Builder::new().suffix(".png").tempfile()?;
let thumbnail_cmd = Command::new("ffmpeg")
.args(["-i", &self.0.to_string_lossy()])
.args(["-vframes", "1"])
.args(["-ss", &(duration / 2.0).to_string()])
.arg(&*outfile.path().to_string_lossy())
.arg("-y")
.output()?;
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(buffer)
}
}