Skip to content

Instantly share code, notes, and snippets.

@toabctl
Last active November 17, 2017 13:15
Show Gist options
  • Save toabctl/3be45855ede528a5fb97c31aa7a7b7d5 to your computer and use it in GitHub Desktop.
Save toabctl/3be45855ede528a5fb97c31aa7a7b7d5 to your computer and use it in GitHub Desktop.
Fill Iptc/Xmp tags based on GPS location and OpenStreetMap data
#!/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