From 7a0d219f0806ab1f20c7d3535028380c73d9d628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sn=C3=ADda=C5=88ov=C3=BD=20Mistr?= Date: Tue, 12 Dec 2023 18:54:48 +0100 Subject: [PATCH] =?UTF-8?q?N=C3=A1hledy=20p=C5=99es=20magick=20+=20mal?= =?UTF-8?q?=C3=A9=20zm=C4=9Bny?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/error.rs | 2 +- src/files.rs | 72 +++++++++++++++++------------ src/filters.rs | 9 ++++ src/main.rs | 7 ++- src/markup.rs | 3 +- static/style.css | 4 +- templates/macros/catalog-entry.html | 2 +- 7 files changed, 61 insertions(+), 38 deletions(-) diff --git a/src/error.rs b/src/error.rs index 2826d49..5d6da93 100755 --- a/src/error.rs +++ b/src/error.rs @@ -152,7 +152,7 @@ impl From for NekrochanError { Self::OverboardError } else { error!("{e:#?}"); - + Self::InternalError } } diff --git a/src/files.rs b/src/files.rs index 2242dcf..698018f 100755 --- a/src/files.rs +++ b/src/files.rs @@ -2,7 +2,6 @@ use actix_multipart::form::tempfile::TempFile; use anyhow::Error; use chrono::Utc; use glob::glob; -use image::io::Reader as ImageReader; use std::{collections::HashSet, process::Command}; use tokio::{ fs::{remove_file, rename}, @@ -144,18 +143,34 @@ async fn process_image( new_name: String, thumb_name: Option, ) -> Result<(u32, u32), NekrochanError> { - let original_name_ = original_name.clone(); + let new_name_ = new_name.clone(); - let img = spawn_blocking(move || { - ImageReader::open(format!("/tmp/{new_name}"))? - .decode() - .map_err(|_| { - NekrochanError::FileError(original_name_, "nepodařilo se dekódovat obrázek") - }) + let identify_out = spawn_blocking(move || { + Command::new("identify") + .args(["-format", "%wx%h", &format!("/tmp/{new_name_}[0]")]) + .output() }) .await??; - let (width, height) = (img.width(), img.height()); + let invalid_dimensions = "imagemagick vrátil neplatné rozměry"; + let out_string = String::from_utf8_lossy(&identify_out.stdout); + + let (width, height) = out_string + .trim() + .split_once('x') + .ok_or(NekrochanError::FileError( + original_name.clone(), + invalid_dimensions, + ))?; + + let (width, height) = ( + width + .parse() + .map_err(|_| NekrochanError::FileError(original_name.clone(), invalid_dimensions))?, + height + .parse() + .map_err(|_| NekrochanError::FileError(original_name.clone(), invalid_dimensions))?, + ); if width > cfg.files.max_width || height > cfg.files.max_height { return Err(NekrochanError::FileError( @@ -168,29 +183,27 @@ async fn process_image( return Ok((width, height)); }; - let thumb_w = if width > cfg.files.thumb_size { - cfg.files.thumb_size - } else { - width - }; + let thumb_size = cfg.files.thumb_size; - let thumb_h = if height > cfg.files.thumb_size { - cfg.files.thumb_size - } else { - height - }; - - spawn_blocking(move || { - let thumb = img.thumbnail(thumb_w, thumb_h); - - thumb - .save(format!("./uploads/thumb/{thumb_name}")) - .map_err(|_| { - NekrochanError::FileError(original_name, "nepodařilo se vytvořit náhled obrázku") - }) + let output = spawn_blocking(move || { + Command::new("convert") + .arg(&format!("/tmp/{new_name}")) + .arg("-thumbnail") + .arg(&format!("{thumb_size}x{thumb_size}>")) + .arg(&format!("./uploads/thumb/{thumb_name}")) + .output() }) .await??; + if !output.status.success() { + println!("{}", String::from_utf8_lossy(&output.stderr)); + + return Err(NekrochanError::FileError( + original_name, + "nepodařilo se vytvořit náhled obrázku", + )); + } + Ok((width, height)) } @@ -226,8 +239,7 @@ async fn process_video( )); } - let invalid_dimensions = "ffprobe vrátil neplatné rozměry"; - + let invalid_dimensions = "ffmeg vrátil neplatné rozměry"; let out_string = String::from_utf8_lossy(&ffprobe_out.stdout); let (width, height) = out_string diff --git a/src/filters.rs b/src/filters.rs index 97081c6..56f06eb 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -13,6 +13,7 @@ lazy_static! { pub fn czech_humantime(time: &DateTime) -> askama::Result { let duration = (Utc::now() - *time).abs(); + let seconds = duration.num_seconds(); let minutes = duration.num_minutes(); let hours = duration.num_hours(); let days = duration.num_days(); @@ -22,6 +23,14 @@ pub fn czech_humantime(time: &DateTime) -> askama::Result { let mut time = "Teď".into(); + if seconds > 0 { + time = format!( + "{} {}", + seconds, + czech_plural("sekunda|sekundy|sekund", seconds)? + ); + } + if minutes > 0 { time = format!( "{} {}", diff --git a/src/main.rs b/src/main.rs index 42ed7e9..4900ccd 100755 --- a/src/main.rs +++ b/src/main.rs @@ -135,8 +135,9 @@ where ::Error: ResponseError + 'static, { let (req, res) = res.into_parts(); + let status = res.status(); - let error_code = res.status().as_u16(); + let error_code = status.as_u16(); let error_message = match res.into_body().try_into_bytes().ok() { Some(bytes) => String::from_utf8(bytes.to_vec()).unwrap_or_default(), None => String::default(), @@ -147,7 +148,9 @@ where error_message, }; - let res = template_response(&template)?; + let mut res = template_response(&template)?; + *(res.status_mut()) = status; + let res = ServiceResponse::new(req, res).map_into_right_body(); Ok(ErrorHandlerResponse::Response(res)) diff --git a/src/markup.rs b/src/markup.rs index afefdcd..def81f0 100644 --- a/src/markup.rs +++ b/src/markup.rs @@ -1,8 +1,7 @@ -use std::collections::HashMap; - use fancy_regex::{Captures, Regex}; use lazy_static::lazy_static; use sqlx::query_as; +use std::collections::HashMap; use crate::{ ctx::Ctx, diff --git a/static/style.css b/static/style.css index 12c0f87..e79a7ec 100755 --- a/static/style.css +++ b/static/style.css @@ -339,8 +339,8 @@ summary { } .thumb { - max-width: 150px; - max-height: 150px; + max-width: 200px; + max-height: 200px; } .post-content { diff --git a/templates/macros/catalog-entry.html b/templates/macros/catalog-entry.html index 42de933..a58c533 100644 --- a/templates/macros/catalog-entry.html +++ b/templates/macros/catalog-entry.html @@ -4,7 +4,7 @@ /{{ post.board }}/{{ post.id }} {% if let Some(file) = post.files.0.get(0) %} - + {% else %}

[Link]