Created
August 11, 2019 15:23
-
-
Save huntfx/37db342a8b8e98bd6870fc8751fa1ab7 to your computer and use it in GitHub Desktop.
Figure out the date an image was created, and set the created/modified time to match. Run the Python file from inside a folder to apply to all images.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import time | |
from contextlib import suppress | |
if os.name == 'nt': | |
from ctypes import windll, wintypes, byref | |
def set_creation_time(path, timestamp): | |
"""Set the creation time of files in Windows. | |
Source: https://stackoverflow.com/a/56805533/2403000 | |
""" | |
timestamp = int((timestamp * 10000000) + 116444736000000000) | |
ctime = wintypes.FILETIME(timestamp & 0xFFFFFFFF, timestamp >> 32) | |
handle = windll.kernel32.CreateFileW(path, 256, 0, None, 3, 128, None) | |
windll.kernel32.SetFileTime(handle, byref(ctime), None, None) | |
windll.kernel32.CloseHandle(handle) | |
else: | |
set_creation_time = lambda path, timestamp: None | |
def str_to_timestamp(string, time_format): | |
return time.mktime(time.strptime(string, time_format)) | |
def get_timestamp_from_filename(filename): | |
"""Calculate the timestamp of a file based on its name. | |
If it is unable to calculate, None will be returned. | |
""" | |
filename_len = len(filename) | |
filename_prefix = filename.split('_', 1)[0] | |
# 20120401_165412 (Android) | |
if filename_len == 15 and filename[:4].isdigit(): | |
with suppress(ValueError): | |
return str_to_timestamp(filename, '%Y%m%d_%H%M%S') | |
if filename_len == 16: | |
# 20190209184635_1 (Steam) | |
if filename[-2] == '_' and filename[:-2].isdigit() and filename[-1].isdigit(): | |
with suppress(ValueError): | |
return str_to_timestamp(filename[:-1], '%Y%m%d%H%M%S_') | |
# 2015-01-29_00002 (Steam) | |
elif filename[:4].isdigit() and filename[-5:].isdigit(): | |
return str_to_timestamp(filename[:-5], '%Y-%m-%d_') | |
# For Honor2018-8-29-0-3-48 (UPlay) | |
if filename_len > 18: | |
dash_split = filename.rsplit('-', 5) | |
if len(dash_split) == 6: | |
date_string = dash_split[0][-4:] + '-' + '-'.join(dash_split[1:]) | |
if date_string.count('-') == 5 and '_' not in date_string: | |
with suppress(ValueError): | |
return str_to_timestamp(date_string, '%Y-%m-%d-%H-%M-%S') | |
# IMG_20160803_175206 (Instagram) | |
if filename_len == 19 and filename_prefix == 'IMG': | |
with suppress(ValueError): | |
return str_to_timestamp(filename, 'IMG_%Y%m%d_%H%M%S') | |
# FaceApp_1492541591338 (FaceApp) | |
if filename_len == 21 and filename_prefix == 'FaceApp': | |
with suppress(ValueError): | |
return int(filename[8:]) / 1000 | |
if filename_len == 23: | |
if filename_prefix == 'IMG': | |
# IMG_20161224_134354_765 (Instagram) | |
if filename[12] == filename[19] == '_': | |
with suppress(ValueError): | |
return str_to_timestamp(filename[:-4], 'IMG_%Y%m%d_%H%M%S') | |
# IMG_2016-07-09-15295765 (Pokemon Go) | |
if filename[8] == filename[11] == filename[14] == '-': | |
with suppress(ValueError): | |
return str_to_timestamp(filename, 'IMG_%Y-%m-%d-%H%M%S%f') | |
# 2016-09-27 13-49-41.513 (Lifecam) | |
if filename[:4].isdigit() and filename[10] == ' ' and filename[19] == '.': | |
with suppress(ValueError): | |
return str_to_timestamp(filename, '%Y-%m-%d %H-%M-%S.%f') | |
# Screenshot_20181104-153209 (Android) | |
if filename_len == 26 and filename_prefix == 'Screenshot': | |
with suppress(ValueError): | |
return str_to_timestamp(filename, 'Screenshot_%Y%m%d-%H%M%S') | |
# Screenshot_2016-03-19-15-21-29 (Android) | |
if filename_len == 30 and filename_prefix == 'Screenshot': | |
with suppress(ValueError): | |
return str_to_timestamp(filename, 'Screenshot_%Y-%m-%d-%H-%M-%S') | |
# HighResScreenShot_2015-12-06_14-12-26 (Elite Dangerous) | |
if filename_len == 37 and filename_prefix == 'HighResScreenShot': | |
with suppress(ValueError): | |
return str_to_timestamp(filename, 'HighResScreenShot_%Y-%m-%d_%H-%M-%S') | |
# 2013-05-19 12.03.16 252886351658901753_8111220388 (4K Stogram) | |
if filename_len >= 49 and filename[:4].isdigit() and filename[10] == filename[19] == ' ': | |
with suppress(ValueError): | |
return str_to_timestamp(filename[:19], '%Y-%m-%d %H.%M.%s') | |
return None | |
def edit_time(path, modified=None, created=None, access=None): | |
"""Edit the times of a file.""" | |
if modified is not None or access is not None: | |
if modified is None: | |
modified = os.stat(path).st_mtime | |
if access is None: | |
access = os.stat(path).st_atime | |
os.utime(path, (access, modified)) | |
if created is not None: | |
set_creation_time(path, created) | |
def edit_file(path, access_time=None): | |
"""Parse a filename and set the time created/modified.""" | |
path = os.path.normpath(path) | |
timestamp = get_timestamp_from_filename(path.rsplit(os.path.sep, 1)[-1].rsplit('.', 1)[0]) | |
if timestamp is None: | |
print('Failed to update {}'.format(path)) | |
return None | |
if access_time is None: | |
access_time = time.time() | |
edit_time(path, modified=timestamp, created=timestamp, access=access_time) | |
print('Updated {}'.format(path)) | |
return timestamp | |
def edit_folder(path): | |
"""Parse and set time created/modified for all files within a folder.""" | |
count = 0 | |
for root, dirs, files in os.walk(path): | |
for file in files: | |
file_path = os.path.join(root, file) | |
if edit_file(file_path): | |
count += 1 | |
return count | |
if __name__ == '__main__': | |
count = edit_folder(os.path.abspath(__file__).rsplit(os.path.sep, 1)[0]) | |
print('Number of files updated: {}'.format(count)) | |
input('Press enter to exit...') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment