Code cleanup
This commit is contained in:
parent
7351a4b032
commit
ca29854ab3
3 changed files with 77 additions and 39 deletions
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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?;
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue