import os
import subprocess
def check_file_exists(path, file_name):
for root, dirs, files in os.walk(path):
for file in files:
if file.lower() == file_name.lower():
return True, os.path.join(root, file)
return False, None
def main(file_list_path):
failed_list = []
with open(file_list_path, 'r') as file:
lines = file.readlines()
for line in lines:
folder_file_path = line.strip()
folder, file_name = os.path.split(folder_file_path)
heic_file_name = file_name
jpg_file_name = file_name.replace('.HEIC', '.JPG').replace('.heic', '.jpg')
heic_exists, heic_file_path = check_file_exists(folder, heic_file_name)
if heic_exists:
continue
jpg_exists, jpg_file_path = check_file_exists(folder, jpg_file_name)
if not jpg_exists:
failed_list.append(folder_file_path)
continue
suffixed_jpg_file_name = jpg_file_name.replace('.JPG', '(1).JPG').replace('.jpg', '(1).jpg')
suffixed_jpg_exists, suffixed_jpg_file_path = check_file_exists(folder, suffixed_jpg_file_name)
if suffixed_jpg_exists:
print(f'rclone copy "Google Photos:album/{folder_file_path}" "{folder}/"')
failed_list.append(folder_file_path)
else:
rclone_command = f'rclone copy "Google Photos:album/{folder_file_path}" "{folder}/"'
try:
subprocess.run(rclone_command, shell=True, check=True)
os.remove(jpg_file_path)
print(f'Successfully replaced {jpg_file_path} with {folder_file_path}.')
except Exception as e:
failed_list.append(folder_file_path)
print(f"Failed to copy or delete file for {folder_file_path}: {e}")
return failed_list
os.chdir('/Users/salbahra/Downloads/google-photos/albums')
file_list_path = '/Users/salbahra/Downloads/filtered_heic_list_case_insensitive.txt' # replace with the path to your file list
failed_files = main(file_list_path)
if failed_files:
print("The following files failed to copy or delete:")
for failed_file in failed_files:
print(failed_file)
else:
print("All files processed successfully.")
import os
import subprocess
import datetime
import json
from pathlib import Path
import unicodedata
from urllib.parse import unquote
# Function to normalize Unicode strings
def normalize_unicode(string):
return unicodedata.normalize('NFC', string)
# Function to get modified dates for all files in an album from rclone
def get_rclone_modified_dates(album_name):
rclone_command = ["rclone", "lsjson", f"Google Photos:album/{album_name}"]
result = subprocess.run(rclone_command, capture_output=True, text=True)
dates = {}
if result.returncode == 0:
try:
files_info = json.loads(result.stdout)
for file_info in files_info:
modified_date_str = file_info['ModTime']
modified_date = datetime.datetime.strptime(modified_date_str, '%Y-%m-%dT%H:%M:%S%z')
decoded_name = unquote(file_info['Name'])
dates[decoded_name] = modified_date
except (KeyError, ValueError, json.JSONDecodeError):
print(f"Error parsing dates for album {album_name}")
else:
print(f"Error running rclone command for album {album_name}: {result.stderr}")
return dates
# Function to change file's modified date
def change_file_modified_date(filepath, modified_date):
modified_timestamp = modified_date.timestamp()
os.utime(filepath, (modified_timestamp, modified_timestamp))
# Function to find all video files in a directory
def find_media_files(directory):
video_extensions = ('.avi', '.mp4', '.mov', '.mkv', '.m4v', '.mpg', '.wmv', '.jpg', '.jpeg', '.png', '.heic', '.gif')
for root, _, files in os.walk(directory):
for file in files:
if file.lower().endswith(video_extensions):
yield os.path.join(root, file)
# Function to get all albums from the local disk
def get_all_albums(local_root):
return [name for name in os.listdir(local_root) if os.path.isdir(os.path.join(local_root, name))]
# Function to update videos modified date
def update_media_modified_date(directory, album_name, dates):
for filepath in find_media_files(directory):
filename = Path(filepath).name
normalized_filename = normalize_unicode(filename)
modified_time = os.path.getmtime(filepath)
modified_date = datetime.datetime.fromtimestamp(modified_time)
if modified_date < datetime.datetime(2024, 7, 1):
print(f"Skipping {filepath}, already updated")
continue
if normalized_filename in dates:
modified_date = dates[normalized_filename]
print(f"Updating {filepath} to modified date {modified_date}")
# change_file_modified_date(filepath, modified_date)
else:
print(f"Skipping {filepath}, no date found")
# Main function to process all albums
def process_all_albums(local_root):
albums = get_all_albums(local_root)
for album in albums:
album_directory = os.path.join(local_root, album)
normalized_album = normalize_unicode(album)
print(f"Processing album: {normalized_album}")
dates = get_rclone_modified_dates(normalized_album)
print(dates)
update_media_modified_date(album_directory, normalized_album, dates)
local_root_directory = "/Users/salbahra/Downloads/google-photos/albums"
process_all_albums(local_root_directory)
import os
import time
import subprocess
import json
import datetime
def get_metadata(file_path):
try:
result = subprocess.run(
['exiftool', '-json', file_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True
)
metadata = json.loads(result.stdout)
return metadata[0] if metadata else {}
except Exception as e:
print(f"An error occurred: {e}")
return {}
def get_creation_date(metadata):
date_formats = ['%Y:%m:%d %H:%M:%S', '%Y/%m/%d %H:%M:%S']
date_keys = [
'CreateDate', 'CreationDate', 'DateTimeOriginal', 'MediaCreateDate',
'TrackCreateDate', 'ModifyDate', 'MediaModifyDate', 'TrackModifyDate'
]
for key in date_keys:
if key in metadata:
for date_format in date_formats:
try:
return datetime.datetime.strptime(metadata[key], date_format)
except ValueError:
continue
return None
def update_file_modification_date(file_path, date):
mod_time = time.mktime(date.timetuple())
os.utime(file_path, (mod_time, mod_time))
def process_files_in_directory(directory):
for root, _, files in os.walk(directory):
for file in files:
file_path = os.path.join(root, file)
modified_time = os.path.getmtime(file_path)
modified_date = datetime.datetime.fromtimestamp(modified_time)
if modified_date < datetime.datetime(2024, 7, 1):
print(f"Skipping {file_path}, already updated")
continue
if file.lower().endswith(('.jpg', '.jpeg', '.png', '.heic', '.gif')):
date = get_creation_date(get_metadata(file_path))
elif file.lower().endswith(('.avi', '.mp4', '.mov', '.mkv', '.m4v', '.mpg', '.wmv')):
date = get_creation_date(get_metadata(file_path))
else:
continue
if date:
print(f"Updating {file_path} to {date}")
# update_file_modification_date(file_path, date)
else:
print(f"No date found for {file_path}, skipping.")
directory_to_process = '/Users/salbahra/Downloads/google-photos/albums'
process_files_in_directory(directory_to_process)
import os
import datetime
from pathlib import Path
def is_media_file(filename):
media_extensions = {'.avi', '.mp4', '.mov', '.mkv', '.m4v', '.mpg', '.wmv',
'.jpg', '.jpeg', '.png', '.heic', '.gif', '.3gp'}
return Path(filename).suffix.lower() in media_extensions
def get_creation_time(filepath):
return datetime.datetime.fromtimestamp(os.path.getmtime(filepath))
def find_recent_media_files(directory, date_threshold):
for root, _, files in os.walk(directory):
for file in files:
filepath = os.path.join(root, file)
if is_media_file(file):
creation_time = get_creation_time(filepath)
if creation_time > date_threshold:
print(f"Found: {filepath} (Created: {creation_time})")
current_directory = '/Users/salbahra/Downloads/google-photos/albums'
date_threshold = datetime.datetime(2024, 7, 1)
print(f"Searching for media files created after {date_threshold} in {current_directory}")
find_recent_media_files(current_directory, date_threshold)
print("Search completed.")