-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathrelabel_photo_with_datetimeoriginal.sh
More file actions
executable file
·273 lines (214 loc) · 6.53 KB
/
Copy pathrelabel_photo_with_datetimeoriginal.sh
File metadata and controls
executable file
·273 lines (214 loc) · 6.53 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
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#!/bin/bash
# BUGS: This program fails hard if the filename STARTS WITH A "--" as can happen via erroneous renaming
# -------
# This renames the images given on the command line
#
# One might run this as follows:
#
# ls | xargs ~qq/assorted/relabel_photo_with_datetimeoriginal.sh
#
# Or better:
#
# find . -name "*.jpg" -exec ~qq/assorted/relabel_photo_with_datetimeoriginal.sh '{}' ';'
#
# Or else one can grab several files and several directories (all examined at level 1 only):
#
# ~qq/assorted/relabel_photo_with_datetimeoriginal.sh --directory=SOMEDIR SOMEFILE1 SOMEFILE2 --directory=SOMEOTHERDIR
# -------
# ---
# Is exiftool there?
# ---
which exiftool >/dev/null 2>&1
if [[ $? != 0 ]]; then
echo "Command 'exiftool' does not exist -- exiting" >&2
echo "Maybe install it using 'dnf install perl-Image-ExifTool'" >&2
exit 1
fi
which file >/dev/null 2>&1
if [[ $? != 0 ]]; then
echo "Command 'file' does not exist -- exiting" >&2
exit 1
fi
# ---
# Transform a datetime "YYYY:MM:DD hh:mm:ss" into "Y=....;M=..;D=..;h=..;m=..;s=.." which is
# shell command that can be evaled later.
# The result is printed to STDOUT.
# ---
function transformDatetime {
local NAME=$1
local DATETIME=$2
local FILE=$3
# get rid of surrounding whitespace
DATETIME=$(echo $DATETIME)
if [[ -z $DATETIME ]]; then
echo "$NAME(): No value found" >&2
return
fi
echo "$NAME(): File '$FILE' has time '$DATETIME'" >&2
local RESULT=$(echo $DATETIME | perl -e 'if (<> =~ /^\s*(\d\d\d\d):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)\s*$/) { print "Y=$1;M=$2;D=$3;h=$4;m=$5;s=$6" }')
if [[ -z $RESULT ]]; then
echo "$NAME(): Some values from the date/time are unset or invalid" >&2
return
fi
echo $RESULT
}
# ---
# Get datetime from "datetimeoriginal"
# The result is printed to STDOUT
# ---
function dateTimeFromDateTimeOriginal {
local NAME=dateTimeFromDateTimeOriginal
local FILE=$1
local DATETIME=$(exiftool -l "-EXIF:DateTimeOriginal" "$FILE" | tail -1)
if [[ $? != 0 ]]; then
echo "$NAME(): exiftool returned $?" >&2
return
fi
transformDatetime "$NAME" "$DATETIME" "$FILE"
}
# ---
# Get datetime form "profile" (doesn't work)
# The result is printed to STDOUT
# ---
function dateTimeFromProfileDateTime {
local NAME=dateTimeFromProfileDateTime
local FILE=$1
local DATETIME=$(exiftool -l "-ProfileDateTime" "$FILE" | tail -1)
if [[ $? != 0 ]]; then
echo "$NAME(): exiftool returned $?" >&2
return
fi
transformDatetime "$NAME" "$DATETIME" "$FILE"
}
# ---
# Process a single file
# ---
function processFile {
local FILE=$1
# Sanity checks
if [[ -z $FILE ]]; then
echo "Empty file argument -- skipping!" >&2
return
fi
if [[ ! -f $FILE ]]; then
echo "File '$FILE' does not exist -- skipping this file!" >&2
return
fi
# Determine suffix for later renaming
local MIME=$(file --mime-type --brief -- "$FILE")
if [[ $? != 0 ]]; then
echo "Could not run 'file' command -- exiting" >&2
exit 1
fi
echo "Mime type of '$FILE': $MIME" >&2
local SUFFIX=
if [[ $MIME == 'image/jpeg' ]]; then
SUFFIX=".jpg"
elif [[ $MIME == 'image/png' ]]; then
SUFFIX=".png"
elif [[ $MIME == 'image/gif' ]]; then
SUFFIX=".gif"
elif [[ $MIME == 'image/x-canon-cr2' ]]; then
SUFFIX=".cr2"
else
echo "Unknown mime type '$MIME' for file '$FILE' -- skipping this file!" >&2
return
fi
# Try to get a good datetime
local CMD=$(dateTimeFromDateTimeOriginal "$FILE")
# This does not actually work:
# if [[ -z $CMD ]]; then
# CMD=$(dateTimeFromProfileDateTime "$FILE")
# fi
if [[ -z $CMD ]]; then
echo "No good datetime could be extracted from file '$FILE' -- skipping this file" >&2
return
fi
eval "$CMD"
local NEW="${Y}-${M}-${D}_${h}:${m}:${s}"
echo "New name base: $NEW" >&2
local DIR=$(dirname -- "$FILE")
local PRIOR_FILE=$(basename -- "$FILE")
local NEW_FILE="${NEW}${SUFFIX}"
if [[ $PRIOR_FILE == $NEW_FILE ]]; then
echo "File '$FILE' already has correct name -- skipping this file" >&2
return
fi
local INDEX=1
local NEWFQFILE="${DIR}/${NEW}${SUFFIX}"
while [[ -f ${NEWFQFILE} ]]; do
echo "Cannot rename '$FILE' to '$NEWFQFILE' -- destination exists. Attaching index $INDEX" >&2
NEWFQFILE="${DIR}/${NEW}.${INDEX}${SUFFIX}"
let INDEX=${INDEX}+1
done
/bin/mv -- "$FILE" "$NEWFQFILE"
if [[ $? != 0 ]]; then
echo "Could not rename '$FILE' to '$NEWFQFILE' -- skipping this file!" >&2
else
echo "Successfully renamed '$FILE' to '$NEWFQFILE'" >&2
fi
}
# ---
# Loop over a whole directory, collecting files at level 1
# We (ugly-ly) fill the global variable MORE_FILES (an array)
# with the files found. No selection on files is done yet.
# ---
MORE_FILES=()
function handleDirectory {
local DIR=$1
if [[ -z $DIR ]]; then
echo "Empty directory argument -- skipping!" >&2
return
fi
if [[ ! -d $DIR ]]; then
echo "Directory '$DIR' does not exist (or is not a directory) -- skipping this!" >&2
return
fi
# http://stackoverflow.com/questions/8213328/bash-script-find-output-to-array
local FILE=
while IFS= read -d $'\0' -r FILE ; do
MORE_FILES=("${MORE_FILES[@]}" "$FILE")
done < <(find "$DIR" -maxdepth 1 -type f -print0)
# echo "$DIR --> ${MORE_FILES[@]}"
}
# ------
# Process all files given on the command line
# ------
# An argument that reads as "--directory=X" means "process all the files from that directory"
# Any other argument is taken to indicate a file directly
ALL_FILES=()
NEXT_COMES_DIRECTORY=
for PARAM in "$@"; do
if [[ -n $NEXT_COMES_DIRECTORY ]]; then
DIRECTORY=$PARAM
NEXT_COMES_DIRECTORY=
elif [[ $PARAM =~ --directory(=.+)? ]]; then
if [[ $PARAM =~ --directory=(.+)? ]]; then
DIRECTORY=`echo $PARAM | cut --delimiter="=" --fields=2`
NEXT_COMES_DIRECTORY=
else
DIRECTORY=
NEXT_COMES_DIRECTORY=1
fi
else
# Assume this is a file
ALL_FILES=("${ALL_FILES[@]}" "$PARAM")
fi
if [[ -n $DIRECTORY ]]; then
MORE_FILES=()
handleDirectory $DIRECTORY
DIRECTORY=''
# MORE_FILES now contains more files
ALL_FILES=("${ALL_FILES[@]}" "${MORE_FILES[@]}")
MORE_FILES=()
fi
done
COUNT=0
for FILE in "${ALL_FILES[@]}"; do
echo "--------------------------" >&2
echo $FILE >&2
echo "--------------------------" >&2
processFile "$FILE"
let COUNT=$COUNT+1
done
echo "Done, processed $COUNT files" >&2