diff --git a/Cargo.lock b/Cargo.lock index 8398e05..881844c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -910,6 +910,7 @@ dependencies = [ "tower-http", "tracing", "tracing-subscriber", + "walkdir", ] [[package]] @@ -1366,6 +1367,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1817,6 +1827,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1924,6 +1944,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 6577625..f0f0797 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ tokio = { version = "1.25.0", features = ["full"] } tower-http = { version = "0.3.5", features = ["fs", "trace", "compression-br"] } tracing = "0.1.37" tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +walkdir = "2.5.0" diff --git a/src/main.rs b/src/main.rs index ffcadee..b6bffb4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ use tokio::{task, sync::Semaphore}; use tower_http::{trace::{self, TraceLayer}, compression::CompressionLayer}; use tracing::Level; use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt}; +use walkdir::WalkDir; mod config; mod error; @@ -185,23 +186,24 @@ async fn update_config_and_image_list_cache_job( }; // Read all image files from the image_dir - let images: HashSet<_> = match image_dir.read_dir() { - Ok(images) => { - // flatten ignores io error while traversing the iterator - images.flatten().filter_map(|entry| { - let path = entry.path(); - if path.extension().unwrap_or_default().to_ascii_lowercase() == "jpg" { - Some(path) - } else { + let images: HashSet<_> = WalkDir::new(&image_dir) + .into_iter() + .filter_map(|entry| { + match entry { + Ok(entry) => { + let path = entry.path(); + if path.extension().unwrap_or_default().eq_ignore_ascii_case("jpg") { + Some(path.to_path_buf()) + } else { + None + } + }, + Err(error) => { + tracing::error!("Could not read image dir: {:#}", error); None } - }).collect() - }, - Err(error) => { - tracing::error!("Could not read images: {:#}", error); - continue - }, - }; + } + }).collect(); let update_image_metadata = if image_dir_change != last_image_dir_change { tracing::debug!("Update image list because image dir was modified"); @@ -221,8 +223,9 @@ async fn update_config_and_image_list_cache_job( // Update image list if update_image_metadata { let images = images.clone(); + let image_dir = image_dir.clone(); let image_metadata = task::spawn_blocking(move || { - read_image_metadata(&images) + read_image_metadata(&image_dir, &images) }).await.unwrap_or_else(|error| { tracing::error!("Could not read images due to panic: {:#}", error); Vec::new() @@ -349,7 +352,7 @@ async fn converted_image( image_path.exists() .then_some(()) - .ok_or(anyhow!("Requested image not found!")) + .ok_or(anyhow!("Requested image {} not found!", image_path.display())) .context(StatusCode::NOT_FOUND)?; // Check if we have the file already in cache @@ -465,11 +468,11 @@ fn fix_image_orientation(image: DynamicImage, exif: &Exif) -> DynamicImage { } } -fn read_image_metadata(images: &HashSet) -> Vec { +fn read_image_metadata(image_dir: &Path, images: &HashSet) -> Vec { let mut files = vec![]; for path in images { - let image_info = match read_image_info(path) { + let image_info = match read_image_info(image_dir, path) { Ok(image_info) => image_info, Err(error) => { tracing::warn!("Skipping {:?} due to error: {:#}", path, error); @@ -491,7 +494,7 @@ fn extract_exif_string(field: &exif::Field) -> Option { } } -fn read_image_info(path: &Path) -> Result { +fn read_image_info(image_dir: &Path, path: &Path) -> Result { let file = File::open(path)?; let mut file = BufReader::new(file); @@ -534,7 +537,7 @@ fn read_image_info(path: &Path) -> Result { width, height, created: datetime.unwrap_or_default(), - name: path.file_name().expect("invalid file path").to_owned(), + name: path.strip_prefix(image_dir).expect("invalid path prefix").into(), ..Default::default() }) }