LoginSignup
0
0

More than 3 years have passed since last update.

Amazon Photosと同期してファイル更新日が上書きされた写真群をできるだけ撮影日時に近い日付でGoogleフォトに保存する

Posted at

困っている状況

  • Amazon Photosでファイル同期すると、ローカルファイルの時刻のうちmtime(更新日時)とatime(アクセス日時)が更新されてしまう
  • Exif情報のあるファイルは良いが、Exif情報のないファイルの場合はAmazon Photoで同期した日に撮影したかのように見えて困る
  • Google Photosに移行したいが、上書きされてしまったファイル情報は戻らず困っている

Google Photosの挙動を確認

  • Exif情報があれば、Exif情報のDateTimeOriginalを日時として採用するらしい
  • Exif情報がなければ、mtime(更新日時)を日時として採用するらしい

課題

上記を踏まえると、Amazon Photosのアプリに上書きされたmtimeを参照してしまうExif情報を含まない画像が、Amazon Photosで同期した日時の写真として認識されてしまうのが問題であり、何らかの方法で撮影日時を認識させてやれば良い。

対策

  • 全ファイルをなめて、Exif情報を含む画像ファイルは処理をパスする
  • Exif情報を含まない画像の場合、
    • バックアップファイルのExif情報がないか探す
    • ローカルファイル、バックアップファイルのctime,mtime,atimeを全て読み込み、最も古い日時をもってmtimeを上書きする
      • 実際にはLinux上にあるバックアップファイルのctimeはmtimeと同じようなタイミングで更新されるため、Windows上にあるctimeを参照することが専らとなる

コード

Exif情報の読み込み

細かいことは、python3のPILでexifが読み込めない時 - Qiitaを参照。

def get_exiftime(path):
    '''
    Parameters
    ----------
    path : string

    Returns
    -------
    exiftime : datetime
    '''
    try:
        with Image.open(path) as im:
            exifdict = piexif.load(im.info['exif'])["Exif"]
            return datetime.datetime.strptime(
                        exifdict[36867].decode(),
                        '%Y:%m:%d %H:%M:%S'
            )
    except:
        # 今回はExif情報を読み込めなくても処理継続する
        return None

ctime、mtimeの読み込み

わざわざリストで返却しているのは、後で連結するため

def get_cmtime(path):
    '''
    Parameters
    ----------
    path : string

    Returns
    -------
    ctime : datetime
    mtime : datetime
    '''
    fstat = os.stat(path)
    return [datetime.datetime.fromtimestamp(fstat.st_ctime), datetime.datetime.fromtimestamp(fstat.st_mtime), ]

ループ

フォルダ構造からファイル名から完全にそのままバックアップされていることを想定した処理なので注意。

srv_dpath = 'サーバのディレクトリへのパス'
loc_dpath = 'ローカルディレクトリへのパス'

# ディレクトリとか非画像ファイルとかの除外は環境に合わせて実装してちょ
flist = ['ファイル名のリストだと思いネェ']

for filename in flist:
    loc_fpath = f'{loc_dpath}/{filename}'
    srv_fpath = f'{srv_dpath}/{filename}'
    loc_exiftime = get_exiftime(loc_fpath)
    if loc_exiftime is not None:
        continue
    else:
        srv_exiftime = get_exiftime(srv_fpath)
        if srv_exiftime is not None:
            # バックアップにのみExif情報を含む場合。もし自動処理するならsrv_fpathをloc_fpathにコピーすればいい。
            raise Exception('local file was changed!')
        else:
            oldesttime = sorted(get_cmtime(srv_fpath) + get_cmtime(loc_fpath))[0]
            newtime = time.mktime(oldesttime.timetuple())
            #os.utime(srv_fpath, (newtime, newtime))  # サーバも修正するのは勇気がいるので、ご利用は計画的に
            os.utime(loc_fpath, (newtime, newtime))
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0