2015-11-29 14:34:20 +01:00
|
|
|
import os.path
|
2015-12-06 03:17:15 +01:00
|
|
|
import ntpath
|
2015-12-06 01:52:21 +01:00
|
|
|
from time import localtime, strftime, strptime, mktime
|
2015-11-29 14:34:20 +01:00
|
|
|
import shutil
|
2017-11-30 22:37:56 +01:00
|
|
|
import exifread
|
2015-11-29 14:34:20 +01:00
|
|
|
|
2017-11-25 19:02:08 +01:00
|
|
|
unknownDateFolderName = "date-unknown"
|
2015-11-29 14:34:20 +01:00
|
|
|
|
|
|
|
def getMinimumCreationTime(exif_data):
|
|
|
|
creationTime = None
|
|
|
|
dateTime = exif_data.get('DateTime')
|
2021-11-16 23:14:24 +01:00
|
|
|
if (dateTime is None):
|
|
|
|
dateTime = exif_data.get('Image DateTime')
|
2015-11-29 14:34:20 +01:00
|
|
|
dateTimeOriginal = exif_data.get('EXIF DateTimeOriginal')
|
|
|
|
dateTimeDigitized = exif_data.get('EXIF DateTimeDigitized')
|
|
|
|
|
|
|
|
# 3 differnt time fields that can be set independently result in 9 if-cases
|
|
|
|
if (dateTime is None):
|
|
|
|
if (dateTimeOriginal is None):
|
|
|
|
# case 1/9: dateTime, dateTimeOriginal, and dateTimeDigitized = None
|
|
|
|
# case 2/9: dateTime and dateTimeOriginal = None, then use dateTimeDigitized
|
2017-11-25 19:21:49 +01:00
|
|
|
creationTime = dateTimeDigitized
|
2015-11-29 14:34:20 +01:00
|
|
|
else:
|
|
|
|
# case 3/9: dateTime and dateTimeDigitized = None, then use dateTimeOriginal
|
|
|
|
# case 4/9: dateTime = None, prefere dateTimeOriginal over dateTimeDigitized
|
|
|
|
creationTime = dateTimeOriginal
|
|
|
|
else:
|
|
|
|
# case 5-9: when creationTime is set, prefere it over the others
|
|
|
|
creationTime = dateTime
|
|
|
|
|
|
|
|
return creationTime
|
|
|
|
|
2015-12-06 01:52:21 +01:00
|
|
|
def postprocessImage(images, imageDirectory, fileName):
|
|
|
|
imagePath = os.path.join(imageDirectory, fileName)
|
2015-11-29 14:34:20 +01:00
|
|
|
image = open(imagePath, 'rb')
|
2015-12-06 01:52:21 +01:00
|
|
|
creationTime = None
|
2017-11-25 19:21:49 +01:00
|
|
|
try:
|
2015-11-29 14:34:20 +01:00
|
|
|
exifTags = exifread.process_file(image, details=False)
|
2015-12-06 01:52:21 +01:00
|
|
|
creationTime = getMinimumCreationTime(exifTags)
|
2015-11-29 14:34:20 +01:00
|
|
|
except:
|
|
|
|
print("invalid exif tags for " + fileName)
|
|
|
|
|
|
|
|
# distinct different time types
|
|
|
|
if creationTime is None:
|
2015-12-06 01:52:21 +01:00
|
|
|
creationTime = localtime(os.path.getctime(imagePath))
|
2015-11-29 14:34:20 +01:00
|
|
|
else:
|
2015-12-06 01:52:21 +01:00
|
|
|
try:
|
|
|
|
creationTime = strptime(str(creationTime), "%Y:%m:%d %H:%M:%S")
|
|
|
|
except:
|
|
|
|
creationTime = localtime(os.path.getctime(imagePath))
|
2015-11-29 14:34:20 +01:00
|
|
|
|
2015-12-06 01:52:21 +01:00
|
|
|
images.append((mktime(creationTime), imagePath))
|
|
|
|
image.close()
|
2015-11-29 14:34:20 +01:00
|
|
|
|
2017-11-25 19:02:08 +01:00
|
|
|
# Creates the requested path recursively.
|
|
|
|
def createPath(newPath):
|
|
|
|
if not os.path.exists(newPath):
|
|
|
|
os.makedirs(newPath)
|
2015-11-29 14:34:20 +01:00
|
|
|
|
2017-11-25 19:02:08 +01:00
|
|
|
# Pass None for month to create 'year/eventNumber' directories instead of 'year/month/eventNumber'.
|
|
|
|
def createNewFolder(destinationRoot, year, month, eventNumber):
|
|
|
|
if month is not None:
|
|
|
|
newPath = os.path.join(destinationRoot, year, month, str(eventNumber))
|
|
|
|
else:
|
|
|
|
newPath = os.path.join(destinationRoot, year, str(eventNumber))
|
|
|
|
|
|
|
|
createPath(newPath)
|
2015-11-29 14:34:20 +01:00
|
|
|
|
2015-12-06 01:52:21 +01:00
|
|
|
def createUnknownDateFolder(destinationRoot):
|
|
|
|
path = os.path.join(destinationRoot, unknownDateFolderName)
|
2017-11-25 19:02:08 +01:00
|
|
|
createPath(path)
|
2015-11-29 14:34:20 +01:00
|
|
|
|
2017-11-30 22:48:57 +01:00
|
|
|
def writeImages(images, destinationRoot, minEventDeltaDays, splitByMonth=False):
|
|
|
|
minEventDelta = minEventDeltaDays * 60 * 60 * 24 # convert in seconds
|
2015-11-29 14:34:20 +01:00
|
|
|
sortedImages = sorted(images)
|
|
|
|
previousTime = None
|
|
|
|
eventNumber = 0
|
2017-11-25 19:02:08 +01:00
|
|
|
previousDestination = None
|
2015-12-06 01:52:21 +01:00
|
|
|
today = strftime("%d/%m/%Y")
|
2015-11-29 14:34:20 +01:00
|
|
|
|
|
|
|
for imageTuple in sortedImages:
|
2015-12-06 03:17:15 +01:00
|
|
|
destination = ""
|
|
|
|
destinationFilePath = ""
|
2015-12-06 01:52:21 +01:00
|
|
|
t = localtime(imageTuple[0])
|
|
|
|
year = strftime("%Y", t)
|
2017-11-25 19:02:08 +01:00
|
|
|
month = splitByMonth and strftime("%m", t) or None
|
2015-12-06 01:52:21 +01:00
|
|
|
creationDate = strftime("%d/%m/%Y", t)
|
2015-12-06 03:17:15 +01:00
|
|
|
fileName = ntpath.basename(imageTuple[1])
|
|
|
|
|
2015-12-06 01:52:21 +01:00
|
|
|
if(creationDate == today):
|
|
|
|
createUnknownDateFolder(destinationRoot)
|
|
|
|
destination = os.path.join(destinationRoot, unknownDateFolderName)
|
2015-12-06 03:17:15 +01:00
|
|
|
destinationFilePath = os.path.join(destination, fileName)
|
2017-11-25 19:21:49 +01:00
|
|
|
|
2015-12-06 01:52:21 +01:00
|
|
|
else:
|
|
|
|
if (previousTime == None) or ((previousTime + minEventDelta) < imageTuple[0]):
|
|
|
|
eventNumber = eventNumber + 1
|
2017-11-25 19:02:08 +01:00
|
|
|
createNewFolder(destinationRoot, year, month, eventNumber)
|
|
|
|
|
2015-11-29 14:34:20 +01:00
|
|
|
previousTime = imageTuple[0]
|
|
|
|
|
2017-11-25 19:02:08 +01:00
|
|
|
destComponents = [destinationRoot, year, month, str(eventNumber)]
|
|
|
|
destComponents = [v for v in destComponents if v is not None]
|
|
|
|
destination = os.path.join(*destComponents)
|
|
|
|
|
|
|
|
# it may be possible that an event covers 2 years.
|
|
|
|
# in such a case put all the images to the event in the old year
|
2015-12-06 01:52:21 +01:00
|
|
|
if not (os.path.exists(destination)):
|
2017-11-25 19:02:08 +01:00
|
|
|
destination = previousDestination
|
|
|
|
# destination = os.path.join(destinationRoot, str(int(year) - 1), str(eventNumber))
|
2015-12-06 01:52:21 +01:00
|
|
|
|
2017-11-25 19:02:08 +01:00
|
|
|
previousDestination = destination
|
2015-12-06 03:17:15 +01:00
|
|
|
destinationFilePath = os.path.join(destination, fileName)
|
|
|
|
|
|
|
|
if not (os.path.exists(destinationFilePath)):
|
2015-12-06 01:52:21 +01:00
|
|
|
shutil.move(imageTuple[1], destination)
|
2015-12-06 03:17:15 +01:00
|
|
|
else:
|
|
|
|
if (os.path.exists(imageTuple[1])):
|
|
|
|
os.remove(imageTuple[1])
|
2015-12-06 01:52:21 +01:00
|
|
|
|
|
|
|
|
2017-11-30 22:48:57 +01:00
|
|
|
def postprocessImages(imageDirectory, minEventDeltaDays, splitByMonth):
|
2015-12-06 01:52:21 +01:00
|
|
|
images = []
|
|
|
|
for root, dirs, files in os.walk(imageDirectory):
|
|
|
|
for file in files:
|
|
|
|
postprocessImage(images, imageDirectory, file)
|
|
|
|
|
2017-11-30 22:48:57 +01:00
|
|
|
writeImages(images, imageDirectory, minEventDeltaDays, splitByMonth)
|