-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathupdate_exif.py
More file actions
executable file
·106 lines (84 loc) · 2.8 KB
/
update_exif.py
File metadata and controls
executable file
·106 lines (84 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/python
import os, sys, datetime, json, subprocess
DRYRUN = True
JSON = '.json'
EXIFTOOL = 'exiftool'
def main():
init()
walk_dir(sys.argv[1])
def walk_dir(root_d):
"""
Recursively walk all directories and update EXIF DateTimeOriginal from metadata
"""
for f in os.listdir(root_d):
ff = os.path.join(root_d, f)
if os.path.isfile(ff) and is_image(ff) and not is_exif_set(ff):
timestamp = get_metadata_timestamp(ff)
if timestamp:
update_exif(ff, timestamp)
if os.path.isdir(ff):
walk_dir(ff)
def update_exif(f, timestamp):
if DRYRUN:
info('Dry run: would be setting EXIF DateTimeOriginal in {} to {}'.format(f, timestamp))
return
devnull = open(os.devnull, 'wb')
run = '{} -overwrite_original "-DateTimeOriginal={}" "{}"'.format(EXIFTOOL, timestamp, f)
res = subprocess.call(run, shell=True, stdout=devnull, stderr=devnull)
if res == 0:
info('Set EXIF DateTimeOriginal in {} to {}'.format(f, timestamp))
else:
error('Could not update EXIF DateTimeOriginal in {}'.format(f))
def is_exif_set(f):
devnull = open(os.devnull, 'wb')
run = '{} "{}" | grep "Date/Time Original"'.format(EXIFTOOL, f)
res = subprocess.call(run, shell=True, stdout=devnull, stderr=devnull)
return res == 0
def get_metadata_timestamp(f):
"""
Check for <file>.json and then <file>.<ext>.json for metadata
"""
if os.path.exists(f + JSON):
return read_metadata(f + JSON)
elif os.path.exists(os.path.splitext(f)[0] + JSON):
return read_metadata(os.path.splitext(f)[0] + JSON)
else:
warn('No metadata exists for {}'.format(f))
return None
def read_metadata(mf):
with open(mf) as f:
md = json.load(f)
f.close()
return datetime.datetime.fromtimestamp(float(md['photoTakenTime']['timestamp']))
def is_image(f):
"""
Only flag JPEG and PNG. GIFs don't support EXIF and HEIC are guaranteed to have timestamps.
"""
if os.path.splitext(f)[1].lower() in ['.jpg', '.jpeg', '.png']:
return True
else:
return False
def walk_error(e):
error(e)
def info(msg):
log(msg, 'I')
def warn(msg):
log(msg, 'W')
def error(msg):
log(msg, 'E')
def log(msg, level):
print('{} | {}'.format(level, msg))
def init():
if len(sys.argv) not in [2, 3]:
print('Wrong arguments!')
print('- first arg: directory with images')
print('- second arg: optional -e to execute the changes (the default is a dry run)')
sys.exit(1)
if len(sys.argv) == 3 and sys.argv[2] == '-e':
global DRYRUN
DRYRUN = False
if os.environ.get('EXIFTOOL'):
global EXIFTOOL
EXIFTOOL = os.environ.get('EXIFTOOL')
if __name__ == "__main__":
main()