Exclude folders from processing, add Page number to list view
The include folders argument changed from -x to -i -x is used for excluding folder or files form processing In the list view the page number and max pages is also printed out (cosmetic)
This commit is contained in:
16
README.md
16
README.md
@@ -21,8 +21,9 @@ See more information for [Python XMP Tool kit](http://python-xmp-toolkit.readthe
|
||||
|
||||
## Command line arguments
|
||||
|
||||
reverse_geolocate.py [-h] -x
|
||||
reverse_geolocate.py [-h] -i
|
||||
[XMP SOURCE FOLDER [XMP SOURCE FOLDER ...]]
|
||||
[-x [EXCLUDE XMP SOURCE FOLDER [EXCLUDE XMP SOURCE FOLDER ...]]]
|
||||
[-l LIGHTROOM FOLDER] [-s]
|
||||
[-f <overwrite, location, city, state, country, countrycode>]
|
||||
[-g GOOGLE API KEY] [-o] [-e EMIL ADDRESS] [-w]
|
||||
@@ -32,7 +33,8 @@ reverse_geolocate.py [-h] -x
|
||||
|
||||
Argument | Argument Value | Description
|
||||
--- | --- | ---
|
||||
-x, --xmp | XMP sidecar source folder or XMP sidecar file itself | Must given argument. It sets the path where the script will search for XMP sidecar files. It will traverse into subdirectories. A single XMP sidecar file can also be given. If the same file folder combination is found only one is processed.
|
||||
-i, --include-source | XMP sidecar source folder or XMP sidecar file itself | Must given argument. It sets the path where the script will search for XMP sidecar files. It will traverse into subdirectories. A single XMP sidecar file can also be given. If the same file folder combination is found only one is processed.
|
||||
-x, --exclude-source | Folder or File | If given those files and folders will be excluded from work
|
||||
-l, --lightroom | Lightroom DB base folder | The folder where the .lrcat file is located. Optional, if this is set, LR values are read before any Google maps connection is done. Fills the Latitude and Longitude and the location names. Lightroom data never overwrites data already set in the XMP sidecar file. It is recommended to have Lightroom write the XMP sidecar file before this script is run
|
||||
-s, --strict | | Do strict check for Lightroom files and include the path into the check
|
||||
-f, --field | Keyword: overwrite, location, city, state, country, countrycode | In the default no data is overwritten if it is already set. With the 'overwrite' flag all data is set new from the Google Maps location data. Other arguments are each of the location fields and if set only this field will be set. This can be combined with the 'overwrite' flag to overwrite already set data
|
||||
@@ -53,13 +55,19 @@ If the Lightroom lookup is used without the --strict argument and several files
|
||||
#### Example
|
||||
|
||||
```
|
||||
reverse_geolocate.py -x Photos/2017/01 -x Photos/2017/02 -l LightRoom/MyCatalogue -f overwrite -g <API KEY>
|
||||
reverse_geolocate.py -i Photos/2017/01 -i Photos/2017/02 -l LightRoom/MyCatalogue -f overwrite -g <API KEY>
|
||||
```
|
||||
|
||||
Will find all XMP sidecar files in both folders *Photos/2017/01* and *Photos/2017/02* and all folder below it. Uses the Lightroom database at *LightRoom/MyCatalogue*. The script will overwrite all data, even if it is already set
|
||||
|
||||
```
|
||||
reverse_geolocate.py -x Photos/2017/01/Event-01/some_photo.xmp -f location
|
||||
reverse_geolocate.py -i Photos/2017/01 -i Photos/2017/02 -x Photos/2017/02/Folder\ A -x Photos/2017/01/Folder\ B/some_file.xmp -l LightRoom/MyCatalogue
|
||||
```
|
||||
|
||||
Will exlucde "Photos/2017/02/Folder A" from processing. For -x also a file (including the .xmp extension) can be given.
|
||||
|
||||
```
|
||||
reverse_geolocate.py -i Photos/2017/01/Event-01/some_photo.xmp -f location
|
||||
```
|
||||
|
||||
Only works on *some_photo.xmp* file and will only set the *location* field if it is not yet set.
|
||||
|
||||
@@ -13,7 +13,8 @@ import argparse, sqlite3, requests, configparser, textwrap
|
||||
import glob, os, sys, re
|
||||
# Note XMPFiles does not work with sidecar files, need to read via XMPMeta
|
||||
from libxmp import XMPMeta, XMPError, consts
|
||||
from shutil import copyfile
|
||||
from shutil import copyfile, get_terminal_size
|
||||
from math import ceil
|
||||
|
||||
##############################################################
|
||||
### FUNCTIONS
|
||||
@@ -33,8 +34,8 @@ class writable_dir_folder(argparse.Action):
|
||||
# init new output array
|
||||
out = []
|
||||
# if we have a previous list in the namespace extend current list
|
||||
if type(namespace.xmp_sources) is list:
|
||||
out.extend(namespace.xmp_sources)
|
||||
if type(getattr(namespace, self.dest)) is list:
|
||||
out.extend(getattr(namespace, self.dest))
|
||||
# add the new dir to it
|
||||
out.append(prospective_dir)
|
||||
# and write that list back to the self.dest in the namespace
|
||||
@@ -350,7 +351,11 @@ def shortenPath(path, length = 30, file_only = False, path_only = False):
|
||||
# RETURN: line counter +1
|
||||
# DESC : prints header line and header seperator line
|
||||
def printHeader(header, lines = 0, header_line = 0):
|
||||
global page_no
|
||||
if lines == header_line:
|
||||
# add one to the pages shown and reset the lines to start new page
|
||||
page_no += 1
|
||||
lines = 0
|
||||
# print header
|
||||
print("{}".format(header))
|
||||
lines += 1
|
||||
@@ -376,7 +381,7 @@ parser = argparse.ArgumentParser(
|
||||
|
||||
# xmp folder (or folders), or file (or files)
|
||||
# note that the target directory or file needs to be writeable
|
||||
parser.add_argument('-x', '--xmp',
|
||||
parser.add_argument('-i', '--include-source',
|
||||
required = True,
|
||||
nargs = '*',
|
||||
action = writable_dir_folder,
|
||||
@@ -384,6 +389,14 @@ parser.add_argument('-x', '--xmp',
|
||||
metavar = 'XMP SOURCE FOLDER',
|
||||
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
|
||||
parser.add_argument('-x', '--exclude-source',
|
||||
nargs = '*',
|
||||
action = writable_dir_folder,
|
||||
dest = 'exclude_sources',
|
||||
metavar = 'EXCLUDE XMP SOURCE FOLDER',
|
||||
help = 'Folders and files that will be excluded.'
|
||||
)
|
||||
|
||||
# LR database (base folder)
|
||||
# get .lrcat file in this folder
|
||||
@@ -480,8 +493,9 @@ if not args.verbose:
|
||||
args.verbose = 0
|
||||
|
||||
if args.debug:
|
||||
print("### ARGUMENT VARS: X: {xmp}, L: {lr}, F: {fc}, M: {osm}, G: {gp}, E: {em}, N: {nbk}, W: {wrc}, V: {v}, D: {d}, T: {t}".format(
|
||||
xmp = args.xmp_sources,
|
||||
print("### ARGUMENT VARS: I: {incl}, X: {excl}, L: {lr}, F: {fc}, M: {osm}, G: {gp}, E: {em}, N: {nbk}, W: {wrc}, V: {v}, D: {d}, T: {t}".format(
|
||||
incl = args.xmp_sources,
|
||||
excl = args.exclude_sources,
|
||||
lr = args.lightroom_folder,
|
||||
fc = args.field_controls,
|
||||
osm = args.use_openstreetmap,
|
||||
@@ -662,24 +676,30 @@ xmp = XMPMeta()
|
||||
for xmp_file_source in args.xmp_sources:
|
||||
# if folder, open and loop
|
||||
# NOTE: we do check for folders in there, if there are we recourse traverse them
|
||||
if os.path.isdir(xmp_file_source):
|
||||
# also check that folder is not in exclude list
|
||||
if os.path.isdir(xmp_file_source) and xmp_file_source.rstrip('/') not in [x.rstrip('/') for x in args.exclude_sources]:
|
||||
# open folder and look for any .xmp files and push them into holding array
|
||||
# if there are folders, dive into them
|
||||
# or glob glob all .xmp files + directory
|
||||
for root, dirs, files in os.walk(xmp_file_source):
|
||||
for file in sorted(files):
|
||||
# but has no .BK. inside
|
||||
if file.endswith(".xmp") and ".BK." not in file:
|
||||
# 1) but has no .BK. inside
|
||||
# 2) file is not in exclude list
|
||||
# 3) full folder is not in exclude list
|
||||
if file.endswith(".xmp") and ".BK." not in file \
|
||||
and "{}/{}".format(root, file) not in args.exclude_sources \
|
||||
and root.rstrip('/') not in [x.rstrip('/') for x in args.exclude_sources]:
|
||||
if "{}/{}".format(root, file) not in work_files:
|
||||
work_files.append("{}/{}".format(root, file))
|
||||
count['all'] += 1
|
||||
else:
|
||||
if xmp_file_source not in work_files:
|
||||
# not already added to list and not in the exclude list either
|
||||
if xmp_file_source not in work_files and xmp_file_source not in args.exclude_sources:
|
||||
work_files.append(xmp_file_source)
|
||||
count['all'] += 1
|
||||
|
||||
if args.debug:
|
||||
print("### Work Files {}".format(work_files))
|
||||
|
||||
# if we have read only we print list format style
|
||||
if args.read_only:
|
||||
# various string lengths
|
||||
@@ -692,10 +712,14 @@ if args.read_only:
|
||||
'state': 18,
|
||||
'city': 20,
|
||||
'location': 25,
|
||||
'path': 30,
|
||||
'path': 40,
|
||||
}
|
||||
# after how many lines do we reprint the header
|
||||
header_repeat = 40;
|
||||
header_repeat = 50;
|
||||
# how many pages will we have
|
||||
page_all = ceil(len(work_files) / header_repeat)
|
||||
# current page number
|
||||
page_no = 1
|
||||
# the formatted line for the output
|
||||
format_line = " {{filename:<{}}} | {{latitude:>{}}} | {{longitude:>{}}} | {{code:<{}}} | {{country:<{}}} | {{state:<{}}} | {{city:<{}}} | {{location:<{}}} | {{path:<{}}}".format(
|
||||
format_length['filename'],
|
||||
@@ -715,7 +739,7 @@ if args.read_only:
|
||||
header_line = '''{}
|
||||
{}
|
||||
{}'''.format(
|
||||
'', # can later be set to something else, eg page numbers
|
||||
'> Page {page_no:,}/{page_all:,}', # can later be set to something else, eg page numbers
|
||||
format_line.format( # the header title line
|
||||
filename = 'File',
|
||||
latitude = 'Latitude',
|
||||
@@ -740,7 +764,10 @@ if args.read_only:
|
||||
)
|
||||
)
|
||||
# print header
|
||||
printHeader(header_line)
|
||||
printHeader(header_line.format(page_no = page_no, page_all = page_all))
|
||||
# print no files found if we have no files
|
||||
if not work_files:
|
||||
print("{:<60}".format('[!!!] No files found'))
|
||||
# now we just loop through each file and work on them
|
||||
for xmp_file in work_files:
|
||||
if not args.read_only:
|
||||
@@ -789,7 +816,7 @@ for xmp_file in work_files:
|
||||
if args.read_only:
|
||||
# for read only we print out the data formatted
|
||||
# headline check, do we need to print that
|
||||
count['read'] = printHeader(header_line, count['read'], header_repeat)
|
||||
count['read'] = printHeader(header_line.format(page_no = page_no, page_all = page_all), count['read'], header_repeat)
|
||||
# the data content
|
||||
print(format_line.format(
|
||||
filename = shortenPath(xmp_file, format_length['filename'], file_only = True), # shorten from the left
|
||||
|
||||
Reference in New Issue
Block a user