Photo Renamer
lupaxa-photo-renamer safely copies or moves photographs and videos into
consistent, date-based filenames. It reads image EXIF or video metadata when
available, falls back to filesystem modification time in the default mode,
detects common source apps, and reports progress with
Rich.
A Rich terminal screenshot will be added under
mkdocs/assets/. Until then, the startup panel, progress bar, and summary table are shown directly in your terminal.
Installation
Python 3.13 or newer is required.
pip install lupaxa-photo-renamer
For local development:
git clone https://github.com/lupaxa-miscellaneous-toolbox/photo-renamer.git
cd photo-renamer
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
Video timestamp extraction uses MediaInfo. If it is unavailable on your system, install the MediaInfo package with your operating system's package manager.
Quick start
Preview the work first:
photo-renamer --dry-run --recursive ~/Pictures
Then run the same command without --dry-run:
photo-renamer --recursive ~/Pictures
By default, files are copied, originals remain untouched, and results are
written below PATH/renamed/. Existing relative directories are preserved:
Pictures/holiday/day-1/IMG-20260801-WA0001.JPG
→ Pictures/renamed/holiday/day-1/2026-08-01_14-55-22.jpg
Use --move only when you intentionally want to remove each successfully
processed source.
Common examples
# Include a detected source label in each filename
photo-renamer --recursive --format source ~/Pictures
# --preserve-source is an alias for --format source
photo-renamer --preserve-source ~/Pictures
# Put a source folder inside each preserved relative path
photo-renamer --recursive --organise ~/Pictures
# → renamed/holiday/day-1/WhatsApp/2026-08-01_14-55-22.jpg
# Drop relative paths, retaining only source folders
photo-renamer --recursive --flatten --organise ~/Pictures
# → renamed/WhatsApp/2026-08-01_14-55-22.jpg
# Choose another output root and move instead of copy
photo-renamer --recursive --output /Volumes/Archive --move ~/Pictures
Flag summary
| Flag | Purpose |
|---|---|
--output DIR |
Output root; defaults to renamed under PATH |
--recursive |
Scan subdirectories; off by default |
--dry-run |
Plan and report without writing |
--move |
Move files instead of copying |
--timestamp auto|exif|filesystem |
Select the timestamp strategy |
--format datetime|source|source-first |
Select the filename format |
--preserve-source |
Alias for --format source |
--organise |
Nest the detected source inside the relative path |
--flatten |
Remove relative path segments from destinations |
--include EXT,... |
Process only listed supported extensions |
--exclude EXT,... |
Exclude listed extensions |
--skip-existing |
Skip files already matching a target naming pattern |
--force |
Process matching names even with --skip-existing |
--timezone ZONE |
Convert timestamps to an IANA zone before naming |
--log-file PATH |
Append a tab-separated audit log |
--workers N |
Concurrent copy/move workers (default 1) |
--yes / -y |
Assume yes for over-cap workers confirmation |
--verbose / --quiet |
Increase or suppress terminal output |
Run photo-renamer --help for the authoritative command syntax.
Filename formats
| Format | Example |
|---|---|
datetime |
2026-08-01_14-55-22.jpg |
source |
2026-08-01_14-55-22_WhatsApp.jpg |
source-first |
WhatsApp_2026-08-01_14-55-22.jpg |
Extensions are preserved and lowercased. datetime is the default.
Supported formats
| Kind | Extensions |
|---|---|
| Images | JPG, JPEG, PNG, HEIC, HEIF, WebP, TIF, TIFF |
| Videos | MP4, MOV, AVI, MKV, M4V, 3GP |
--include and --exclude filter this supported set; they do not enable
arbitrary formats.
Safety
| Guarantee | Behaviour |
|---|---|
| Copy by default | Moving requires --move |
| Dry run | --dry-run performs no file or log writes |
| Never overwrite | Collisions receive _001, _002, and so on |
| Output excluded | The resolved output tree is never scanned |
| Continue on errors | Per-file I/O errors are reported; later files still process |
| Non-zero on failure | The command exits non-zero if any file failed |
Troubleshooting
| Symptom | What to try |
|---|---|
| No files scanned | Add --recursive; check --include / --exclude |
| Missing metadata | Use --timestamp auto or --timestamp filesystem |
| Video dates not found | Install MediaInfo; auto still falls back to mtime |
| Wrong wall-clock time | Pass an IANA zone such as --timezone Europe/London |
Unexpected _001 suffix |
Destination already existed or was reserved in the same run |
See the usage guide for more detail.
FAQ
| Question | Answer |
|---|---|
| Does it change metadata? | No. It copies or moves files and changes destination names only. |
| Does it find duplicate photos? | No. Collisions prevent overwrites; they are not content hashes. |
| Can I undo a move? | Not in v1. Prefer copy mode, --dry-run, and --log-file. |
What does --preserve-source preserve? |
The source label in the filename (--format source), not originals. |
| Where do unknown sources go? | They use the Unknown label when naming or organising by source. |
Testing
make init
make python-install-dev
make python-check
Or without Make:
python -m pip install -e ".[test]"
pytest
Coverage for lupaxa.photo_renamer is reported by default.
Documentation
The published guide is at https://photo-renamer.thelupaxaproject.org/.
Site Markdown lives in mkdocs/.
python -m pip install -r requirements.txt
make mkdocs-serve
make mkdocs-build builds the site. A strict build is python -m mkdocs build --strict.
This project is released under the MIT License; see LICENCE.
Metadata
Release files for lupaxa-photo-renamer 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lupaxa_photo_renamer-0.1.4.tar.gz | 17.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lupaxa_photo_renamer-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.1 kB
Release files / lupaxa_photo_renamer-0.1.4.tar.gz
| Download URL | lupaxa_photo_renamer-0.1.4.tar.gz |
|---|---|
| Size | 17.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f7821b663a628ae06469b687b0ceea169bca1a4786799100167f22bafa3680de
|
|
BLAKE2b-256 checksum How to use checksums |
896e6c29fa52d0440986b7382542ded94ca3e935d13fdc8d55aeb43d25d70c65
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / lupaxa_photo_renamer-0.1.4-py3-none-any.whl
| Download URL | lupaxa_photo_renamer-0.1.4-py3-none-any.whl |
|---|---|
| Size | 22.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5692fdca389d823ce447ed3efbab4fcb4c3b3097ca94c31237057af4ff42da69
|
|
BLAKE2b-256 checksum How to use checksums |
a7810ad189dabdeeb6d8c4b1bd3e6248189bd26687990c0d34e45ba6ab6bb5ef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log