Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Mossuru777/2cee729681706489bc430694d283a0e1 to your computer and use it in GitHub Desktop.
Save Mossuru777/2cee729681706489bc430694d283a0e1 to your computer and use it in GitHub Desktop.
GooglePhoto転送時に使ったExif復元ツール
import glob
import locale
import os
import sys
from datetime import datetime, timedelta, timezone
from typing import Optional
from pyexiv2 import Image
TZ_JST = timezone(timedelta(hours=9))
EXPECTED_DATETIME_RANGE_MIN = datetime(2004, 1, 1, 0, 0, 0, 0, TZ_JST)
EXPECTED_DATETIME_RANGE_MAX = datetime(EXPECTED_DATETIME_RANGE_MIN.year, 12, 31, 23, 59, 59, 0, TZ_JST)
EXIF_TAG_NAME = "Exif.Photo.DateTimeOriginal"
OFFSET = timedelta(hours=9, minutes=3)
def main(args) -> None:
paths = []
for path in args[1:]:
if os.path.isdir(path):
paths.extend([filepath for filepath in glob.glob(f"{os.path.abspath(path)}/*.jpg")])
elif os.path.splitext(path)[1].lower() == "jpg":
paths.append(path)
files = []
for filepath in paths:
abs_filepath = os.path.abspath(filepath)
image = Image(abs_filepath, locale.getdefaultlocale())
mtime_dt = datetime.fromtimestamp(os.path.getmtime(abs_filepath), TZ_JST)
files.append((abs_filepath, image, mtime_dt))
target_files = []
for file in files:
filepath, image, mtime_dt = file
filename = os.path.basename(filepath)
print(f"{filename}: ", end="")
exif_date_dt = get_exif_date_dt(image)
if exif_date_dt is None:
if EXPECTED_DATETIME_RANGE_MIN <= mtime_dt <= EXPECTED_DATETIME_RANGE_MAX:
print(f"{mtime_dt.strftime('%Y/%m/%d %H:%M:%S')} -> ", end="")
else:
print(f"[Failed: Unable to identify possible datetime] (mtime: {mtime_dt.strftime('%Y/%m/%d %H:%M:%S')})")
image.close()
continue
else:
if EXPECTED_DATETIME_RANGE_MIN <= exif_date_dt <= EXPECTED_DATETIME_RANGE_MAX:
print(f"{exif_date_dt.strftime('%Y/%m/%d %H:%M:%S')} [Skip]")
image.close()
continue
else:
print(f"{exif_date_dt.strftime('%Y/%m/%d %H:%M:%S')} -> ", end="")
offset_dt = get_offset_date(mtime_dt)
target_files.append((filepath, image, offset_dt))
print(f"{offset_dt.strftime('%Y/%m/%d %H:%M:%S')}")
for target_file in target_files:
filepath, image, offset_dt = target_file
set_original_date(image, offset_dt)
image.close()
os.utime(filepath, (datetime.now().timestamp(), offset_dt.timestamp()))
def get_exif_date_dt(image: Image) -> Optional[datetime]:
exif = image.read_exif()
if EXIF_TAG_NAME in exif:
exif_val = exif[EXIF_TAG_NAME]
exif_val_dt = datetime.strptime(exif_val + "+0900", "%Y:%m:%d %H:%M:%S%z")
return exif_val_dt
return None
def get_offset_date(mtime_dt: datetime) -> datetime:
if OFFSET is not None:
return mtime_dt - OFFSET
else:
return mtime_dt
def set_original_date(image: Image, set_date_dt: datetime) -> None:
set_date_str = set_date_dt.strftime("%Y:%m:%d %H:%M:%S")
image.modify_exif({EXIF_TAG_NAME: set_date_str})
if __name__ == '__main__':
if len(sys.argv) >= 2:
main(sys.argv)
else:
print('Arguments are too short')
import glob
import locale
import os
import sys
from datetime import datetime, timedelta, timezone
from typing import Optional
from pyexiv2 import Image
TZ_JST = timezone(timedelta(hours=9))
SET_DATETIME = datetime(2003, 5, 22, 23, 59, 59, 0, TZ_JST)
EXIF_SKIP_RANGE_MIN = datetime(SET_DATETIME.year, SET_DATETIME.month, SET_DATETIME.day, 0, 0, 0, 0, TZ_JST)
EXIF_SKIP_RANGE_MAX = datetime(SET_DATETIME.year, SET_DATETIME.month, SET_DATETIME.day, 23, 59, 59, 0, TZ_JST)
EXIF_TAG_NAME = "Exif.Photo.DateTimeOriginal"
def main(args) -> None:
paths = []
for path in args[1:]:
if os.path.isdir(path):
paths.extend([filepath for filepath in glob.glob(f"{os.path.abspath(path)}/*.jpg")])
elif os.path.splitext(path)[1].lower() == "jpg":
paths.append(path)
files = []
for filepath in paths:
abs_filepath = os.path.abspath(filepath)
image = Image(abs_filepath, locale.getdefaultlocale())
mtime_dt = datetime.fromtimestamp(os.path.getmtime(abs_filepath))
files.append((abs_filepath, image, mtime_dt))
target_files = []
for file in files:
filepath, image, mtime_dt = file
filename = os.path.basename(filepath)
print(f"{filename}: ", end="")
exif_date_dt = get_exif_date_dt(image)
if exif_date_dt is None:
print(f"{mtime_dt.strftime('%Y/%m/%d %H:%M:%S')} -> ", end="")
else:
if EXIF_SKIP_RANGE_MIN <= exif_date_dt <= EXIF_SKIP_RANGE_MAX:
print(f"{exif_date_dt.strftime('%Y/%m/%d %H:%M:%S')} [Skip]")
image.close()
continue
else:
print(f"{exif_date_dt.strftime('%Y/%m/%d %H:%M:%S')} -> ", end="")
target_files.append((filepath, image))
print(f"{SET_DATETIME.strftime('%Y/%m/%d %H:%M:%S')}")
for target_file in target_files:
filepath, image = target_file
set_original_date(image, SET_DATETIME)
image.close()
os.utime(filepath, (datetime.now().timestamp(), SET_DATETIME.timestamp()))
def get_exif_date_dt(image: Image) -> Optional[datetime]:
try:
exif = image.read_exif()
if EXIF_TAG_NAME in exif:
exif_val = exif[EXIF_TAG_NAME]
exif_val_dt = datetime.strptime(exif_val + "+0900", "%Y:%m:%d %H:%M:%S%z")
return exif_val_dt
except ValueError:
pass
return None
def set_original_date(image: Image, set_date_dt: datetime) -> None:
set_date_str = set_date_dt.strftime("%Y:%m:%d %H:%M:%S")
image.modify_exif({EXIF_TAG_NAME: set_date_str})
if __name__ == '__main__':
if len(sys.argv) >= 2:
main(sys.argv)
else:
print('Arguments are too short')
import glob
import os
import sys
from datetime import datetime, timedelta, timezone
TZ_JST = timezone(timedelta(hours=9))
EXPECTED_MTIME_RANGE_MIN = datetime(2004, 1, 1, 0, 0, 0, 0, TZ_JST)
EXPECTED_MTIME_RANGE_MAX = datetime(EXPECTED_MTIME_RANGE_MIN.year, 12, 31, 23, 59, 59, 0, TZ_JST)
OFFSET = timedelta(hours=9, minutes=0)
def main(args) -> None:
paths = []
for path in args[1:]:
if os.path.isdir(path):
paths.extend([filepath for filepath in glob.glob(f"{os.path.abspath(path)}/*.mov")])
elif os.path.splitext(path)[1].lower() == "mov":
paths.append(path)
files = []
for filepath in paths:
mtime_dt = datetime.fromtimestamp(os.path.getmtime(filepath), TZ_JST)
abs_filepath = os.path.abspath(filepath)
files.append((abs_filepath, mtime_dt))
target_files = []
for file in files:
filepath, mtime_dt = file
filename = os.path.basename(filepath)
print(f"{filename}: ", end="")
if not (EXPECTED_MTIME_RANGE_MIN <= mtime_dt <= EXPECTED_MTIME_RANGE_MAX):
print(f"[Failed: Unable to identify possible datetime] (mtime: {mtime_dt.strftime('%Y/%m/%d %H:%M:%S')})")
continue
offset_dt = get_offset_date(mtime_dt)
target_files.append((filepath, offset_dt))
print(f"{mtime_dt.strftime('%Y/%m/%d %H:%M:%S')} -> {offset_dt.strftime('%Y/%m/%d %H:%M:%S')}")
for target_file in target_files:
filepath, offset_dt = target_file
os.utime(filepath, (datetime.now().timestamp(), offset_dt.timestamp()))
def get_offset_date(mtime_dt: datetime) -> datetime:
if OFFSET is not None:
return mtime_dt + OFFSET
else:
return mtime_dt
if __name__ == '__main__':
if len(sys.argv) >= 2:
main(sys.argv)
else:
print('Arguments are too short')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment