thumbnails -> previews
parent
d11d20f210
commit
a43a9d6caf
|
@ -64,6 +64,6 @@ webbrowser = { version = "^0.5.5", optional = true }
|
||||||
nonempty = "0.6.0"
|
nonempty = "0.6.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["desktop", "thumbnails"]
|
default = ["desktop", "previews"]
|
||||||
desktop = ["webbrowser", "opener", "is_executable"]
|
desktop = ["webbrowser", "opener", "is_executable"]
|
||||||
thumbnails = []
|
previews = []
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -16,7 +16,6 @@ use log::{info, warn};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use crate::database::UpEndDatabase;
|
use crate::database::UpEndDatabase;
|
||||||
use crate::thumbnails::ThumbnailStore;
|
|
||||||
|
|
||||||
mod addressing;
|
mod addressing;
|
||||||
mod database;
|
mod database;
|
||||||
|
@ -24,8 +23,8 @@ mod filesystem;
|
||||||
mod routes;
|
mod routes;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
#[cfg(feature = "thumbnails")]
|
#[cfg(feature = "previews")]
|
||||||
mod thumbnails;
|
mod previews;
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
@ -100,14 +99,14 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
let upend = Arc::new(open_result.db);
|
let upend = Arc::new(open_result.db);
|
||||||
|
|
||||||
#[cfg(feature = "thumbnails")]
|
#[cfg(feature = "previews")]
|
||||||
let thumbnail_store = Some(Arc::new(ThumbnailStore::new(
|
let preview_store = Some(Arc::new(crate::previews::PreviewStore::new(
|
||||||
upend.db_path.join("thumbnails"),
|
upend.db_path.join("previews"),
|
||||||
upend.clone(),
|
upend.clone(),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
#[cfg(not(feature = "thumbnails"))]
|
#[cfg(not(feature = "previews"))]
|
||||||
let thumbnail_store = None;
|
let preview_store = None;
|
||||||
|
|
||||||
let mut bind: SocketAddr = matches
|
let mut bind: SocketAddr = matches
|
||||||
.value_of("BIND")
|
.value_of("BIND")
|
||||||
|
@ -131,7 +130,7 @@ fn main() -> Result<()> {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
job_container: job_container.clone(),
|
job_container: job_container.clone(),
|
||||||
thumbnail_store,
|
preview_store,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Start HTTP server
|
// Start HTTP server
|
||||||
|
|
|
@ -16,19 +16,19 @@ use self::video::VideoPath;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod video;
|
pub mod video;
|
||||||
|
|
||||||
pub trait Thumbnailable {
|
pub trait Previewable {
|
||||||
fn get_thumbnail(&self) -> Result<Vec<u8>>;
|
fn get_thumbnail(&self) -> Result<Vec<u8>>;
|
||||||
}
|
}
|
||||||
pub struct ThumbnailStore {
|
pub struct PreviewStore {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
db: Arc<UpEndDatabase>,
|
db: Arc<UpEndDatabase>,
|
||||||
|
|
||||||
locks: Mutex<HashMap<Hash, Arc<Mutex<PathBuf>>>>,
|
locks: Mutex<HashMap<Hash, Arc<Mutex<PathBuf>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThumbnailStore {
|
impl PreviewStore {
|
||||||
pub fn new<P: AsRef<Path>>(path: P, db: Arc<UpEndDatabase>) -> Self {
|
pub fn new<P: AsRef<Path>>(path: P, db: Arc<UpEndDatabase>) -> Self {
|
||||||
ThumbnailStore {
|
PreviewStore {
|
||||||
path: PathBuf::from(path.as_ref()),
|
path: PathBuf::from(path.as_ref()),
|
||||||
db,
|
db,
|
||||||
locks: Mutex::new(HashMap::new()),
|
locks: Mutex::new(HashMap::new()),
|
|
@ -1,11 +1,11 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::{cmp::min, convert::TryInto, fs::File, io::Read, path::Path};
|
use std::{cmp::min, convert::TryInto, fs::File, io::Read, path::Path};
|
||||||
|
|
||||||
use super::Thumbnailable;
|
use super::Previewable;
|
||||||
|
|
||||||
pub struct TextPath<'a>(pub &'a Path);
|
pub struct TextPath<'a>(pub &'a Path);
|
||||||
|
|
||||||
impl<'a> Thumbnailable for TextPath<'a> {
|
impl<'a> Previewable for TextPath<'a> {
|
||||||
fn get_thumbnail(&self) -> Result<Vec<u8>> {
|
fn get_thumbnail(&self) -> Result<Vec<u8>> {
|
||||||
let mut f = File::open(self.0)?;
|
let mut f = File::open(self.0)?;
|
||||||
let mut buffer = vec![0u8; min(1024, f.metadata()?.len().try_into()?)];
|
let mut buffer = vec![0u8; min(1024, f.metadata()?.len().try_into()?)];
|
|
@ -5,11 +5,11 @@ use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use super::Thumbnailable;
|
use super::Previewable;
|
||||||
|
|
||||||
pub struct VideoPath<'a>(pub &'a Path);
|
pub struct VideoPath<'a>(pub &'a Path);
|
||||||
|
|
||||||
impl<'a> Thumbnailable for VideoPath<'a> {
|
impl<'a> Previewable for VideoPath<'a> {
|
||||||
fn get_thumbnail(&self) -> Result<Vec<u8>> {
|
fn get_thumbnail(&self) -> Result<Vec<u8>> {
|
||||||
let duration_cmd = Command::new("ffprobe")
|
let duration_cmd = Command::new("ffprobe")
|
||||||
.args(["-v", "error"])
|
.args(["-v", "error"])
|
|
@ -3,7 +3,7 @@ use crate::database::entry::{Entry, InEntry};
|
||||||
use crate::database::hierarchies::{list_roots, resolve_path, UHierPath};
|
use crate::database::hierarchies::{list_roots, resolve_path, UHierPath};
|
||||||
use crate::database::lang::Query;
|
use crate::database::lang::Query;
|
||||||
use crate::database::UpEndDatabase;
|
use crate::database::UpEndDatabase;
|
||||||
use crate::thumbnails::ThumbnailStore;
|
use crate::previews::PreviewStore;
|
||||||
use crate::util::hash::{decode, encode};
|
use crate::util::hash::{decode, encode};
|
||||||
use crate::util::jobs::JobContainer;
|
use crate::util::jobs::JobContainer;
|
||||||
use actix_files::NamedFile;
|
use actix_files::NamedFile;
|
||||||
|
@ -29,7 +29,7 @@ pub struct State {
|
||||||
pub upend: Arc<UpEndDatabase>,
|
pub upend: Arc<UpEndDatabase>,
|
||||||
pub vault_name: Option<String>,
|
pub vault_name: Option<String>,
|
||||||
pub job_container: Arc<RwLock<JobContainer>>,
|
pub job_container: Arc<RwLock<JobContainer>>,
|
||||||
pub thumbnail_store: Option<Arc<ThumbnailStore>>,
|
pub preview_store: Option<Arc<PreviewStore>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -315,17 +315,17 @@ pub async fn get_thumbnail(
|
||||||
state: web::Data<State>,
|
state: web::Data<State>,
|
||||||
hash: web::Path<String>,
|
hash: web::Path<String>,
|
||||||
) -> Result<NamedFile, Error> {
|
) -> Result<NamedFile, Error> {
|
||||||
if let Some(thumbnail_store) = &state.thumbnail_store {
|
if let Some(preview_store) = &state.preview_store {
|
||||||
let address =
|
let address =
|
||||||
Address::decode(&decode(hash.into_inner()).map_err(ErrorInternalServerError)?)
|
Address::decode(&decode(hash.into_inner()).map_err(ErrorInternalServerError)?)
|
||||||
.map_err(ErrorInternalServerError)?;
|
.map_err(ErrorInternalServerError)?;
|
||||||
if let Address::Hash(hash) = address {
|
if let Address::Hash(hash) = address {
|
||||||
let thumbnail_path = thumbnail_store
|
let preview_path = preview_store
|
||||||
.get(hash)
|
.get(hash)
|
||||||
.map_err(error::ErrorInternalServerError)?;
|
.map_err(error::ErrorInternalServerError)?;
|
||||||
|
|
||||||
let mut file = NamedFile::open(&thumbnail_path)?.disable_content_disposition();
|
let mut file = NamedFile::open(&preview_path)?.disable_content_disposition();
|
||||||
if let Some(mime_type) = tree_magic_mini::from_filepath(&thumbnail_path) {
|
if let Some(mime_type) = tree_magic_mini::from_filepath(&preview_path) {
|
||||||
if let Ok(mime) = mime_type.parse() {
|
if let Ok(mime) = mime_type.parse() {
|
||||||
file = file.set_content_type(mime);
|
file = file.set_content_type(mime);
|
||||||
}
|
}
|
||||||
|
@ -333,10 +333,10 @@ pub async fn get_thumbnail(
|
||||||
Ok(file)
|
Ok(file)
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorBadRequest(
|
Err(ErrorBadRequest(
|
||||||
"Address does not refer to a thumbnailable object.",
|
"Address does not refer to a previewable object.",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(error::ErrorNotImplemented("Thumbnails not enabled."))
|
Err(error::ErrorNotImplemented("Previews not enabled."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue