Created
August 11, 2025 15:21
-
-
Save KingWaffleIII/232ec3c86ba872238a83026bf8b9bb25 to your computer and use it in GitHub Desktop.
Changes Google Photos Takeout photos/videos EXIF and file metadata datetimes to the correct value from the supplemental metadata JSON file. Put in same dir as the photos/vids and exiftool.exe.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import glob | |
| import subprocess | |
| import json | |
| from datetime import datetime | |
| def get_correct_datetime(file_path): | |
| directory = os.path.dirname(file_path) | |
| base = os.path.basename(file_path) | |
| pattern = os.path.join(directory, base + ".*.json") | |
| matches = glob.glob(pattern) | |
| if matches: | |
| with open(matches[0],) as f: | |
| metadata = json.load(f) | |
| wrong_format = metadata['photoTakenTime']['formatted'] # 10 Aug 2025, 23:06:42 UTC | |
| correct_format = datetime.strptime(wrong_format[:-4], '%d %b %Y, %H:%M:%S') # Convert to datetime object | |
| return correct_format.replace(second=0).strftime('%Y:%m:%d %H:%M') | |
| return None | |
| imgs = [] | |
| for ext in ('*.jpg', '*.jpeg', '*.png', '*.webp'): | |
| imgs.extend(glob.glob(os.path.join(os.getcwd(), ext))) | |
| vids = glob.glob(os.path.join(os.getcwd(), '*.mp4')) | |
| for file in imgs: | |
| try: | |
| correct_datetime = get_correct_datetime(file) | |
| if not correct_datetime: | |
| print(f"No supplemental metadata JSON found for {file}, skipping.") | |
| continue | |
| check = subprocess.run(['exiftool.exe', '-j', '-CreateDate', file], capture_output=True, text=True) | |
| metadata = json.loads(check.stdout) | |
| if not metadata or 'CreateDate' not in metadata[0]: | |
| subprocess.run(['exiftool.exe', '-overwrite_original', f'-AllDates={correct_datetime}', file]) | |
| subprocess.run(['exiftool.exe', '-overwrite_original', | |
| f'-FileCreateDate={correct_datetime}', | |
| f'-FileModifyDate={correct_datetime}', file]) | |
| print(f"Processed image: {file}\n") | |
| except Exception as e: | |
| print(f"Error processing image {file}: {e}\n") | |
| for file in vids: | |
| try: | |
| correct_datetime = get_correct_datetime(file) | |
| if not correct_datetime: | |
| print(f"No supplemental metadata JSON found for {file}, skipping.") | |
| continue | |
| check = subprocess.run(['exiftool.exe', '-j', '-CreateDate', file], capture_output=True, text=True) | |
| metadata = json.loads(check.stdout) | |
| if not metadata or 'CreateDate' not in metadata[0]: | |
| subprocess.run([ | |
| 'exiftool.exe', '-overwrite_original', | |
| f'-CreateDate={correct_datetime}', | |
| f'-ModifyDate={correct_datetime}', | |
| f'-TrackCreateDate={correct_datetime}', | |
| f'-TrackModifyDate={correct_datetime}', | |
| f'-MediaCreateDate={correct_datetime}', | |
| f'-MediaModifyDate={correct_datetime}', file]) | |
| subprocess.run(['exiftool.exe', '-overwrite_original', | |
| f'-FileCreateDate={correct_datetime}', | |
| f'-FileModifyDate={correct_datetime}', file]) | |
| print(f"Processed video: {file}\n") | |
| except Exception as e: | |
| print(f"Error processing video {file}: {e}\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment