diff --git a/Cargo.lock b/Cargo.lock
index bb76989..f365f06 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -74,12 +74,30 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "anyhow"
+version = "1.0.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
+[[package]]
+name = "bird-detector"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "clap",
+ "env_logger",
+ "image",
+ "log",
+]
+
 [[package]]
 name = "bitflags"
 version = "2.4.1"
@@ -318,17 +336,6 @@ dependencies = [
  "wasm-bindgen",
 ]
 
-[[package]]
-name = "krmdet"
-version = "0.1.0"
-dependencies = [
- "chrono",
- "clap",
- "env_logger",
- "image",
- "log",
-]
-
 [[package]]
 name = "libc"
 version = "0.2.150"
diff --git a/Cargo.toml b/Cargo.toml
index 6949982..101fc93 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "krmdet"
+name = "bird-detector"
 version = "0.1.0"
 edition = "2021"
 
@@ -12,3 +12,4 @@ clap = "4.4.7"
 log = "0.4.20"
 env_logger = "0.10.0"
 chrono = "0.4.31"
+anyhow = "1.0.75"
diff --git a/birds/.gitignore b/birds/.gitignore
deleted file mode 100644
index d6b7ef3..0000000
--- a/birds/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/src/main.rs b/src/main.rs
index c9ef6de..96f6a4a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,29 +1,68 @@
 use std::os::unix::fs::MetadataExt;
 use std::path::PathBuf;
+use std::time::Duration;
+use anyhow::Context;
+
 use chrono::{NaiveDateTime, Utc};
 use image::{GenericImageView, Pixel};
 use log::{debug, error, info};
 
-fn main() {
-    open_and_reduce_img();
-}
+/// Folder the camera images are uploaded to
+const FOLDER_WITH_NEW_IMAGES: &str = "/dev/shm/camera";
+
+/// File created in the uploads directory when the upload finishes.
+const COMMIT_FILENAME : &str = "commit";
 
+/// Folder where the cropped bird pics are saved
+const FOLDER_WITH_BIRD_IMAGES: &str = "/backup/krmitko";
 
-const FOLDER_WITH_IMAGES : &str = "../2/";
+/// Image cropping config: left top X
+const CROP_X : u32 = 1872;
 
-const FOLDER_OUTPUT : &str = "birds";
+/// Image cropping config: left top Y
+const CROP_Y : u32 = 1329;
 
-const THUMB_W : usize = 12;
-const THUMB_H : usize = 8;
+/// Image cropping config: crop width
+const CROP_W : u32 = 1000;
 
-const THRESHOLD_DEVIATION : u32 = 500;
+/// Image cropping config: crop height
+const CROP_H : u32 = 750;
 
-fn open_and_reduce_img() {
-    env_logger::init_from_env("LOGGING");
+/// Thumbnail width, used for bird detection (together with height creates the kernel size)
+/// This is a compromise between sensitivity and susceptibility to false positives.
+const THUMB_W: usize = 12;
 
-    info!("Bird finder starts");
+/// Thumbnail height
+const THUMB_H: usize = 8;
+
+/// Threshold for bird detection.
+/// Bird is detected if the sum of deviations from a median value in a picture exceeds this threshold.
+const THRESHOLD_DEVIATION: u32 = 500;
+
+fn main() {
+    env_logger::init();
 
-    let paths = std::fs::read_dir(FOLDER_WITH_IMAGES).unwrap();
+    let commit_file = PathBuf::from(FOLDER_WITH_NEW_IMAGES).join(COMMIT_FILENAME);
+
+    loop {
+        if !commit_file.exists() {
+            debug!("No commit file, wait.");
+            std::thread::sleep(Duration::from_secs(10));
+            continue;
+        }
+
+        if let Err(e) = process_camera_pics() {
+            error!("Error processing pics: {e}");
+        }
+
+        let _ = std::fs::remove_dir_all(FOLDER_WITH_NEW_IMAGES);
+    }
+}
+
+fn process_camera_pics() -> anyhow::Result<()> {
+    info!("Processing camera pics");
+
+    let paths = std::fs::read_dir(FOLDER_WITH_NEW_IMAGES).context("Read folder with images")?;
 
     let mut crops = vec![];
     let mut thumbs = vec![];
@@ -33,16 +72,20 @@ fn open_and_reduce_img() {
     for dir_entry in paths {
         let Ok(dir_entry) = dir_entry else { continue; };
         let Ok(meta) = dir_entry.metadata() else { continue; };
-        if !meta.is_file() {
+        if !meta.is_file() || !dir_entry.file_name().to_string_lossy().ends_with(".jpg") {
             continue;
         }
 
-        timestamps.push(meta.ctime());
-
         debug!("{}", dir_entry.path().display());
 
-        let img = image::open(dir_entry.path()).unwrap();
-        let crop = img.crop_imm(1872, 1329, 1000, 750);
+        let Ok(img) = image::open(dir_entry.path()) else {
+            continue;
+        };
+
+        // File loaded fine, assume it's OK
+        timestamps.push(meta.ctime());
+
+        let crop = img.crop_imm(CROP_X, CROP_Y, CROP_W, CROP_H);
         let thumb = crop.thumbnail(THUMB_W as u32, THUMB_H as u32);
 
         crops.push(crop);
@@ -86,12 +129,15 @@ fn open_and_reduce_img() {
         if deviation > THRESHOLD_DEVIATION {
             info!("LIKELY BIRD!!!! in picture #{thumb_num}");
 
-            let datetime = parse_unix_ts(timestamps[thumb_num]).format("%Y-%m-%d_%H-%M-%S");
-            let path = format!("{}/{}.jpg", FOLDER_OUTPUT, datetime);
+            let datetime_str = parse_unix_ts(timestamps[thumb_num]).format("%Y-%m-%d_%H-%M-%S");
+            let path = format!("{}/{}.jpg", FOLDER_WITH_BIRD_IMAGES, datetime_str);
             let mut pb = PathBuf::from(path);
+
+            // Ensure we do not overwrite a file if there are multiple in the same second!
+            // This adds -2, -3 etc. to the file name
             let mut cnt = 2;
             while pb.exists() {
-                pb.set_file_name(format!("{}-{cnt}.jpg", datetime));
+                pb.set_file_name(format!("{}-{cnt}.jpg", datetime_str));
                 cnt += 1;
             }
 
@@ -101,9 +147,7 @@ fn open_and_reduce_img() {
         }
     }
 
-
-    // crop.save(format!("{}/{}", FOLDER_OUTPUT, dir_entry.file_name().to_string_lossy())).unwrap();
-    // thumb.save(format!("{}/th-{}", FOLDER_OUTPUT, dir_entry.file_name().to_string_lossy())).unwrap();
+    Ok(())
 }
 
 fn parse_unix_ts(ts: i64) -> chrono::DateTime<Utc> {