Archiving image files using Applescript and Finder too slow

Hello,

My programming skills are limited. Applescript usually does what I want it to do. This post concerns file management. I need to create ZIP-archives of object image files.

I have a larger folder of JPG-files. The files are named already using an object number followed by underscore and a running number (z.B. Object1_01.JPG, Object1_02.JPG, etc.). I attempted to use Applescript and Automator to select for each object the respective files and use Mac’s Archive to produce loss-free ZIP archives. The workflow then loops through the directory until all ZIPs are created and the original JPGs are moved into a subfolder called ZIPPED.

The problem I am having is that it works fine with 200 files, but takes ages for 2000 files. I read it may be an issue with Finder or that Finder is not destined to do what I want it to do.

My Workflow has two Applescripts, Applescript # 1:


on run {input, parameters}
	
	
	with timeout of 1000 seconds
		
		
		
		tell application "Finder"
			
			set sourcefolder to get selection as alias
			
			set theFiles to (sort files in sourcefolder by name)
			
			set t to (time string of (current date))
			
			
			set namearray to {}
			
			set theFilename to name of (select (first file of sourcefolder whose name contains "_01"))
			
			set myArray1 to my theSplit(theFilename, ".")
			set theBasename to item 1 of myArray1
			set theExtension to item 2 of myArray1
			
			set myArray2 to my theSplit(theBasename, "_")
			set musNo to item 1 of myArray2
			set theFace to item 2 of myArray2
			
			
			select (every file of sourcefolder whose name begins with musNo)
			
		end tell
		
		
	end timeout
	
	
	return input
	return musNo
	return sourcefolder
	return ResultFolder
end run


on theSplit(theString, theDelimiter)
	-- save delimiters to restore old settings
	set oldDelimiters to AppleScript's text item delimiters
	-- set delimiters to delimiter to be used
	set AppleScript's text item delimiters to theDelimiter
	-- create the array
	set theArray to every text item of theString
	-- restore the old setting
	set AppleScript's text item delimiters to oldDelimiters
	-- return the result
	return theArray
end theSplit


on dateformat(theDate)
	set {year:y, day:d, time:t} to theDate
	copy theDate to b
	set b's month to January
	tell (y * 10000 + (b - 2500000 - theDate) div -2500000 * 100 + d) as string
		set date_string to text 1 thru 4 & "-" & text 5 thru 6 & "-" & text 7 thru 8
	end tell
	return date_string
end dateformat


Then Automator, get selected Finder Items

Create Archive

Applescript # 2


on run {input, parameters}
	
	
	with timeout of 1000 seconds
		
		
		
		tell application "Finder"
			
			set theFiles to (get selection)
			
			set theFilename to name of item 1 of (get selection) as string
			
			set myArray1 to my theSplit(theFilename, ".")
			set theBasename to item 1 of myArray1
			set theExtension to item 2 of myArray1
			
			set myArray2 to my theSplit(theBasename, "_")
			set musNo to item 1 of myArray2
			set theFace to item 2 of myArray2
			
			
			
			
			set theArchive to (select (first file of container of item 1 of (get selection) whose name contains "Archive.zip"))
			
			set {theName, theExtension} to {name, name extension} of theArchive
			
			if theExtension is not "" then
				set theName to text 1 thru -((count theExtension) + 2) of theName -- just
				set theExtension to "." & theExtension
			end if
			
			set the name of theArchive to musNo & theExtension as string
			
			set currentDir to ((target of front Finder window) as text) as alias
			
			set outputFolder to POSIX path of (currentDir) & "ZIPPED"
			do shell script "mkdir -p " & quoted form of outputFolder
			
			set theFiles to select (every file of currentDir whose name begins with musNo and name extension is "JPG")
			
			set Zippedfolder to quoted form of outputFolder
			
			set TheFilesCount to number of items of theFiles
			
			move items 1 thru TheFilesCount of theFiles to folder "ZIPPED" of currentDir
			
			
		end tell
		
		tell application "Finder" to get (container of (path to me)) as text
		
	end timeout
	
	
	return input
	return musNo
end run


on theSplit(theString, theDelimiter)
	-- save delimiters to restore old settings
	set oldDelimiters to AppleScript's text item delimiters
	-- set delimiters to delimiter to be used
	set AppleScript's text item delimiters to theDelimiter
	-- create the array
	set theArray to every text item of theString
	-- restore the old setting
	set AppleScript's text item delimiters to oldDelimiters
	-- return the result
	return theArray
end theSplit


on dateformat(theDate)
	set {year:y, day:d, time:t} to theDate
	copy theDate to b
	set b's month to January
	tell (y * 10000 + (b - 2500000 - theDate) div -2500000 * 100 + d) as string
		set date_string to text 1 thru 4 & "-" & text 5 thru 6 & "-" & text 7 thru 8
	end tell
	return date_string
end dateformat


and finally a loop action.

Does anyone have an idea how to make this faster? Particularly important is loss-free Archiving.

Thanks for any suggestions!

Below is a script doing some parts of the job very quickly.
Alas I have no free time available to apply your filter upon file names.

use AppleScript version "2.5"
use framework "Foundation"
use scripting additions

property |⌘| : a reference to current application

set theLib to choose folder -- Dossier à sélectionner

set theURL to (|⌘|'s NSArray's arrayWithObject:(theLib as «class furl»))'s firstObject()

set theManager to |⌘|'s NSFileManager's defaultManager()
-- build an URL pointing to the folder named "ZIPPED"
set theZIPPEDURL to theURL's URLByAppendingPathComponent:"ZIPPED"
-- create this folder
set {theResult, theError} to theManager's createDirectoryAtURL:theZIPPEDURL withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
-- Now we have an URL to the final storage
set skipsPackageDescendants to |⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer --> 2
set skipHidden to |⌘|'s NSDirectoryEnumerationSkipsHiddenFiles as integer --> 4
set theOptions to skipsPackageDescendants + skipHidden
set allURLs to (theManager's enumeratorAtURL:theURL includingPropertiesForKeys:{} options:theOptions errorHandler:(missing value))'s allObjects()
set theFormat to "(self.pathExtension =[c] 'jpg') OR (self.pathExtension =[c] 'jpeg')"
set thePredicate to |⌘|'s NSPredicate's predicateWithFormat:theFormat
set jpegURLs to (allURLs's filteredArrayUsingPredicate:thePredicate)
-- Now we have an array of NSURLs pointing to picture.jpeg files
repeat with anURL in jpegURLs
	set theName to anURL's lastPathComponent() as string
	-- insert here your code related to file names
	set maybe to theName contains "_01"
	set furl to (anURL as «class furl»)
	set origPath to POSIX path of furl --anURL's |path|() as string
	set turl to furl as string
	set zipPath to POSIX path of (turl & ".zip") --zipURL's |path|() as string
	do shell script "ditto -ck " & quoted form of origPath & " " & quoted form of zipPath
	set destinationURL to (theZIPPEDURL's URLByAppendingPathComponent:(anURL's |lastPathComponent|()))
	set {theResult, theError} to (theManager's moveItemAtURL:anURL toURL:destinationURL |error|:(reference))
end repeat

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) dimanche 17 mai 2020 22:19:55

Thanks a lot. I look into it!

The plain AppleScript (and not Finder) is slower than AsObjC. So, when you want to write effective plain Apple-script, you should avoid any unnecessary operations, especially if they are time-consuming. Let’s begin with this code line:

set theFiles to sort files in sourcefolder by name

Sort operation is time consuming. I don’t see where you use its result further in the code. So it’s just useless with you. It can be thrown into the trash.

Now, let’s see this code line:


set theFiles to select (every file of currentDir whose name begins with musNo and name extension is "JPG")

Selecting Finder items is time consuming. I don’t see where you use selecting result further in the code. So it’s just useless with you. It can be modified. No need selecting the files. It is enough getting references to this files:


set theFiles to every file of currentDir whose name begins with musNo and name extension is "JPG"

Now, this. Not so important. It is not time consuming, but is useless:


set t to (time string of (current date))
set namearray to {}