Skip to content

SciTee/snapsort

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SnapSort

Throw all your photos into one place — phone exports, camera dumps, WhatsApp saves, random downloads — and before long you have thousands of files in a single folder, full of duplicates and names like IMG-20210815-WA0007.jpg. SnapSort brings order to that mess. It sorts the pile into a clean year/month structure based on when each photo was actually taken, and removes duplicate files reliably by looking at their contents.

It is a single, fast command-line tool, and it is built to be safe with an irreplaceable photo library: by default it runs as a dry run and only tells you what it would do. Nothing moves until you explicitly say so.

before/                          after/
├── IMG_1234.jpg                 ├── 2021/
├── IMG-20210815-WA0007.jpg      │   └── 08/
├── DCIM/                        │       ├── IMG_1234.jpg
│   └── DSC_0001.JPG             │       └── DSC_0001.jpg
├── Downloads/                   ├── 2022/
│   └── photo (copy).jpg         │   └── 03/
└── photo.jpg   ← duplicate      │       └── photo.jpg
                                 └── (duplicate skipped)

Safety first: it's a dry run by default

The thing you do not want when tidying a photo archive is a tool that starts moving thousands of files on the first try. So SnapSort inverts the usual default:

  • Without --apply, SnapSort only scans, plans, and prints what it would do. It does not create, move, copy, or delete a single file.
  • With --apply, it carries out exactly that plan. Even then it never overwrites an existing file — colliding names get a numeric suffix — and a failure on one file is reported without stopping the rest.

So the safe workflow is always: look at the dry run first, then apply.

# 1. See what would happen (safe, changes nothing)
snapsort ~/Pictures/unsorted

# 2. Happy with the plan? Do it for real.
snapsort ~/Pictures/unsorted --apply

Features

  • Sorts into a configurable folder structure (default YYYY/MM) using the EXIF capture date, falling back to the file's modification time.
  • Content-based duplicate detection — finds duplicates even when the file names differ.
  • Dry run by default; changes require --apply.
  • Configurable file-name pattern (e.g. %Y-%m-%d_%H%M%S).
  • Never overwrites: name collisions get unique suffixes.
  • Closing summary (moved / skipped / duplicates / errors).
  • Optional --copy mode that leaves the originals in place.

Options

Option Description
<SOURCE> Directory to scan (required).
-d, --dest <DIR> Destination root. Defaults to <source>/sorted.
--apply Actually move files. Without it, SnapSort only prints the plan.
--copy Copy instead of move, leaving the originals untouched.
--dir-pattern <PATTERN> Folder layout. Default %Y/%m.
--name-pattern <PATTERN> Rename files using a pattern. Default: keep original names.
--ext <EXT> Restrict to these extensions (repeatable). Default: a built-in media list.
-v, --verbose Debug-level logging (to stderr).

Pattern tokens

Both --dir-pattern and --name-pattern understand the same date tokens:

Token Meaning Example
%Y year, 4 digits 2021
%m month, zero-padded 08
%d day, zero-padded 15
%H hour (24h) 14
%M minute 30
%S second 05
%% a literal percent %

For example, --name-pattern '%Y-%m-%d_%H%M%S' turns DSC_0001.JPG into 2021-08-15_143005.jpg (the original extension is kept).

How duplicate detection works

SnapSort hashes the contents of every file with BLAKE3. Two files with the same hash are byte-for-byte identical, so renamed copies are still recognised — no matter how they were transferred between devices or apps. Within a group of identical files, the one with the shortest, tidiest path is kept and the rest are skipped.

Example output

$ snapsort ~/Pictures/unsorted
DRY RUN — 4 file(s) scanned under /home/me/Pictures/unsorted (pass --apply to perform)
  move /home/me/Pictures/unsorted/IMG_1234.jpg -> /home/me/Pictures/unsorted/sorted/2021/08/IMG_1234.jpg
  move /home/me/Pictures/unsorted/DCIM/DSC_0001.JPG -> /home/me/Pictures/unsorted/sorted/2021/08/DSC_0001.jpg
  skip /home/me/Pictures/unsorted/photo.jpg (duplicate of /home/me/Pictures/unsorted/IMG_1234.jpg)
Summary: 2 to move, 1 duplicate(s) skipped, 0 without a date, 0 error(s)

Installation

From source

With a Rust toolchain installed:

cargo install --path .

or build a release binary directly:

cargo build --release
# binary at target/release/snapsort

Prebuilt binaries

Tagged releases ship prebuilt binaries for Linux, Windows and macOS, built by CI. Grab the archive for your platform from the Releases page, unpack it, and put snapsort somewhere on your PATH.

Roadmap

  • More date sources (video metadata, sidecar files).
  • A --by-day style layout and richer pattern tokens.
  • Maybe a small GUI down the line; the CLI stays the core.

License

MIT — see LICENSE.

About

Sort messy photo collections into a clean year/month structure and remove duplicates — a safe, dry-run-by-default CLI.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages