fix-thumb3
This commit is contained in:
parent
cbb8025a0c
commit
76805803b4
143
src/thumbnail.rs
143
src/thumbnail.rs
|
@ -1,6 +1,6 @@
|
||||||
use actix_web::error::ErrorInternalServerError;
|
use actix_web::error::ErrorInternalServerError;
|
||||||
use image::{imageops::FilterType, DynamicImage, ImageFormat};
|
use image::{imageops::FilterType, DynamicImage, ImageFormat};
|
||||||
use log::warn;
|
use log::{warn, error};
|
||||||
use std::{collections::HashMap, io::Cursor};
|
use std::{collections::HashMap, io::Cursor};
|
||||||
|
|
||||||
use crate::{app_state::AppState, s3_utils::upload_to_s3};
|
use crate::{app_state::AppState, s3_utils::upload_to_s3};
|
||||||
|
@ -13,74 +13,47 @@ pub const THUMB_WIDTHS: [u32; 7] = [10, 40, 110, 300, 600, 800, 1400];
|
||||||
/// - "unsafe/1440x/production/image/439efaa0-816f-11ef-b201-439da98539bc.jpg" -> ("439efaa0-816f-11ef-b201-439da98539bc", 1440, "jpg")
|
/// - "unsafe/1440x/production/image/439efaa0-816f-11ef-b201-439da98539bc.jpg" -> ("439efaa0-816f-11ef-b201-439da98539bc", 1440, "jpg")
|
||||||
/// - "unsafe/production/image/5627e002-0c53-11ee-9565-0242ac110006.png" -> ("5627e002-0c53-11ee-9565-0242ac110006", 0, "png")
|
/// - "unsafe/production/image/5627e002-0c53-11ee-9565-0242ac110006.png" -> ("5627e002-0c53-11ee-9565-0242ac110006", 0, "png")
|
||||||
/// - "unsafe/development/image/439efaa0-816f-11ef-b201-439da98539bc.jpg/webp" -> ("439efaa0-816f-11ef-b201-439da98539bc", 0, "webp")
|
/// - "unsafe/development/image/439efaa0-816f-11ef-b201-439da98539bc.jpg/webp" -> ("439efaa0-816f-11ef-b201-439da98539bc", 0, "webp")
|
||||||
|
/// - "059ab1e0-66c7-11e9-adda-e3ab2ab4e37e_800.jpg" -> ("059ab1e0-66c7-11e9-adda-e3ab2ab4e37e", 800, "jpg")
|
||||||
pub fn parse_file_path(requested_path: &str) -> (String, u32, String) {
|
pub fn parse_file_path(requested_path: &str) -> (String, u32, String) {
|
||||||
let mut path = requested_path.to_string();
|
let mut path = requested_path.to_string();
|
||||||
if requested_path.ends_with("/webp") {
|
// Удаляем /webp в конце, если есть
|
||||||
|
if path.ends_with("/webp") {
|
||||||
path = path.replace("/webp", "");
|
path = path.replace("/webp", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Получаем последнюю часть пути (имя файла с расширением)
|
||||||
|
let filename = path.split('/').last().unwrap_or(&path);
|
||||||
|
|
||||||
let path_parts: Vec<&str> = path.split('/').collect();
|
// Разделяем имя файла и расширение
|
||||||
let mut extension = String::new();
|
let (mut base_filename, extension) = filename
|
||||||
|
.rsplit_once('.')
|
||||||
|
.unwrap_or((filename, ""));
|
||||||
|
|
||||||
|
// Инициализируем переменные
|
||||||
let mut width = 0;
|
let mut width = 0;
|
||||||
let mut base_filename = String::new();
|
|
||||||
|
// Проверяем наличие ширины в имени файла
|
||||||
// Получаем последнюю часть пути (имя файла)
|
if let Some((name, width_str)) = base_filename.rsplit_once('_') {
|
||||||
if let Some(last_part) = path_parts.last() {
|
|
||||||
// Разделяем имя файла и расширение
|
|
||||||
if let Some((name, ext)) = last_part.rsplit_once('.') {
|
|
||||||
extension = ext.to_string();
|
|
||||||
base_filename = name.to_string();
|
|
||||||
} else {
|
|
||||||
base_filename = last_part.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверяем наличие ширины в пути
|
|
||||||
for part in path_parts.iter() {
|
|
||||||
if part.ends_with('x') {
|
|
||||||
if let Ok(w) = part.trim_end_matches('x').parse::<u32>() {
|
|
||||||
width = w;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Извлечение ширины из base_filename, если она есть
|
|
||||||
if let Some((name_part, width_str)) = base_filename.rsplit_once('_') {
|
|
||||||
if let Ok(w) = width_str.parse::<u32>() {
|
if let Ok(w) = width_str.parse::<u32>() {
|
||||||
width = w;
|
width = w;
|
||||||
base_filename = name_part.to_string();
|
base_filename = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверка на старую ширину в путях, начинающихся с "unsafe"
|
// Если ширина не найдена и путь начинается с "unsafe",
|
||||||
if path.starts_with("unsafe") && width == 0 {
|
// ищем ширину в формате "1440x"
|
||||||
if path_parts.len() >= 2 {
|
if width == 0 && path.starts_with("unsafe") {
|
||||||
if let Some(old_width_str) = path_parts.get(1) { // Получаем второй элемент
|
for part in path.split('/') {
|
||||||
let old_width_str = old_width_str.trim_end_matches('x');
|
if part.ends_with('x') {
|
||||||
if let Ok(w) = old_width_str.parse::<u32>() {
|
if let Ok(w) = part.trim_end_matches('x').parse::<u32>() {
|
||||||
width = w;
|
width = w;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если ширина не найдена в пути, проверяем имя файла
|
|
||||||
if width == 0 {
|
|
||||||
if let Some((name, width_str)) = base_filename.rsplit_once('_') {
|
|
||||||
if let Ok(w) = width_str.parse::<u32>() {
|
|
||||||
width = w;
|
|
||||||
base_filename = name.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Очищаем base_filename от возможных префиксов пути
|
(base_filename.to_string(), width, extension.to_string())
|
||||||
if let Some(uuid) = base_filename.split('/').last() {
|
|
||||||
base_filename = uuid.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
(base_filename, width, extension)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Генерирует миниатюры изображения.
|
/// Генерирует миниатюры изображения.
|
||||||
|
@ -135,52 +108,74 @@ pub async fn thumbdata_save(
|
||||||
content_type: String,
|
content_type: String,
|
||||||
) -> Result<(), actix_web::Error> {
|
) -> Result<(), actix_web::Error> {
|
||||||
if content_type.starts_with("image") {
|
if content_type.starts_with("image") {
|
||||||
warn!("original file name: {}", original_filename);
|
warn!("[THUMB] Processing image: {}", original_filename);
|
||||||
let (base_filename, _, extension) = parse_file_path(&original_filename);
|
let (base_filename, _, extension) = parse_file_path(&original_filename);
|
||||||
warn!("detected file extension: {}", extension);
|
warn!("[THUMB] Parsed: base={}, ext={}", base_filename, extension);
|
||||||
|
|
||||||
let ext = extension.to_lowercase();
|
let ext = extension.to_lowercase();
|
||||||
let filename = format!("{}.{}", base_filename, ext);
|
let filename = format!("{}.{}", base_filename, ext);
|
||||||
|
warn!("[THUMB] Normalized filename: {}", filename);
|
||||||
|
|
||||||
let img = match image::load_from_memory(&original_data) {
|
let img = match image::load_from_memory(&original_data) {
|
||||||
Ok(img) => img,
|
Ok(img) => {
|
||||||
|
warn!("[THUMB] Successfully loaded image from memory, size: {}x{}",
|
||||||
|
img.width(), img.height());
|
||||||
|
img
|
||||||
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("cannot load image from memory: {}", e);
|
error!("[THUMB] Failed to load image from memory: {}", e);
|
||||||
return Err(ErrorInternalServerError("cant load image"));
|
return Err(ErrorInternalServerError("cant load image"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
warn!("generate thumbnails for {}", filename);
|
let format = match determine_image_format(&ext) {
|
||||||
|
Ok(f) => {
|
||||||
|
warn!("[THUMB] Using format: {:?}", f);
|
||||||
|
f
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
error!("[THUMB] Format error: {}", e);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Определяем формат изображения
|
|
||||||
let format = determine_image_format(&ext)?;
|
|
||||||
|
|
||||||
// Генерация миниатюр с использованием определённого формата
|
|
||||||
match generate_thumbnails(&img, format).await {
|
match generate_thumbnails(&img, format).await {
|
||||||
Ok(thumbnails_bytes) => {
|
Ok(thumbnails_bytes) => {
|
||||||
|
warn!("[THUMB] Generated {} thumbnails", thumbnails_bytes.len());
|
||||||
|
|
||||||
for (thumb_width, thumbnail) in thumbnails_bytes {
|
for (thumb_width, thumbnail) in thumbnails_bytes {
|
||||||
let thumb_filename = format!("{}_{}.{}", base_filename, thumb_width, ext);
|
let thumb_filename = format!("{}_{}.{}", base_filename, thumb_width, ext);
|
||||||
// Загружаем миниатюру в S3
|
warn!("[THUMB] Saving thumbnail: {}", thumb_filename);
|
||||||
if let Err(e) = upload_to_s3(
|
|
||||||
|
match upload_to_s3(
|
||||||
&state.storj_client,
|
&state.storj_client,
|
||||||
&state.bucket,
|
&state.bucket,
|
||||||
&thumb_filename,
|
&thumb_filename,
|
||||||
thumbnail,
|
thumbnail.clone(),
|
||||||
&content_type,
|
&content_type,
|
||||||
)
|
).await {
|
||||||
.await
|
Ok(_) => {
|
||||||
{
|
warn!("[THUMB] Successfully saved thumbnail: {}", thumb_filename);
|
||||||
warn!("cannot load thumb {}: {}", thumb_filename, e);
|
// Сохраняем путь к миниатюре в Redis
|
||||||
|
state.set_path(&thumb_filename, &thumb_filename).await;
|
||||||
|
warn!("[THUMB] Cached path in Redis: {}", thumb_filename);
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
error!("[THUMB] Failed to save thumbnail {}: {}", thumb_filename, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Ok(())
|
||||||
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("cannot generate thumbnails for {}: {}", filename, e);
|
error!("[THUMB] Failed to generate thumbnails: {}", e);
|
||||||
return Err(e);
|
Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
warn!("[THUMB] Skipping non-image content type: {}", content_type);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Выбирает ближайший подходящий размер из предопределённых.
|
/// Выбирает ближайший подходящий размер из предопределённых.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user