Created
June 18, 2016 02:54
-
-
Save dalemyers/12b7e62cea976a48107e5c83bb6fe340 to your computer and use it in GitHub Desktop.
Small photo archiving script for personal use
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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