Code cleanup

This commit is contained in:
Arnaud_Cayrol 2026-01-27 22:03:44 +01:00
parent 7351a4b032
commit ca29854ab3
3 changed files with 77 additions and 39 deletions

View file

@ -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
}

View file

@ -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<PathBuf>,
/// Face with landmark points drawn (future)
/// Face with landmark points drawn (future: facial landmark detection)
#[allow(dead_code)]
landmarks: Option<PathBuf>,
/// Before/after alignment visualization (future)
/// Before/after alignment visualization (future: face alignment)
#[allow(dead_code)]
alignment: Option<PathBuf>,
}
@ -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?;

View file

@ -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()));
}
}