A photo culling tool for reviewing and organizing photos before importing to your photo library.
Riffle handles the curation stage between camera and photo library. Import photos, review and rate them, then export selected photos to Immich, PhotoPrism, Google Photos, iCloud Photos, or other photo management software.
Import → Curate → Library → Export
Import
- Exact duplicate detection using SHA256 hashing
- Smart candidate selection based on EXIF metadata
- Organizes photos by date into
YYYY/MM - MonthName/folders - Pre-generates thumbnails for fast gallery loading
- Preserves EXIF metadata and file timestamps
- Supports HEIC, HEIF, MOV, MP4, and common image formats
Library
- Browse organized photos in masonry grid layout
- Burst detection for rapid-fire sequences (configurable)
- Photo metadata display (camera, settings, GPS)
- Image lightbox with full-screen view
- Side-by-side compare mode for detailed photo comparison
- Video playback support
Curate (Photo Culling Interface)
- Fast keyboard-driven review (P/X/U/1-5/C)
- Accept, reject, unflag, or rate photos quickly
- Full-screen lightbox curation with auto-advance
- Side-by-side compare mode for choosing between similar shots
- Visual progress tracking
- Undo with fade-out animations
Trash (Virtual Safety Net)
- Review rejected photos before final deletion
- No immediate file deletion
- Easy recovery of mistakenly rejected photos
Calendar
- Month-by-month grid
- Cover photos for each month
Albums
- Organize photos into custom collections
- Add/remove photos from multiple albums
Stats
- Analytics dashboard showing photo collection statistics over time
- Stacked bar charts grouped by decade
- Breakdown by curated, uncurated, and trashed photos
Settings
- Import configuration (folder path, move/copy mode, history)
- Library management (folder paths, storage stats, rebuild thumbnails)
- Burst detection (enable/disable, time window, similarity threshold, rebuild)
- Export configuration (folder path, organization, deduplication, cleanup)
Export
- Filter photos by minimum rating (0-5) and curation status
- Configurable folder organization (maintain structure or flatten)
- Duplicate handling options (skip or include)
- Optional cleanup (delete from library after export)
- Session tracking with per-photo export status logging
- Preserves original file timestamps
- Export to folder for import into other photo management software
services:
riffle:
image: ghcr.io/sheshbabu/riffle/riffle:latest
ports:
- "8080:8080"
volumes:
- ./data:/data
- ./import:/import
- ./library:/library
- ./thumbnails:/thumbnails
- ./export:/export
restart: unless-stoppedInstall system dependencies:
# macOS
brew install exiftool ffmpeg libheif vips
# Linux
apt-get install libimage-exiftool-perl ffmpeg libheif-dev libvips-devBuild from source:
$ make buildCreate .env file in the project root:
cp .env.example .envEdit .env and set your folder paths:
IMPORT_PATH=/path/to/import/folder
LIBRARY_PATH=/path/to/library
THUMBNAILS_PATH=/path/to/thumbnails
EXPORT_PATH=/path/to/export
Start the server:
$ ./riffleOpen your browser to http://localhost:8080
Run development server with auto-reload:
$ make watchOr run once:
$ make devThis project uses offline reverse geocoding with data from GeoNames. Location data is stored locally for fast lookups without network requests.
Note that cities1000 dataset includes places with population > 1000, providing city-level accuracy.
Download React:
curl -L -o assets/react.production.min.js https://cdn.jsdelivr.net/npm/react@18.3.1/umd/react.production.min.js
curl -L -o assets/react-dom.production.min.js https://cdn.jsdelivr.net/npm/react-dom@18.3.1/umd/react-dom.production.min.js- go-exiftool - EXIF metadata extraction
- go-sqlite3 - SQLite database driver
- goimagehash - Perceptual image hashing
- goheif - HEIC/HEIF format support
- bimg - Fast image processing with libvips
- golang.org/x/image - Extended image format support