Last active
November 17, 2017 13:15
-
-
Save toabctl/3be45855ede528a5fb97c31aa7a7b7d5 to your computer and use it in GitHub Desktop.
Fill Iptc/Xmp tags based on GPS location and OpenStreetMap data
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
#!/usr/bin/python3 | |
# Author: Thomas Bechtold <[email protected]> | |
import argparse | |
import os | |
import requests | |
import time | |
# GNOME gobject introspection | |
import gi | |
gi.require_version('GExiv2', '0.10') | |
from gi.repository import GLib | |
from gi.repository import GExiv2 | |
# requests to http://nominatim.openstreetmap.org/ should be max. 1 per second | |
# see https://operations.osmfoundation.org/policies/nominatim/ | |
LAST_WAIT_CALL = None | |
def _wait(): | |
global LAST_WAIT_CALL | |
if LAST_WAIT_CALL: | |
diff = time.time() - LAST_WAIT_CALL | |
if diff < 1: | |
wait_for = 1 - diff | |
time.sleep(wait_for) | |
LAST_WAIT_CALL = time.time() | |
def _get_location_data(longitude, latitude, email): | |
"""get location data as json for the given long/lat""" | |
payload = { | |
'format': 'jsonv2', | |
'accept-language': 'en-US', | |
'zoom': 10, | |
'lat': latitude, | |
'lon': longitude} | |
if email: | |
payload['email'] = email | |
_wait() | |
r = requests.get('http://nominatim.openstreetmap.org/reverse', | |
params=payload) | |
if r.status_code != 200: | |
r.raise_for_status() | |
return r.json() | |
def _metadata_update(path, copyright_holder, email): | |
metadata = GExiv2.Metadata.new() | |
try: | |
metadata.open_path(path) | |
except GLib.Error as e: | |
print('Can not handle {}: {}'.format(path, e)) | |
else: | |
lon, lat, alt = metadata.get_gps_info() | |
if lon == 0 and lat == 0 and alt == 0: | |
print('No GPS info for "{}". Skipping'.format(path)) | |
return | |
location_data = _get_location_data(lon, lat, email) | |
address = location_data.get('address', {}) | |
dirty = False | |
if 'country_code' in address: | |
metadata.set_tag_string('Iptc.Application2.CountryCode', | |
address['country_code']) | |
metadata.set_tag_string('Xmp.iptcExt.CountryCode', | |
address['country_code']) | |
dirty = True | |
if 'country' in address: | |
metadata.set_tag_string('Iptc.Application2.CountryName', | |
address['country']) | |
metadata.set_tag_string('Xmp.iptcExt.CountryName', | |
address['country']) | |
dirty = True | |
if 'state' in address: | |
metadata.set_tag_string('Iptc.Application2.ProvinceState', | |
address['state']) | |
metadata.set_tag_string('Xmp.iptcExt.ProvinceState', | |
address['state']) | |
dirty = True | |
if 'city' in address: | |
metadata.set_tag_string('Iptc.Application2.City', | |
address['city']) | |
metadata.set_tag_string('Xmp.iptcExt.City', | |
address['city']) | |
dirty = True | |
if 'city_district' in address: | |
metadata.set_tag_string('Iptc.Application2.SubLocation', | |
address['city_district']) | |
metadata.set_tag_string('Xmp.iptcExt.SubLocation', | |
address['city_district']) | |
dirty = True | |
if copyright_holder: | |
copy = 'Copyright {}. All rights reserved'.format(copyright_holder) | |
metadata.set_tag_string('Iptc.Application2.Copyright', copy) | |
metadata.set_tag_string('Xmp.iptcExt.AOCopyrightNotice', copy) | |
dirty = True | |
if dirty: | |
metadata.save_file(path) | |
print('Updated tags for "{}"'.format(path)) | |
def parse_args(): | |
parser = argparse.ArgumentParser( | |
description='Fill IPTC tag location information based on GPS ' | |
'image data') | |
parser.add_argument('path', type=str, nargs='+', | |
help='file or directory') | |
parser.add_argument('--copyright', type=str, default=None, | |
help='a copyright holder') | |
parser.add_argument('--email', type=str, default=None, | |
help='This should be used if you plan todo a large ' | |
'number of requests against ' | |
'http://nominatim.openstreetmap.org') | |
args = parser.parse_args() | |
return args | |
def main(): | |
args = parse_args() | |
GExiv2.initialize() | |
for path in args.path: | |
if os.path.isfile(path): | |
_metadata_update(path, args.copyright, args.email) | |
elif os.path.isdir(path): | |
for root, dirs, files in os.walk(path): | |
for file_path in files: | |
_metadata_update(os.path.join(root, file_path), | |
args.copyright, args.email) | |
else: | |
raise('What is this?') | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment