Add Exif storing and update to Metadata endpoint
This commit is contained in:
74
src/main.rs
74
src/main.rs
@@ -34,6 +34,7 @@ use rayon::prelude::*;
|
||||
use crate::auth::login;
|
||||
use crate::data::*;
|
||||
use crate::database::*;
|
||||
use crate::database::models::InsertImageExif;
|
||||
use crate::files::{
|
||||
RealFileSystem, RefreshThumbnailsMessage, is_image_or_video, is_valid_full_path, move_file,
|
||||
};
|
||||
@@ -53,6 +54,7 @@ mod auth;
|
||||
mod data;
|
||||
mod database;
|
||||
mod error;
|
||||
mod exif;
|
||||
mod files;
|
||||
mod state;
|
||||
mod tags;
|
||||
@@ -146,17 +148,29 @@ async fn get_file_metadata(
|
||||
request: HttpRequest,
|
||||
path: web::Query<ThumbnailRequest>,
|
||||
app_state: Data<AppState>,
|
||||
exif_dao: Data<Mutex<Box<dyn ExifDao>>>,
|
||||
) -> impl Responder {
|
||||
let tracer = global_tracer();
|
||||
let context = extract_context_from_request(&request);
|
||||
let mut span = tracer.start_with_context("get_file_metadata", &context);
|
||||
match is_valid_full_path(&app_state.base_path, &path.path, false)
|
||||
|
||||
let full_path = is_valid_full_path(&app_state.base_path, &path.path, false);
|
||||
|
||||
match full_path
|
||||
.ok_or_else(|| ErrorKind::InvalidData.into())
|
||||
.and_then(File::open)
|
||||
.and_then(|file| file.metadata())
|
||||
{
|
||||
Ok(metadata) => {
|
||||
let response: MetadataResponse = metadata.into();
|
||||
let mut response: MetadataResponse = metadata.into();
|
||||
|
||||
// Query EXIF data if available
|
||||
if let Ok(mut dao) = exif_dao.lock() {
|
||||
if let Ok(Some(exif)) = dao.get_exif(&path.path) {
|
||||
response.exif = Some(exif.into());
|
||||
}
|
||||
}
|
||||
|
||||
span.add_event(
|
||||
"Metadata fetched",
|
||||
vec![KeyValue::new("file", path.path.clone())],
|
||||
@@ -181,6 +195,7 @@ async fn upload_image(
|
||||
request: HttpRequest,
|
||||
mut payload: mp::Multipart,
|
||||
app_state: Data<AppState>,
|
||||
exif_dao: Data<Mutex<Box<dyn ExifDao>>>,
|
||||
) -> impl Responder {
|
||||
let tracer = global_tracer();
|
||||
let context = extract_context_from_request(&request);
|
||||
@@ -224,11 +239,12 @@ async fn upload_image(
|
||||
.span_builder("file write")
|
||||
.start_with_context(&tracer, &context);
|
||||
|
||||
if !full_path.is_file() && is_image_or_video(&full_path) {
|
||||
let uploaded_path = if !full_path.is_file() && is_image_or_video(&full_path) {
|
||||
let mut file = File::create(&full_path).unwrap();
|
||||
file.write_all(&file_content).unwrap();
|
||||
|
||||
info!("Uploaded: {:?}", full_path);
|
||||
full_path
|
||||
} else {
|
||||
warn!("File already exists: {:?}", full_path);
|
||||
|
||||
@@ -245,8 +261,56 @@ async fn upload_image(
|
||||
);
|
||||
info!("Uploaded: {}", new_path);
|
||||
|
||||
let mut file = File::create(new_path).unwrap();
|
||||
let new_path_buf = PathBuf::from(&new_path);
|
||||
let mut file = File::create(&new_path_buf).unwrap();
|
||||
file.write_all(&file_content).unwrap();
|
||||
new_path_buf
|
||||
};
|
||||
|
||||
// Extract and store EXIF data if file supports it
|
||||
if exif::supports_exif(&uploaded_path) {
|
||||
let relative_path = uploaded_path
|
||||
.strip_prefix(&app_state.base_path)
|
||||
.expect("Error stripping base path prefix")
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
match exif::extract_exif_from_path(&uploaded_path) {
|
||||
Ok(exif_data) => {
|
||||
let timestamp = Utc::now().timestamp();
|
||||
let insert_exif = InsertImageExif {
|
||||
file_path: relative_path.clone(),
|
||||
camera_make: exif_data.camera_make,
|
||||
camera_model: exif_data.camera_model,
|
||||
lens_model: exif_data.lens_model,
|
||||
width: exif_data.width,
|
||||
height: exif_data.height,
|
||||
orientation: exif_data.orientation,
|
||||
gps_latitude: exif_data.gps_latitude,
|
||||
gps_longitude: exif_data.gps_longitude,
|
||||
gps_altitude: exif_data.gps_altitude,
|
||||
focal_length: exif_data.focal_length,
|
||||
aperture: exif_data.aperture,
|
||||
shutter_speed: exif_data.shutter_speed,
|
||||
iso: exif_data.iso,
|
||||
date_taken: exif_data.date_taken,
|
||||
created_time: timestamp,
|
||||
last_modified: timestamp,
|
||||
};
|
||||
|
||||
if let Ok(mut dao) = exif_dao.lock() {
|
||||
if let Err(e) = dao.store_exif(insert_exif) {
|
||||
error!("Failed to store EXIF data for {}: {:?}", relative_path, e);
|
||||
} else {
|
||||
debug!("EXIF data stored for {}", relative_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("No EXIF data or error extracting from {}: {:?}", uploaded_path.display(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!("Invalid path for upload: {:?}", full_path);
|
||||
@@ -645,6 +709,7 @@ fn main() -> std::io::Result<()> {
|
||||
let user_dao = SqliteUserDao::new();
|
||||
let favorites_dao = SqliteFavoriteDao::new();
|
||||
let tag_dao = SqliteTagDao::default();
|
||||
let exif_dao = SqliteExifDao::new();
|
||||
App::new()
|
||||
.wrap(middleware::Logger::default())
|
||||
.service(web::resource("/login").route(web::post().to(login::<SqliteUserDao>)))
|
||||
@@ -673,6 +738,7 @@ fn main() -> std::io::Result<()> {
|
||||
favorites_dao,
|
||||
))))
|
||||
.app_data::<Data<Mutex<SqliteTagDao>>>(Data::new(Mutex::new(tag_dao)))
|
||||
.app_data::<Data<Mutex<Box<dyn ExifDao>>>>(Data::new(Mutex::new(Box::new(exif_dao))))
|
||||
.wrap(prometheus.clone())
|
||||
})
|
||||
.bind(dotenv::var("BIND_URL").unwrap())?
|
||||
|
||||
Reference in New Issue
Block a user