import os, re, shutil, calendar, datetime import exifread class Media(): def __init__(self, path, name, kind): self.path = path self.name = name self.kind = kind def order_by_tag(self, export_dir): if self.kind != 'photo': raise NotImplementedError("order_by_tag is only for photos.") with open(self.path, 'rb') as ph: tags = exifread.process_file(ph) if 'Image DateTime' in tags: date_taken = str(tags["Image DateTime"]).split() elif 'EXIF DateTimeOriginal' in tags: date_taken = str(tags["EXIF DateTimeOriginal"]).split() else: raise ValueError(f"No valid EXIF date tag found in {self.name}") year, month, day = map(int, date_taken[0].split(':')) hour, minute, second = map(int, date_taken[1].split(':')) date_obj = datetime.datetime(year, month, day, hour, minute, second) month_dir = os.path.join(export_dir, str(year), calendar.month_name[month]) os.makedirs(month_dir, exist_ok=True) shutil.move(self.path, os.path.join(month_dir, self.name)) os.utime(os.path.join(month_dir, self.name), (date_obj.timestamp(), date_obj.timestamp())) def order_by_match(self, matches, export_dir): if re.search(r's100', self.path): return if re.search(r'Screenshot', self.path, re.IGNORECASE): return m = next((re.search(pattern, self.path) for pattern in matches if re.search(pattern, self.path)), None) if not m: return year = int(m.group(1)) if year < 2000 or year > 2030: return month = int(m.group(2)) day = int(m.group(3)) date_obj = datetime.datetime(year, month, day) month_dir = os.path.join(export_dir, str(year), calendar.month_name[month]) os.makedirs(month_dir, exist_ok=True) shutil.move(self.path, os.path.join(month_dir, self.name)) os.utime(os.path.join(month_dir, self.name), (date_obj.timestamp(), date_obj.timestamp())) root_dir = './' export_dir = './Export/' matches = (r'(\d{4})-(\d{2})-(\d{2})', r'(\d{4})(\d{2})(\d{2})') media = list() for root, dirs, files in os.walk(root_dir): for file in files: path = os.path.join(root, file) ext = os.path.splitext(path)[1].lower() if ext in ('.jpg', '.jpeg', '.png', '.webp', '.heic'): media.append(Media(path, file, 'photo')) elif ext in ('.mov', '.mp4', '.3gp'): media.append(Media(path, file, 'video')) for element in media: try: element.order_by_tag(export_dir) except (ValueError, NotImplementedError): element.order_by_match(matches, export_dir) except Exception as e: print(f'Error processing {element.name}: {e}')