#!/bin/bash [ -z "${move+x}" ] && move=false [ -z "${forcedate+x}" ] && forcedate=false [ -z "${setdate+x}" ] && setdate=true [ -z "${setoriginalfilename+x}" ] && setoriginalfilename=false [ -z "${movecreatedate+x}" ] && movecreatedate=false [ -z "${setartist+x}" ] && setartist=false # Pathdefinitions Default [ -z "${dest+x}" ] && dest=/srv/nfs/data/userdata/SHARED && dest=${dest%/} [ -z "${mimedestpicdefault+x}" ] && mimedestpicdefault="Bilder" [ -z "${mimedestviddefault+x}" ] && mimedestviddefault="Videos" [ -z "${subdestdefault+x}" ] && subdestdefault="Familie" # Pathdefinitions Runtime [ -z "${mimedestpic+x}" ] && mimedestpic="${mimedestpicdefault}" [ -z "${mimedestvid+x}" ] && mimedestvid="${mimedestviddefault}" [ -z "${subdestpic+x}" ] && subdestpic="${subdestdefault}" [ -z "${subdestvid+x}" ] && subdestvid="${subdestdefault}" help () { cat << EOF Usage: $(basename $0) [move=[true|copy]] [setdate=[true|false]] [forcedate=[true|false]] [setoriginalfilename=[false|true|force]] [] Defaults: # commands move=$move [false|true|copy|rename|renameinplace|copyrename] false: file is not moved to destination; true: file is moved; copy: copy file to destination copy: copy file to final destinateion renameinplace: rename file to YYYYMMDD_HHmmss-c.ext in place (just rename file) rename: move like true, but rename ist like renameinplace copyrename: rename file in place and copy it to final destination with new name forcedate=$forcedate [false|true] false: datetimeoriginal and createdate is only updated from filename, if not set; true: tags are always updated setdate=$setdate [false|true] false: do not set date-tags, only if you are sure, tags are ok, and you want move or copy files; setoriginalfilename=$setoriginalfilename [false|true|force] false: do not set originalfilename from filname (default); true: set it, if not set; force: set it, also if exists; setartist=$setartist [false|true|] true: set USERNAME from user, running the script; set this User Name # destination dest=$dest mimedestpic=$mimedestpic mimedestvid=$mimedestvid subdestpic=$subdestpic subdestvid=$subdestvid # or set subdestdefault, which is default for subdestpic and subdestvid subdestdefault=$subdestdefault # final destinationpath ${dest}/${mimedestpic}/${subdestpic}/%Y/%Y_%m" ${dest}/${mimedestvid}/${subdestvid}/%Y/%Y_%m" Supported Filet-extensions *.jpg, *.jpeg, *.png, *.mp4, *.mov, *.3gp, *.gif Examples: # Scan current directory for all jpg|jpeg|mp4|mov|png|3gp|gif files, set datetimeoriginal and createdate $(basename $0) # set datetimeoriginal and createdate from given file (only one is possible) # only if tags are not set $(basename $0) # set datetimeoriginal and createdate from given file (only one is possible) # overwrite existing tags forcedate=true $(basename $0) # set datetimeoriginal and createdate from given file (only one is possible) # overwrite existing tags # move file to destination dir (${dest}/${mimedestpicdefault}/${subdestpic} or ${dest}/${mimedestviddefault}/${subdestvid}) in subdirectories %Y/%Y_%m/. move=true forcedate=true $(basename $0) # Final command to move File exiftool -o . '-Directory exiftool -o . '-Directory EOF } export FILELOGLEVEL=WARN export SCRIPT_LOG=~/logs/exif.log parsedatetime() { filename="$(basename "${@}")" # 2015-09-11_17:41:53-1.jpg # 2020.04.02_15-32-20+02:00.jpg # 2020.04.13_10-59-14+02:00.jpg # WhatsApp Image 2019-07-29 at 12.45.02.jpeg loginfo "fn: $filename" if [[ $filename =~ ^.*([0-9]{4})(\.|-)([0-9]{2})(\.|-)([0-9]{2})( |_|-|" at ")([0-9]{2})(\.|-|:)([0-9]{2})(\.|-|:)([0-9]{2})(\.|-|\+|\(| ).*$ ]]; then result="$(printf "%04d:%02d:%02d %02d:%02d:%02d" "${BASH_REMATCH[1]#0}" "${BASH_REMATCH[3]#0}" "${BASH_REMATCH[5]#0}" "${BASH_REMATCH[7]#0}" "${BASH_REMATCH[9]#0}" "${BASH_REMATCH[11]#0}")" fi if [ -z "${result}" ]; then # signal-2020-08-09-171936.jpg if [[ $filename =~ ^.*([0-9]{4})(\.|-)([0-9]{2})(\.|-)([0-9]{2})( |_|-|" at ")([0-9]{2})([0-9]{2})([0-9]{2})(\.|-|\+|_|\(| ).*$ ]]; then result="$(printf "%04d:%02d:%02d %02d:%02d:%02d" "${BASH_REMATCH[1]#0}" "${BASH_REMATCH[3]#0}" "${BASH_REMATCH[5]#0}" "${BASH_REMATCH[7]#0}" "${BASH_REMATCH[8]#0}" "${BASH_REMATCH[9]#0}")" fi fi if [ -z "${result}" ]; then if [[ $filename =~ ^.*([0-9]{4})([0-9]{2})([0-9]{2})(_|-)([0-9]{2})([0-9]{2})([0-9]{2}).*$ ]]; then result="$(printf "%04d:%02d:%02d %02d:%02d:%02d" "${BASH_REMATCH[1]#0}" "${BASH_REMATCH[2]#0}" "${BASH_REMATCH[3]#0}" "${BASH_REMATCH[5]#0}" "${BASH_REMATCH[6]#0}" "${BASH_REMATCH[7]#0}")" fi fi if [ -z "${result}" ]; then # Whatsapp-Bilder # Whatsapp-Videos if [[ $filename =~ ^(IMG-|VID-)([0-9]{4})([0-9]{2})([0-9]{2})(-WA)([0-9]{2})([0-9]{2}).*$ ]]; then result="$(printf "%04d:%02d:%02d %02d:%02d:%02d" "${BASH_REMATCH[2]#0}" "${BASH_REMATCH[3]#0}" "${BASH_REMATCH[4]#0}" "${BASH_REMATCH[6]#0}" "${BASH_REMATCH[7]#0}" "00")" fi fi if [ -z "${result}" ]; then # eYe20130323123316.jpg if [[ $filename =~ ^(eYe)([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2}).*$ ]]; then result="$(printf "%04d:%02d:%02d %02d:%02d:%02d" "${BASH_REMATCH[2]#0}" "${BASH_REMATCH[3]#0}" "${BASH_REMATCH[4]#0}" "${BASH_REMATCH[5]#0}" "${BASH_REMATCH[6]#0}" "${BASH_REMATCH[7]#0}")" fi fi if [ -z "${result}" ]; then # ./2016-01-22/IMG_4225.jpg if [[ "$(dirname ${@})" =~ ^.*/([0-9]{4})(\.|-)([0-9]{2})(\.|-)([0-9]{2}).*$ ]]; then result="$(printf "%04d:%02d:%02d %02d:%02d:%02d" "${BASH_REMATCH[1]#0}" "${BASH_REMATCH[3]#0}" "${BASH_REMATCH[5]#0}" "00" "00" "00")" fi fi echo "$result" return 0 } run_fix () { file="${@}" mime="$(file --mime-type "$file" | awk '{print $NF}')" loginfo "file: $file : mime-type: $mime" newDateTimeOriginal="$(parsedatetime "$file")" loginfo "newDateTimeOriginal: $newDateTimeOriginal" case $mime in image/png) MIMEDEST="${mimedestpic}/${subdestpic}" ;; image/jpeg) MIMEDEST="${mimedestpic}/${subdestpic}" ;; image/gif) MIMEDEST="${mimedestpic}/${subdestpic}" ;; video/mp4|video/m4a|video/3gpp|application/octet-stream) MIMEDEST="${mimedestvid}/${subdestvid}" ;; *) logwarn "unsupportet mimetype »${mime}« for »${file}«" ;; esac if [ -n "${MIMEDEST+x}" ] ; then case $setoriginalfilename in true) loginfo "set original filename: " $setoriginalfilename && exiftool -overwrite_original "-originalfilename&1 |tee -a ${LOGFILE})" else loginfo "$(exiftool '-Directory&1 |tee -a ${LOGFILE})" fi ;; copy) export UMASK=002 echo copy to ${dest}/${MIMEDEST}/%Y/%Y_%m if $movecreatedate ; then loginfo "$(exiftool -o . '-Directory&1 |tee -a ${LOGFILE})" logwarn "$(readlink -f "$file"): $(exiftool -filename -if '(not ($datetimeoriginal or $createdate))' "$file")" else loginfo "$(exiftool -o . '-Directory&1 |tee -a ${LOGFILE})" logwarn "$(readlink -f "$file"): $(exiftool -filename -if '(not ($datetimeoriginal or $createdate))' "$file")" fi ;; renameinplace) echo rename inplace if $movecreatedate ; then loginfo "$(exiftool '-FileName&1 | tee -a ${LOGFILE})" else loginfo "$(exiftool '-FileName&1 | tee -a ${LOGFILE})" fi ;; rename) export UMASK=002 echo move to ${dest}/${MIMEDEST}/%Y/%Y_%m if $movecreatedate ; then loginfo "$(exiftool -v '-FileName&1 | tee -a ${LOGFILE})" else loginfo "$(exiftool -v '-FileName&1 | tee -a ${LOGFILE})" fi ;; copyrename) export UMASK=002 echo move to ${dest}/${MIMEDEST}/%Y/%Y_%m if $movecreatedate ; then loginfo "$(exiftool -o . '-FileName&1 | tee -a ${LOGFILE})" else loginfo "$(exiftool -o . '-FileName&1 | tee -a ${LOGFILE})" fi ;; *) logwarn "value for move is neither »true« nor »copy«" esac fi loginfo "----------------" loginfo "" } run_check () { file="${@}" mime="$(file --mime-type "$file" | awk '{print $NF}')" loginfo "file: $file : mime-type: $mime" newDateTimeOriginal="$(parsedatetime "$file")" loginfo "search for DateTime-File: $newDateTimeOriginal" #echo $newDateTimeOriginal|sed -e 's/://g;s/ /_/' if [ $(find ${dest} -name "$(echo $newDateTimeOriginal|sed -e 's/://g;s/ /_/')*"|wc -l) -eq 0 ]; then loginfo " not found" echo "$@" |tee -a holdfiles else loginfo " found" echo "$@" |tee -a rmfiles fi } if [ $# -gt 0 ]; then case $1 in -h|help|--help) help ;; -c) shift loginfo "Check if createdate-file already exists" run_check "${@}" ;; *) loginfo "Progress only one file from cmdline ${@}" run_fix "${@}" ;; esac else loginfo "Progress all *.jpg, *.jpeg, *.png and mp4, *.3gp, *.gif *.mov files in pwd $(pwd)" all=$(find ${maxdepth:+-maxdepth} ${maxdepth:+$maxdepth} -type f |grep -i ".jpg$\|.jpeg$\|.mp4$\|.mov$\|.png$\|.3gp$\|.gif$"|wc -l) find ${maxdepth:+-maxdepth} ${maxdepth:+$maxdepth} -type f |grep -i ".jpg$\|.jpeg$\|.mp4$\|.mov$\|.png$\|.3gp$\|.gif$"|while read file; do let "i=i+1" export SCRIPT_LOG=./$(basename $0).log export LOGFILE=./$(basename $0).move.log loginfo "$i/$all" run_fix "$file" done fi