Skip to content

Instantly share code, notes, and snippets.

@dalemyers
Created June 18, 2016 02:54
Show Gist options
  • Save dalemyers/12b7e62cea976a48107e5c83bb6fe340 to your computer and use it in GitHub Desktop.
Save dalemyers/12b7e62cea976a48107e5c83bb6fe340 to your computer and use it in GitHub Desktop.
Small photo archiving script for personal use
import Tkinter
import tkFileDialog
import os
import hashlib
import datetime
import pytz
import shutil
from PIL import Image
from PIL.ExifTags import TAGS
UK_TIME_ZONE = pytz.timezone("Europe/London")
SEATTLE_TIME_ZONE = pytz.timezone("US/Pacific")
IMAGE_EXTENSIONS = ["png","bmp","raw","jpg","jpeg","tiff"]
def get_md5(file_path):
return hashlib.md5(open(file_path, 'rb').read()).hexdigest()
def get_directory(prompt, initial_directory="/"):
tk_root = Tkinter.Tk()
directory = tkFileDialog.askdirectory(parent=tk_root, initialdir=initial_directory, title=prompt)
if len(directory) > 0:
return directory
else:
return None
def get_photos(directory):
for dir_name, subdir_list, file_list in os.walk(directory):
for filename in file_list:
ext = filename.split(".")[-1]
if ext.lower() in IMAGE_EXTENSIONS:
yield os.path.join(dir_name, filename)
def parse_exif_datetime(value):
return datetime.datetime.strptime(value, '%Y:%m:%d %H:%M:%S')
def get_exif(photo_path):
photo = Image.open(str(photo_path))
exif_data = {}
# Populate Exif Data
try:
exif_raw_data = photo._getexif()
for tag, value in exif_raw_data.items():
decoded = TAGS.get(tag, tag)
exif_data[decoded] = value
except:
pass
if len(exif_data.keys()) == 0:
return {}
# Normalise Exif Data
for key, value in exif_data.items():
if type(key) != str:
exif_data[str(key)] = exif_data[key]
del exif_data[key]
key = str(key)
if type(value) == str or type(value) == unicode:
exif_data[key] = value.strip()
if key.startswith("DateTime"):
exif_data[key] = parse_exif_datetime(value)
if "MakerNote" in exif_data.keys():
del exif_data["MakerNote"]
return exif_data
def set_date_info(photo_info):
new_time = None
for key in ["DateTimeOriginal", "DateTimeDigitized", "DateTime"]:
try:
new_time = photo_info["exif"][key]
break
except:
pass
if new_time == None:
try:
new_time = datetime.datetime.strptime(photo_info["raw_name"], '%Y-%m-%d %H.%M.%S')
except:
return False
photo_info["new_name"] = new_time.strftime('%Y-%m-%d_%H.%M.%S')
photo_info["year"] = "%02d" % (new_time.year,)
photo_info["month"] = "%02d" % (new_time.month,)
photo_info["day"] = "%02d" % (new_time.day,)
photo_info["hour"] = "%02d" % (new_time.hour,)
photo_info["minute"] = "%02d" % (new_time.minute,)
photo_info["second"] = "%02d" % (new_time.second,)
return True
def get_name_and_extension(photo_info):
photo_info["extension"] = photo_info["path"].split(".")[-1]
tempname = photo_info["path"]
tempname = tempname.replace("\\","/")
tempname = tempname.split("/")[-1]
tempname = tempname[:-len("." + photo_info["extension"])]
photo_info["raw_name"] = tempname
def get_photo_info(photos, directory):
for photo in get_photos(directory):
photo_info = {"path":photo}
get_name_and_extension(photo_info)
photo_info["exif"] = get_exif(photo_info["path"])
if not set_date_info(photo_info):
print "Unable to find date: " + photo_info["path"]
continue
photo_info["md5"] = get_md5(photo)
#print photo_info
photos.append(photo_info)
def get_name_count(file_path, name, file_hash):
test_name = os.path.splitext(name)[0]
matches = 0
for existing_file in os.listdir(file_path):
if existing_file.startswith(name):
if get_md5(os.path.join(file_path,existing_file)) == file_hash:
print "Existing: " + os.path.join(file_path,existing_file)
return -1
matches += 1
return matches + 1
def add_extension(filename, extension):
temp_name = filename
temp_ext = extension
if temp_name[-1] == "/" or temp_name[-1] == "\\":
temp_name = temp_name[:-1]
if extension[0] == ".":
temp_ext = extension[1:]
return temp_name + "." + temp_ext.lower()
def move(photo_info, photos_dir):
# Check if photos_dir exists
if not os.path.isdir(photos_dir):
os.makedirs(photos_dir)
# Check if full dir with year and month exists
full_dir = os.path.join(photos_dir, photo_info["year"], photo_info["month"])
if not os.path.isdir(full_dir):
os.makedirs(full_dir)
# Check if file with same name exists
count = get_name_count(full_dir, photo_info["new_name"], photo_info["md5"])
if count > 1:
photo_info["new_name"] += "_" + str(count)
if count == -1:
# There is an identical file so don't bother moving, and just delete
print "Deleting file due to already existing: ",
os.remove(photo_info["path"])
return
full_path = os.path.join(full_dir, photo_info["new_name"])
# Add extension back in
full_path = add_extension(full_path, photo_info["extension"])
# Copy the file
shutil.move(photo_info["path"], full_path)
def main():
photos_dir = get_directory('Where should the photos be moved to?')
new_dir = get_directory("Where are the photos to be moved?")
photos = []
get_photo_info(photos, new_dir)
print "Found all info. Beginning move..."
for photo in photos:
move(photo, photos_dir)
print photos
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment