diff --git a/Cargo.lock b/Cargo.lock index 52d0785..ba94779 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1333,6 +1333,12 @@ dependencies = [ "url", ] +[[package]] +name = "human_bytes" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39b528196c838e8b3da8b665e08c30958a6f2ede91d79f2ffcd0d4664b9c64eb" + [[package]] name = "humantime" version = "1.3.0" @@ -2440,6 +2446,7 @@ dependencies = [ "gettext-rs", "gtk-macros", "gtk4", + "human_bytes", "im-rc", "image", "libadwaita", diff --git a/Cargo.toml b/Cargo.toml index c9c7715..aa01341 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,5 @@ once_cell = "1.5" url = "2.2" scraper = "0.12" surf = "2.2" -async-std = "1.12" \ No newline at end of file +async-std = "1.12" +human_bytes = { version = "0.4", default-features = false } \ No newline at end of file diff --git a/src/backend/card.rs b/src/backend/card.rs index bca21a6..2625a5e 100644 --- a/src/backend/card.rs +++ b/src/backend/card.rs @@ -13,6 +13,7 @@ use crate::vec_of_strings; use super::{ Data, Image, + ImageError, Log, LogLevel, Social, @@ -271,7 +272,7 @@ impl Card { if occurrences.len() > 0 { logger.log(LogLevel::Debug, gettext!( - "Looking for valid occurrence for \"{}\"", name + "Looking for valid occurrences for \"{}\"", name )); } @@ -298,10 +299,25 @@ impl Card { } } Err(err) => { - logger.log(LogLevel::Debug, gettext!( - "Image \"{}\" did not meet the requirements: {}.", - image.url, err - )); + match err { + ImageError::RequestError(_) => { + logger.log(LogLevel::Error, format!( + "{}: \"{}\".", err, image.url + )); + }, + ImageError::TooHeavy{..} | ImageError::Unsupported(_) => { + logger.log(LogLevel::Warning, gettext!( + "{}: Image \"{}\" did not meet the requirements: {}.", + social, image.url, err + )); + }, + _ => { + logger.log(LogLevel::Debug, gettext!( + "{}: Image \"{}\" did not meet the requirements: {}.", + social, image.url, err + )); + } + } } } } diff --git a/src/backend/image.rs b/src/backend/image.rs index 5e29ef9..d0a74d8 100644 --- a/src/backend/image.rs +++ b/src/backend/image.rs @@ -8,6 +8,7 @@ use std::{ io::Cursor, }; +use human_bytes::human_bytes; use image; use url::{Url, ParseError}; @@ -82,7 +83,7 @@ impl Image { self.bytes.replace(Some(bytes)); Ok(self.bytes.borrow().clone().unwrap()) } else { - Err(ImageError::Unexpected) + Err(ImageError::RequestError(resp.status().canonical_reason())) } } } @@ -92,12 +93,11 @@ impl Image { &self, social: &Social, kinds: &Vec, - _constraints: &SocialConstraints + constraints: &SocialConstraints ) -> Result { - if let (None, None) = (self.width.get(), self.height.get()) { - let bytes = self.fetch().await?; + if let (None, None) = (self.width.get(), self.height.get()) { let (width, height) = async_std::task::spawn_blocking( move || -> Result<(u32, u32), ImageError> { let image = image::load_from_memory(&bytes)?; Ok((image.width(), image.height())) @@ -108,6 +108,21 @@ impl Image { self.height.set(Some(height)); } + if let Some(size) = self.size.get() { + if size > constraints.image_size { + return Err(ImageError::TooHeavy{ + actual: human_bytes(size as f64), + max: human_bytes(constraints.image_size as f64) + }); + } + } + + if let Some(format) = self.format.get() { + if !constraints.image_formats.contains(&format) { + return Err(ImageError::Unsupported("Format is unsupported".to_string())); + } + } + if let (Some(width), Some(height)) = (self.width.get(), self.height.get()) { for kind in kinds.iter() { let (min_width, min_height) = social.image_size(kind); @@ -121,7 +136,10 @@ impl Image { None => (0, 0) }; - Err(ImageError::TooTiny(format!("{}x{}", sizes.0, sizes.1))) + Err(ImageError::TooTiny{ + actual: format!("{}×{}px", width, height), + min: format!("{}×{}px", sizes.0, sizes.1) + }) } else { Err(ImageError::Unexpected) } @@ -158,22 +176,37 @@ impl Image { #[derive(Debug)] pub enum ImageError { FetchError(surf::Error), + RequestError(&'static str), ImageError(image::error::ImageError), - TooTiny(String), - TooHeavy, - Unsupported, + TooTiny{ + actual: String, + min: String + }, + TooHeavy{ + actual: String, + max: String + }, + Unsupported(String), Unexpected, } impl Display for ImageError { fn fmt(&self, f: &mut Formatter) -> FmtResult { match *self { - ImageError::FetchError(ref e) => write!(f, "NetworkError: {}", e), - ImageError::ImageError(ref e) => write!(f, "ImageError: {}", e), - ImageError::TooTiny(ref s) => write!(f, "Image is too tiny, minimum size is {}", s), - ImageError::TooHeavy => write!(f, "TooHeavy"), - ImageError::Unsupported => write!(f, "Unsupported"), - ImageError::Unexpected => write!(f, "UnexpectedError"), + ImageError::FetchError(ref e) => + write!(f, "Network Error: {}", e), + ImageError::RequestError(ref s) => + write!(f, "Request Error: {}", s), + ImageError::ImageError(ref e) => + write!(f, "Image Error: {}", e), + ImageError::TooTiny{ref actual, ref min} => + write!(f, "Image is too tiny ({}), minimum dimensions are {}", actual, min), + ImageError::TooHeavy{ref actual, ref max} => + write!(f, "Images is too heavy ({}), max size is {}", actual, max), + ImageError::Unsupported(ref s) => + write!(f, "Images is unsupported: {}", s), + ImageError::Unexpected => + write!(f, "Unexpected Error"), } } }