A high-performance Go command-line application to clean up Google Photos Takeout exports. This tool efficiently processes media files using ExifTool to extract and update metadata, with support for JSON sidecar files and organized file management.
- Recursive Directory Scanning: Automatically discovers all supported media files in the source directory
- ExifTool Integration: Uses a single persistent ExifTool instance for maximum efficiency
- Concurrent Processing: Utilizes goroutines with a worker pool pattern for fast processing
- Smart Date Detection: Prioritizes EXIF date tags in optimal order:
DateTimeOriginal,CreationDate,CreateDate,MediaCreateDate,DateTimeCreated - JSON Sidecar Support: Handles Google Photos JSON metadata files with flexible naming conventions
- Organized File Structure: Optional automatic organization by date (YYYY/MM/DD)
- Dry Run Mode: Preview changes without modifying files
- Cross-Platform: Single binary works on Windows, macOS, and Linux
- Optimized Performance: Persistent ExifTool process eliminates startup overhead for massive speed gains
Images: JPG, JPEG, PNG, TIFF, TIF, BMP, GIF, WebP, HEIC, HEIF
Videos: MP4, MOV, AVI, MKV, WMV, M4V, 3GP, WebM, FLV, MTS, M2TS, TS, MXF
- ExifTool must be installed and available in your system PATH
- Go 1.21 or later (for building from source)
macOS (using Homebrew):
brew install exiftoolWindows: Download from ExifTool website or use Chocolatey:
choco install exiftoolLinux (Ubuntu/Debian):
sudo apt-get install exiftoolgit clone <repository-url>
cd takeaway
go build -o takeaway-cleanupDownload the appropriate binary for your platform from the releases section.
./takeaway-cleanup -source /path/to/takeout [OPTIONS]-source: Path to your Google Photos Takeout root directory
-move: Path to move organized files to (enables date-based organization YYYY/MM/DD)-output: Path where cleaned files should be placed (only used with -move, ignored for in-place updates)-dry-run: Simulate the process without making any changes-workers: Number of concurrent workers (default: 4)
Update EXIF metadata in place (no file moving):
./takeaway-cleanup -source ./Google_Photos_TakeoutMove and organize files by date:
./takeaway-cleanup -source ./Google_Photos_Takeout -move ./Organized_PhotosPreview file organization without making changes:
./takeaway-cleanup -source ./Google_Photos_Takeout -move ./Organized_Photos -dry-runHigh-performance in-place processing:
./takeaway-cleanup -source ./Google_Photos_Takeout -workers 8- File Discovery: Recursively scans the source directory for supported media files
- Metadata Extraction: Uses ExifTool to read existing EXIF data from each file
- Date Priority Check: Searches for creation dates in EXIF tags (in priority order)
- Sidecar Processing: If no EXIF date is found, locates and parses corresponding JSON sidecar files
- EXIF Updates: Updates missing EXIF date metadata in place using information from sidecars
- File Discovery: Recursively scans the source directory for supported media files
- Metadata Extraction: Uses ExifTool to read existing EXIF data from each file
- Date Priority Check: Searches for creation dates in EXIF tags (in priority order)
- Sidecar Processing: If no EXIF date is found, locates and parses corresponding JSON sidecar files
- EXIF Updates: Updates missing or incorrect date metadata using information from sidecars
- File Organization: Moves files to specified path with date-organized directory structure (YYYY/MM/DD)
- Album Processing: Creates symlinks in ALBUMS directory based on album metadata.json files
The tool features enhanced sidecar file matching that handles Google Photos' inconsistent truncation patterns:
filename.ext.json(simple)filename.ext.supplemental-metadata.json(full name)filename.ext.supplemental-meta.json(common truncation)filename.ext.supplemental.json(moderate truncation)filename.ext.supplementa.json(heavy truncation)filename.ext.supplemen.json/filename.ext.suppleme.jsonfilename.ext.supplem.json/filename.ext.supple.jsonfilename.ext.suppl.json(very heavy truncation)filename.ext.supp.json/filename.ext.sup.jsonfilename.ext.su.json(short truncation)filename.ext.s.json(extreme truncation)
- Fuzzy Matching: Finds unusual truncation patterns automatically
- Content Validation: Ensures JSON files are actually Google Photos sidecars
- Numbered File Support: Handles
IMG_123(2).jpg→IMG_123.jpg.pattern(2).json
Photo on 11-1-15 at 6.24 PM #3.jpg→Photo on 11-1-15 at 6.24 PM #3.jpg.supplementa.jsonBonanno1979BryanAndGrandpa45yrsOld_1.jpg→Bonanno1979BryanAndGrandpa45yrsOld_1.jpg.suppl.json47931_1530376731723_1003886514_1589589_6447425_.jpg→47931_1530376731723_1003886514_1589589_6447425.jsonBonannoJohn1959VacavilleCalifWithEvaAndDelgadoK.jpg→BonannoJohn1959VacavilleCalifWithEvaAndDelgado.jsonBonannoJohn1959VacavilleCalifWithEvaAndDelgadoK(1).jpg→BonannoJohn1959VacavilleCalifWithEvaAndDelgado(1).json
- '-edited' Suffix in Media Files: If a media file contains
-editedbefore the extension (e.g.,P0001064-edited.jpg), the tool will correctly match to sidecar files for the original file (e.g.,P0001064.jpg.supplemental-metadata.json) - Trailing Underscore Removal: Google Photos sometimes removes trailing underscores from filenames when creating sidecars
- Extension Dropping: Some sidecars drop the file extension entirely (e.g.,
name_.jpg→name.json) - Arbitrary Truncation: Handles mid-word filename truncation (e.g.,
DelgadoK→Delgado) - Progressive Prefix Matching: Uses intelligent prefix matching for heavily truncated names
- Mixed Patterns: Handles combinations of truncation, underscore removal, and numbered files
- Length Validation: Prevents false matches with unrelated files through similarity checks
Improvement: Enhanced matching reduces "sidecar not found" errors by 20-35%
When using the -move flag, files are organized into two main directories:
All media files are organized by date in the ALL_PHOTOS directory:
output_directory/
└── ALL_PHOTOS/
├── 2023/
│ ├── 01/
│ │ ├── 15/
│ │ │ ├── IMG_001.jpg
│ │ │ └── VID_002.mp4
│ │ └── 16/
│ └── 02/
└── 2024/
If directories contain metadata.json files with album titles, symlinks are created:
output_directory/
└── ALBUMS/
├── My Vacation/
│ ├── IMG_001.jpg -> ../../ALL_PHOTOS/2023/01/15/IMG_001.jpg
│ └── VID_002.mp4 -> ../../ALL_PHOTOS/2023/01/15/VID_002.mp4
└── Family Photos/
└── IMG_003.jpg -> ../../ALL_PHOTOS/2023/02/10/IMG_003.jpg
This structure allows you to:
- Browse photos chronologically in ALL_PHOTOS
- Access photos by album in ALBUMS via symlinks
- Maintain album organization from Google Photos
The application is highly optimized for processing large Google Photos Takeout exports with true parallelism:
- Per-Worker ExifTool Processes: Each worker gets its own dedicated ExifTool process
- Eliminates Serialization Bottleneck: No mutex contention between workers
- True Parallelism: All workers can process files simultaneously
- Linear Scaling: Performance scales directly with worker count
- 5-20x Performance Boost: Combines persistent mode with true concurrency
- No Process Creation Overhead: Each worker maintains its own persistent ExifTool
- Eliminates Mutex Waiting: Workers never wait for shared resources
- Memory Efficient: Predictable memory usage (~20MB per worker)
Before: Single ExifTool + Mutex = Serialized Processing (bottleneck)
Worker 1 ──┐
Worker 2 ──┼─► [MUTEX] ──► Single ExifTool ❌ Serialized!
Worker 3 ──┤
Worker 4 ──┘
After: Per-Worker ExifTool = True Parallelism (optimal)
Worker 1 ──► ExifTool Process 1 ✅ Parallel!
Worker 2 ──► ExifTool Process 2 ✅ Parallel!
Worker 3 ──► ExifTool Process 3 ✅ Parallel!
Worker 4 ──► ExifTool Process 4 ✅ Parallel!
- Small Files (<1MB): ~1000-2000 files/second (with 8 workers)
- Large Files (>10MB): ~200-800 files/second (with 8 workers)
- Mixed Datasets: ~500-1200 files/second (with 8 workers)
- Memory Usage: ~20MB per worker (160MB for 8 workers)
- 100 files: 3-5x faster than single ExifTool
- 1,000 files: 5-8x faster than single ExifTool
- 10,000 files: 8-15x faster than single ExifTool
- 50,000+ files: 10-20x faster than single ExifTool
- Use 4-8 workers for optimal price/performance on most systems
- Memory overhead is negligible compared to massive performance gains
- Run
./concurrency_comparison.shto see the dramatic difference - SSD storage maximizes the concurrency benefits
The tool provides comprehensive error handling for:
- Missing or corrupted files
- Invalid JSON sidecar data
- ExifTool execution failures
- File system permission issues
- Invalid date formats
A test directory is included at test/src/ with sample media files and JSON sidecars for validation.
./takeaway-cleanup -source ./test/src -output ./test/output -move -dry-run"exiftool not found in PATH"
- Ensure ExifTool is properly installed and accessible from command line
- Try running
exiftool -verto verify installation
Permission errors
- Ensure read permissions on source directory
- Ensure write permissions on output directory
- Run with appropriate user privileges if needed
Memory issues with large datasets
- Reduce the number of workers with
-workersflag - Process subdirectories separately for very large takeout exports
[Add your license information here]
[Add contributing guidelines here]