Rename By Metadata of Photos/Videos Files

Prepare

windows

linux

apt install mediainfo

windows && linux

1
2
pip{3} install exifread
pip{3} install pymediainfo

Talk is cheap, show xxxx

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env python3

# finalx

# for win:
# https://github.com/pypa/pip/issues/4205 fix installing pymediainfo issue
# https://github.com/sbraz/pymediainfo/issues/39 fix pymediainfo module not found issue(dll)
# useful dll link:
# https://mediaarea.net/en/MediaInfo/Download/Windows

import os
import sys
import logging
import re
import time
import traceback
import platform
from distutils.version import StrictVersion

## prepare depends packages
#import importlib
#def install_and_import(package):
# try:
# importlib.import_module(package)
# except ImportError:
# import pip
# if StrictVersion(pip.__version__) < StrictVersion('10.0.0'):
# pip.main(['install', package])
# else:
# pip._internal.main(['install', package])
# finally:
# globals()[package] = importlib.import_module(package)
#
#if platform.system() == 'Windows':
# install_and_import('exifread')
# install_and_import('setuptools')
# install_and_import('certifi')
# install_and_import('pymediainfo')

if platform.system() == 'Windows':
import certifi #just make sure it's installed or raise exception

# pip3 install exifread
import exifread
# pip3 install pymediainfo
import pymediainfo

# now begin
""" Retrieve the files in specified path with below suffixs(case ignored):
.jpg
.jpeg
.jpe

.mov
.mp4
.m4v
.3gp
.3g2
.m2v
.mkv
"""
gRegImg = re.compile(r".*\.(?:(?:jpg)|(?:jpeg)|(?:jpe))$", re.IGNORECASE|re.UNICODE)
gRegVid = re.compile(r".*\.(?:(?:mov)|(?:mp4)|(?:m4v)|(?:3gp)|(?:3g2)|(?:m2v)|(?:mkv))$", re.IGNORECASE|re.UNICODE)
def isFilePathImg(filepath):
logging.debug("{} match:{}".format(filepath, re.match(gRegImg, filepath)))
return re.match(gRegImg, filepath)


def isFilePathVideo(filepath):
logging.debug("{} match:{}".format(filepath, re.match(gRegVid, filepath)))
return re.match(gRegVid, filepath)


def getMediaFiles(dir):

pathnames = []
for (dirpath, dirnames, filenames) in os.walk(dir):
pathnames.extend(
(os.path.join(dirpath, afile) for afile in filenames if (isFilePathImg(afile) or isFilePathVideo(afile)))
)

logging.debug("getMediaFiles returns {}".format(pathnames))
return pathnames


def getImgDateTaken(filepath):

dateTaken = None
with open(filepath, 'rb') as fh:
tagsOfDateTime = ('Image DateTime', 'EXIF DateTimeOriginal', 'EXIF DateTimeDigitized')
tagsOfGps = ('GPS GPSDate', 'GPS GPSTimeStamp')
tagsAll = exifread.process_file(fh)
#print tagsAll

if tagsAll:
for tag in tagsOfDateTime:
if tag in tagsAll:
dateTaken = tagsAll[tag]
#logging.info("type: {}, repr:{}, str:{}".format(type(dateTaken), repr(dateTaken), str(dateTaken)))
break

ret = None
if (dateTaken):
ret = time.strptime(str(dateTaken), "%Y:%m:%d %H:%M:%S")

return ret


def getVideoDateTaken(filepath):
mediaInfo = pymediainfo.MediaInfo.parse(filepath)

if (not mediaInfo):
return None

trackGeneral = mediaInfo.tracks[0]
if not trackGeneral:
return None

if not trackGeneral.encoded_date:
return None

return time.strptime(trackGeneral.encoded_date, "%Z %Y-%m-%d %H:%M:%S")


def getDateBirth(filepath):
return time.localtime(
os.path.getmtime(filepath)
);


def getNewPathNameUnderSameDir(pathname, newBaseNameHint):
dirName = os.path.dirname(pathname)
extName = os.path.splitext(pathname)[1]
newPathName = os.path.join(dirName, newBaseNameHint + extName)

count = 1;
while os.path.exists(newPathName):

if pathname == newPathName:
break

assert count < 1000000 # impossible
# '_' < [0-9A-Za-z]
newPathName = os.path.join(dirName, newBaseNameHint + "_{:0>4X}".format(count) + extName)

count += 1

return newPathName


def do_gogogo(dirs, doMove):
for adir in (os.path.abspath(i) for i in dirs):

logging.basicConfig(level=logging.INFO, filename=os.path.join(adir, "Log_MyRenameByExif.txt"),
format='%(asctime)s %(levelname)s#%(lineno)d: %(message)s')

# '_' < [0-9A-Za-z]
for pathname in sorted(getMediaFiles(adir)):
logging.info("Processing {}".format(pathname))

isImg = isFilePathImg(pathname)
isVideo = isFilePathVideo(pathname)

assert os.path.isfile(pathname)
assert (isImg or isVideo)

prefix = None
dateTakenTm = getImgDateTaken(pathname) if isImg else getVideoDateTaken(pathname)

if dateTakenTm:
prefix = "meta"
else:
dateTakenTm = getDateBirth(pathname)
prefix = "FAKE"

newPathName = getNewPathNameUnderSameDir(pathname, time.strftime('%Y%m%d_%H%M%S', dateTakenTm))

if pathname == newPathName:
logging.info("\tSkiping src = dst\n\n");
continue

if (doMove):
logging.info("\t[{}] DO! --> {}\n\n".format(prefix, newPathName))
os.rename(pathname, newPathName)
else:
logging.info("\t[{}] Will move --> {}\n\n".format(prefix, newPathName))


def gogogo(dirs, doMove=False):
try:
do_gogogo(dirs, doMove)
except Exception:
logging.critical(traceback.format_exc())

# default search path is CWD
if __name__ == '__main__':
dirs = ["."]
if len(sys.argv) > 1:
dirs = sys.argv[1:]

gogogo(dirs, doMove=False)