feat: Add media serving functionality with optional metadata stripping
This commit is contained in:
@@ -15,3 +15,5 @@ serde = { version = "1.0.228", features = ["derive"] }
|
||||
nom-exif = { version = "2.5.4", features = ["serde", "async", "tokio"] }
|
||||
dotenvy = "0.15.7"
|
||||
config = "0.15.19"
|
||||
image = "0.25.8"
|
||||
tokio = { version = "1.48.0", features = ["rt"] }
|
||||
@@ -4,7 +4,9 @@ use std::{
|
||||
};
|
||||
|
||||
use chrono::{DateTime, Datelike, NaiveDateTime, Utc};
|
||||
use image::{ImageFormat, load_from_memory};
|
||||
use nom_exif::{AsyncMediaParser, AsyncMediaSource, ExifIter, MediaParser, MediaSource, TrackInfo};
|
||||
use tokio::task;
|
||||
|
||||
use crate::{
|
||||
error::{CoreError, CoreResult},
|
||||
@@ -190,3 +192,34 @@ pub fn is_invalid_exif_tag(tag_name: &str, tag_value: &str) -> bool {
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub async fn strip_metadata_from_bytes(
|
||||
file_bytes: Vec<u8>,
|
||||
mime_type: &str,
|
||||
) -> CoreResult<Vec<u8>> {
|
||||
if mime_type != "image/jpeg" && mime_type != "image/png" {
|
||||
return Ok(file_bytes);
|
||||
}
|
||||
|
||||
let mime_type = mime_type.to_string();
|
||||
|
||||
task::spawn_blocking(move || -> CoreResult<Vec<u8>> {
|
||||
let img = load_from_memory(&file_bytes)
|
||||
.map_err(|e| CoreError::Unknown(format!("Failed to parse image: {}", e)))?;
|
||||
|
||||
let mut buffer = std::io::Cursor::new(Vec::new());
|
||||
|
||||
match mime_type.as_str() {
|
||||
"image/jpeg" => img
|
||||
.write_to(&mut buffer, ImageFormat::Jpeg)
|
||||
.map_err(|e| CoreError::Unknown(format!("Failed to re-encode JPEG: {}", e)))?,
|
||||
"image/png" => img
|
||||
.write_to(&mut buffer, ImageFormat::Png)
|
||||
.map_err(|e| CoreError::Unknown(format!("Failed to re-encode PNG: {}", e)))?,
|
||||
_ => unreachable!(), // We already checked this
|
||||
}
|
||||
Ok(buffer.into_inner())
|
||||
})
|
||||
.await
|
||||
.map_err(|e| CoreError::Unknown(format!("Blocking task failed: {}", e)))?
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ pub trait MediaService: Send + Sync {
|
||||
async fn get_media_filepath(&self, id: Uuid, user_id: Option<Uuid>) -> CoreResult<String>;
|
||||
async fn get_media_thumbnail_path(&self, id: Uuid, user_id: Option<Uuid>)
|
||||
-> CoreResult<String>;
|
||||
async fn get_media_for_serving(&self, id: Uuid, user_id: Option<Uuid>) -> CoreResult<Media>;
|
||||
async fn delete_media(&self, id: Uuid, user_id: Uuid) -> CoreResult<()>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user