Releases: jaimetur/PhotoMigrator
v4.0.0
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases
Release: v4.0.0
Release Date: 2026-03-20
🚨 Breaking Changes:
🌟 New Features:
- Added full NextCloud Photos integration (WebDAV-based) across CLI, execution modes, automatic migration, and web interface (Issue: #567).
- Added a dedicated
NextCloud Photostab in the web interface, placed betweenImmich PhotosandOther Features(Issue: #567). - Added
ClassNextCloudPhotosbackend service with album/assets upload, download, cleanup, and rename/remove workflows. - Added Google Photos integration (official Library API based) across CLI, execution modes, automatic migration, and web interface.
- Added a dedicated
Google Photostab in the web interface (next toGoogle Takeout). - Added Administration Panel for admin users to create/edit/delete users and configure per-user subpaths for
/app/dataand/app/volumes. - Added per-user
Config.inipersistence in SQLite database, encrypting sensitive values at rest. - Added structured Configuration File tab editor based on sections/fields (Google Takeout, Google Photos, Synology Photos, Immich Photos, NextCloud Photos, TimeZone) with per-field help extracted from config comments.
- Added a new
Upload to Servertab in the web interface with destination-folder picker, separateUpload Local FolderandUpload Local Zipactions, and optional ZIP extraction mode (Extract ZIPs on upload: Yes/No). - Added
ClassGooglePhotosbackend service with OAuth refresh-token auth and supported upload/download modules. - Added secure multi-user mode in Docker Web Interface with login/session authentication and bootstrap admin credentials (
admin/admin123by default). - Added a dedicated
Background Progresspanel in Automatic Migration Live Dashboard to render Local Folder analysis progress (folder scan + files scan in current folder) without polluting the logs panel. (Issue #1037)
🚀 Enhancements:
- Extended automatic migration endpoint parsing in web UI to support
nextcloud[-photos][-1..3]for both source and target. - Added Google Photos OAuth credentials support in
Config.iniand config loader ([Google Photos]section with account 1/2/3). - Extended automatic migration endpoint parsing in web UI to support
google[-photos][-1..3]for both source and target. - Updated CLI/source-target validation and help text to include
nextcloudandgoogle-photosas cloud clients. - Improved name-pattern handling across cloud modules: wildcard-only patterns like
*are now accepted for album selection, and literal patterns with special regex characters (for example album names containing parentheses) now work for matching/replacing without requiring manual escaping. - Improved album rename matching for literal album names containing regex metacharacters (such as parentheses), so rename workflows work without manual escaping.
- Improved markdown render to detect italic font and bold+italic.
- Improved album download progress visualization for cloud clients (NextCloud, Synology, Immich, Google Photos) by showing a nested per-album assets progress bar labeled as
Downloading '<AlbumName>' Assets. - Improved album upload progress visualization for cloud clients (NextCloud, Synology, Immich, Google Photos) by showing a nested per-album assets progress bar labeled as
Uploading '<AlbumName>' Assets. - Restricted folder/file browser API access to each user's assigned subfolders only, and enforced the same path restrictions at command execution time.
- Enhancements in Web UI.
- Forbidden Import/Export/Save configuration file in demo roles.
- Added NextCloud dual-folder configuration in
Config.iniand config loader with per-accountNEXTCLOUD_PHOTOS_FOLDER_<id>(assets/no-albums) andNEXTCLOUD_ALBUMS_FOLDER_<id>(folder-based albums). - Separated markdown render in a new static file
- Smoothed Automatic Migration Live Dashboard rendering by switching to manual refresh-on-change updates (dirty panels only), stabilizing Background Progress row order, and reducing completion-row churn to minimize panel flicker/tremor in CLI.
- Added vertical scroll to the
Access Logstable in the Administration Panel, limiting visible height (about 20 recent entries) while keeping older entries accessible by scrolling. - Improved
Background Progresslabel normalization to keep only text after:, trim trailing:variants (:,:,:), and remove trailing path clauses such asin .../in folder ...(Linux/Windows paths, quoted or unquoted). - Improved
Background Progresstitle normalization to keep only the text after:(when present) and then trim surrounding whitespace. - Improved CLI Live Dashboard Background Progress routing for Takeout post-processing
tqdmlines by accepting additional prefixes (includingTQDM ...) and indeterminate progress frames (for example81 files [00:00, ...]) so those updates are rendered in theBackground Progresspanel instead of the logs panel. - Improved CLI Live Dashboard responsiveness on terminal resize by syncing layout dimensions on each refresh cycle and recalculating visible
Logs Panelrows from the current panel height. - Refined CLI Live Dashboard log coloring rules to style only explicit Automatic Migration events (
Asset Pulled,Asset Pushed,Asset Duplicated,Album Created,Album Pulled,Album Pushed,Asset Fail/Failed) instead of broad keyword matches. - Updated GPTH to version 5.0.6 which includes several enhancements and bug fixing.
🐛 Bug fixes:
- Fixed web command/help text normalization so
--client=nextcloudexamples are parsed consistently in UI descriptions. - Fixed
Automatic Migrationcloud-session initialization for NextCloud and Google Photos clients by enabling lazy thread-safe auto-login on first API call, preventingsession is not initialized. Call login() firsterrors in source/target worker flows. - Fixed
Automatic Migrationdashboard crash in frozen binaries when Rich unicode tables are missing (ModuleNotFoundError: rich._unicode_data.unicode17-0-0) by adding packaging includes forrich._unicode_dataand graceful dashboard fallback. - Fixed NextCloud
Download All/Download Assetspath behavior to scanNEXTCLOUD_PHOTOS_FOLDER_<id>recursively while excludingNEXTCLOUD_ALBUMS_FOLDER_<id>when nested, preventing duplicate album downloads and supporting direct/Photoslayouts. - Other bug fixing.
📚 Documentation:
- Added NextCloud Photos help page and linked it from README/help index.
- Added Google Photos help page and linked it from README/help index.
- Updated CLI/configuration/automatic-migration docs to include NextCloud and Google Photos support.
- Changed header styles in help documents.
- Updated documentation with all changes.
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
Windows:
Docker Launcher:
Full Changelog: v3.8.0...v4.0.0
v3.8.0
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases
Release: v3.8.0
Release Date: 2026-03-17
🚨 Breaking Changes:
🌟 New Features:
- New Web Interface to configure and execute the different features & modules directly.
- Added themes support to Web Interface.
- Docker support to deploy the tool in docker and expose the new Web Interface (default port: 6078).
- New docker-compose.yml and .env file to easily configure and deploy the tool with docker compose.
- Added deterministic Live Photo upload support for Immich by pairing photo+video companions (same basename) and linking them through Immich API (
livePhotoVideoId) across Immich upload features and Automatic Migration. - Added automatic burst stacking for Immich uploads (including Automatic Migration) using conservative heuristics (same folder, normalized basename, short time window, and size-ratio guard), creating Immich stacks with preferred primary asset ordering.
🚀 Enhancements:
- Web Live Dashboard on Automatic Migration feature.
- Adjusted Goggle Photos Panel layout.
- Enhancements in Execution Log windows to parse progress bar properly.
- Allow page reload while task is running.
- Enhancements in Web interface layout and feature descriptions.
- Added confirmation dialog on those modules that remove/rename/merge assets/albums on Synology/Immich Photos features.
- Added confirmation dialog on Auto Rename Folders Content Based feature.
- Improved Immich
Remove Orphan Assetsmodule to detect unsupported newer Immich API versions and abort gracefully with a clear message instead of failing with a raw 404 error. - Added a safeguard in
organize_files_by_dateto skip files already organized in the expected date folder structure (year,year/month,year-month) and avoid redundant re-nesting. - Improved Web Interface execution log buffering for long-running jobs with progress bars: progress refresh updates no longer flood line history, the in-memory log is compacted by progress key, and default web log buffer size was increased and made configurable via
PHOTOMIGRATOR_WEB_MAX_JOB_OUTPUT_LINES. - Simplified docker-compose.yml file.
- Horizontal scroll on log panel when lines are too large.
- Improved markdown render for code blocks.
🐛 Bug fixes:
- Added validation for
--google-takeoutpath to block reserved special-folder names (Archive,Trash,Locked folder) and abort early with a clear message; same validation is enforced in Web UI folder selection (Issue #1008). - Fixed a queue accounting bug in
Automatic Migrationthat could stall execution when processing album folders still marked as active (.active) in parallel workers (Issue #1009). - Fixed
Automatic Migrationstartup with--log-level=DEBUGby passing profiling label arguments correctly toprofile_and_print(Issue #1009). - Fixed Google Takeout GPTH input root normalization to handle direct
Google Photospaths reliably (without copy fallback), preventing "Discover Media = 0" scenarios on NAS layouts (Issue #1013). - Fixed
LocalFolder.get_albums_owned_by_user()raisingUnboundLocalError(albums_filtered) when called withfilter_assets=Falseduring automatic migration album checks (Issue #1014). - Fixed Synology Live Photo downloads where ZIP payloads could be saved with
.HEIFextension; ZIP payloads are now detected and extracted properly (Issue #1028). - Fixed download/migration EXIF date overwrite behavior: EXIF date tags are now only filled when missing, preserving existing shooting dates (Issue #1029).
- Fixed Exiftool command line overflowing max length (#1052).
- Fixed Exiftool not embebed on docker-dev version.
- Fixed
Download All(Immich/Synology) creating redundantALL_PHOTOS/YYYY/MM/YYYY/MMfolders by avoiding a duplicate date-organization pass after assets are already downloaded directly intoYYYY/MM. - Fixed Immich album deletion status handling to treat HTTP
204 No Content(and any2xx) as success, avoiding false warnings likeFailed to remove album ... Status: 204. - Fixed Immich Live Photo linking reliability during uploads by retrying transient
404responses when settinglivePhotoVideoId, and skipping link attempts when either media component was uploaded as duplicate. - Fixed Web Interface log color classification to prioritize the explicit line log level prefix (e.g.
WARNING:), preventing warning lines from being painted as errors when message text contains words likeClient Error. - Fixed Web Interface active-job reconnect endpoint routing conflict by prioritizing
/api/jobs/_activeover dynamic/api/jobs/{job_id}matching, preventing false{"detail":"Job not found"}responses when querying active jobs. - Other bug fixing.
📚 Documentation:
- Included Documentation links on Web interface.
- Made link relatives to current release.
- Updated documentation with all changes.
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
Windows:
Docker Launcher:
What's Changed
- fix: stream Immich multipart upload to avoid OOM by @zhijiee in #1034
- Fixed stream Immich multipart upload to avoid OOM. by @jaimetur in #1040
- main to 3.8.0 by @jaimetur in #1042
- Fixed Exiftool command line overflowing max length by @stefan-sherwood in #1052
New Contributors
- @zhijiee made their first contribution in #1034
- @stefan-sherwood made their first contribution in #1052
Full Changelog: v3.6.2...v3.8.0
v3.7.1
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases+
Release: v3.7.1
Release Date: 2026-03-16
🚨 Breaking Changes:
🌟 New Features:
🚀 Enhancements:
🐛 Bug fixes:
- Fixed stream Immich multipart upload to avoid OOM.
📚 Documentation:
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
Windows:
Docker Launcher:
What's Changed
- fix: stream Immich multipart upload to avoid OOM by @zhijiee in #1034
- Fixed stream Immich multipart upload to avoid OOM. by @jaimetur in #1040
- main to 3.8.0 by @jaimetur in #1042
New Contributors
Full Changelog: v3.6.2...v3.7.1
v3.7.0
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases+
Release: v3.7.0
-
Release Date: 2026-01-09
-
Main Changes:
-
🚨 Breaking Changes:
-
🌟 New Features:
-
🚀 Enhancements:
- Most of the Code Translated into English.
-
🐛 Bug fixes:
-
📚 Documentation:
- Most of the Comments Translated into English.
- Updated documentation with all changes.
-
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
Windows:
Docker Launcher:
What's Changed
- 3.6.2 by @jaimetur in #992
- Bug fix file_path variable name and typo fix by @WizardOfYendor1 in #1012
- Bug fix file_path variable name and message spelling by @jaimetur in #1018
- Bug fix file_path variable name and message spelling (#1018) by @jaimetur in #1019
- 3.7.0 by @jaimetur in #1020
- main to 3.7.0 by @jaimetur in #1021
- main to 3.7.0 (#1021) by @jaimetur in #1022
- v3.7.0 by @jaimetur in #1023
- 3.7.0 by @jaimetur in #1024
New Contributors
- @WizardOfYendor1 made their first contribution in #1012
Full Changelog: v3.6.1...v3.7.0
v3.6.2
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases+
Release: v3.6.2
-
Release Date: 2025-09-11
-
Main Changes:
-
🚨 Breaking Changes:
- Now your special folders (
Archive,Trash,Locked folder) will be directly moved toSpecial Folderssubfolder within the output directory inGoogle Takeout Processingfeature.
- Now your special folders (
-
🌟 New Features:
- Added support for Special Folders management such as
Archive,Trash,Locked folderduringGoogle Takeout Processingfeature.
- Added support for Special Folders management such as
-
🐛 Bug fixes:
- Fixed bug in guess dates from filepath where it was looking into the grandparents folder even if the parent folder was not a month folder.
- Fixed bug in guess dates from filename where it was detecting false positives in filenames as hashnames (i.e.: "5752a2c4-1908-4696-9117-fdfa750fbd88.jpg" --> incorrect 1908).
- Fixed bug when extract zips that contains non-supporting folders for special system such as Synology NAS or SMB mounted devices such as folders ending with Whitespace that was renamed by the system as
*_ADMIN_Whitespace_conflict*. Now native extractor makes an intelligent sanitization of folder names before to extract the archive.
-
📚 Documentation:
- Updated documentation with all changes.
-
🚀 Enhancements:
-
Added new function to Sanitize (fix folders/files ending with spaces or dosts to avoid SMB mingling names) your Takeout input folder during
Google Takeout Procesing Feature. -
Improved
Folder Analyzerto read date tags from groups EXIF/XMP/QuickTime/Track/Media/Matroska/RIFF only (other groups are not reliable). -
Improved
Folder Analyzerto choose the oldest date with time when two or more candidates has the same date but one has time o other not. -
Improved
Auto Rename Albumsfeature to read date tags from groups EXIF/XMP/QuickTime/Track/Media/Matroska/RIFF only (other groups are not reliable). -
Improved
Auto Rename Albumsfeature to choose the oldest date with time when two or more candidates has the same date but one has time o other not. -
Updated GPTH to version
5.0.5(by @Xentraxx & @jaimetur) which includes new features, performance improvements and bugs fixing extracting metadata info from Google Takeouts. -
✨ GPTH New Features
- Added support for Special Folders management such as
Archive,Trash,Locked folder. Now those folders are excluded from all album strategies and are moved directly to the output folder.
- Added support for Special Folders management such as
-
🚀 GPTH Improvements
- Moved logic of each Step to step's service module. Now each step has a service associated to it which includes all the logic and interation with other services used by this step.
- Added percentages to all progress bars.
- Added Total time to Telemetry Summary in Step 3.
- Fixed _extractBadPathsFromExifError method to detect from exiftool output bad files with relative paths.
- Performance Improvements in
step_03_merge_media_entities_service.dart.- Now grouping method can be easily changed. Internal
_fullHashGroupis now used instead of 'groupIdenticalFast' to avoid calculate buckets again.
- Now grouping method can be easily changed. Internal
-
🐛 Bug Fixes
- Fixed duplicated files/symlinks in Albums when a file belong to more than 1 album (affected strategies: shortcut, reverse-shortcut & duplicate-copy).
- Fixed error decoding Exiftool output with UTF-8/latin chars.
-
-
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
Windows:
Docker Launcher:
What's Changed
- 3.6.2 by @jaimetur in #992
- Bug fix file_path variable name and typo fix by @WizardOfYendor1 in #1012
- Bug fix file_path variable name and message spelling by @jaimetur in #1018
- Bug fix file_path variable name and message spelling (#1018) by @jaimetur in #1019
- 3.7.0 by @jaimetur in #1020
- main to 3.7.0 by @jaimetur in #1021
- main to 3.7.0 (#1021) by @jaimetur in #1022
- v3.7.0 by @jaimetur in #1023
- 3.7.0 by @jaimetur in #1024
New Contributors
- @WizardOfYendor1 made their first contribution in #1012
Full Changelog: v3.6.1...v3.6.2
v3.6.1
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases+
Release: v3.6.1
-
Release Date: 2025-09-09
-
Main Changes:
-
🚀 Enhancements:
-
Now
Logs,Extracted_dates_metadata.jsonandDuplcicates.csvfiles are saved at Output folder by default whenGoogle Takeout Processingfeature is detected. -
Improved FixSymLinks to be case-insensitive when looking for real files of symlinks.
-
Improvements in Analysis Output Statistics to separate Physical and Symlinks files.
-
Show GPTH Tool and EXIF Tool version in Global Configuration settings at the beginning of the tool.
-
Updated GPTH to version
5.0.4(by @Xentraxx & @jaimetur) which includes new features, performance improvements and bugs fixing extracting metadata info from Google Takeouts.-
✨ GPTH New Features
- New album moving strategy
ignoreto completely ignore all Albums content. The difference withnothingstrategy is thatnothingdon't create Albums folders but process and move all Albums content intoALL_PHOTOSfolder.
- New album moving strategy
-
🚀 GPTH Improvements
- Replace all
print()functions bylogPrint()method from LoggerMixin class. In this way all messages are registered both on screen and also on the logger (and saved to disk if flag--save-logis enabled). - All console messages have now a Step prefix to identify from which step or service they come from.
- Moving Strategies re-defined
- Included Timeouts on ExifTool operations.
- Log saving enabled by default. Use flag
--no-save-logto disable it. - Changed log name from
gpth-{version}_{timestamp}.logtogpth_{version}_{timestamp}.log. - Added progress bar to Step 3 (Merge Media Entities).
- Changed default value for flag `--update-creation-time. Now is enabled by default.
- Smart split in writeBatchSafe: we parse stderr, separate only the conflicting files, retry the rest in a single batch, and write the conflicting ones per-file (without blocking progress). If paths can’t be extracted, we fall back to your original recursive split.
- Replace all
-
🐛 Bug Fixes
- Added
reverse-shortcutstrategy to interactive mode. - Fixed some moving strategies that was missing some files in the input folder
- Fixed exiftool_service.dart to avoid IFD0 pointer references.
- Fixed exiftool_service.dart to avoid use of -common_args when -@ ARGFILE is used.
- Fixed PNG management writting XMP instead of EXIF for those files.
- (ExifToolService): I added -F to the common arguments (_commonWriteArgs). It’s an immediate patch that often turns “Truncated InteropIFD” into a success.
- (Step 7): If we detect a “problematic” JPEG, we force XMP (CreateDate/DateTimeOriginal/ModifyDate + signed GPS), both when initially building the tags (via _forceJpegXmp) and again on retry when a batch fails and stderr contains Truncated InteropIFD (in-place conversion of those entries with _retagEntryToXmpIfJpeg).
- Added
-
-
-
🐛 Bug fixes:
- Fixed albums_input_folder in Move Albums step within
Google Takeout Processingfeature.
- Fixed albums_input_folder in Move Albums step within
-
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
Windows:
Docker Launcher:
Full Changelog: v3.6.0...v3.6.1
v3.6.0
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases+
Release: v3.6.0
-
Release Date: 2025-08-31
-
Main Changes:
-
🚨 Breaking Changes:
-
Auto-Rename Albums content basednow uses as dates separator-instead of.and as group of dates separator--instead of-. Those separators can be customized using two new parameters (see below).
-
-
🌟 New Features:
- Added new parameter
-dateSep, --date-separator <DATE_SEPARATOR>to specify the Dates Separator for the FeatureAuto-Rename Albums Content Based. - Added new parameter
-rangeSep, --range-separator <RANGE_OF_DATES_SEPARATOR>to specify the Range of Dates Separator for the FeatureAuto-Rename Albums Content Based. - Added new parameter
-gpthLog, --gpth-logto Save GPTH log messages into a log file withinLogsfolder.
- Added new parameter
-
🚀 Enhancements:
-
Improvements in
Auto Rename Albums Foldersfeature to Compute the best 'oldest_date' per file using the following priority:- date_dict
- EXIF native (piexif)
- EXIF exiftool
- Filesystem ctime
- Filesystem mtime
-
Updated GPTH to version
5.0.2(by @Xentraxx & @jaimetur) which includes new features, performance improvements and bugs fixing extracting metadata info from Google Takeouts.-
✨ GPTH New Features
- Support for 7zip and unzip extractors (if found in your system). This is because the native extractor does not extract properly filenames or dirnames with UTF-8/latin1 chars.
- Support new
Extrafiles from Google Takeout with following suffixes:-motion,-animation,-collage. - New flag
--keep-inputto Work on a temporary sibling copy of --input (suffix _tmp), keeping the original untouched. - New flag
--keep-duplicatesto keep duplicates files in_Duplicatessubfolder within output folder. - New flag
--save-logto save log messages into disk file. - Created GitHub Action
build-and-create-release.ymlto Automatically build all binaries, create new release (stable or pre-release), update it wiht the release-notes and upload the binaries to the new release. - Step 8 (Update creation time) is now multi-platform. Also update creation date for physical files and symlinks on linux/macos.
-
🚀 GPTH Improvements
- Created a single package gpth-lib with all the exported modules for an easier way to manage imports and refactoring.
- Added new flag
fallbackToExifToolOnNativeMissinGlobalConfigServiceClass to specify if we want to fallback to ExifTool on Native EXIF reader fail. (Normally if Native fails is because EXIF is corrupt, so fallback to ExifTool does not help). - Added new flag
enableExifToolBatchinGlobalConfigServiceClass to specify if we want to enable/disable call ExifTool with batches of files instead of one call per file (this speed-up a lot the EXIF writting time with ExifTool). - Added new flag
maxExifImageBatchSizeinGlobalConfigServiceClass to specify the maximum number of Images for each batch passed in any call to ExifTool. - Added new flag
maxExifVideoBatchSizeinGlobalConfigServiceClass to specify the maximum number of Videos for each batch passed in any call to ExifTool. - Added new flag
forceProcessUnsupportedFormatsinGlobalConfigServiceClass to specify if we want to forze process unsupported format such as.AVI,.MPGor.BMPfiles with ExifTool. - Added new flag
silenceUnsupportedWarningsinGlobalConfigServiceClass to specify if we want to recive or silence warnings due to unsupported format on ExifTool calls. - Added new flag
enableTelemetryInMergeMediaEntitiesStepinGlobalConfigServiceClass to enable/disable Telemetry in Step 3: Merge Media Entities. - Code Structure refactored for a better understanding and easier way to find each module.
- Code Refactored to isolate the execution logic of each step into the .execute() function of the step's class. In this way the media_entity_collection module is much clearer and easy to understand and maintain.
- Adapted all methods to work with this new structure
- Homogenized logs for all steps.
- New code re-design to include a new
MediaEntitymodel with the following attributes:albumsMap: List of AlbumsInfo obects, where each object represent the album where each file of the media entity have been found. This List which can contain many usefull info related to the Album.dateTaken: a single dataTaken for all the files within the entitydateAccuracy: a single dateAccuracy for all the files within the entity (based on which extraction method have been used to extract the date)dateTimeExtractionMethod: a single dateTimeExtractionMethod for all the files within the entity (method used to extract the dataTaken assigned to the entity)partnerShared: true if the entity is partnerSharedprimaryFile: contains the best ranked file within all the entity files (canonical first, then secondaries ranked by lenght of basename, then lenght of pathname)secondaryFiles: contains all the secondary files in the entityduplicatesFiles: contains files which has at least one more file within the entity in the same folder (duplicates within folder)
- Created internal/external methods for Class
MediaEntityfor an easy utilization. - All modules have been adapted to the new
MediaEntitystructure. - All Tests have been adapted to the new
MediaEntitystructure. - Removed
filesattribute fromMediaEntityClass. - Merged
media_entity_moving_strategy.dartmodule withmedia_entity_moving_service.dartmodule and now it is stored underlib/steps/step_06_moving_files/servicesfolder. - New behaviour during
Find Duplicatesstep:- Now, all identical content files are collected within the same MediaEntity.
- In a typical Takeout, you might have the same file within
Photos from yyyyfolder and within one or more Album folder - So, both of them are collected within the same entity and will not be considered as duplicated because one of them could have associated json and the others not
- So, we should extract dates for all the files within the same media entity.
- In a typical Takeout, you might have the same file within
- If one media entity contains two or more files within the same folder, then this is a duplicated file (based on content), even if they have different names, and the tool will remove the worst ranked duplicated file.
- Now, all identical content files are collected within the same MediaEntity.
- Moved
Write EXIFstep to Step 7 (after Move Files step) in order to write EXIF data only to those physical files in output folder (skipping shortcuts).- This changed was needed because until Step 6 (based on the selected album strategy), don't create the output physical files, we don't know which files need EXIF write.
- With this change we reduce a lot the number of EXIF files to write because we can skip writing EXIF for shortcut files created by shorcut or reverse-shortcut strategy, but also we can skip all secondaryFiles if selected strategy is None or Json.
- The only strategy that has no benefit from this change is duplicate-copy, because in this strategy all files in output folder are physical files and all of them need to have EXIF written.
- Renamed
Step 3: Remove DuplicatestoStep 3: Merge Media Entitiesbecause this represents much better the main purpose of this step. - Performance Optimization in
Step 3: Merge Media Entities. Step 3: Merge Media Entitiesnow only consider within-folder duplicates. And take care of the primaryFile/secondaryFiles based on a ranking for the rest of the pipeline.Step 7: Write EXIFnow take into account all the files in the MediaEntity file except duplicatesFiles and files withisShortcut=trueattribute.Step 6: Move Filesnow manage hardlinks/juntions as fallback of native shorcuts using API toWindowsSymlinkServicewhen no admin rights are granted.Step 8: Update Creation Timenow take into account all the files in the MediaEntity file except duplicatesFiles.Step 8: Update Creation Timenow update creation time also for shortcuts.- Improvements on Statistics results.
- Added more statistics to
Step 3: Remove Duplicate - Added more statistics to
Step 6: Move Files - Added more statistics to
Step 8: Update Creation Time. - Total execution time is now shown as hh:mm:ss instead of only minutes.
- Added more statistics to
-
🐛 GPTH Bug Fixes
- Fixed #65: Now all supported media files are moved from input folder to output folder. So after running GPTH input folder should only contain .json files and unsupported media types.
- Fixed #76: Now interactive mode ask for album strategy.
- Changed zip_extraction_service.dart to support extract UTF-8/latin1 chars on folder/files names.
-
-
-
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
- [Download x64 vers...
v3.5.2
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases+
Release: v3.5.2
-
Release Date: 2025-08-24
-
Main Changes:
-
🚀 Enhancements:
- Separate Steps for Analyze Input Takeout files and Analyze Output files in feature
Google Takeout Fixing. Now the Analyzer for the Input Takeout folder is executed after Pre-Processing steps, in this way the extracted dates JSON dictionary will match for all input files during GPTH processing phase even if any file was renamed during any pre-processing step. - Show dictMiss files in GPTH log to see those files that have not been found in dates dictionary when it was passed as argument using --fileDates
- Separate Steps for Analyze Input Takeout files and Analyze Output files in feature
-
🐛 Bug fixes:
- Fixed a bug in GPTH in JSON Matcher service when the JSON filename lenght is longer than 51 chars. In those cases the tool was trying to find a truncated JSON variant and never try to match with the full filename, but PhotoMigrator fixes Truncations during Pre-process, so it was never found.
- Fixed a bug in GPTH Step 7 (Move Files) that progress bar was not showing the correct number of operations.
-
📚 Documentation:
- Updated documentation with all changes.
-
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
Windows:
Docker Launcher:
What's Changed
- 3.5.2 by @jaimetur in #941
- Jaime's commit by @jaimetur in #942
- Jaime's commit by @jaimetur in #943
- 3.5.2 by @jaimetur in #944
- Actualizar 4-google-takeout.md by @jaimetur in #946
- 3.5.2 by @jaimetur in #948
- 3.5.2 by @jaimetur in #950
- Jaime's commit by @jaimetur in #952
- Jaime's commit by @jaimetur in #954
- Jaime's commit by @jaimetur in #956
- 3.5.2 by @jaimetur in #958
- Jaime's commit by @jaimetur in #960
Full Changelog: v3.5.1...v3.5.2
v3.5.1
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases
Release: v3.5.1
-
Release Date: 2025-08-20
-
Main Changes:
-
🚀 Enhancements:
- Extracted Dates JSON now contains all Dates in Local UTC format.
- Extracted Dates JSON now includes ExecutionTimestamp Tag for reference.
- Extracted Dates JSON Tags renamed for a better understanding.
- Enhancements in extract_dates() function to avoid guess date from file path when the file path cotains the execution timestamp.
- Included support in GPTH to use the Extracted Dates JSON dictionary. This will speed-up GPTH Date extraction a lot.
- Updated GPTH to version
4.3.0(by @Xentraxx & @jaimetur) which includes new features, performance improvements and bugs fixing extracting metadata info from Google Takeouts.
-
🚀 Enhancements in GPTH Tool:
-
Improved non-zero exit code quitting behaviour - Now with nice descriptive error messages because I was tired of looking up what is responsible for a certain exit code.
-
Step 4 (Extract Dates) & 5 (Write EXIF) Optimization
-
⚡ Performance
- Step 4 (READ-EXIF) now support --fileDates flag to provide a JSON dictionary with the Extracted dates per file (PhotoMigrator creates this file and can now be used by GPTH Tool).
- Step 4 (READ-EXIF) now uses batch reads and a fast native mode, with ExifTool only as fallback → about 3x faster metadata extraction.
- Step 5 (WRITE-EXIF) supports batch writes and argfile mode, plus native JPEG writers → up to 5x faster on large collections.
-
🔧 API
- Added batch write methods in
ExifToolService. - Updated
MediaEntityCollectionto use new helpers for counting written tags.
- Added batch write methods in
-
📊 Logging
- Statistics are clearer: calls, hits, misses, fallback attempts, timings.
- Date, GPS, and combined writes are reported separately.
- Removed extra blank lines for cleaner output.
-
🧪 Testing
- Extended mocks with batch support and error simulation.
- Added tests for GPS writing, batch operations, and non-image handling.
-
✅ Benefits
- Much faster EXIF processing with less ExifTool overhead.
- More reliable and structured API.
- Logging is easier to read and interpret.
- Stronger test coverage across edge cases.
-
-
Step 6 (Find Albums) Optimization
-
⚡ Performance
- Replaced
_groupIdenticalMediawith_groupIdenticalMediaOptimized.- Two-phase strategy:
- First group by file size (cheap).
- Only hash files that share the same size.
- Switched from
readAsBytes()(full memory load) to streaming hashing withmd5.bind(file.openRead()). - Files are processed in parallel batches instead of sequentially.
- Concurrency defaults to number of CPU cores, configurable via
maxConcurrent.
- Two-phase strategy:
- Replaced
-
🔧 Implementation
- Added an in-memory hash cache keyed by
(path|size|mtime)to avoid recalculating.- Introduced a custom semaphore to limit concurrent hashing and prevent I/O overload.
- Errors are handled gracefully: unprocessable files go into dedicated groups without breaking the process.
- Added an in-memory hash cache keyed by
-
✅ Benefits
- Processing time reduced from 1m20s → 4s on large collections.
- Greatly reduced memory usage.
- Scales better on multi-core systems.
- More robust and fault-tolerant album detection.
- Processing time reduced from 1m20s → 4s on large collections.
-
-
-
🐛 Bug Fixes in GPTH Tool:
- Changed exif tags to be utilized
- Before we used the following lists of tags in this exact order to find a date to set:
- Exiftool reading: 'DateTimeOriginal', 'MediaCreateDate', 'CreationDate', 'TrackCreateDate', 'CreateDate', 'DateTimeDigitized', 'GPSDateStamp' and 'DateTime'.
- Native dart exif reading: 'Image DateTime', 'EXIF DateTimeOriginal', 'EXIF DateTimeDigitized'.
- Some of those values are prone to deliver wrong dates (e.g. DateTimeDigitized) and the order did not completely make sense. We therefore now read those tags and the oldest DateTime we can find:
- Exiftool reading: 'DateTimeOriginal','DateTime','CreateDate','DateCreated','CreationDate','MediaCreateDate','TrackCreateDate','EncodedDate','MetadataDate','ModifyDate'.
- Native dart exif reading: same as above.
- Before we used the following lists of tags in this exact order to find a date to set:
- Fixed typo in partner sharing - Functionality was fundamentally broken due to a typo.
- Fixed small bug in interactive mode in the options of the limit filezise dialogue
- Fixed unzipping through command line by automatically detecting if input directory contains zip files
- Changed exif tags to be utilized
-
🐛 Bug fixes:
- Fixed a bug when guessed date from filepath extract the same date than TIMESTAMP (if the path contains the current TIMESTAMP).
-
📚 Documentation:
- Updated documentation with all changes.
-
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
Windows:
Docker Launcher:
What's Changed
- 3.5.0 by @jaimetur in #919
- 3.5.1 by @jaimetur in #920
- Commit from PyCharm by @jaimetur in #921
- Commit from PyCharm by @jaimetur in #922
- Commit from PyCharm by @jaimetur in #923
- 3.5.1 by @jaimetur in #924
- 3.5.1 by @jaimetur in #925
- Commit from PyCharm by @jaimetur in #926
- 3.5.1 by @jaimetur in #927
- 3.5.1 by @jaimetur in #929
- Jaime's commit by @jaimetur in #931
- Jaime's commit by @jaimetur in #932
- 3.5.1 by @jaimetur in #934
- 3.5.1 by @jaimetur in #937
- Jaime's commit by @jaimetur in #939
Full Changelog: v3.5.0...v3.5.1
v3.5.0
🗓️ CHANGELOG
Planned Roadmap for the following releases
Changelog for the past releases
Release: v3.5.0
-
Release Date: 2025-07-30
-
Main Changes:
-
🚀 Enhancements:
- Updated GPTH to version
4.1.0(by @Xentraxx) which includes several new features, improvements and bugs fixing extracting metadata info from Google Takeouts.
- Updated GPTH to version
-
✨ New Features in GPTH Tool:
- Partner Sharing Support - Added
--divide-partner-sharedflag to separate partner shared media from personal uploads into dedicatedPARTNER_SHAREDfolder (Issue #56)- Automatically detects partner shared photos from JSON metadata (
googlePhotoOrigin.fromPartnerSharing) - Creates separate folder structure while maintaining date division and album organization
- Works with all album handling modes (shortcut, duplicate-copy, reverse-shortcut, json, nothing)
- Preserves album relationships for partner shared media
- Automatically detects partner shared photos from JSON metadata (
- Added folder year date extraction strategy - New fallback date extractor that extracts year from parent folder names like "Photos from 2005" when other extraction methods fail (Issue #28)
- Centralized concurrency management - Introduced
ConcurrencyManagerfor consistent concurrency calculations across all services, eliminating hardcoded multipliers scattered throughout the codebase - Displaying version of Exiftool when found - Instead of just displaying that Exif tool was found, we display the version now as well.
- Partner Sharing Support - Added
-
🚀 Performance Improvements in GPTH Tool:
- EXIF processing optimization - Native
exif_readerlibrary integration for 15-40% performance improvement in EXIF data extraction- Uses fast native library for supported formats (JPEG, TIFF, HEIC, PNG, WebP, AVIF, JXL, CR3, RAF, ARW, DNG, CRW, NEF, NRW)
- Automatic fallback to ExifTool for unsupported formats or when native extraction fails
- Centralized MIME type constants verified against actual library source code
- Improved error logging with GitHub issue reporting guidance when native extraction fails
- GPS coordinate extraction optimization - Dedicated coordinate extraction service with native library support
- 15-40% performance improvement for GPS-heavy photo collections
- Clean architectural separation between date and coordinate extraction
- Centralized MIME type support across all EXIF processing operations
- Significantly increased parallelization - Changed CPU concurrency multiplier from ×2 to ×8 for most operations, dramatically improving performance on multi-core systems
- Removed concurrency caps - Eliminated
.clamp()limits that were artificially restricting parallelization on high-core systems - Platform-optimized concurrency:
- Linux: Improved from
CPU cores + 1toCPU cores × 8(massive improvement for Linux users) - macOS: Improved from
CPU cores + 1toCPU cores × 6 - Windows: Maintained at
CPU cores × 8(already optimized)
- Linux: Improved from
- Operation-specific concurrency tuning:
- Hash operations:
CPU cores × 4(balanced for CPU + I/O workload) - EXIF/Metadata:
CPU cores × 6(I/O optimized for modern SSDs) - Duplicate detection:
CPU cores × 6(memory intensive, conservative) - Network operations:
CPU cores × 16(high for I/O waiting)
- Hash operations:
- Adaptive concurrency scaling - Dynamic performance-based concurrency adjustment that scales up to ×24 for high-performance scenarios
- EXIF processing optimization - Native
-
🐛 Bug Fixes in GPTH Tool:
- Fixed memory exhaustion during ZIP extraction - Implemented streaming extraction to handle large ZIP files without running out of memory
- Fixed atomic file operations - Changed to atomic file rename operations to resolve situations where only the json was renamed in file extension correction (Issue #60)
- Fixed album relationship processing - Improved album relationship service to handle edge cases properly (Issue #61)
- Fixed interactive presenter display - Corrected display issue in interactive mode (Issue #62)
- Fixed date division behavior for albums - The
--divide-to-datesflag now only applies to ALL_PHOTOS folder, leaving album folders flattened without date subfolders (Issue #55) - Reaorganised ReadMe for a more intuitive structure - First Installation, then prerequisites and then the quickstart.
- Step 8 now also uses a progress bar instead of simple print statements
- Supressed some unnecessary ouput
-
📚 Documentation:
- Updated documentation with all changes.
-
💾 Download
Download the tool either for Linux, MacOS or Windows (for both x64 and arm64 architectures) or Docker version (platform & architecture independent) as you prefer, directly from following links:
Linux::
Mac OS:
Windows:
Docker Launcher:
What's Changed
- 3.4.4 by @jaimetur in #914
- Commit from Pycharm by @jaimetur in #915
- New Release v3.5.0 by @jaimetur in #916
Full Changelog: v3.4.4...v3.5.0