applescript, folder action, move copied items fails, timing issue? - applescript

Please help, I can't think of a fix for this.
A folder action is meant to do this for each file copied into a folder:
Derive a subfolder name, and a new filename.
Create subfolder.
Move file into it.
Rename subfolder and file.
Files are copied from a different volume and are usually 500…1500 MB.
Problem: The moving step (step 3) in the folder action script fails if the files are that large and their number is >1
and they are copied from a different volume.
The script works fine when copying: small files, or from the same volume, or only one file.
In a test, all of 200 Alias' were correctly processed, but only 23 of 512. This is not a problem, the number of added_items is usually <10 and unlikely to ever be >50. But it may help targeting the issue.
I suspected a timing issue, but all attempts to fix it using generous timeout's didn't work.
The script (note - before trying, set the regex in the do shell script lines to something workable):
on adding folder items to this_folder after receiving added_items
repeat with the_item in added_items
with timeout of 3600 seconds
tell application "Finder"
if kind of the_item is not "Folder" then
repeat -- wait until item is copied. Thanks to original coder on the WWW.
set {size:fileSize, busy status:Busy} to (info for (the_item))
if not Busy and (fileSize is greater than 0) then exit repeat
delay 1
end repeat
with timeout of 600 seconds
set new_folder_name to do shell script "echo '" & (name of the_item) ¬
& "' | sed -E 's/llooongRegex/replace/g'"
set new_item_name to do shell script "echo '" & (name of the_item) ¬
& "' | sed -E 's/otherRegex/replace/g'"
set new_folder to (make new folder at this_folder with properties {name:(new_folder_name & "-temp")}) as alias -- "-temp" in case new folder and file will have the same name
move file the_item to folder new_folder -- <== fails if ((added_items >1) AND (files big, tested with 0.5…1.5GB) AND (copied from different volume)) ==> Timing issue?
set name of (first item of (get contents of new_folder)) to new_item_name
set name of new_folder to new_folder_name
end timeout
end if
end tell
end timeout
end repeat
end adding folder items to
P.S.: is folder-action frequent enough for a tag?

After replacing the repeat -- wait until item is copied.... clause with a simple delay 60, the script works. So it is a timing problem.
Waiting for the target folder to stop changing size as describe here works as long as only 1 file copying (bunch of files dropped) is running. Two or more drag'n drops, and it hiccups again (nice word, #vadian!).
Ditto when checking for the size of individual added items to remain constant.

Related

AppleScript - Move all the files contained in subfolder to a top folder

I am looking for an edit to the current script. What I need is moving all the files from subfolders (recursively) in to one top folder, however if a file with the same name exist, create a new top-folder and continue there, this is what I have so far:
tell application "Finder"
try
set Random_name to random number from 100 to 9999
set theTopFolder to (choose folder)
set theFiles to a reference to every file of (entire contents of folder theTopFolder)
set theNewFolder to make new folder at theTopFolder with properties {name:"Flattened Files"}
move theFiles to theNewFolder
on error
set theNewFolder to make new folder at theTopFolder with properties {name:"Flattened Files" & Random_name}
move theFiles to theNewFolder
end try
end tell
Just to be clear the structure of the path is not:
Mainfolder/subfolder/file.xxx but Mainfolder/subfolder/sulbfolder2/subfolder3/....100/file.xxx so the script needs to work recursively which it does but it stops when a file exist with the same name
When a file with the same name exist my edit creates a new folder with Flattened Files+random number however when another file with the same name is moved the script stops for an error instead going ahead and creating a new Flattened Files+randonnumber folder. Any ideas?
Thank you
Your script isn't using recursion, it just lets the Finder get all the files. The additional error you are getting is because you are trying to move the whole list of files again.
One solution would be to step through the file items, testing for duplicates as you go, and make new folders as needed. The following script just moves duplicates to added folders (note that an error will still stop the script). I don't know how you are sorting the file list, so I included a line to uncomment to continue moving file items to the added folder.
set theTopFolder to (choose folder)
tell application "Finder"
set theNewFolder to make new folder at theTopFolder with properties {name:"Flattened Files"}
set theFiles to every file of (entire contents of folder theTopFolder) as alias list
repeat with aFile in theFiles
if file ((theNewFolder as text) & (name of aFile)) exists then -- use added folders for duplicates
set counter to 1
set done to false
repeat until done
set suffix to text -2 thru -1 of ("000000" & counter) -- leading zeros for sorting
set alternateFolder to (theTopFolder as text) & "Flattened Files" & space & suffix
tell me to (do shell script "mkdir -p " & quoted form of POSIX path of alternateFolder) -- make new folder as needed
if file (alternateFolder & ":" & (name of aFile)) exists then -- continue to next one
set counter to counter + 1
else
move aFile to folder alternateFolder
# set theNewFolder to folder alternateFolder -- uncomment to continue moving here after a duplicate
set done to true
end if
end repeat
else
move aFile to folder (theNewFolder as text)
end if
end repeat
end tell

