I’m working on a folder action script that moves items dropped in a folder after making sure their names are 31 characters or less.
It all works well, prompting a user for a new name if the current one is too long then renaming files, but once it does the rename it immediately triggers itself again (i.e. the folder sees it as a new item and starts the script over).
Is there a way to not let the script trigger a new “on adding folder items” event?
Thanks!
Here are the offending parts of the script:
on adding folder items to thefolder after receiving theaddeditems
repeat with eachItem in theaddeditems
-- check name length. Over 31 characters (with extension) and system barfs
set theFileInfo to info for eachItem -- get info for the incoming file
set currentName to the name of theFileInfo
set n to the number of characters of the currentName
if n > 31 then
try
set the ext to text ((offset of "." in currentName)) thru -1 of currentName
set the new_name to ((characters 1 thru 26 of currentName) as string) & ext
on error the error_message number the error_number
display dialog "Error: " & error_message
end try
tell me to display dialog "File name too long." & return & "It can only be 31 characters in length. Please rename:" default answer new_name buttons {"Cancel", "OK"} default button 2
copy the result as list to {new_name, button_pressed}
if the button_pressed is "Cancel" then return 0
set_item_name(eachItem, new_name)
end if
-- do actual useful work with the files here
end adding folder items to
on set_item_name(this_item, new_item_name)
tell application "Finder"
set the parent_container_path to (the container of this_item) as text
if not (exists item (the parent_container_path & new_item_name)) then
try
set the name of this_item to new_item_name
on error the error_message number the error_number
if the error_number is -59 then
set the error_message to "This name contains improper characters, such as a colon (:)."
else --the suggested name is too long
set the error_message to error_message -- "The name is more than 31 characters long."
end if
tell me to display dialog the error_message default answer new_item_name buttons {"Cancel", "Skip", "OK"} default button 3
copy the result as list to {new_item_name, button_pressed}
if the button_pressed is "Skip" then return 0
my set_item_name(this_item, new_item_name)
end try
else --the name already exists
tell me to display dialog "This name is already taken, please rename." default answer new_item_name buttons {"Cancel", "Skip", "OK"} default button 3
copy the result as list to {new_item_name, button_pressed}
if the button_pressed is "Skip" then return 0
my set_item_name(this_item, new_item_name)
end if
end tell
end set_item_name
You need to move the file before you change the name in any way, or the script will be called again because it’s a folder action and changing the name makes the folder see the file as a new file.
Sometimes you can check to see if your script has already altered the file name, and skip it in that case. I don’t see how you’d do that in this case though.
Forgive a noob, but I’m floundering in my file copying skills…
The following code gives me an Error: Can’t make container of file “:‘:Users:joeuser:tmp:filename.txt’” into type string
set newPath to the quoted form of ("/Users/joeuser/tmp/" & currentName)
do shell script ("ditto " & item_path & " " & newPath) -- copy the file into a temp directory before renaming
set theFile to POSIX file newPath -- create an object pointing to the new file
set the parent_container_path to (the container of theFile) as text
The “container” line is just to proof that the theFile object is okay (which it obviously isn’t). In actuallity I then pass theFile to set_item_name.
I know I’m make a beginner’s mistake here somewhere. Any insight appreciated.
set_item_name generates the following error: Can’t make «class ctnr» of “Users/admin/tmp/filename.txt” into type string
Here’s the script as it stands now (note the non-op section is triggered when a file name is over 31 characters long, everything else seems to work well):
property destination_foldername : "/Volumes/Internal/Test"
on adding folder items to thefolder after receiving theaddeditems
repeat with eachItem in theaddeditems
set theFileInfo to info for eachItem -- get info for the incoming file
-- check name length. Over 31 characters (with extension) and system barfs
set currentName to the name of theFileInfo
set the item_path to the quoted form of the POSIX path of eachItem
set the destination_directory to POSIX path of the destination_foldername
set the destination_path to the quoted form of (destination_directory & "/" & (name of the theFileInfo))
set n to the number of characters of the currentName
if n > 31 then
try
set newPath to the quoted form of ("/Users/admin/tmp/" & currentName)
do shell script ("ditto " & item_path & " " & newPath)
-- build a truncated name to suggest
set the ext to text ((offset of "." in currentName)) thru -1 of currentName
set the new_name to ((characters 1 thru 27 of currentName) as string) & ext
on error the error_message number the error_number
display dialog "Error: " & error_message
end try
tell me to display dialog "File name too long." & return & "It can only be 31 characters in length. Please rename:" default answer new_name buttons {"Cancel", "OK"} default button 2
copy the result as list to {new_name, button_pressed}
if the button_pressed is "Cancel" then return 0
try
set_item_name(newPath, new_name) -- THIS IS WHERE THINGS STOP PLAYING NICE
on error the error_message number the error_number
display dialog "Error: " & error_message
end try
end if
-- do the actual work with the file here
end repeat
end adding folder items to
-- the following comes from Apple's own "Trim File Names.scpt"
on set_item_name(this_item, new_item_name)
tell application "Finder"
--activate
set the parent_container_path to (the container of this_item) as text -- THIS LINE GENERATES THE ERROR
if not (exists item (the parent_container_path & new_item_name)) then
try
set the name of this_item to new_item_name
on error the error_message number the error_number
if the error_number is -59 then
set the error_message to "This name contains improper characters, such as a colon (:)."
else --the suggested name is too long
set the error_message to error_message -- "The name is more than 31 characters long."
end if
--beep
tell me to display dialog the error_message default answer new_item_name buttons {"Cancel", "Skip", "OK"} default button 3
copy the result as list to {new_item_name, button_pressed}
if the button_pressed is "Skip" then return 0
my set_item_name(this_item, new_item_name)
end try
else --the name already exists
--beep
tell me to display dialog "This name is already taken, please rename." default answer new_item_name buttons {"Cancel", "Skip", "OK"} default button 3
copy the result as list to {new_item_name, button_pressed}
if the button_pressed is "Skip" then return 0
my set_item_name(this_item, new_item_name)
end if
end tell
end set_item_name
newPath (in the handler this_item) is a literal string (actually a quoted POSIX path).
First of all you can’t get the name of a string and AppleScript works with HFS paths (colon separated)
I ended up abandoning my call to Apple’s set_item_name and went with the following which works for me:
property destination_foldername : "/Volumes/Internal/Test"
on adding folder items to thefolder after receiving theaddeditems
repeat with eachItem in theaddeditems
set theFileInfo to info for eachItem -- get info for the incoming file
-- check name length. Over 31 characters (with extension) and system barfs
set currentName to the name of theFileInfo
set the item_path to the quoted form of the POSIX path of eachItem
set the destination_directory to POSIX path of the destination_foldername
set the destination_path to the quoted form of (destination_directory & "/" & (name of the theFileInfo))
set n to the number of characters of the currentName
if n > 31 then
try
set the new_name to currentName
repeat while the number of characters of the new_name > 31
set the ext to text ((offset of "." in currentName)) thru -1 of currentName
set the new_name to ((characters 1 thru 27 of currentName) as string) & ext
tell me to display dialog "File name too long." & return & "It can only be 31 characters in length. Please rename:" default answer new_name buttons {"Cancel", "OK"} default button 2
copy the result as list to {new_name, button_pressed}
if the button_pressed is "Cancel" then return 0
end repeat
set newPath to the quoted form of ("/Users/admin/tmp/" & new_name)
do shell script ("ditto " & item_path & " " & newPath)
set item_path to newPath
set destination_path to the quoted form of (destination_directory & "/" & new_name)
on error the error_message number the error_number
display dialog "Error: " & error_message
end try
end if
-- copy the file to the share
do shell script ("ditto " & item_path & " " & destination_path)
end repeat