upend/src/previews/mod.rs

79 lines
2.3 KiB
Rust

use crate::util::hash::Hash;
use crate::{database::UpEndDatabase, util::hash::encode};
use anyhow::{anyhow, Result};
use std::{
collections::HashMap,
fs::File,
io::Write,
path::{Path, PathBuf},
sync::{Arc, Mutex},
};
use self::text::TextPath;
use self::video::VideoPath;
pub mod text;
pub mod video;
pub trait Previewable {
fn get_thumbnail(&self) -> Result<Vec<u8>>;
}
pub struct PreviewStore {
path: PathBuf,
db: Arc<UpEndDatabase>,
locks: Mutex<HashMap<Hash, Arc<Mutex<PathBuf>>>>,
}
#[cfg(feature = "previews")]
impl PreviewStore {
pub fn new<P: AsRef<Path>>(path: P, db: Arc<UpEndDatabase>) -> Self {
PreviewStore {
path: PathBuf::from(path.as_ref()),
db,
locks: Mutex::new(HashMap::new()),
}
}
fn get_path(&self, hash: &Hash) -> Arc<Mutex<PathBuf>> {
let mut locks = self.locks.lock().unwrap();
if let Some(path) = locks.get(hash) {
path.clone()
} else {
let thumbpath = self.path.join(encode(hash));
let path = Arc::new(Mutex::new(thumbpath));
locks.insert(hash.clone(), path.clone());
path
}
}
pub fn get(&self, hash: Hash) -> Result<PathBuf> {
let path_mutex = self.get_path(&hash);
let thumbpath = path_mutex.lock().unwrap();
if thumbpath.exists() {
Ok(thumbpath.clone())
} else {
let connection = self.db.connection()?;
let files = connection.retrieve_file(hash)?;
if let Some(file) = files.get(0) {
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."))
}?;
std::fs::create_dir_all(&self.path)?;
let mut file = File::create(&*thumbpath)?;
file.write_all(&data)?;
Ok(thumbpath.clone())
} else {
Err(anyhow!("Object not found, or is not a file."))
}
}
}
}