Last active
May 21, 2018 11:55
-
-
Save mrzapp/aadd466e28cff60c4ef5b0fea64422e1 to your computer and use it in GitHub Desktop.
A bash script for renaming photos downloaded using Google Takeout. It assigns a sensible file name to each photo and copies it to a new location with error logs and replicated directory structure.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
INPUT_FOLDER=$1 | |
OUTPUT_FOLDER=$2 | |
if [ -z "$INPUT_FOLDER" ] || [ -z "$OUTPUT_FOLDER" ]; then | |
echo "Usage: sort.sh <input folder> <output folder>" | |
exit 1; | |
fi | |
echo > "$OUTPUT_FOLDER/omitted.log" | |
echo > "$OUTPUT_FOLDER/failed.log" | |
CORRECT_FILE_REGEX='[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]_[0-2][0-9]-[0-5][0-9]-[0-5][0-9]' | |
UNIT_TIMESTAMP_MILLISECONDS_REGEX='([0-9]{13})' | |
UNIT_TIMESTAMP_SECONDS_REGEX='([0-9]{10})' | |
FOLDER_REGEX='([1-2][0-9][0-9][0-9])-([0-1][0-9])-([0-3][0-9])' | |
EXIF_REGEX='([1-2][0-9][0-9][0-9]):([0-1][0-9]):([0-3][0-9]) ([0-2][0-9]):([0-5][0-9]):([0-5][0-9])' | |
FILE_REGEX='([1-2][0-9][0-9][0-9])([0-1][0-9])([0-3][0-9])' | |
FILE_ALT_REGEX='([0-1][0-9])([0-1][0-9])([0-3][0-9])-([0-2][0-9])([0-5][0-9])([0-5][0-9])' | |
ANY_NUMBER_REGEX='([0-9]+)\.' | |
find "$INPUT_FOLDER" -print0 | while read -d $'\0' FILE; do | |
FILENAME=$(echo "$(basename "$FILE")" | cut -f 1 -d '.') | |
EXTENSION=$(echo "${FILE#*.}" | tr '[:upper:]' '[:lower:]') | |
if [ "$EXTENSION" != "jpg" ] && [ "$EXTENSION" != "jpeg" ] && [ "$EXTENSION" != "mts" ] && [ "$EXTENSION" != "mp4" ]; then | |
echo "$FILE" >> "$OUTPUT_FOLDER/omitted.log" | |
continue; | |
fi | |
if [[ $FILE =~ $CORRECT_FILE_REGEX ]]; then | |
echo "$FILE is OK" | |
continue; | |
fi | |
# Fetch the date from create date | |
EXIF_OUTPUT=$(exiftool -s -CreateDate "$FILE") | |
[[ $EXIF_OUTPUT =~ $EXIF_REGEX ]] | |
YEAR=${BASH_REMATCH[1]} | |
MONTH=${BASH_REMATCH[2]} | |
DAY=${BASH_REMATCH[3]} | |
HOUR=${BASH_REMATCH[4]} | |
MINUTE=${BASH_REMATCH[5]} | |
SECOND=${BASH_REMATCH[6]} | |
# Fetch the date from date/time original | |
if [ -z $YEAR ] || [ -z $MONTH ] || [ -z $DAY ]; then | |
EXIF_OUTPUT=$(exiftool -s -DateTimeOriginal "$FILE") | |
[[ $EXIF_OUTPUT =~ $EXIF_REGEX ]] | |
YEAR=${BASH_REMATCH[1]} | |
MONTH=${BASH_REMATCH[2]} | |
DAY=${BASH_REMATCH[3]} | |
HOUR=${BASH_REMATCH[4]} | |
MINUTE=${BASH_REMATCH[5]} | |
SECOND=${BASH_REMATCH[6]} | |
fi | |
# Fetch the date from media create date | |
if [ -z $YEAR ] || [ -z $MONTH ] || [ -z $DAY ]; then | |
EXIF_OUTPUT=$(exiftool -s -MediaCreateDate "$FILE") | |
[[ $EXIF_OUTPUT =~ $EXIF_REGEX ]] | |
YEAR=${BASH_REMATCH[1]} | |
MONTH=${BASH_REMATCH[2]} | |
DAY=${BASH_REMATCH[3]} | |
HOUR=${BASH_REMATCH[4]} | |
MINUTE=${BASH_REMATCH[5]} | |
SECOND=${BASH_REMATCH[6]} | |
fi | |
# Fetch the date from the filename | |
if [ -z $YEAR ] || [ -z $MONTH ] || [ -z $DAY ]; then | |
# YYYYMMDD format | |
if [[ $FILE =~ $FILE_REGEX ]]; then | |
YEAR=${BASH_REMATCH[1]} | |
MONTH=${BASH_REMATCH[2]} | |
DAY=${BASH_REMATCH[3]} | |
# YYMMDD-HHMMSS format | |
elif [[ $FILE =~ $FILE_ALT_REGEX ]]; then | |
YEAR="20${BASH_REMATCH[1]}" | |
MONTH=${BASH_REMATCH[2]} | |
DAY=${BASH_REMATCH[3]} | |
HOUR=${BASH_REMATCH[4]} | |
MINUTE=${BASH_REMATCH[5]} | |
SECOND=${BASH_REMATCH[6]} | |
# UNIX timestamp with milliseconds | |
elif [[ $FILENAME =~ $UNIX_TIMESTAMP_MILLISECONDS_REGEX ]]; then | |
TIMESTAMP=$(date -d @$(echo "($FILENAME + 500) / 1000" | bc) +'%Y:%m:%d %H:%M:%S') | |
[[ $TIMESTAMP =~ $EXIF_REGEX ]] | |
YEAR=${BASH_REMATCH[1]} | |
MONTH=${BASH_REMATCH[2]} | |
DAY=${BASH_REMATCH[3]} | |
HOUR=${BASH_REMATCH[4]} | |
MINUTE=${BASH_REMATCH[5]} | |
SECOND=${BASH_REMATCH[6]} | |
# UNIX timestamp with seconds | |
elif [[ $FILENAME =~ $UNIX_TIMESTAMP_SECONDS_REGEX ]]; then | |
TIMESTAMP=$(date -d @$FILENAME +'%Y:%m:%d %H:%M:%S') | |
[[ $TIMESTAMP =~ $EXIF_REGEX ]] | |
YEAR=${BASH_REMATCH[1]} | |
MONTH=${BASH_REMATCH[2]} | |
DAY=${BASH_REMATCH[3]} | |
HOUR=${BASH_REMATCH[4]} | |
MINUTE=${BASH_REMATCH[5]} | |
SECOND=${BASH_REMATCH[6]} | |
# Fetch the date from the folder | |
elif [[ $FILE =~ $FOLDER_REGEX ]]; then | |
YEAR=${BASH_REMATCH[1]} | |
MONTH=${BASH_REMATCH[2]} | |
DAY=${BASH_REMATCH[3]} | |
fi | |
fi | |
# Determine the output folder | |
THIS_OUTPUT_FOLDER="" | |
if [[ $FILE =~ $FOLDER_REGEX ]]; then | |
THIS_OUTPUT_FOLDER=$OUTPUT_FOLDER | |
else | |
THIS_OUTPUT_FOLDER="$OUTPUT_FOLDER/$(basename "$(dirname "$FILE")")" | |
fi | |
# Make sure the folder exists | |
if [ ! -d "$THIS_OUTPUT_FOLDER" ]; then | |
mkdir "$THIS_OUTPUT_FOLDER" | |
fi | |
# Build the filename | |
FILENAME="" | |
if [ ! -z $YEAR ] && [ ! -z $MONTH ] && [ ! -z $DAY ]; then | |
FILENAME="${YEAR}-${MONTH}-${DAY}" | |
else | |
echo "No date found for $FILE" | |
echo "$FILE" >> "$OUTPUT_FOLDER/failed.log" | |
continue; | |
fi | |
if [ ! -z $HOUR ] || [ ! -z $MINUTE ] || [ ! -z $SECOND ]; then | |
FILENAME="${FILENAME}_${HOUR}-${MINUTE}-${SECOND}" | |
else | |
# If no time was found, create an appendix | |
APPENDIX=0 | |
[[ $(basename "$FILE") =~ $ANY_NUMBER_REGEX ]] | |
# If an existing appendix was found, use it | |
if [ ! -z ${BASH_REMATCH[1]} ]; then | |
APPENDIX=${BASH_REMATCH[1]} | |
# If not, construct one, and don't overwrite existing files | |
else | |
while ls "${THIS_OUTPUT_FOLDER}/${FILENAME}_${APPENDIX}."* 1> /dev/null 2>&1; do | |
let APPENDIX++ | |
done | |
fi | |
FILENAME="${FILENAME}_${APPENDIX}" | |
fi | |
FILENAME="${FILENAME}.${EXTENSION}" | |
cp "$FILE" "$THIS_OUTPUT_FOLDER/$FILENAME" | |
echo "$THIS_OUTPUT_FOLDER/$FILENAME" | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment