118 lines
3.7 KiB
Python
118 lines
3.7 KiB
Python
import argparse
|
|
import traceback
|
|
from photoapp.image import get_jpg_info, get_hash, get_mtime, special_magic
|
|
from itertools import chain
|
|
from photoapp.types import Photo, PhotoSet, known_extensions, regular_images, files_raw, files_video, map_extension
|
|
import os
|
|
|
|
|
|
"""
|
|
Photo sorting rules:
|
|
|
|
jpeg
|
|
exif date
|
|
file modification date
|
|
raw
|
|
group with exif date of jpeg with same name
|
|
file modification date
|
|
mov, video, or other
|
|
modification date
|
|
"""
|
|
|
|
|
|
def pprogress(done, total=None):
|
|
print(" complete: {}{}\r".format(done, " / {} ".format(total) if total else ''), end='')
|
|
|
|
|
|
def group_by_extension(files):
|
|
byext = {k: [] for k in known_extensions}
|
|
excluded = []
|
|
|
|
for item in files:
|
|
if not os.path.isfile(item): # Not a file
|
|
excluded.append(item)
|
|
continue
|
|
extension = item.split(".")
|
|
if len(extension) < 2: # no extension
|
|
excluded.append(item)
|
|
continue
|
|
extension = map_extension(extension[-1].lower())
|
|
if extension not in known_extensions: # an extension we don't support
|
|
excluded.append(item)
|
|
continue
|
|
byext[extension.lower()].append(item)
|
|
|
|
return (byext, excluded)
|
|
|
|
|
|
def get_photosets(files):
|
|
byext, skipped = group_by_extension(files)
|
|
|
|
photosets = []
|
|
|
|
# process regular images first.
|
|
for item in chain(*[byext[ext] for ext in regular_images]):
|
|
photosets.append(get_jpg_info(item))
|
|
|
|
# process raws
|
|
for item in chain(*[byext[ext] for ext in files_raw]):
|
|
itemmeta = Photo(hash=get_hash(item), path=item, size=os.path.getsize(item),
|
|
format=special_magic(item), fname=os.path.basename(item))
|
|
fprefix = os.path.basename(item)[::-1].split(".", 1)[-1][::-1]
|
|
fmatch = "{}.jpg".format(fprefix.lower()) # if we're inspecting "foobar.raw", match it with "foobar.jpg"
|
|
# TODO does this account for extension mappinh like jpeg->jpg?
|
|
foundmatch = False
|
|
for photo in photosets:
|
|
for fmt in photo.files[:]:
|
|
if os.path.basename(fmt.path).lower() == fmatch:
|
|
foundmatch = True
|
|
photo.files.append(itemmeta)
|
|
break
|
|
if foundmatch:
|
|
break
|
|
if not foundmatch:
|
|
mtime = get_mtime(item)
|
|
print("no match found for", itemmeta.path, "but importing anyway")
|
|
photosets.append(PhotoSet(date=mtime, date_real=mtime, files=[itemmeta]))
|
|
# TODO handle any xmp without an associated regular image or cr2
|
|
|
|
# process other known formats
|
|
for item in chain(*[byext[ext] for ext in files_video]):
|
|
itemmeta = Photo(hash=get_hash(item), path=item, size=os.path.getsize(item),
|
|
format=special_magic(item), fname=os.path.basename(item))
|
|
mtime = get_mtime(item)
|
|
photosets.append(PhotoSet(date=mtime, date_real=mtime, files=[itemmeta]))
|
|
|
|
return photosets, skipped
|
|
|
|
|
|
def batch_ingest(library, files):
|
|
sets, skipped = get_photosets(files)
|
|
|
|
print("\nUpdating database")
|
|
done = 0
|
|
total = len(sets)
|
|
for photoset in sets:
|
|
try:
|
|
library.add_photoset(photoset)
|
|
pprogress(done, total)
|
|
done += 1
|
|
except Exception:
|
|
traceback.print_exc()
|
|
pass
|
|
print("\nUpdate complete")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Library ingestion tool")
|
|
parser.add_argument("files", nargs="+")
|
|
args = parser.parse_args()
|
|
|
|
library = PhotoLibrary("photos.db", "./library", "./cache")
|
|
|
|
batch_ingest(library, args.files)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|