A powerful command-line tool to organize and rename photos and videos based on their EXIF creation date, with support for batch processing Google Photos takeouts.
- ✅ Smart Date Detection: Uses EXIF data for images, filename patterns for videos/GIFs
- ✅ Batch Processing: Process multiple Google Photos takeout zip files automatically
- ✅ Progressive Mode: Process zip files one at a time with user control
- ✅ Live Photo Cleanup: Remove .mov files that match photo names (iPhone live photos)
- ✅ Intelligent Organization: Year/month folder structure with sequential numbering
- ✅ Dry Run Mode: Safe testing without making any changes
- ✅ Comprehensive Statistics: Detailed reporting of all operations
- ✅ Error Recovery: Robust error handling with cleanup on failures
- ✅ Interactive Controls: Quit anytime with 'Q' or Ctrl+C in progressive mode
- ✅ Conflict-Safe Processing: Automatic file renaming prevents overwriting existing photos
npm install
Organize photos and videos in a directory based on their creation dates.
# Basic usage
node src/index.js <directory> [options]
# Examples
node src/index.js /path/to/photos
node src/index.js /path/to/photos --dry-run --verbose
Options:
-d, --dry-run
- Show what would be done without making changes-v, --verbose
- Show detailed output during processing
Remove .mov files that match photo names (iPhone live photos).
node src/index.js cleanup-live <directory> [options]
# Examples
node src/index.js cleanup-live /path/to/photos --dry-run
node src/index.js cleanup-live /path/to/photos --debug --verbose
Options:
-d, --dry-run
- Show what would be done without making changes-v, --verbose
- Show detailed output during processing--debug
- Show detailed matching information for each file pair
Process multiple Google Photos takeout zip files automatically.
node src/index.js batch <source-directory> <target-directory> [options]
# Examples
node src/index.js batch /Users/john/Downloads /Users/john/Photos
node src/index.js batch /Downloads /Photos --progressive
Options:
-p, --progressive
- Process one zip file at a time (interactive mode)- Global options (
--dry-run
,--verbose
) also apply
When using --progressive
mode:
- Enter/Space - Continue to next zip file
- Q - Quit gracefully (shows final statistics)
- Ctrl+C - Immediate exit
- Extraction: Each zip file is extracted to a temporary directory
- Detection: Automatically finds the Google Photos folder within Takeout structure
- Organization: Organizes photos by date using the same logic as the main command
- Conflict-Safe Merging: Copies organized files to the target directory with automatic conflict resolution
- Cleanup: Removes temporary files and original zip files after successful processing
When files with the same name exist in the target directory, the tool automatically renames the incoming file to avoid overwriting existing photos. For example:
- Existing:
2023-01-15_001.jpg
- Incoming:
2023-01-15_001.jpg
→ Renamed to:2023-01-15_002.jpg
This ensures no photos are ever lost or overwritten during batch processing.
- JPEG (.jpg, .jpeg)
- PNG (.png)
- TIFF (.tiff, .tif)
- BMP (.bmp)
- WebP (.webp)
- HEIC/HEIF (.heic, .heif)
- RAW formats (.raw, .cr2, .nef, .arw, .dng)
- MP4 (.mp4)
- AVI (.avi)
- MOV (.mov)
- MKV (.mkv)
- WMV (.wmv)
- FLV (.flv)
- WebM (.webm)
- M4V (.m4v)
- GIF (.gif) - uses filename patterns (EXIF unreliable for GIFs)
DateTimeOriginal
- When photo was actually takenCreateDate
- Alternative creation dateDateTime
- File modification date in cameraDateTimeDigitized
- When photo was digitized
Recognizes these patterns in filenames:
20220416_073730.mp4
→ 2022-04-16VID_20200624_205041.avi
→ 2020-06-24IMG_20210315_142530.gif
→ 2021-03-15- Any
YYYYMMDD
pattern (years 2009-2025)
Note: Video metadata is not used as it often contains file creation dates rather than actual recording dates.
If no EXIF date or filename pattern is found, uses file modification time.
Files are organized into a year/month hierarchy with sequential numbering:
target-directory/
├── 2023/
│ ├── 01/ # January 2023
│ │ ├── 2023-01-15_001.jpg
│ │ ├── 2023-01-15_002.jpg
│ │ └── 2023-01-20_001.mp4
│ └── 02/ # February 2023
│ └── 2023-02-10_001.jpg
└── 2024/
└── 03/ # March 2024
├── 2024-03-20_001.heic
└── 2024-03-20_002.mov
All commands provide comprehensive statistics:
- Files processed (images, videos, total)
- Files moved and renamed
- JSON files removed (Google Photos metadata)
- Live videos removed (cleanup command)
- Empty directories removed
- Errors encountered
- Files copied to target (batch mode)
- Files renamed to avoid conflicts (batch mode)
- Graceful recovery: Errors with individual files don't stop processing
- Cleanup on failure: Temporary files are removed even if processing fails
- Progressive mode safety: Errors stop processing to allow manual intervention
- Detailed error reporting: Verbose mode shows full error details
{
"chalk": "^4.1.2",
"ora": "^5.4.1",
"commander": "^9.4.1",
"exifr": "^7.1.3",
"fs-extra": "^10.1.0",
"yauzl": "^2.10.0"
}
- Always test first: Use
--dry-run
to see what will happen - Use progressive mode: For large batch operations, use
--progressive
to control the process - Check statistics: Review the final statistics to ensure everything processed correctly
- Backup important data: While the tool is safe, always backup irreplaceable photos
- Verbose output: Use
--verbose
for troubleshooting or detailed progress information
node src/index.js /Users/john/Photos --dry-run --verbose
node src/index.js /Users/john/Photos
# Progressive mode for control
node src/index.js batch /Users/john/Downloads /Users/john/OrganizedPhotos --progressive
# Automatic processing
node src/index.js batch /Users/john/Downloads /Users/john/OrganizedPhotos
node src/index.js cleanup-live /Users/john/Photos --dry-run --debug
node src/index.js cleanup-live /Users/john/Photos