diff --git a/Cargo.lock b/Cargo.lock index fb9cf4a..60b9158 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index f5d8a1d..ae648a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] diff --git a/src/thumbnails/mod.rs b/src/thumbnails/mod.rs index a6660d2..94d7259 100644 --- a/src/thumbnails/mod.rs +++ b/src/thumbnails/mod.rs @@ -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>; @@ -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.")) }?; diff --git a/src/thumbnails/video.rs b/src/thumbnails/video.rs new file mode 100644 index 0000000..e2dc394 --- /dev/null +++ b/src/thumbnails/video.rs @@ -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> { + 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::()?; + 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) + } +}