-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdropboximport.py
134 lines (112 loc) · 4.24 KB
/
dropboximport.py
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
#!/usr/bin/env python
"""Rename files like Dropbox Camera Upload feature does.
"""
#TODO: time shift for video files, maybe optional for images too
from __future__ import division, print_function
import datetime
import os
import shutil
from PIL import Image
from PIL import ExifTags
import enzyme
DATEEXIFKEY = [key for (key, value) in ExifTags.TAGS.items()
if value == 'DateTimeOriginal'][0]
FILEFMT = "%Y-%m-%d %H.%M.%S"
DIRFMT = "%Y-%m-%d"
VIDEOFILES = ['.mp4', '.3gp', '.mov', '.mkv', '.webm', '.avi', '.ogm', '.ogv']
IMAGEFILES = ['.jpg', '.jpeg']
def import_file(filename, targetdir='',
filefmt=FILEFMT, dirfmt=DIRFMT,
shift_seconds=0, shift_img=False, shift_vid=True,
sort_in_dir=False, rename=True):
"""Rename file according to metadata date/time.
Puts files into target dir, creating optional subdirs.
Formats for both filename and subdirs are the same used by ``strftime``.
"""
dir, name = os.path.split(filename)
basename, fileext = os.path.splitext(name)
if targetdir == '':
targetdir = dir
filetime = get_time(filename, shift_seconds, shift_img, shift_vid)
if filetime:
if rename:
datetimestring = filetime.strftime(filefmt)
name = datetimestring + fileext
if sort_in_dir:
datestring = filetime.strftime(dirfmt)
targetdir = os.path.join(targetdir, datestring)
if not os.path.isdir(targetdir):
try:
os.makedirs(targetdir)
except:
print("Could not create dir {0}".format(targetdir))
return filename
newfilename = os.path.join(targetdir, name)
if os.path.exists(newfilename):
return filename
try:
shutil.copy2(filename, newfilename)
except IOError:
return filename
else:
return None
else:
return filename
def get_time(filename, shift_seconds=0, shift_img=False, shift_vid=False):
"""Get file date, from metadata or file system.
Time is optionally shifted by given amount of seconds.
Wether to shift for images or videos is decided separately.
"""
ext = os.path.splitext(filename)[1]
if ext.lower() in IMAGEFILES:
filedt = get_exif_time(filename)
if shift_img:
filedt = shift_time(filedt, shift_seconds)
elif ext.lower() in VIDEOFILES:
filedt = get_video_time(filename)
if shift_vid:
filedt = shift_time(filedt, shift_seconds)
else:
filedt = get_file_time(filename)
return filedt
def shift_time(dt, shift_seconds):
return dt + datetime.timedelta(seconds=shift_seconds)
def get_exif_time(filename):
"""Get time from EXIF metadata using ``PIL`` or ``Pillow`` package."""
img = Image.open(filename)
exf = img._getexif()
if exf:
timestr = exf.get(DATEEXIFKEY, None)
if timestr:
return datetime.datetime.strptime(timestr, "%Y:%m:%d %H:%M:%S")
else:
return get_file_time(filename)
def get_video_time(filename):
"""Get file data from video metadata using ``enzyme`` package.
This one is tricky, as
(at least in the MP4 headers of files shot with cell phones)
the time is stored as seconds since epoch **in UTC**.
Thus the information on the timezone where the shot happened is needed.
For now, it is assumed that it is the same timezone as the system
currently running this code.
Also, as I've met cell phones that put
very erroneous capture file time in the header,
I have restricted the recognized capture time to *after* the epoch.
"""
try:
mdata = enzyme.parse(filename)
except enzyme.exceptions.NoParserError:
return get_file_time(filename)
tmepoch = mdata.timestamp
# here is the place where too old (erroneous) date is not supported
if tmepoch and tmepoch > 0:
return datetime.datetime.fromtimestamp(tmepoch)
else:
return get_file_time(filename)
def get_file_time(filename):
"""Get file last modification name from file system."""
try:
mtime = os.path.getmtime(filename)
except OSError:
return None
return datetime.datetime.fromtimestamp(mtime)