Moving entire folders with AppleScript

This is my very first use of AppleScript. I'm trying to use it to move a 100+ folders (and their content files) from one location to another. I'm not just moving the files because I want to maintain the filing system. So I've got the folders listed in a .txt file in this format:
Macintosh HD:Users:Tom:Music:iTunes:Afrika Bambaataa
Macintosh HD:Users:Tom:Music:iTunes:Air
And then I run the following in AppleScript:
tell application "Finder"
set TextFile to (choose file with prompt "Select your text file" of type {"txt"})
set My_Folder to (choose folder with prompt "Select your destination folder")
set List_files to paragraphs of (read TextFile)
move List_files to My_Folder
end tell
However the error I receive is the following:
error "Finder got an error: Handler can’t handle objects of this class." number -10010
Any help on what I'm doing wrong here?
Much appreciated!
tell application "Finder"
set TextFile to (choose file with prompt "Select your text file" of type {"txt"})
set My_Folder to (choose folder with prompt "Select your destination folder")
set List_files to paragraphs of (read TextFile)
move List_files to My_Folder
end tell
Currently, List_files is just a list of text objects, i.e.
{"Macintosh HD:Users:Tom:Music:iTunes:Afrika Bambaataa",
"Macintosh HD:Users:Tom:Music:iTunes:Air", ...}
so what you're asking Finder to do is move some text to a folder, which doesn't make sense. You need to tell Finder that this text represents a path to a folder, by using the folder specifier. Since this can't be done en masse, you have to iterate through the list:
repeat with fp in List_files
move folder fp to My_Folder
end repeat
However, I wouldn't actually do it like this, as that will require 100+ separate move commands - one for each item in List_files. Instead, we'll edit the list items first by prepending the folder specifier to each item, and then move the list of folders altogether in a single command:
repeat with fp in List_files
set fp's contents to folder fp
end repeat
move List_files to My_Folder
Depending how big the files are and how long the transfer will take, the script might time out before the transfer is complete. I'm not honestly sure what impact this would have on an existing file transfer. I suspect that AppleScript will simply lose its connection with Finder, but that the transfer will continue anyway since the command has already been issued (another benefit of using a single move command instead of multiples). But, if you want to avoid finding out, we can extend the timeout duration to be safe:
with timeout of 600 seconds -- ten minutes
move List_files to alias "Macintosh HD:Users:CK:Example:"
end timeout
The final script looks something like this:
tell application "Finder"
set TextFile to (choose file with prompt "Select your text file" of type {"txt"})
set My_Folder to (choose folder with prompt "Select your destination folder")
set List_files to paragraphs of (read TextFile as «class utf8»)
if the last item of the List_files = "" then set ¬
List_files to items 1 thru -2 of List_files
repeat with fp in List_files
set fp's contents to folder fp
end repeat
move List_files to My_Folder
end tell
The extra line that starts if the last item of... is just a safety precaution in case the last line of the text file is a blank line, which is often the case. This checks to see if List_files contains an empty string as its last item, and, if so, removes it; leaving it in would throw an error later in the script.
EDIT: Dealing with folders that don't exist
If the repeat loop throws an error due to an unrecognised folder name, then we can exclude that particular folder from the list. However, it's easier if we create a new list that contains only the folders that have been verified (i.e. the ones that didn't throw an error):
set verified_folders to {}
repeat with fp in List_files
try
set end of verified_folders to folder fp
end try
end repeat
move the verified_folders to My_folder
This also means we can delete the line beginning if the last item of..., as the check that this performs is now going to be caught be the try...end try error-catching block instead.

Applescript to not quit when erroring

I have an applescript that is used to copy a file (using rsync) from a source to a multitude of locations:
set Servers to {"afp://service.username:password#MACSERVER1.domain.com/Public/", "afp://service.username:password#MACSERVER2.domain.com/Public/", "afp://service.username:password#MACSERVER3.domain.com/Public/", "afp://service.username:password#MACSERVER4.domain.com/Public/", "afp://service.username:password#MACSERVER5.domain.com/Public/"}
--these are constant so no need to change
set Source to "/Shared Items/Public/DeployStudio/Masters/HFS/Sierra.hfs.dmg"
set Destination to "/Volumes/Public/DeployStudio/Masters/HFS"
--the scripts that goes recursively through the list of servers
repeat with i from 1 to count of Servers
set thisServer to item i of Servers
--this will mount each server destination in turn creating a /Volumes/Public folder
mount volume thisServer
--these are two rsync scripts which creates logfiles
do shell script "/usr/bin/rsync -rlptD --log- file=/Users/username/Documents/logs/Sierra-rsync.log " & (quoted form of Source) & " " & (quoted form of Destination)
--not sure this is needed but added this 5 sec delay to stop ejecting disk errors
delay 5
--eject the mounted volume so we don't have multiple Public folders
tell application "Finder"
eject disk "Public"
end tell
end repeat
This works great and produces a log of what it does. Unless there is a problem. Then it will just quit. I would like to change it so it ignores errors and keeps going. Any ideas? Thanks
To ignore errors in the repeat loop wrap the affected code in a try block
repeat with i from 1 to count of Servers
set thisServer to item i of Servers
try
...
end try
end repeat

