Skip to content

Instantly share code, notes, and snippets.

@crearo
Last active June 27, 2021 18:20
Show Gist options
  • Save crearo/fa38892631ad3384f1bfd1f478925606 to your computer and use it in GitHub Desktop.
Save crearo/fa38892631ad3384f1bfd1f478925606 to your computer and use it in GitHub Desktop.
Add Exif Tags to Google Photo via Drive Takeout
#!/usr/bin/python
"""
[ ] List out if there are images which have been missed. (ie, image was there, but no json file)
[ ] Put the images in various directories.
[ ] Add EXIF tags to each of the photos.
"""
import json
import os
import sys
import shutil
from collections import Counter
from pathlib import Path
from subprocess import PIPE, run
input_dir = os.getcwd() + '\\Photos'
output_dir = os.getcwd() + '\\out'
def log_warning(str):
print("------------------WARNING------------------")
print(str)
print("-------------------------------------------")
def _delete_files(dir: Path):
shutil.rmtree(dir)
def _setup_output_folder(output_path: Path):
if len(list(output_path.glob("**/*"))) > 0:
_delete_files(output_path)
print("Deleted all files in output directory")
if not output_path.exists():
output_path.mkdir()
print("Created output directory")
def cmd(command):
# result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
# print(result.stderr, result.stdout)
# return result.stdout
os.system(command)
def add_media_metadata(json_file: Path, media_file: Path):
command = f'exiftool.exe -d %s -tagsfromfile {json_file.absolute()} "-GPSAltitude<GeoDataAltitude" "-GPSLatitude<GeoDataLatitude" "-GPSLatitudeRef<GeoDataLatitude" "-GPSLongitude<GeoDataLongitude" "-GPSLongitudeRef<GeoDataLongitude" "-Keywords<Tags" "-Subject<Tags" "-Caption-Abstract<Description" "-ImageDescription<Description" "-CreateDate<PhotoTakenTimeTimestamp" "-PreviewDateTime<PhotoTakenTimeTimestamp" "-DateTimeOriginal<PhotoTakenTimeTimestamp" "-ModifyDate<PhotoTakenTimeTimestamp" -ext "*" -overwrite_original {media_file.absolute()}'
cmd(command)
# pass
def main():
output_path = Path(output_dir)
_setup_output_folder(output_path)
internal_dirs = len([f for f in os.listdir(input_dir) if Path(Path(output_path).joinpath(f)).is_dir()])
if internal_dirs != 0:
log_warning("You have directories within the main folder. This program doesn't look inside these directories "
"currently, but I can add it if you would like.")
all_files = list(Path(input_dir).glob('**/*'))
json_files = list(Path(input_dir).glob('**/*.json'))
media_files = {} # media files with corresponding json files.
# using json files as the source of truth, instead of finding images and then searching for their corresponding json
for json_file in json_files:
with open(json_file.absolute(), 'r') as _file:
try:
media_name = json.load(_file)['title']
except KeyError:
log_warning(f"No Key For Image: {json_file}")
sys.exit()
corresponding_media_path = json_file.parent.joinpath(media_name)
media_files[json_file] = corresponding_media_path
media_files_without_json = list((Counter(all_files) - Counter(json_files)).elements())
if len(media_files_without_json) != 0:
log_warning(f"There are media files without a corresponding json! In total:{len(media_files_without_json)}"
"\nThese will be stored in out/unsorted.")
json_files_without_media = [f for f in media_files.values() if not Path(f).exists()]
if len(json_files_without_media) != 0:
log_warning(f"There are json files without corresponding media! In total:{len(json_files_without_media)}")
# read all json files, create the output dir, move the corresponding media to the out folder.
for json_file, media_file in media_files.items():
if not media_file.exists():
output_path_for_json_without_media = output_path.joinpath('json-without-media')
if not output_path_for_json_without_media.exists():
output_path_for_json_without_media.mkdir()
shutil.copyfile(json_file, output_path_for_json_without_media.joinpath(json_file.name))
print("No corresponding media file for json file:", json_file.name, "Placed json file in:",
output_path_for_json_without_media.name)
continue
with open(json_file.absolute(), 'r') as _file:
# Exif tool
add_media_metadata(json_file, media_file)
# Move the file to its corresponding folder
try:
corresponding_out_dir_name = json.load(_file)['googlePhotosOrigin']['mobileUpload']['deviceFolder'][
'localFolderName']
except KeyError:
log_warning('Key Error for ' + str(json_file.name))
if corresponding_out_dir_name is None or corresponding_out_dir_name == '':
corresponding_out_dir_name = 'unspecified-folder'
corresponding_media_path = media_file.absolute()
corresponding_media_output_dir = output_path.joinpath(corresponding_out_dir_name)
if not corresponding_media_output_dir.exists():
corresponding_media_output_dir.mkdir()
shutil.copyfile(corresponding_media_path,
corresponding_media_output_dir.joinpath(corresponding_media_path.name))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment