82 lines
3.1 KiB
Python
82 lines
3.1 KiB
Python
from datetime import datetime, timedelta
|
|
from os import listdir
|
|
from os.path import exists, isfile, join, splitext
|
|
from PIL import Image, ExifTags
|
|
from pytimeparse.timeparse import timeparse
|
|
from shutil import copy
|
|
import json
|
|
|
|
|
|
class ImageSorter:
|
|
def __init__(self, args):
|
|
self.args = args
|
|
self.mapping = self.read_mapping_config() if args.config_mapping_file else {}
|
|
self.verbose = self.args.verbose
|
|
|
|
def sort_files(self):
|
|
self.print_log(f"Reading files from {self.args.input_dir}")
|
|
|
|
files = [f for f in listdir(self.args.input_dir) if isfile(join(self.args.input_dir, f))]
|
|
for file in files:
|
|
filepath = join(self.args.input_dir, file)
|
|
self.print_log(f"Start handling file {filepath}")
|
|
if splitext(file)[1].lower() != ".jpg":
|
|
continue
|
|
|
|
date_taken = self.get_date_taken(filepath)
|
|
if date_taken:
|
|
self.write_file(filepath, date_taken)
|
|
|
|
def get_date_taken(self, file):
|
|
try:
|
|
with Image.open(file) as img:
|
|
exif = {ExifTags.TAGS[k]: v for k, v in img._getexif().items() if k in ExifTags.TAGS}
|
|
camera_model = exif.get("Model")
|
|
self.print_log(f"Camera model is {camera_model}")
|
|
|
|
date_str = exif.get("DateTime")
|
|
if not date_str:
|
|
self.print_log("No DateTime EXIF data found")
|
|
return None
|
|
|
|
date_taken = datetime.strptime(date_str, "%Y:%m:%d %H:%M:%S")
|
|
self.print_log(f"Original date taken is {date_taken.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
return date_taken + self.get_camera_model_time_delta(camera_model)
|
|
except Exception as e:
|
|
self.print_log(f"Error reading EXIF data from {file}: {e}")
|
|
return None
|
|
|
|
def read_mapping_config(self):
|
|
try:
|
|
with open(self.args.config_mapping_file, "r") as f:
|
|
return json.load(f)
|
|
except Exception as e:
|
|
self.print_log(f"Error reading config mapping file: {e}")
|
|
return {}
|
|
|
|
def get_camera_model_time_delta(self, camera_model):
|
|
time_str = self.mapping.get(camera_model, "0s")
|
|
seconds = timeparse(time_str)
|
|
self.print_log(f"Found timedelta {seconds} seconds for camera model {camera_model}")
|
|
return timedelta(seconds=seconds)
|
|
|
|
def write_file(self, filepath, date_taken):
|
|
base_name = f"Picture_{date_taken.strftime('%Y%m%d_%H%M%S')}"
|
|
new_file_name = f"{base_name}_{self.args.suffix}" if self.args.suffix else base_name
|
|
|
|
count = 1
|
|
final_file_name = new_file_name
|
|
while exists(join(self.args.output_dir, f"{final_file_name}.jpg")):
|
|
final_file_name = f"{new_file_name} ({count})"
|
|
count += 1
|
|
self.print_log(f"File already exists, trying {final_file_name}.jpg instead")
|
|
|
|
output_file = join(self.args.output_dir, f"{final_file_name}.jpg")
|
|
copy(filepath, output_file)
|
|
self.print_log(f"Copied {filepath} to {output_file}")
|
|
self.print_log()
|
|
|
|
def print_log(self, msg=""):
|
|
if self.verbose:
|
|
print(msg)
|