# AutoIngest

**Author:** Jeremy Anderson  
**Contact:** info@dcos.net  
**Website:** [dcos.net](https://dcos.net)

---

## What It Does

AutoIngest is a Windows tray-resident tool that silently moves photos off an SD card or USB drive into a dated folder on your PC. Plug in the card, the `.jpg`s are **moved** (not copied) to `~/Pictures/YYYY-MM-DD/`, and any RAW/HEIC/PNG files are converted to JPG and the originals removed from the card. A small toast pops into the corner while it's working, then disappears. Duplicate-aware within a single day — if you re-insert the same card on the same day, byte-identical files are skipped.

Built for eBay sellers who just want the photos off the camera and into a folder, with nothing to click.

## Features

### Silent move-import (the core)
- Polls for removable drives every 4 seconds via kernel32 `GetDriveType` and `GetVolumeInformationW`
- Probes DCIM, Pictures, and root folders for image files
- **Moves** JPG/JPEG files directly to `~/Pictures/<today's date>/` — no dupes left on the device
- Converts all other formats (RAW, HEIC, PNG, etc.) to progressive JPG, then deletes the original from the card
- Same-day duplicate aware: within today's import folder, byte-identical files (matched by size then SHA-256) are skipped rather than re-imported
- Verify-before-delete: a file is only removed from the card after the destination is confirmed present and correctly sized
- Single-instance enforcement via named mutex

### Toast UI
- Lives in the system tray by default — no window at startup
- A small borderless toast pops into the bottom-right corner when an import starts
- Shows live status (`Moving 3/12: IMG_004.jpg`) and a scrolling log
- Auto-hides ~4 seconds after the import completes
- Left-click the tray icon to peek at status on demand; right-click for the menu (show status, open import folder, reset drive memory, about, exit)

### Image Conversion
- Powered by [Magick.NET](https://github.com/dlemstra/Magick.NET) (ImageMagick 7 bindings)
- Handles 30+ input formats: JPG, PNG, BMP, TIFF, WebP, CR2, CR3, NEF, ARW, DNG, HEIC, HEIF, SVG, RAW, and more
- Converts at native resolution (no downscaling) to preserve full image detail
- Outputs progressive, optimized JPG

## Architecture

```
AutoIngest/
├── AutoIngest.csproj         Project file, package reference, assembly metadata
├── App/                      WinForms UI layer (namespace AutoIngest.App)
│   ├── Program.cs            Entry point, single-instance mutex
│   ├── MainForm.cs           Tray icon, toast show/hide, monitor wiring
│   ├── MainForm.Designer.cs  Toast popup layout (WinForms Designer)
│   ├── MainForm.resx         Designer resource header
│   └── app.manifest          Windows 10/11 compatibility manifest
├── Core/                     Config/models layer (namespace AutoIngest.Core)
│   └── ConfigManager.cs      JSON config persistence
└── Engine/                   Import/conversion layer (namespace AutoIngest.Engine)
    ├── SDCardMonitor.cs      Background drive polling, photo discovery, move/convert pipeline
    └── ImageConverter.cs     Magick.NET wrapper for universal format-to-JPG conversion
```

**Single NuGet dependency:** `Magick.NET-Q16-AnyCPU`

## Design Decisions

| Decision | Rationale |
|----------|-----------|
| Move, not copy | The card is the source of truth; leaving dupes after import causes confusion. Move it once, done. |
| Same-day dedupe | Re-inserting a card on the same day shouldn't double-import. Within today's folder, byte-identical files are skipped; name collisions with different content get a `_1`, `_2` suffix. (We are not a cross-day dedupe tool — different days go in different folders.) |
| Tray + toast, no main window | This is a silent utility. You shouldn't have to manage a window — it just tells you when it's working. |
| C# / .NET 8 over Python | Single-exe deployment. No runtime, pip, or native extension installation on the end user's PC. |
| WinForms over WPF | Simple, direct control layout, no XAML complexity. |
| Magick.NET over System.Drawing | One library handles all 30+ formats including RAW, HEIC, SVG. |
| kernel32 P/Invoke over WMI | Deterministic, fast drive detection without COM initialization overhead. |
| Polling (4s interval) over WMI events | WMI event subscriptions require COM apartment threading and have inconsistent delivery across Windows versions. |
| Flat output directory | Matches the workflow: pull to date folder, open in browser, attach to listing. |

## Building

### Prerequisites
- Windows 10/11
- [Visual Studio 2022 Community](https://visualstudio.microsoft.com/vs/community/) (free) with ".NET desktop development" workload
- .NET 8 SDK (installed by VS2022 with the desktop workload)

### Build from Visual Studio
1. Open `AutoIngest.sln`
2. Build → Build Solution (or Ctrl+Shift+B)
3. The output exe is in `AutoIngest/bin/Debug/net8.0-windows/`

### Build from command line
```bat
cd AutoIngest
dotnet restore
dotnet build -c Release
```

### Publish as single exe
```bat
REM Framework-dependent (~15 MB, requires .NET 8 desktop runtime on target PC)
publish.bat

REM Self-contained (~60-80 MB, runs on any Win10/11 PC)
publish-standalone.bat
```

## Deployment

Copy the resulting `AutoIngest.exe` to the target PC. No installer required.

- **Framework-dependent build:** Requires .NET 8 Desktop Runtime. Windows 11 includes this by default. Windows 10 may need it from [dotnet.microsoft.com](https://dotnet.microsoft.com/download/dotnet/8.0).
- **Self-contained build:** No prerequisites. Runs on any Windows 10/11 PC.

## Configuration

Config file: `~/.autoingest_config.json` — created automatically on first run. Holds JPG quality and auto-import toggle.

## Tech Stack

| Component | Technology |
|-----------|------------|
| Language | C# 12 / .NET 8 |
| UI Framework | Windows Forms |
| Image Processing | Magick.NET-Q16-AnyCPU (ImageMagick 7) |
| Drive Detection | kernel32 `GetDriveType` + `GetVolumeInformationW` via P/Invoke |
| Serialization | System.Text.Json |
| Target | Windows 10 1809+ / Windows 11 |

## License

MS-PL (Microsoft Public License). See [LICENSE](LICENSE). Author: Jeremy Anderson (info@dcos.net, https://dcos.net).
