pip install exifread
Replace path_to_sort
by the path where all the photos are stored at
import os | |
import shutil | |
import datetime | |
import exifread | |
def sort_files_by_date(path): | |
"""Sorts files within folders by capture date, then last modification date, then creation date. | |
Args: | |
path: The path to the directory containing the files. | |
""" | |
for root, dirs, files in os.walk(path): | |
for file in files: | |
file_path = os.path.join(root, file) | |
try: | |
# Attempt to get the capture date from metadata | |
capture_date = get_capture_date_from_metadata(file_path) | |
if capture_date: | |
sort_by_date(int(round(capture_date.timestamp())), file_path) | |
continue | |
except Exception as e: | |
# If metadata fails, try last modification date | |
print(f"Error getting capture date for {file_path}: {e}") | |
sort_by_date(os.path.getmtime(file_path), file_path) | |
def get_capture_date_from_metadata(file_path) -> datetime.datetime|None: | |
"""Extracts the capture date from the file's EXIF metadata. | |
Args: | |
file_path: The path to the file. | |
Returns: | |
The capture date as a datetime.datetime object, or None if it cannot be extracted. | |
""" | |
with open(file_path, 'rb') as f: | |
tags = exifread.process_file(f) | |
if 'EXIF DateTimeOriginal' in tags: | |
capture_date_str = tags['EXIF DateTimeOriginal'].values | |
try: | |
capture_date = datetime.datetime.strptime(capture_date_str, '%Y-%m-%d %H:%M:%S') | |
return capture_date | |
except: | |
# Use alternative format | |
capture_date = datetime.datetime.strptime(capture_date_str, '%Y:%m:%d %H:%M:%S') | |
return capture_date | |
return None | |
def sort_by_date(date, file_path): | |
"""Moves the file to a new directory based on the given date. | |
Args: | |
date: The date as a timestamp. | |
file_path: The path to the file. | |
""" | |
date_time = datetime.datetime.fromtimestamp(date) | |
year_dir = f"{date_time.year}" | |
date_dir = f"{date_time.year}-{date_time.month:02d}-{date_time.day:02d}" | |
new_path = os.path.join(os.path.dirname(file_path), year_dir, date_dir) | |
os.makedirs(new_path, exist_ok=True) | |
shutil.move(file_path, os.path.join(new_path, os.path.basename(file_path))) | |
# Example usage | |
path_to_sort = "/path/to/photos" | |
sort_files_by_date(path_to_sort) |