Files
photoimport/photoimport.py
T

143 lines
5.2 KiB
Python

#!/usr/bin/env python3
import os
import sys
import subprocess
import shutil
def get_exif_date(file_path):
"""
Uses exiftool to extract the File Creation Date/Time (CreateDate).
Returns the formatted date string or an error message if extraction fails.
"""
try:
result = subprocess.run(
['exiftool', '-d', "%Y-%m-%d", '-CreateDate', file_path],
capture_output=True,
text=True,
check=True
)
output = result.stdout.strip()
if ':' in output:
date_string = output.split(':', 1)[1].strip()
else:
date_string = output
if date_string:
return date_string.replace('-', '\\')
return "Date not found in metadata."
except subprocess.CalledProcessError as e:
return f"ERROR: exiftool failed. Check file integrity or permissions. (Details: {e.stderr.strip()})"
except FileNotFoundError:
return "CRITICAL ERROR: exiftool command not found. Please ensure exiftool is installed and in your system PATH."
def scan_photos(root_dir, base_target_path):
"""
Recursively scans the given directory (root_dir), extracts EXIF date,
prints file details with proposed destination paths, then asks for confirmation
before copying files.
"""
accepted_extensions = ('.jpg', '.jpeg', '.dng', '.raw', '.cr2', '.cr3', '.raf')
print(f"--- Starting photo scan in: {root_dir} ---")
found_files = []
try:
for foldername, subfolders, filenames in os.walk(root_dir):
for filename in filenames:
full_path = os.path.join(foldername, filename)
_, ext = os.path.splitext(filename)
if ext.lower() in accepted_extensions:
found_files.append(full_path)
except FileNotFoundError:
print(f"\nFATAL ERROR: The path '{root_dir}' was not found. Please check the drive letter.")
return
except Exception as e:
print(f"\nAN UNEXPECTED ERROR OCCURRED DURING DIRECTORY TRAVERSAL: {e}")
return
if not found_files:
print("\n--- Scan complete. No specified photo files found in this directory or its subdirectories. ---")
return
# Collect file info first (file_path, date_str, dest_dir)
file_info_list = []
for file_path in found_files:
date_time_str = get_exif_date(file_path)
if not base_target_path.endswith('\\'):
destination_dir = base_target_path + '\\' + date_time_str
else:
destination_dir = base_target_path + date_time_str
file_info_list.append((file_path, date_time_str, destination_dir))
# Print all items and their proposed destinations
print("\n========================================================")
print("--- File Name & Proposed Destination Directory ---")
print("========================================================\n")
for file_path, date_time_str, dest_dir in file_info_list:
print(f"File: {os.path.basename(file_path)}")
print(f" -> Extracted Date: {date_time_str}")
print(f" -> Proposed Destination Directory: {dest_dir}")
print("-" * 40)
print(f"\n========================================================")
print(f"--- Scan complete. Found {len(file_info_list)} files. ---")
print("Files with the same date will point to the same destination directory.")
# Ask for confirmation
response = input("\nDo you want to copy these items? (y/yes): ").strip().lower()
if response not in ('y', 'yes'):
print("Aborted. No files were copied.")
return
# Copy files
copied_count = 0
skipped_exists_count = 0
created_dirs_count = 0
for file_path, date_time_str, dest_dir in file_info_list:
dest_file = os.path.join(dest_dir, os.path.basename(file_path))
# Create destination directory if it doesn't exist
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
created_dirs_count += 1
# Check if file already exists in destination
if os.path.exists(dest_file):
print(f"File already exists: {dest_file} (skipped)")
skipped_exists_count += 1
else:
shutil.copy2(file_path, dest_file)
copied_count += 1
# Summary
print("\n========================================================")
print("--- Copy Operation Complete ---")
print("========================================================")
print(f"Files copied: {copied_count}")
if skipped_exists_count > 0:
print(f"Files skipped: {skipped_exists_count} (already exists)")
if created_dirs_count > 0:
print(f"Directories created: {created_dirs_count}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python photoimport.py <drive_path> <target_display_path>")
print("Example (for Windows): python photoimport.py Q:\\ I:\\Photos")
sys.exit(1)
root_scan_dir = sys.argv[1]
base_target_path = sys.argv[2]
print(f"Using base target path for grouping: {base_target_path}")
if not root_scan_dir.endswith(os.sep):
root_scan_dir = root_scan_dir + os.sep
scan_photos(root_scan_dir, base_target_path)