Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .fvm/fvm_config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"flutterSdkVersion": "3.13.3",
"flavors": {}
}
}
5 changes: 4 additions & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
github: TheLastGimbus
ko_fi: thelastgimbus
liberapay: TheLastGimbus
custom: [ "https://www.paypal.me/TheLastGimbus" ]
custom:
- "https://www.paypal.me/TheLastGimbus"
- "https://ko-fi.com/thelastgimbus"
- "https://liberapay.com/TheLastGimbus"
9 changes: 4 additions & 5 deletions .github/workflows/build-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
build:
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
Expand All @@ -26,14 +26,13 @@ jobs:
else
echo "Unknown OS: $RUNNER_OS"
exit 69
fi
- uses: dart-lang/setup-dart@v1
- run: dart pub get
- name: Build exe
run: dart compile exe bin/gpth.dart -o ./${{ steps.exe_name.outputs.name }}
- name: Upload apk as artifact
- name: Upload exe as artifact
uses: actions/upload-artifact@v3
with:
name: gpth-nightly-${{ runner.os }}
name: gpth-nightly-${{ matrix.os }}
path: ./${{ steps.exe_name.outputs.name }}
if-no-files-found: error
if-no-files-found: error
7 changes: 4 additions & 3 deletions .github/workflows/dart-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ name: Dart tests

on:
push:
branches: [ master ]
branches: [master]
pull_request:
branches: [ master ]
branches: [master]

jobs:
tests:
Expand All @@ -23,4 +23,5 @@ jobs:
- run: dart pub get
- name: Verify formatting
run: dart format --output=none --set-exit-if-changed .
- run: dart analyze --fatal-infos
- name: Run analyzer
run: dart analyze --fatal-infos --fatal-warnings
18 changes: 9 additions & 9 deletions .github/workflows/new-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Build and publish new release on version tag
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- "v[0-9]+.[0-9]+.[0-9]+"

jobs:
make-release:
Expand All @@ -14,10 +14,10 @@ jobs:
run: echo "tag=$(echo ${{ github.ref }} | sed 's/refs\/tags\///')" >> $GITHUB_OUTPUT
- name: Get changelog
run: python scripts/get_changelog.py --version ${{ steps.clean_tag.outputs.tag }} > ./body-file.txt
# Just in case changelogs won't work out
# - name: Get tag message
# id: tag_message
# run: echo "name=message=$(git tag -l --format='%(contents)' ${{ github.ref }})" >> $GITHUB_OUTPUT
# Just in case changelogs won't work out
# - name: Get tag message
# id: tag_message
# run: echo "name=message=$(git tag -l --format='%(contents)' ${{ github.ref }})" >> $GITHUB_OUTPUT
- name: Create GH-Release
uses: softprops/action-gh-release@v1
with:
Expand All @@ -28,7 +28,7 @@ jobs:
needs: make-release
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -62,7 +62,7 @@ jobs:
# because proper certificates cost money (a lot :/ )
certificate: ${{ secrets.WINDOZA_CERT_BASE64 }}
password: ${{ secrets.WINDOZA_CERT_PASSWORD }}
folder: '.'
folder: "."
- name: Add files to GH-Release
uses: softprops/action-gh-release@v1
with:
Expand All @@ -79,8 +79,8 @@ jobs:
with:
pkgname: gpth-bin
pkgbuild: ./PKGBUILD
commit_username: 'TheLastGimbus'
commit_email: '[email protected]'
commit_username: "TheLastGimbus"
commit_email: "[email protected]"
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: ${{ steps.clean_tag.outputs.tag }}
test: true
31 changes: 30 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Ignore IDE directories
.idea/
.vscode/

Expand All @@ -8,8 +9,36 @@
# Conventional directory for build output.
build/

# Ignore photos and output directories
photos/

ALL_PHOTOS/
output/

# Ignore log files
*.log

# Ignore analysis options
analysis_options.yaml

# Ignore generated files
*.g.dart
*.freezed.dart

# Ignore coverage output
coverage/

# Ignore test result files
test-results/

# Ignore temporary files
*.tmp
*.temp

# Ignore macOS specific files
.DS_Store

