I often need to copy files which are selected in a Finder window to one of a small number of frequently-used destination folders. This is easily done with a mouse but I prefer to use a keyboard, so I wrote the script contained below. The operation of this script requires little explanation except to note that the script copies files only.
-- Revised 2021.07.01
use framework "AppKit"
use framework "Foundation"
use scripting additions
on main()
set preferencesFolder to POSIX path of (path to preferences)
set settingPlist to preferencesFolder & "FinderCopySetting.plist"
set dataPlist to preferencesFolder & "FinderCopyData.plist"
try
set dialogDefault to settingOne of readPlist(settingPlist) as text
on error
set dialogDefault to "Add a Destination"
end try
try
set destinationFolders to readPlist(dataPlist)
set destinationNames to (destinationFolders's allKeys()'s sortedArrayUsingSelector:"caseInsensitiveCompare:") as list
on error
set destinationFolders to (current application's NSMutableDictionary's new())
set destinationNames to {}
end try
set dialogMenu to destinationNames & {"--", "Add a Destination", "Delete a Destination"}
set dialogResult to (choose from list dialogMenu with title "Finder Copy" default items dialogDefault)
if dialogResult = false then error number -128
set dialogResult to item 1 of dialogResult
set destinationFolder to (destinationFolders's valueForKey:dialogResult)
if dialogResult = "Add a Destination" then
set {destinationFolders, currentName} to addDestination(destinationFolders, destinationNames)
writePlist(dataPlist, destinationFolders)
set dialogResult to currentName
else if dialogResult = "Delete a Destination" then
set destinationFolders to deleteDestination(destinationFolders, destinationNames)
writePlist(dataPlist, destinationFolders)
else if dialogResult begins with "-" then
error number -128
else
copyOne(destinationFolder)
end if
set theSetting to current application's NSDictionary's dictionaryWithDictionary:{settingOne:dialogResult}
writePlist(settingPlist, theSetting)
end main
on addDestination(destinationFolders, destinationNames)
try
tell application "Finder"
set currentName to name of Finder window 1
set currentPath to target of Finder window 1 as alias
end tell
set currentPath to POSIX path of currentPath
on error
errorDialog("Add a Destination", "A Finder window was not found or the target of the front Finder window cannot be a destination")
end try
set dialogPath to (current application's NSString's stringWithString:currentPath)'s pathComponents()
if (count dialogPath) < 7 then
set dialogPath to text 1 thru -2 of currentPath
else
set dialogPath to current application's NSString's stringWithFormat_("/%@/%@/.../%@/%@", item 2 of dialogPath, item 3 of dialogPath, item -3 of dialogPath, item -2 of dialogPath) as text
end if
set currentName to text returned of (display dialog "Destination name for " & quote & dialogPath & quote default answer currentName buttons {"Cancel", "OK"} default button 2 cancel button 1 with title "Finder Copy")
if currentName = "" then error number -128
if currentName is in destinationNames then errorDialog("Add a Destination", "A destination named " & quote & currentName & quote & " already exists")
destinationFolders's setObject:currentPath forKey:currentName
return {destinationFolders, currentName}
end addDestination
on deleteDestination(destinationFolders, destinationNames)
if destinationNames = {} then errorDialog("Delete a Destination", "There are no destinations to delete")
set deleteItems to (choose from list destinationNames with title "Finder Destination" with prompt "Select destinations to delete:" default items {item 1 of destinationNames} with multiple selections allowed)
if deleteItems = false then error number -128
set deleteItems to current application's NSArray's arrayWithArray:deleteItems
(destinationFolders's removeObjectsForKeys:deleteItems)
return destinationFolders
end deleteDestination
on copyOne(thePath)
tell application "Finder" to set selectedFiles to selection as alias list
if selectedFiles = {} then errorDialog("Finder Copy", "File not selected or selected item cannot be copied")
set fileManager to current application's NSFileManager's defaultManager()
repeat with aFile in selectedFiles
copyTwo(POSIX path of aFile, thePath, fileManager)
end repeat
end copyOne
on copyTwo(aFile, thePath, fileManager)
set aFileURL to (current application's |NSURL|'s fileURLWithPath:aFile)
set aFileString to (current application's NSString's stringWithString:aFile)
set aFileName to aFileString's lastPathComponent()
set aNewFile to (thePath's stringByAppendingPathComponent:aFileName)
if (aFileString's isEqual:aNewFile) then errorDialog("File Copy", "The source and destination folders are the same")
set {theResult, isDirectory} to (aFileURL's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
set {theResult, isPackage} to (aFileURL's getResourceValue:(reference) forKey:(current application's NSURLIsPackageKey) |error|:(missing value))
if isDirectory as boolean = true and isPackage as boolean = false then
display alert "Finder Copy" message quote & aFileName & quote & " is a folder" buttons {"Cancel", "Skip"} default button 2 cancel button 1 as critical
return
end if
if (fileManager's fileExistsAtPath:aNewFile) then
display alert "Finder Copy" message "The destination already contains " & quote & aFileName & quote buttons {"Cancel", "Skip", "Overwrite"} default button 2 cancel button 1 as critical
if button returned of result = "Skip" then return
set aNewFileURL to current application's |NSURL|'s fileURLWithPath:aNewFile
(fileManager's trashItemAtURL:aNewFileURL resultingItemURL:(missing value) |error|:(missing value))
end if
set theResult to (fileManager's copyItemAtPath:aFileString toPath:aNewFile |error|:(missing value))
if (theResult as boolean) is false then errorDialog("File Copy", "An error occurred while copying " & quote & aFileName & quote)
end copyTwo
on readPlist(thePath)
return (current application's NSMutableDictionary's dictionaryWithContentsOfFile:thePath)
end readPlist
on writePlist(thePath, theDictionary)
theDictionary's writeToFile:thePath atomically:true
end writePlist
on errorDialog(textOne, textTwo)
display alert textOne message textTwo buttons {"OK"} default button 1 as critical
error number -128
end errorDialog
main()