Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
macOS Automator script to rename photos/videos based on creation date. Blog post: https://paulgalow.com/macos-quick-action-rename-photos-videos-timestamp
#!/bin/bash
# macOS Automator script to rename photos/videos based on creation date
# Blog post: https://paulgalow.com/macos-quick-action-rename-photos-videos-timestamp
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
# Create subfolder to store renamed files
createDestination() {
readonly destination="$(dirname "$file")/sorted"
mkdir -p "$destination"
}
# Check for file MIME type
hasMIMEType() {
file -I "$file" | grep -q "$1"
}
# Send notification to user
sendNotification() {
osascript <<-EndOfMessage
display notification \
"$1" \
with title "Rename (Timestamp)"
EndOfMessage
}
# Determine file extension
setFileExtension() {
if hasMIMEType "image/jpeg"
then
extension="jpg"
elif hasMIMEType "video/quicktime"
then
extension="mov"
else
return 1
fi
}
# Retrieve EXIF timestamp from media file
getTimeStamp() {
local -r timestampRaw=$(mdls -name kMDItemContentCreationDate -raw "$file" | cut -d ' ' -f -2)
timestamp=${timestampRaw//:/-}
}
# Rename file, handle timestamp collisions
renameFile() {
# Exit function if file type is not supported
setFileExtension || return 0
getTimeStamp || return 0
createDestination || return 1
# Check if to be renamed file already exists
if [[ -f "$destination/$timestamp.$extension" ]]
then
# If file exists append random string to file
local -r randomString=$(md5 -q "$file")
cp "$file" "$destination/$timestamp-$randomString.$extension"
else
cp "$file" "$destination/$timestamp.$extension"
fi
}
# Send notification to user after the process has finished
presentResults() {
# Count files in destination folder
local counter=0
for file in "$destination"/*.*
do
(( counter ++ ))
done
# Check if renaming was successful
if [ $counter != 0 ] && [ -n "$destination" ]
then
sendNotification "$counter photos/videos have been renamed. Opening destination folder…"
open "$destination"
else
sendNotification "Could not renamd any photos/videos."
fi
}
# Main loop to collect input files from Automator
processFiles() {
while read -r file; do
renameFile
done
}
sendNotification "Processing photos/videos.\\nThis can take a while…"
processFiles
presentResults
exit 0
@eshill

This comment has been minimized.

Copy link

@eshill eshill commented Oct 21, 2019

Hi! Thanks for the script!
I tried to run it, but I see such a mistake:

When executing the "Run shell script" action, an error occurred: "zsh:1: no such file or directory: !/bin/bash 
cp: /2019-06-14 15-54-48.mov: Read-only file system 
presentResults:3: no matches found: /*.* 

You don't know how to fix it?

@paulgalow

This comment has been minimized.

Copy link
Owner Author

@paulgalow paulgalow commented Oct 21, 2019

It looks like you are running this with zsh as the interpreter. Perhaps there is an option to change that to bash? Since macOS Catalina the default shell has been switched from bash to zsh. That might be the issue here. Can you confirm you are running Catalina?

@eshill

This comment has been minimized.

Copy link

@eshill eshill commented Oct 21, 2019

Can you confirm you are running Catalina?

Yes!

@alisey

This comment has been minimized.

Copy link

@alisey alisey commented Oct 28, 2019

mdls has an option for printing only a specific attribute's value: mdls -name kMDItemContentCreationDate -raw <filename>

@paulgalow

This comment has been minimized.

Copy link
Owner Author

@paulgalow paulgalow commented Apr 15, 2020

mdls has an option for printing only a specific attribute's value: mdls -name kMDItemContentCreationDate -raw <filename>

Thanks for pointing me to this, @alisey. I have updated the gist after your suggestion. And sorry for my late reply. I somehow managed to completely miss your comment.

@Minagamb

This comment has been minimized.

Copy link

@Minagamb Minagamb commented Oct 2, 2020

Hi, I am using your code, but there seems to be an error. The timestamp after the photo is renamed does not correlate with the actual time stamp on the photo. For instance, a photo was renamed to 2020-07-03 18 01 07.jpg, but the actual timestamp is at 11:01 am, not 6:01 pm. Everything else is correct except for the time. Also, how can I get rid of the dashes on the date? All the renamed dates are off by 7 hours too much.

@paulgalow

This comment has been minimized.

Copy link
Owner Author

@paulgalow paulgalow commented Oct 2, 2020

Hi @Minagamb, the resulting timestamps are UTC based so perhaps that explains why your timestamps are 7 hours off. Regarding the dashes on the date, try replacing timestamp=${timestampRaw//:/-} with timestamp=${timestampRaw//[:|-]/}.

@Minagamb

This comment has been minimized.

Copy link

@Minagamb Minagamb commented Oct 2, 2020

how do I change from UTC? The photos are collected PST

@Minagamb

This comment has been minimized.

Copy link

@Minagamb Minagamb commented Oct 2, 2020

Also thank you for getting rid of the dashes!

@Minagamb

This comment has been minimized.

Copy link

@Minagamb Minagamb commented Oct 2, 2020

how can I convert from UTC to my local time zone? or can I just subtract the 7 hours into the script so that each file has 7 hours subtracted from it? Sorry for bombarding you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.