# Ignore Windows specific files
Thumbs.db
dartsdk.zip
test_takeout/
test_output/
136 changes: 104 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,80 +5,85 @@
[![commit activity](https://img.shields.io/github/commit-activity/y/TheLastGimbus/GooglePhotosTakeoutHelper)](https://github.com/TheLastGimbus/GooglePhotosTakeoutHelper/graphs/contributors)

# Google Photos Takeout Helper 📸🆘

## What is this for 🧐

If you ever want to move from Google Photos to other platform/solution, your fastest choice to export all photos is [Google Takeout 🥡](https://takeout.google.com/)

But when you download it, you will find yourself with zips with hundreds of little folders with weird `.json` files inside 🍝.
But when you download it, you will find yourself with zips with hundreds of little folders with weird `.json` files inside 🍝.
What if you want to just have one folder with all photos, in chronological order? Good luck copying all of that 🙃

This script does just that - it organizes and cleans up your Takeout for you 🧹😌

It will take all of those folders, find all photos in them, set their `file last modified` correctly, and put it in one big folder (or folders divided by a month) 🗄

## How to use:
## How to use

Since `v3.2.0`, `gpth` is interactive 🎉 - you don't need to type any complicated arguments - just get your takeout, run gpth, and follow prompted instructions 💃

If you want to run it on Synology, have problems with interactive, or just love cmd, look at ["Running manually with cmd"](#running-manually-with-cmd). Otherwise, just:

### 1. Get all your photos from [Google Takeout](https://takeout.google.com/) 📥

"deselect all" and then select only Google Photos

<img width="75%" alt="gpth usage image tutorial" src="https://github.com/TheLastGimbus/GooglePhotosTakeoutHelper/assets/40139196/8e85f58c-9958-466a-a176-51af85bb73dd">

### 2. Unzip them all and merge into one, so that all "Takeout" folders become one

**NOTE:** Keep those original zips, you may need them if anything goes wrong

<img width="75%" alt="Unzip image tutorial" src="https://user-images.githubusercontent.com/40139196/229361367-b9803ab9-2724-4ddf-9af5-4df507e02dfe.png">

### 3. Download the executable for your system from [releases tab](https://github.com/TheLastGimbus/GooglePhotosTakeoutHelper/releases) 🛒 ([also available on AUR 😏](https://aur.archlinux.org/packages/gpth-bin))

### 4. Run `gpth`
- On Windoza: just double-click the downloaded `.exe` 🎉 - tell windoza defender that it's safe, and follow prompted instructions 🧾
- On Mac/Linux: open terminal, `cd` to the folder with downloaded executable and run it:

- On Windoza: just double-click the downloaded `.exe` 🎉 - tell windoza defender that it's safe, and follow prompted instructions 🧾
- On Mac/Linux: open terminal, `cd` to the folder with downloaded executable and run it:

```bash
# if you have Mac with M1/M2 chip, you need to enable x86 emulation
# otherwise, just skip it
softwareupdate --install-rosetta

cd Downloads # probably
# add execute permission for file
chmod +x gpth-macos # or gpth-linux
# tell MacOS Gatekeeper to not worry
xattr -r -d com.apple.quarantine gpth-macos
# run it 🏃
./gpth-macos # or ./gpth-linux
# follow prompted instructions 🥰
```

**Fun fact:** `gpth` *moves* files around by default - so if anything goes wrong mid-way, re-export the zips again :pray:

### 5. Most of your photos should have correct original EXIFs (metadata), but if you want, you can insert them everywhere with `exiftool`, so you won't lose their creation time
- Download Phil Harvey's exiftool: https://exiftool.sourceforge.net/
- Open the cmd/terminal, and run
```bash
# cd to folder where you downloaded exiftool
cd Downloads
# run it on your output folder:
# (the '-r' means "run on all files/in sub-folders" aka recursively)
# (Make sure you didn't change file modify dates aka didn't do anything with the files after running gpth
exiftool -overwrite_original -r -if 'not defined DateTimeOriginal' -P "-AllDates<FileModifyDate" "your/output/folder/ALL_PHOTOS/"
```
## Recent Improvements 🚀

The latest version includes several improvements to make the tool more robust and user-friendly:

- **Enhanced Error Handling**: Better error messages and logging for easier troubleshooting
- **Improved File Handling**: Better handling of large files and non-ASCII characters
- **More Language Support**: Added support for edited photos in more languages (Turkish, Arabic, Hindi, Vietnamese, Thai, Indonesian)
- **Robust Date Extraction**: Improved date extraction from filenames with more flexible patterns
- **Better Performance**: Optimized hash calculation for large files
- **Safer File Operations**: Improved sanitization of filenames to prevent errors

Done! Enjoy your photos!!!

### Running manually with cmd

You may still need this mode if:

- You want to run on Synology where there are no ui programs required for interactive
- You can read/discuss in [#157](https://github.com/TheLastGimbus/GooglePhotosTakeoutHelper/discussions/157) for any help
- ~~Interactive unzipping crashes for you (known issue in windoza 😢 #178)~~ - disabled for now
- Want to use this in other script/automation

In that case:

1. Manually unzip all your takeout zips and merge them into one folder
2. Open cmd and:
- For windoza:

```bash
# psst: in windoza cmd, you can just drag and drop files/folders to type them in
# 1. change working directory to where gpth.exe is:
Expand All @@ -89,7 +94,9 @@ In that case:
# select which album solution you like - see --help for all of them
# remember to use "" !
```

- For Linux/macOS:

```bash
# ssh/whatever to where you're running it
cd Downloads # folder with gpth
Expand All @@ -103,36 +110,101 @@ In that case:
You can check all cmd flags by running `gpth --help` - for example, the `--divide-to-dates` flag

## If I helped you, you can consider donating me ☕

I spent **a lot of** time fixing bugs and making this work stable 💖 - would be super thankful for any donations 🥰

[![Donate](https://img.shields.io/badge/Donate-PayPal-blue.svg?logo=paypal&style=for-the-badge)](https://www.paypal.me/TheLastGimbus)
[![Donate using ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/A0A6HO71P)
[![Donate using Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/TheLastGimbus/donate)

## After exporting 🤔

### Be aware if you move your photos on your Android phone... ☝

(99% of the times), if you move some files in Android, their creation and modification time is reset to current.

"Simple Gallery" app usually keeps original file creation time when moving and copying (but I don't guarantee it). It's also pretty cool - check it out: https://github.com/SimpleMobileTools/Simple-Gallery
"Simple Gallery" app usually keeps original file creation time when moving and copying (but I don't guarantee it). It's also pretty cool - check it out: <https://github.com/SimpleMobileTools/Simple-Gallery>

### What to do when you got rid of Google Photos? What are the alternatives? 🗺
- I really recommend you using [Syncthing](https://syncthing.net/) for syncing your photos and files across devices. It does so through your local Wi-Fi, so you're not dependent on any service or internet connection. It will also keep original file creation date and metadata, so it resolves Android issue that I mentioned before.

- [Immich](https://immich.app/) aims to be full blown GPhotos replacement - it's still under development, but already looks great!
- I really recommend you using [Syncthing](https://syncthing.net/) for syncing your photos and files across devices. It does so through your local Wi-Fi, so you're not dependent on any service or internet connection. It will also keep original file creation date and metadata, so it resolves Android issue that I mentioned before.

- [Immich](https://immich.app/) aims to be full blown GPhotos replacement - it's still under development, but already looks great!

- Same with [Photoprism](https://photoprism.org/), tho this one is in development longer (may be more mature)
- Same with [Photoprism](https://photoprism.org/), tho this one is in development longer (may be more mature)

- If you want something more centralized but also self-hosted, [Nextcloud](https://nextcloud.com) is a nice choice, but its approach to photos is still not perfect. (And you need to set up your own server)
- If you want something more centralized but also self-hosted, [Nextcloud](https://nextcloud.com) is a nice choice, but its approach to photos is still not perfect. (And you need to set up your own server)

### Other Takeout projects

I used this tool to export my notes to markdown - you can then edit them with any markdown editor you like :)

https://github.com/vHanda/google-keep-exporter
<https://github.com/vHanda/google-keep-exporter>

### Where is the Python script 🐍 ??

Yeah, the whole thing got re-written in Dart, and now it's way more stable and faster. If you still want Python for some reason, check out v2.x - in releases/tags

### TODO (Pull Requests welcome):
- [ ] GPS data: from JSON to Exif - ~~Thank you @DalenW 💖~~ still thank you, but it is now missing in the Dart version
- [ ] Writing data from `.json`s back to `EXIF` data
### TODO (Pull Requests welcome)

- [x] GPS data: from JSON to Exif - ~~Thank you @DalenW 💖~~ now implemented in the Dart version
- [x] Writing data from `.json`s back to `EXIF` data
- [x] Some way to handle albums - THANK YOU @bitsondatadev 😘 🎉 💃

## New Features

### GPS and EXIF Data

The latest version now includes support for extracting GPS data from JSON files and writing it back to EXIF metadata:

- **GPS Data Extraction**: Automatically extracts GPS coordinates from JSON files during processing
- **EXIF Writing**: New `--write-exif` flag to write JSON data (dates, GPS) to EXIF metadata

To use the EXIF writing feature:

```bash
gpth --input "/path/to/takeout" --write-exif
```

This will go through all files in the input folder and write any available date and GPS data from JSON files to the EXIF metadata of the corresponding images. This is useful if you want to preserve this information when moving to other photo management solutions.

For faster EXIF writing, you can process multiple files in parallel using the `--batch-size` option:

```bash
gpth --input "/path/to/takeout" --write-exif --batch-size 8
```

This will process 8 files simultaneously, which can significantly speed up the EXIF writing process on multi-core systems. The default batch size is 4.

The GPS data is also extracted during normal processing and can be used by other applications that read EXIF data.

### Performance Optimization

If you don't need GPS data and want faster processing, you can use the `--skip-gps` flag:

```bash
gpth --input "/path/to/takeout" --output "/path/to/output" --skip-gps
```

This will skip the GPS data extraction step, which can significantly speed up processing for large collections.

### Dry Run Mode

If you want to see what would happen without actually moving or copying any files, you can use the `--dry-run` flag:

```bash
gpth --input "/path/to/takeout" --output "/path/to/output" --dry-run
```

This will show you a summary of what would happen, including a sample of files that would be processed, without making any changes to your files.

### Enhanced GPS Extraction

The latest version includes improved GPS data extraction that can handle various formats found in Google Photos JSON files, including:

- Standard geoData format
- Nested location structures
- Google Maps style coordinates
- Various naming conventions (latitude/longitude, lat/lng, etc.)

This ensures that as much location data as possible is preserved when processing your photos.
Loading