# camshooter
A Linux GUI tool to select a webcam, preview its live video stream, and save PNG snapshots with a keyboard shortcut.
camshooter is a single, self-contained process — no daemon, no IPC. Pick a camera, watch the live preview, and hit a key to grab a timestamped PNG.
## Features
- Lists available webcams via V4L2 and lets you pick one.
- Live video preview of the selected camera.
- One-key PNG snapshots with timestamped filenames.
- Never overwrites: same-second collisions get a `-N` suffix (configurable).
- Configurable output directory, filename prefix, and collision behavior.
- CLI override for the output directory.
## Requirements
- Linux (Fedora 44 tested; Linux only for now).
- A V4L2-compatible webcam exposed at `/dev/video*`.
- The Rust toolchain (edition 2024).
- `clang` / `llvm` — nokhwa's V4L backend uses bindgen.
On Fedora, install the build dependencies:
```sh
sudo dnf install clang clang-devel llvm-devel
```
`libv4l-devel` is **not** required.
### Camera access
The active Fedora desktop session usually grants access to `/dev/video*` through logind ACLs. If camshooter reports **"No webcams detected"**, add yourself to the `video` group and re-login:
```sh
sudo usermod -aG video $USER
```
## Build & Run
Build a release binary:
```sh
cargo build --release
```
Run it:
```sh
cargo run
# or
./target/release/camshooter
```
Save snapshots to a specific directory (created if missing):
```sh
camshooter -o ~/Pictures/cam
```
## Usage
1. Launch `camshooter`. A window lists the available webcams.
2. Pick a camera: click it, or press a number key `1`–`9`.
3. The live preview appears. Use the keybindings below.
### Keybindings
| `1`–`9` | Select camera (picker) |
| `Space` or `S` | Take a snapshot |
| `Esc` | Back to the camera picker |
| `Q` | Quit |
### Snapshot filenames
Snapshots are named `snapshooter{ddMMyyHHmmss}.png` using a 24-hour clock — for example, a capture on 6 June 2026 at 14:30:12 becomes:
```
snapshooter060626143012.png
```
If a file with that name already exists (a same-second collision), camshooter appends a `-N` suffix (`snapshooter060626143012-1.png`, and so on). It never overwrites an existing file unless `on_collision = "overwrite"` is set in the config.
## Configuration
Configuration is optional. camshooter reads `~/.config/camshooter/config.toml` (respecting `$XDG_CONFIG_HOME`). If the file is missing, built-in defaults are used. All keys are optional:
```toml
output_dir = "~/Pictures/cam" # default save dir; overridden by -o
prefix = "snapshooter" # filename prefix
on_collision = "suffix" # "suffix" | "overwrite"
```
### Output directory precedence
The output directory is resolved in this order (lowest to highest priority):
1. Built-in default — the current directory.
2. `output_dir` in `config.toml`.
3. The `-o` / `--output` flag.
## Project structure
```
src/
main.rs CLI parsing + bootstrap
config.rs TOML config loading
capture.rs camera capture thread
ui.rs egui application
snapshot.rs PNG saving
```
Built with `nokhwa` (V4L2 capture), `eframe` / `egui` (window and GUI), `image` (PNG encoding), `clap` (CLI), `chrono` (timestamps), and `serde` / `toml` (config).
## Testing
Run the test suite:
```sh
cargo test
```
The snapshot filename/collision logic and config parsing are unit-tested and run without any camera hardware.
## Known limitations
- **Linux/V4L2 only** for now.
> Webcams used to appear twice in the picker because a single UVC camera exposes both a
> video-capture and a metadata `/dev/video*` node (the latter streamed black frames). The
> picker now probes each node's V4L2 capabilities and lists only true capture nodes.
## License
Licensed under the [Apache License 2.0](LICENSE).