From ca29854ab3486eb64ac4fd39f62ff858b0748d72 Mon Sep 17 00:00:00 2001 From: Arnaud_Cayrol Date: Tue, 27 Jan 2026 22:03:44 +0100 Subject: [PATCH] Code cleanup --- src/config.rs | 64 ++++++++++++++++++++++++++++++++++----------- src/job/mod.rs | 26 +++++++++++------- src/web/handlers.rs | 26 +++++++++--------- 3 files changed, 77 insertions(+), 39 deletions(-) diff --git a/src/config.rs b/src/config.rs index 3fa4ef4..e51cce7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -157,35 +157,69 @@ impl Config { /// Load configuration from environment variables. /// /// Recognized variables: - /// - IMMICH_API_KEY - /// - IMMICH_BASE_URL + /// - IMMICH_API_KEY - API key for Immich + /// - IMMICH_BASE_URL - Base URL of Immich instance + /// - OUTPUT_DIR - Output directory for processed images/video + /// - RESIZE_SIZE - Output image size in pixels + /// - FACE_RESOLUTION_THRESHOLD - Minimum face size in pixels + /// - MAX_WORKERS - Number of parallel processing workers + /// - VIDEO_FRAMERATE - Output video framerate + /// - VIDEO_ENABLED - Whether to compile video (true/false) + /// - KEEP_INTERMEDIATES - Keep debug images (true/false) pub fn from_env() -> Self { - let mut config = Config::default(); - - if let Ok(key) = std::env::var("IMMICH_API_KEY") { - config.api.api_key = key; - } - if let Ok(url) = std::env::var("IMMICH_BASE_URL") { - config.api.base_url = url; - } - if let Ok(dir) = std::env::var("OUTPUT_DIR") { - config.output_dir = PathBuf::from(dir); - } - - config + Config::default().with_env() } /// Merge environment variables into an existing config. pub fn with_env(mut self) -> Self { + // API settings if let Ok(key) = std::env::var("IMMICH_API_KEY") { self.api.api_key = key; } if let Ok(url) = std::env::var("IMMICH_BASE_URL") { self.api.base_url = url; } + + // Output directory if let Ok(dir) = std::env::var("OUTPUT_DIR") { self.output_dir = PathBuf::from(dir); } + + // Processing settings + if let Ok(val) = std::env::var("RESIZE_SIZE") { + if let Ok(size) = val.parse() { + self.processing.resize_size = size; + } + } + if let Ok(val) = std::env::var("FACE_RESOLUTION_THRESHOLD") { + if let Ok(threshold) = val.parse() { + self.processing.face_resolution_threshold = threshold; + } + } + if let Ok(val) = std::env::var("MAX_WORKERS") { + if let Ok(workers) = val.parse() { + self.processing.max_workers = workers; + } + } + if let Ok(val) = std::env::var("KEEP_INTERMEDIATES") { + self.processing.keep_intermediates = val.eq_ignore_ascii_case("true") || val == "1"; + } + + // Video settings + if let Ok(val) = std::env::var("VIDEO_FRAMERATE") { + if let Ok(fps) = val.parse() { + self.video.framerate = fps; + } + } + if let Ok(val) = std::env::var("VIDEO_ENABLED") { + self.video.enabled = val.eq_ignore_ascii_case("true") || val == "1"; + } + if let Ok(val) = std::env::var("VIDEO_CRF") { + if let Ok(crf) = val.parse() { + self.video.crf = crf; + } + } + self } diff --git a/src/job/mod.rs b/src/job/mod.rs index 9cac463..8818a9a 100644 --- a/src/job/mod.rs +++ b/src/job/mod.rs @@ -46,14 +46,19 @@ struct OutputDirs { /// Debug output directories for visualizing each processing stage. /// Each folder contains images with debug overlays showing what happened at that step. +/// +/// Note: `landmarks` and `alignment` fields are placeholders for future features +/// (facial landmark detection and face alignment). They are intentionally unused +/// until those features are implemented. #[derive(Debug, Clone, Default)] -#[allow(dead_code)] struct DebugDirs { /// Original image with bounding box and crop region overlayed crop: Option, - /// Face with landmark points drawn (future) + /// Face with landmark points drawn (future: facial landmark detection) + #[allow(dead_code)] landmarks: Option, - /// Before/after alignment visualization (future) + /// Before/after alignment visualization (future: face alignment) + #[allow(dead_code)] alignment: Option, } @@ -249,7 +254,10 @@ async fn run_job_inner( break; } - let permit = semaphore.clone().acquire_owned().await.unwrap(); + let permit = match semaphore.clone().acquire_owned().await { + Ok(permit) => permit, + Err(_) => continue, // Semaphore closed, skip remaining tasks + }; let client = client.clone(); let config = config.clone(); let output_dirs = output_dirs.clone(); @@ -356,17 +364,15 @@ async fn run_job_inner( }) .await; - let state_clone = state.clone(); - compile_timelapse( &output_dirs.images, &output_dirs.video, &config.video, - move |frame, total| { - // Note: This callback is sync, so we can't easily update state here. - // The FFmpeg wrapper already handles this internally. + |frame, total| { + // Sync callback - just log progress. State updates would require + // async context or channels, which adds complexity for minimal benefit + // since video compilation is typically fast. tracing::debug!("Video progress: {}/{}", frame, total); - let _ = (&state_clone, frame, total); // Suppress unused warning }, ) .await?; diff --git a/src/web/handlers.rs b/src/web/handlers.rs index 46721b5..57185b4 100644 --- a/src/web/handlers.rs +++ b/src/web/handlers.rs @@ -28,7 +28,10 @@ pub fn create_router(state: AppState) -> Router { .route("/api/health", get(health_check)) .route("/api/connection", get(check_connection)) .route("/api/people", get(get_people)) - .route("/api/people/{person_id}/thumbnail", get(get_person_thumbnail)) + .route( + "/api/people/{person_id}/thumbnail", + get(get_person_thumbnail), + ) .route("/api/progress", get(get_progress)) .route("/api/start", post(start_processing)) .route("/api/cancel", post(cancel_processing)) @@ -159,20 +162,18 @@ async fn get_person_thumbnail( ) })?; - tracing::debug!( - "Thumbnail for {}: {} bytes, type: {}", - person_id, - bytes.len(), - content_type - ); - // Return the image with appropriate headers - Ok(Response::builder() + Response::builder() .status(StatusCode::OK) .header(header::CONTENT_TYPE, content_type) .header(header::CACHE_CONTROL, "public, max-age=3600") .body(Body::from(bytes)) - .unwrap()) + .map_err(|e| { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Failed to build response: {}", e), + ) + }) } /// Get current progress. @@ -228,10 +229,7 @@ async fn start_processing( { let progress = state.progress.read().await; if progress.status == JobStatus::Running || progress.status == JobStatus::CompilingVideo { - return Err(( - StatusCode::CONFLICT, - "A job is already running".to_string(), - )); + return Err((StatusCode::CONFLICT, "A job is already running".to_string())); } }