Skip to content

Instantly share code, notes, and snippets.

@BDeliers
Created February 2, 2023 17:33
Show Gist options
  • Save BDeliers/f61e2c22bef49eae3b8ea1b4caa9b839 to your computer and use it in GitHub Desktop.
Save BDeliers/f61e2c22bef49eae3b8ea1b4caa9b839 to your computer and use it in GitHub Desktop.
Automatically sort your pictures in a date-dependent directories tree !
#!/bin/python3
"""
Script to make directories tree from image's EXIF shot date
BDeliers - January 2023
"""
__docformat__ = 'reStructuredText'
import argparse
import datetime
import os
import shutil
from PIL import Image
EXTENSIONS = ["jpeg", "jpg", "heic", "png", "gif", "tiff", "bmp"]
def GetImageTakenDate(path):
"""
Input an image's path and return its taken date if exists, formatted as a datetime structure
"""
ret = None
im = Image.open(path)
exif = im.getexif()
if ((len(exif) > 0) and (306 in exif.keys())):
ret = datetime.datetime.strptime(exif[306], '%Y:%m:%d %H:%M:%S')
im.close()
return ret
if __name__ == "__main__":
"""
Main entry point
"""
# Parse args
parser = argparse.ArgumentParser(prog="PhotoOrganizer", description="Script to make directories tree from image's EXIF shot date")
parser.add_argument("--input", "-i", required=True, help="Input path to crawl")
parser.add_argument("--output", "-o", required=False, default=None, help="Output path where to create the tree (optionnal, default = Input path)")
parser.add_argument("--granularity", "-g", required=False, default="DAY", choices=["DAY", "MONTH", "YEAR"], help="Granularity of the tree DAY|MONTH|YEAR (optionnal, default = DAY)")
args = parser.parse_args()
INPATH = args.input
OUTPATH = args.output
GRANULARITY = args.granularity
if (OUTPATH == None):
OUTPATH = INPATH
# Get an absolute path if relatives are specified
INPATH = os.path.abspath(INPATH)
OUTPATH = os.path.abspath(OUTPATH)
print("Image files from {} will be organized and copied to {}".format(INPATH, OUTPATH))
fileNames = os.listdir(INPATH)
for elt in fileNames:
# If it's an actual image
inFile = "{}/{}".format(INPATH, elt)
if (os.path.isfile(inFile) and (elt.split('.')[1].lower() in EXTENSIONS)):
takenDate = GetImageTakenDate(inFile)
# If we have a taken date, we can continue
if (takenDate != None):
if (GRANULARITY == "YEAR"):
outDir = "{}/{}".format(OUTPATH, takenDate.year)
elif (GRANULARITY == "MONTH"):
outDir = "{}/{}/{}".format(OUTPATH, takenDate.year, takenDate.month)
else: # DAY
outDir = "{}/{}/{}/{}".format(OUTPATH, takenDate.year, takenDate.month, takenDate.day)
# Else, create an "undefined" folder
else:
outDir = "{}/NoDate".format(OUTPATH)
# Make target directory
if (not os.path.exists(outDir)):
os.makedirs(outDir)
# Actually copy the file to its new location if we don't risk overwriting
if (not os.path.exists("{}/{}".format(outDir, elt))):
try:
shutil.copy2(inFile, outDir)
print("Copied file " + elt)
except Exception:
print("An error occured with the file " + elt)
print(Exception)
else:
print("Skipped file " + elt)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment