6 Commits
Author SHA1 Message Date
clemens 65e352e8a4 Merge branch 'master' of github.com:gullevek/reverse_geolocate 2022-11-11 22:36:30 +09:00
clemens 38083d8a46 Add .venv folder to gitignore 2022-11-11 22:34:48 +09:00
clemens ce676dea72 Changed indent level for parser arguments
They are all now on the same level indented by one step
2022-11-11 22:32:55 +09:00
clemens 8548cc1f0f Add simpe debug print, add 'r' for all regex calls 2022-08-13 15:50:24 +09:00
clemens 63202b53f1 add -p for only list unset GPS long/lat entries 2020-10-20 23:59:32 +09:00
clemens 2836a40616 Add another City location lookup for google API 2020-10-20 22:33:46 +09:00
2 changed files with 155 additions and 111 deletions
+1
View File
@@ -0,0 +1 @@
.venv/
+69 -26
View File
@@ -73,7 +73,7 @@ class readable_dir(argparse.Action):
# check distance values are valid # check distance values are valid
class distance_values(argparse.Action): class distance_values(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None): def __call__(self, parser, namespace, values, option_string=None):
m = re.match('^(\d+)\s?(m|km)$', values) m = re.match(r'^(\d+)\s?(m|km)$', values)
if m: if m:
# convert to int in meters # convert to int in meters
values = int(m.group(1)) values = int(m.group(1))
@@ -128,7 +128,7 @@ def reverseGeolocateInit(longitude, latitude):
'error_message': '' 'error_message': ''
} }
# error if long/lat is not valid # error if long/lat is not valid
latlong_re = re.compile('^\d+\.\d+$') latlong_re = re.compile(r'^\d+\.\d+$')
if not latlong_re.match(str(longitude)) or not latlong_re.match(str(latitude)): if not latlong_re.match(str(longitude)) or not latlong_re.match(str(latitude)):
geolocation['status'] = 'ERROR' geolocation['status'] = 'ERROR'
geolocation['error_message'] = 'Latitude {} or Longitude {} are not valid'.format(latitude, longitude) geolocation['error_message'] = 'Latitude {} or Longitude {} are not valid'.format(latitude, longitude)
@@ -201,7 +201,7 @@ def reverseGeolocateOpenStreetMap(longitude, latitude):
# dict with location, city, state, country, country code # dict with location, city, state, country, country code
# if not fillable, entry is empty # if not fillable, entry is empty
# SAMPLE: http://maps.googleapis.com/maps/api/geocode/json?latlng=<latitude>,<longitude>&language=<lang>&sensor=false&key=<api key> # SAMPLE: http://maps.googleapis.com/maps/api/geocode/json?latlng=<latitude>,<longitude>&language=<lang>&sensor=false&key=<api key>
def reverseGeolocateGoogle(longitude, latitude): def reverseGeolocateGoogle(longitude, latitude): # noqa: C901
# init # init
geolocation = reverseGeolocateInit(longitude, latitude) geolocation = reverseGeolocateInit(longitude, latitude)
temp_geolocation = geolocation.copy() temp_geolocation = geolocation.copy()
@@ -238,7 +238,7 @@ def reverseGeolocateGoogle(longitude, latitude):
'CountryCode': ['country'], 'CountryCode': ['country'],
'Country': ['country'], 'Country': ['country'],
'State': ['administrative_area_level_1', 'administrative_area_level_2'], 'State': ['administrative_area_level_1', 'administrative_area_level_2'],
'City': ['locality'], 'City': ['locality', 'administrative_area_level_3'],
'Location': ['sublocality_level_1', 'sublocality_level_2', 'route'], 'Location': ['sublocality_level_1', 'sublocality_level_2', 'route'],
} }
# print("Error: {}".format(response.json()['status'])) # print("Error: {}".format(response.json()['status']))
@@ -328,7 +328,7 @@ def convertLongToDMS(lat_long):
# number used in google/lr internal # number used in google/lr internal
def longLatReg(longitude, latitude): def longLatReg(longitude, latitude):
# regex # regex
latlong_re = re.compile('^(\d+),(\d+\.\d+)([NESW]{1})$') latlong_re = re.compile(r'^(\d+),(\d+\.\d+)([NESW]{1})$')
# dict for loop # dict for loop
lat_long = { lat_long = {
'longitude': longitude, 'longitude': longitude,
@@ -520,7 +520,7 @@ def formatLen(string, length):
# RETURN: number found in the BK string or 0 for none # RETURN: number found in the BK string or 0 for none
# DESC : gets the BK number for sorting in the file list # DESC : gets the BK number for sorting in the file list
def fileSortNumber(file): def fileSortNumber(file):
m = re.match('.*\.BK\.(\d+)\.xmp$', file) m = re.match(r'.*\.BK\.(\d+)\.xmp$', file)
return int(m.group(1)) if m is not None else 0 return int(m.group(1)) if m is not None else 0
@@ -644,7 +644,9 @@ parser = argparse.ArgumentParser(
# xmp folder (or folders), or file (or files) # xmp folder (or folders), or file (or files)
# note that the target directory or file needs to be writeable # note that the target directory or file needs to be writeable
parser.add_argument('-i', '--include-source', parser.add_argument(
'-i',
'--include-source',
required=True, required=True,
nargs='*', nargs='*',
action=writable_dir_folder, action=writable_dir_folder,
@@ -653,7 +655,9 @@ parser.add_argument('-i', '--include-source',
help='The source folder or folders with the XMP files that need reverse geo encoding to be set. Single XMP files can be given here' help='The source folder or folders with the XMP files that need reverse geo encoding to be set. Single XMP files can be given here'
) )
# exclude folders # exclude folders
parser.add_argument('-x', '--exclude-source', parser.add_argument(
'-x',
'--exclude-source',
nargs='*', nargs='*',
action=writable_dir_folder, action=writable_dir_folder,
dest='exclude_sources', dest='exclude_sources',
@@ -663,7 +667,9 @@ parser.add_argument('-x', '--exclude-source',
# LR database (base folder) # LR database (base folder)
# get .lrcat file in this folder # get .lrcat file in this folder
parser.add_argument('-l', '--lightroom', parser.add_argument(
'-l',
'--lightroom',
# required=True, # required=True,
action=readable_dir, action=readable_dir,
dest='lightroom_folder', dest='lightroom_folder',
@@ -672,7 +678,9 @@ parser.add_argument('-l', '--lightroom',
) )
# strict LR check with base path next to the file base name # strict LR check with base path next to the file base name
parser.add_argument('-s', '--strict', parser.add_argument(
'-s',
'--strict',
dest='lightroom_strict', dest='lightroom_strict',
action='store_true', action='store_true',
help='Do strict check for Lightroom files including Path in query' help='Do strict check for Lightroom files including Path in query'
@@ -682,7 +690,9 @@ parser.add_argument('-s', '--strict',
# FLAG: default: only set not filled # FLAG: default: only set not filled
# other: overwrite all or overwrite if one is missing, overwrite specifc field (as defined below) # other: overwrite all or overwrite if one is missing, overwrite specifc field (as defined below)
# fields: Location, City, State, Country, CountryCode # fields: Location, City, State, Country, CountryCode
parser.add_argument('-f', '--field', parser.add_argument(
'-f',
'--field',
action='append', action='append',
type=str.lower, # make it lowercase for check type=str.lower, # make it lowercase for check
choices=['overwrite', 'location', 'city', 'state', 'country', 'countrycode'], choices=['overwrite', 'location', 'city', 'state', 'country', 'countrycode'],
@@ -694,7 +704,9 @@ parser.add_argument('-f', '--field',
'If with overwrite the field will be overwritten if already set, else it will be always skipped.' 'If with overwrite the field will be overwritten if already set, else it will be always skipped.'
) )
parser.add_argument('-d', '--fuzzy-cache', parser.add_argument(
'-d',
'--fuzzy-cache',
type=str.lower, type=str.lower,
action=distance_values, action=distance_values,
nargs='?', nargs='?',
@@ -707,70 +719,99 @@ parser.add_argument('-d', '--fuzzy-cache',
) )
# Google Maps API key to overcome restrictions # Google Maps API key to overcome restrictions
parser.add_argument('-g', '--google', parser.add_argument(
'-g',
'--google',
dest='google_api_key', dest='google_api_key',
metavar='GOOGLE API KEY', metavar='GOOGLE API KEY',
help='Set a Google API Maps key to overcome the default lookup limitations' help='Set a Google API Maps key to overcome the default lookup limitations'
) )
# use open street maps # use open street maps
parser.add_argument('-o', '--openstreetmap', parser.add_argument(
'-o',
'--openstreetmap',
dest='use_openstreetmap', dest='use_openstreetmap',
action='store_true', action='store_true',
help='Use openstreetmap instead of Google' help='Use openstreetmap instead of Google'
) )
# email of open street maps requests # email of open street maps requests
parser.add_argument('-e', '--email', parser.add_argument(
'-e',
'--email',
dest='email', dest='email',
metavar='EMIL ADDRESS', metavar='EMIL ADDRESS',
help='An email address for OpenStreetMap' help='An email address for OpenStreetMap'
) )
# write api/email settings to config file # write api/email settings to config file
parser.add_argument('-w', '--write-settings', parser.add_argument(
'-w',
'--write-settings',
dest='config_write', dest='config_write',
action='store_true', action='store_true',
help='Write Google API or OpenStreetMap email to config file' help='Write Google API or OpenStreetMap email to config file'
) )
# only read data and print on screen, do not write anything # only read data and print on screen, do not write anything
parser.add_argument('-r', '--read-only', parser.add_argument(
'-r',
'--read-only',
dest='read_only', dest='read_only',
action='store_true', action='store_true',
help='Read current values from the XMP file only, do not read from LR or lookup any data and write back' help='Read current values from the XMP file only, do not read from LR or lookup any data and write back'
) )
# only list unset ones # only list unset ones
parser.add_argument('-u', '--unset-only', parser.add_argument(
'-u',
'--unset-only',
dest='unset_only', dest='unset_only',
action='store_true', action='store_true',
help='Only list unset XMP files' help='Only list unset XMP files'
) )
# only list unset GPS codes
parser.add_argument(
'-p',
'--unset-gps-only',
dest='unset_gps_only',
action='store_true',
help='Only list unset XMP files for GPS fields'
)
# don't try to do auto adjust in list view # don't try to do auto adjust in list view
parser.add_argument('-a', '--no-autoadjust', parser.add_argument(
'-a',
'--no-autoadjust',
dest='no_autoadjust', dest='no_autoadjust',
action='store_true', action='store_true',
help='Don\'t try to auto adjust columns' help='Don\'t try to auto adjust columns'
) )
# compact view, compresses columns down to a minimum # compact view, compresses columns down to a minimum
parser.add_argument('-c', '--compact', parser.add_argument(
'-c',
'--compact',
dest='compact_view', dest='compact_view',
action='store_true', action='store_true',
help='Very compact list view' help='Very compact list view'
) )
# Do not create backup files # Do not create backup files
parser.add_argument('-n', '--nobackup', parser.add_argument(
'-n',
'--nobackup',
dest='no_xmp_backup', dest='no_xmp_backup',
action='store_true', action='store_true',
help='Do not create a backup from the XMP file' help='Do not create a backup from the XMP file'
) )
# verbose args for more detailed output # verbose args for more detailed output
parser.add_argument('-v', '--verbose', parser.add_argument(
'-v',
'--verbose',
action='count', action='count',
dest='verbose', dest='verbose',
help='Set verbose output level' help='Set verbose output level'
@@ -837,7 +878,7 @@ if args.email and not args.use_openstreetmap:
error = True error = True
# if email and not basic valid email (@ .) # if email and not basic valid email (@ .)
if args.email: if args.email:
if not re.match('^.+@.+\.[A-Za-z]{1,}$', args.email): if not re.match(r'^.+@.+\.[A-Za-z]{1,}$', args.email):
print("Not a valid email for OpenStreetMap: {}".format(args.email)) print("Not a valid email for OpenStreetMap: {}".format(args.email))
error = True error = True
# on error exit here # on error exit here
@@ -980,6 +1021,8 @@ if args.lightroom_folder:
cur = lrdb.cursor() cur = lrdb.cursor()
# flag that we have Lightroom DB # flag that we have Lightroom DB
use_lightroom = True use_lightroom = True
if args.debug:
print("### USE Lightroom {}".format(use_lightroom))
# on error exit here # on error exit here
if error: if error:
@@ -1088,7 +1131,7 @@ if args.read_only:
# ### MAIN WORK LOOP # ### MAIN WORK LOOP
# now we just loop through each file and work on them # now we just loop through each file and work on them
for xmp_file in work_files: for xmp_file in work_files: # noqa: C901
if not args.read_only: if not args.read_only:
print("---> {}: ".format(xmp_file), end='') print("---> {}: ".format(xmp_file), end='')
@@ -1111,7 +1154,7 @@ for xmp_file in work_files:
print("### => XMP: {}:{} => {}".format(xmp_fields[xmp_field], xmp_field, data_set[xmp_field])) print("### => XMP: {}:{} => {}".format(xmp_fields[xmp_field], xmp_field, data_set[xmp_field]))
if args.read_only: if args.read_only:
# view only if list all or if data is unset # view only if list all or if data is unset
if not args.unset_only or (args.unset_only and '' in data_set.values()): if (not args.unset_only and not args.unset_gps_only) or (args.unset_only and '' in data_set.values()) or (args.unset_gps_only and (not data_set['GPSLatitude'] or not data_set['GPSLongitude'])):
# for read only we print out the data formatted # for read only we print out the data formatted
# headline check, do we need to print that # headline check, do we need to print that
count['read'] = printHeader(header_line.format(page_no=page_no, page_all=page_all), count['read'], header_repeat) count['read'] = printHeader(header_line.format(page_no=page_no, page_all=page_all), count['read'], header_repeat)
@@ -1287,7 +1330,7 @@ for xmp_file in work_files:
with open(xmp_file, 'w') as fptr: with open(xmp_file, 'w') as fptr:
fptr.write(xmp.serialize_to_str(omit_packet_wrapper=True)) fptr.write(xmp.serialize_to_str(omit_packet_wrapper=True))
else: else:
print("[TEST] Would write {} ".format(data_set, xmp_file), end='') print("[TEST] Would write {} {}".format(data_set, xmp_file), end='')
if from_cache: if from_cache:
print("[UPDATED FROM CACHE]") print("[UPDATED FROM CACHE]")
else: else: