Reference
PATH must be an existing directory to scan.
Options
| Option | Default | Behaviour |
|---|---|---|
--output DIR |
renamed |
Destination root; relative paths resolve below PATH |
--recursive |
off | Search subdirectories |
--dry-run |
off | Plan and report without writing |
--verbose |
off | Print per-file actions and failures |
--quiet |
off | Suppress startup, progress, summary, and verbose output |
--force |
off | Process already named files when --skip-existing is also set |
--skip-existing |
off | Skip files matching a generated date-based name |
--timestamp MODE |
auto |
auto, exif, or filesystem |
--format FORMAT |
datetime |
datetime, source, or source-first |
--preserve-source |
off | Alias for --format source; explicit --format wins |
--organise |
off | Append detected source beneath the preserved relative directory |
--flatten |
off | Remove relative source directories from output paths |
--move |
off | Move instead of copy |
--include EXT,... |
all supported | Include only listed supported extensions |
--exclude EXT,... |
none | Exclude listed extensions |
--timezone ZONE |
unset | Convert timestamps to an IANA zone before formatting |
--log-file PATH |
unset | Append tab-separated audit events on real runs |
Exit codes
| Code | Meaning |
|---|---|
0 |
Every scanned file succeeded or was intentionally skipped |
1 |
At least one file failed (including missing metadata in exif mode) |
2 |
Invalid configuration (unknown timezone, quiet+verbose, bad PATH, …) |
Safety guarantees
Copy is the default. Destinations are claimed exclusively and never overwritten.
Taken names become _001, _002, and so on. The resolved output tree is
excluded from scans. Unreadable subdirectories are skipped without aborting the
run; mistyped PATH values raise a configuration error (exit 2).
Filename formats
| Format | Pattern | Example |
|---|---|---|
datetime |
YYYY-MM-DD_HH-MM-SS.ext |
2026-08-01_14-55-22.jpg |
source |
YYYY-MM-DD_HH-MM-SS_Source.ext |
2026-08-01_14-55-22_WhatsApp.jpg |
source-first |
Source_YYYY-MM-DD_HH-MM-SS.ext |
WhatsApp_2026-08-01_14-55-22.jpg |
Extensions are preserved and lowercased.
Metadata and timestamps
Every output filename uses a resolved timestamp as YYYY-MM-DD_HH-MM-SS.
Image priority
- EXIF
DateTimeOriginal - EXIF
DateTimeDigitized - EXIF
DateTime - Filesystem modification time (when the mode allows fallback)
Video priority
MediaInfo recorded/creation/encoded/tagged dates, then filesystem modification time. Install the MediaInfo system package for embedded video timestamps.
Timestamp modes
| Mode | Behaviour |
|---|---|
auto |
Embedded metadata when available, otherwise filesystem mtime |
exif |
Embedded only (EXIF or MediaInfo); missing dates fail that file |
filesystem |
Always use filesystem mtime |
--timezone ZONE accepts IANA identifiers such as Europe/London. The tool
reads metadata only; it never rewrites EXIF or video tags.
Source detection
Rules are case-insensitive; the first match wins.
| Label | Patterns |
|---|---|
IMG-…-WA…, VID-…-WA… |
|
| Telegram | Photo_…, Video_… |
| Signal | signal-…, or a name ending with _signal before its extension |
| Pixel | PXL_… |
| Samsung | eight digits then _ (for example 20260801_…) |
| iPhone | IMG_ followed by four digits |
| Screenshot | Screenshot…, Screen Shot…, Screen_… |
| Camera | DSC_…, DSCF… |
| Unknown | anything else |
Detection uses the original filename only — not pixels or maker tags.
Architecture
CLI configuration
→ scan supported media
→ extract timestamp
→ detect source
→ build filename
→ resolve organised destination
→ reserve collision-safe name
→ copy or move
→ report and optionally log
Package layout uses Hatchling under src/lupaxa/photo_renamer/. The console
entry point is lupaxa.photo_renamer.cli:main.