Applescript to copy each file individually to target folder

I have all these movies in .dvdmedia format and I want to covert them all to a smaller file size such as .mp4.
But what I need to do is create an applescript that will copy the individual file to a folder 'Conversion'. Once the file in the folder is deleted it copies the next item and deletes the previous.
I've completed an Automation script that once the item is added to the folder is starts formatting the file through TurboHD then deletes the file and moves the converted item to another folder 'Completed'
Does anyone able to help me with this?
Please note that the location of the movies are on a NAS drive
there :) I coded the following. Please note to save it as an Application with Stay open after run handler checked.
You have to set the source and the target path to the paths in your environment.
Finally you have to set the return value. The value sets the interval in seconds to wait until next execution. If each of your conversions takes about an hour, I think I would check every 5 minutes meaning the handler has to return 300.
-- The idle-Handler defines a repetitive task
-- Note: Save as Application with option "Stay open after run handler"
on idle
-- define the folders to watch
set theSourceFolder to (POSIX file "/Users/myHomeFolder/Desktop/Conversion_Source") as alias
set theTargetFolder to (POSIX file "/Volumes/myMountedVolume/Conversion") as alias
-- check the contained files (get visible files only because of .DS_Store etc.)
tell application "System Events"
set availableSourceFiles to every file of theSourceFolder whose visible is true
set filesOfTargetFolder to files of theTargetFolder whose visible is true
end tell
-- if no more source file is available, quit this script
if (count of availableSourceFiles) = 0 then
quit
end if
-- if the target folder is empty start move
if (count of filesOfTargetFolder) = 0 then
-- get the first item from source folder
set sourceFile to (first item of availableSourceFiles) as alias
-- use the Finder to copy the file
tell application "Finder"
-- duplicate the file to the target folder
duplicate sourceFile to theTargetFolder
-- move the source file to trash after copy
move sourceFile to trash
end tell
end if
-- the integer returned is the time to wait (in seconds)
-- here: two minutes
return 120
end idle
Enjoy, Michael / Hamburg

AppleScript: Move contents of folder in user defined amount to folders?

I'm fairly new at this and while having managed to created several basic scripts over the last few weeks I cannot seem to wrap my head around this one:
Choose Folder (with say 1000 Files)
Enter the number of Files per Folder (say 100)
The script then creates 10 Folders (1000 Files / 100 in each folder)
The script then moves the first 100 files sequentially into the the first folder - repeats till done.
The scripts I've put together for this process to this point are dismal, sloppy and outright pathetic so I dare not share them here.
My experiments have also resulted in the item listing causing issues with moving the files sequentially.
instead of:
ValOne_1.wav
ValOne_2.wav
ValOne_3.wav
ValOne_4.wav
ValOne_5.wav
I get:
ValOne_1.wav
ValOne_10.wav
ValOne_100.wav
ValOne_101.wav
ValOne_102.wav
Thanks
The Finder has a "sort" command so you can use that to avoid the numbering problem you mention. It seems to sort them the way you expect. So using that your workflow becomes easy with a little clever coding. Try the following. You only need to adjust the first 2 variables in the script to suit your needs and the rest of the script should just work.
set filesPerFolder to 3
set newFolderBaseName to "StorageFolder_"
set chosenFolder to (choose folder) as text
tell application "Finder"
-- get the files from the chosen folder and sort them properly
set theFiles to files of folder chosenFolder
set sortedFilesList to sort theFiles by name
set theCounter to 1
repeat
-- calculate the list of files to move
-- also remove those files from the sortedFilesList
if (count of sortedFilesList) is greater than filesPerFolder then
set moveList to items 1 thru filesPerFolder of sortedFilesList
set sortedFilesList to items (filesPerFolder + 1) thru end of sortedFilesList
else
set moveList to sortedFilesList
set sortedFilesList to {}
end if
-- calculate the new folder information and make it
set newFolderName to newFolderBaseName & theCounter as text
set newFolderPath to chosenFolder & newFolderName
if not (exists folder newFolderPath) then
make new folder at folder chosenFolder with properties {name:newFolderName}
end if
-- move the moveList files
move moveList to folder newFolderPath
if sortedFilesList is {} then exit repeat
set theCounter to theCounter + 1
end repeat
end tell

Resources