You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dot-files/bin/sort_images_into_folders

106 lines
3.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/bin/env python3
# vim: set noexpandtab tabstop=4 ft=python :
"""
A script moving pictures from one folder to subfolders (depending on the date they are taken)
"""
import os
import argparse
import re
import shutil
import PIL.Image
import PIL.ExifTags
def get_date(filename):
"""
Read EXIF data from a file and return a string containing "yyyymmdd"
:param filename: The files name
"""
image = PIL.Image.open(filename)
image_exif = image._getexif()
if not image_exif:
return None
matches = re.match(r'(?P<year>\d{4}):(?P<month>\d{2}):(?P<day>\d{2})', image_exif[306])
image.close()
if matches is None:
return None
return "%04d%02d%02d" % (int(matches["year"]), int(matches["month"]), int(matches["day"]))
def create_directory(directory):
"""
Try to create the directory return False when theres already something there thats not a
directory
"""
if os.path.exists(directory):
if not os.path.isdir(directory):
print("'%s' exists but is no directory!" % (directory))
return False
else:
print("Creating directory '%s'" % (directory))
os.mkdir(directory)
return True
def main():
"""
Move files to a directory by date
:param args: CLI arguments
"""
# verify we're getting the correct data :)
if PIL.ExifTags.TAGS[306] != "DateTime":
print("ERROR: EXIF index for DateTime changed!")
exit(2)
# parse arguments
parser = argparse.ArgumentParser(description="Move/copy pictures to subfolders")
parser.add_argument("--source", "-s", action="store", default=os.getcwd(), metavar="<path>", \
help="The source directory (default = current)", dest="source")
parser.add_argument("--destination", "-d", action="store", default=os.getcwd(), metavar="<path>", \
help="The destination directory (default = current)", dest="destination")
parser.add_argument("--copy", "-c", action="store_true", dest="copy_files", \
help="Copy the files insted of moving them")
parser.add_argument("--existing", "-e", action="store", dest="existing_files", \
choises=["ask", "skip", "overwrite"], default="ask", \
help="What to do with existing files")
args = parser.parse_args()
# settings
source_directory = args.source
destination_directory = args.destination
copy_files = args.copy_files
existing_files = args.existing_files
# iterate through directory
for filename in os.listdir(source_directory):
if os.path.isfile(os.path.join(source_directory, filename)) and \
re.search(r'\.jpg$', filename, flags=re.IGNORECASE):
date = get_date(os.path.join(source_directory, filename))
if date is None:
print("WARNING: No EXIF data for file '%s'" % (filename))
continue
directory = os.path.join(destination_directory, date)
# create directory if it not exists
if not create_directory(directory):
continue
# copy or move file
write_file = True
if os.path.exists(os.path.join(destination_directory, date, filename)) and \
existing_files != "overwrite":
write_file = False
if existing_files == "ask":
overwrite = input("File '%s' exists! Overwrite? [yn]: ")
while overwrite not in ["y", "n"]:
overwrite = input("File '%s' exists! Overwrite? [yn]: ")
write_file = overwrite == "y"
if not write_file:
print("Skipping file '%s'" % (filename))
elif copy_files:
print("Copy file '%s' to '%s'" % (filename, date))
shutil.copy2(os.path.join(source_directory, filename), \
os.path.join(destination_directory, date, filename))
else:
print("Moving file '%s' to '%s'" % (filename, date))
os.rename(os.path.join(source_directory, filename), \
os.path.join(destination_directory, date, filename))
if __name__ == "__main__":
main()