Complex Files / Folders automation

Hello everybody!

Let’s begin specifying that I’m a perfect newbie with Applescript (Day 3, literally :wink: ) and that my english is a little (lot) rusty so… Be patient, please! :slight_smile:

I’m looking for a way to automate a very annoying, periodical task…

The situation

======> ONE FOLDER [A] WITH HUNDREDS OF FILES IN IT

Every File in Folder [A] is named in the following way: nnnn_XXXXXXX.ext
where:
“nnnn” is an ID number (NOT unique);
“XXXXXXX” a simple name (not unique);
“ext” the file extension (not necessarily the same for all files).

i.e.
FOLDER [A]
0001_The cat.wav
0002_The dog.aiff
0003_The mouse.jpg
0003_The mouse.doc
0004_The monkeyA.wav
0004_The monkeyB.wav
0004_The monkey.jpg
0004_The monkey.xls
0005_The cat.wav


.

======> ANOTHER FOLDER [Z] WITH THOUSANDS OF FILES IN IT

  • Every file in Folder [Z] is named in the following way: nnnn_ExampleNNN.wav,
    where:
    “nnnn” is an ID number (not unique, the same as in Folder [A]);
    “Example” is a fixed text (always the same);
    “NNN” a three digits sequential number (001, 002, 003, 004,…);
    “wav” the File extension (always the same).

i.e.
FOLDER [Z]
0001_Example001.wav
0001_Example002.wav
0001_Example003.wav
0001_Example004.wav
0002_Example001.wav
0002_Example002.wav
0003_Example001.wav
0003_Example002.wav
0003_Example003.wav
0004_Example001.wav
0004_Example002.wav
0004_Example003.wav


.

I’ve already found and edited an Applescript to create - starting from an Excel or Text file containing the “nnnn_XXXXXX” names list - an array of Folders like that:

ARCHIVE
nnnn_XXXXXXX
PHASE_1
PHASE_2
PHASE_3
IMAGES
DOCS
nnnn_XXXXXXX
PHASE_1
PHASE_2
PHASE_3
IMAGES
DOCS
…;

This will be the starting point for the solution I’m looking for.


What I need

1a) Move WAV (extension wav/WAV) Files from Folder [A] to the right “PHASE_1” Folder (USING nnnn NUMBER AS REFERENCE), inside ARCHIVE Folder;

1b) Move EVERY OTHER SOUND Files (aiff/mp3/…) from Folder [A] to the right “PHASE_2” Folder (ALWAYS USING nnnn NUMBER AS REFERENCE), inside ARCHIVE Folder;

1c) Move IMAGE Files (jpg/tiff/…) from Folder [A] to the right “IMAGES” Folder (ALWAYS USING nnnn NUMBER AS REFERENCE), inside ARCHIVE Folder;

1d) Move EVERYTHING ELSE (doc/xls/…) from Folder [A] to the right “DOCS” Folder (ALWAYS USING nnnn NUMBER AS REFERENCE), inside ARCHIVE Folder;

  1. Move Files from Folder [Z] to the right “PHASE_3” Folder (ALWAYS USING nnnn NUMBER AS REFERENCE), inside ARCHIVE Folder;

With the example data used above, the final result would be something like that:

ARCHIVE

  > 0001_XXXXXXX
        > PHASE_1
              0001_The cat.wav
        > PHASE_2
        > PHASE_3
              0001_Example001.wav
              0001_Example002.wav
              0001_Example003.wav
        > IMAGES
        > DOCS

  > 0002_XXXXXXX
        > PHASE_1
        > PHASE_2
              0002_The dog.aiff
        > PHASE_3
              0002_Example001.wav
              0002_Example002.wav
        > IMAGES
        > DOCS

  > 0003_XXXXXXX
        > PHASE_1
        > PHASE_2
        > PHASE_3
              0003_Example001.wav
              0003_Example002.wav
              0003_Example003.wav
        > IMAGES
              0003_The mouse.jpg
        > DOCS
              0003_The mouse.doc

  > 0004_XXXXXXX
        > PHASE_1
              0004_The monkeyA.wav
              0004_The monkeyB.wav
        > PHASE_2
        > PHASE_3
              0004_Example001.wav
              0004_Example002.wav
              0004_Example003.wav
        > IMAGES
              0004_The monkey.jpg
        > DOCS
              0004_The monkey.xls

  > 0005_XXXXXXX
        > PHASE_1
              0005_The cat.wav
        > PHASE_2
        > PHASE_3
        > IMAGES
        > DOCS

  ...
  ..
  .

Ehm… Lots of Blabla, I know… But I’m trying to explain the best as I can, hoping somebody can help…
:rolleyes:

Thanks in advance!!!

I’m trying, step by step, to build an Applescript doing what I described above…

First step: I’ve got a number of Files (named, as descripted above, nnnn_XXXXXXX.ext) and a number of Folders (named nnnn_PHASE_1), all inside a main Folder.

—> The script must put every File inside the right Folder using first 5 characters of name (“nnnn_”) as reference.

I’m trying to adapt a piece of code found in this forum and I’ve got that:, but It doesn’t work:


tell application "Finder"
	set selected to selection
	set mainFolder to item 1 of selected as alias
	set filesList to name of every document file of folder mainFolder whose name extension is in {"aiff", "AIFF"}
	set foldersList to name of every folder of folder mainFolder
	repeat with folderX in foldersList
		set folderName to text 1 thru 5 of (name of folderX as text)
		repeat with oneFile in filesList
			set fileName to text 1 thru 5 of (name of fileX as text)
			if fileName is equal to folderName then
				try
					move file fileX of mainFolder ¬
					to folder folderX of mainFolder replacing no
				end try
			end if
		end repeat
	end repeat
end tell

Running the script give me the following error message:

error “Non posso trasformare name of item 1 of {"1001_PHASE_1", "1002_PHASE_1", "1003_PHASE_1", "1004_PHASE_1"} nel tipo text.” number -1700 from name of item 1 of {“1001_PHASE_1”, “1002_PHASE_1”, “1003_PHASE_1”, “1004_PHASE_1”} to text

Obviously, I’m working with an Italian version… Translation, more or less, is:

error “I cannot transform name of item 1 of {"1001_PHASE_1", "1002_PHASE_1", "1003_PHASE_1", "1004_PHASE_1"} to type text.” number -1700 from name of item 1 of {“1001_PHASE_1”, “1002_PHASE_1”, “1003_PHASE_1”, “1004_PHASE_1”} to text

Can anybody help me understand what I’m doing wrong?

Thanks :slight_smile:

Hi,

maybe this piece of code is of some help?

Kind regards, Eric

The problem with this kind of query is that, while it’s relative easy to move a few files according to this or that criterion, the easiest ways are very slow ” and the poster of the problem is invariably a complete newbie with thousands of files to move! :wink:

Here are two approaches which essentially work in the same way: one using the Finder to move the files and vanilla AppleScript to do the thinking; the other, much faster, using ASObjC throughout. Both scripts assume that the necessary destination folders already exist.

Finder/AS:

-- The necessary destination folders are assumed to exist already.

main()

on main()
	-- Adjust these HFS paths and extension lists to your own requirements before running the script.
	set folderAPath to (path to desktop as text) & "Test:A:"
	set folderZPath to (path to desktop as text) & "Test:Z:"
	set archiveFolderPath to (path to desktop as text) & "Test:ARCHIVE:"
	set otherSoundFileExtensions to {"aiff", "mp3", "aac"}
	set imageExtensions to {"jpg", "jpeg", "tiff", "png"}
	
	-- Deal with the files in folder A. The relevant archive for each is the one with whose name the file name begins.
	tell application "Finder"
		set archiveNames to name of every folder of folder archiveFolderPath
		set fileNamesFromA to name of every file of folder folderAPath
	end tell
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "."
	repeat with thisName in fileNamesFromA
		repeat with thisArchiveName in archiveNames
			if (thisName begins with thisArchiveName) then
				set archivePath to archiveFolderPath & thisArchiveName
				exit repeat
			end if
		end repeat
		
		set thisExtension to text item -1 of thisName
		if (thisExtension is "wav") then
			set destinationFolderPath to archivePath & ":PHASE_1"
		else if (thisExtension is in otherSoundFileExtensions) then
			set destinationFolderPath to archivePath & ":PHASE_2"
		else if (thisExtension is in imageExtensions) then
			set destinationFolderPath to archivePath & ":IMAGES"
		else
			set destinationFolderPath to archivePath & ":DOCS"
		end if
		tell application "Finder" to move file thisName of folder folderAPath to folder destinationFolderPath
	end repeat
	
	-- Deal with the files in folder Z. The relevant archive for each is the one whose name begins with the id at the beginning of the file name.
	tell application "Finder" to set fileNamesFromZ to name of every file of folder folderZPath
	set AppleScript's text item delimiters to "_"
	repeat with thisName in fileNamesFromZ
		set thisID to text item 1 of thisName
		repeat with thisArchiveName in archiveNames
			if (thisArchiveName begins with thisID) then exit repeat
		end repeat
		set destinationFolderPath to archiveFolderPath & thisArchiveName & ":PHASE_3"
		tell application "Finder" to move file thisName of folder folderZPath to folder destinationFolderPath
	end repeat
	set AppleScript's text item delimiters to astid
end main

ASObjC:

-- The necessary destination folders are assumed to exist already.

use AppleScript version "2.4" -- Mac OS 10.10 (Yosemite) or later.
use framework "Foundation"
use scripting additions

main()

on main()
	set |⌘| to current application
	-- Adjust these POSIX paths and extension arrays to your own requirements before running the script.
	set folderAPath to POSIX path of ((path to desktop as text) & "Test:A")
	set folderZPath to POSIX path of ((path to desktop as text) & "Test:Z")
	set archiveFolderPath to POSIX path of ((path to desktop as text) & "Test:ARCHIVE")
	set otherSoundFileExtensions to |⌘|'s class "NSArray"'s arrayWithArray:({"aiff", "mp3", "aac"})
	set imageExtensions to |⌘|'s class "NSArray"'s arrayWithArray:({"jpg", "jpeg", "tiff", "png"})
	
	set folderAURL to |⌘|'s class "NSURL"'s fileURLWithPath:(folderAPath)
	set folderZURL to |⌘|'s class "NSURL"'s fileURLWithPath:(folderZPath)
	set fileManager to |⌘|'s class "NSFileManager"'s defaultManager()
	
	-- Deal with the files in folder A. The relevant archive for each is the one with whose name the file name begins.
	set archiveNames to fileManager's contentsOfDirectoryAtPath:(archiveFolderPath) |error|:(missing value)
	set folderAContents to fileManager's contentsOfDirectoryAtURL:(folderAURL) includingPropertiesForKeys:({}) options:(|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	repeat with thisURL in folderAContents
		set thisFileName to thisURL's lastPathComponent()
		set thisFileNameBeginsWithIt to (|⌘|'s class "NSPredicate"'s predicateWithFormat:("%@ BEGINSWITH self") argumentArray:({thisFileName}))
		set thisArchiveName to (archiveNames's filteredArrayUsingPredicate:(thisFileNameBeginsWithIt))'s firstObject()
		
		set thisExtension to thisURL's pathExtension()
		if ((thisExtension's isEqualToString:("wav")) as boolean) then
			set destinationFolderName to "PHASE_1"
		else if ((otherSoundFileExtensions's containsObject:(thisExtension)) as boolean) then
			set destinationFolderName to "PHASE_2"
		else if ((imageExtensions's containsObject:(thisExtension)) as boolean) then
			set destinationFolderName to "IMAGES"
		else
			set destinationFolderName to "DOCS"
		end if
		set destinationURL to (|⌘|'s class "NSURL"'s fileURLWithPathComponents:({archiveFolderPath, thisArchiveName, destinationFolderName, thisFileName}))
		tell fileManager to moveItemAtURL:(thisURL) toURL:(destinationURL) |error|:(missing value)
	end repeat
	
	-- Deal with the files in folder Z. The relevant archive for each is the one whose name begins with the id at the beginning of the file name.
	set folderZContents to fileManager's contentsOfDirectoryAtURL:(folderZURL) includingPropertiesForKeys:({}) options:(|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	repeat with thisURL in folderZContents
		set thisFileName to thisURL's lastPathComponent()
		set idRange to (thisFileName's rangeOfString:("_"))
		set thisID to (thisFileName's substringToIndex:(idRange's location))
		set beginsWithThisID to (|⌘|'s class "NSPredicate"'s predicateWithFormat:("self BEGINSWITH %@") argumentArray:({thisID}))
		set thisArchiveName to (archiveNames's filteredArrayUsingPredicate:(beginsWithThisID))'s firstObject()
		set destinationURL to (|⌘|'s class "NSURL"'s fileURLWithPathComponents:({archiveFolderPath, thisArchiveName, "PHASE_3", thisFileName}))
		tell fileManager to moveItemAtURL:(thisURL) toURL:(destinationURL) |error|:(missing value)
	end repeat
end main

Thank you Eric and Nigel for the suggestions! :slight_smile:

Sorry for the delay but I’ve got some health problems… Anyway, I’ve finally written this script:



on open droppings
	tell application "Finder"
		set mainFolder to item 1 of droppings as alias
		
		-- Moves a first group of Audio Files.
		
		set fileType to every file of mainFolder whose name extension is in {"aiff", "AIFF", "wav", "WAV"} and name contains "_Track"
		repeat with FileX in fileType
			set fileName to name of FileX as text
			set fileIndex to characters 1 thru 4 of fileName as text
			set folderX to fileIndex & ":PHASE_1:" as string
			move (FileX) to folder folderX of mainFolder replacing no
		end repeat
		
		-- Moves every other Audio Files.
		
		set fileType to every file of mainFolder whose name extension is in {"aiff", "AIFF", "wav", "WAV"}
		repeat with FileX in fileType
			set fileName to name of FileX as text
			set fileIndex to characters 1 thru 4 of fileName as text
			set folderX to fileIndex & ":PHASE_2:" as string
			move (FileX) to folder folderX of mainFolder replacing no
		end repeat
		
		-- Moves every Image Files.
		
		set fileType to every file of mainFolder whose name extension is in {"jpg", "jpeg", "tif", "tiff", "png", "JPG", "JPEG", "TIFF", "TIF", "PNG"}
		repeat with FileX in fileType
			set fileName to name of FileX as text
			set fileIndex to characters 1 thru 4 of fileName as text
			set folderX to fileIndex & ":IMAGES:" as string
			move (FileX) to folder folderX of mainFolder replacing no
		end repeat
		
		-- Moves every other File (if possible).
		
		set fileType to every file of mainFolder
		repeat with FileX in fileType
			set fileName to name of FileX as text
			set fileIndex to characters 1 thru 4 of fileName as text
			set folderX to fileIndex & ":DOCS:" as string
			try
				move (FileX) to folder folderX of mainFolder replacing no
			end try
		end repeat
		
	end tell
end open


The script works perfectly… but only with a limited number of files/folders, I suppose.

After a lot of tests, I’ve finally tried (several times) to move my first real archive, about 7000 files, and nothing: script and Finder get stuck every time. After a while an error message appears, the script quit and I’m… forced to force quit/restart Finder. :frowning:

Probably, as Nigel said, the problem is the slowness of Finder but I don’t know how to fix that (my knowledge in ASObjC is next to zero)…

Help (and thanks again to everybody) !!! :slight_smile:

The script may be crashing. But with 7,000 files, I think there’s a chance that it’s not crashing, it’s just running up against Applescript’s default timeout. That is, the whole script takes place inside a “tell Finder,” and it sends some command that takes the Finder so long to perform that Applescript gives up on waiting for a return Apple Event from the Finder and just quits. I think the default timeout if none is specified is 2 minutes.

Try adding a “with timeout” with a really long timeout.



on open droppings
	with timeout of 600 seconds
		tell application "Finder"
			set mainFolder to item 1 of droppings as alias
			
			-- Moves a first group of Audio Files.
			
			set fileType to every file of mainFolder whose name extension is in {"aiff", "AIFF", "wav", "WAV"} and name contains "_Track"
			repeat with FileX in fileType
				set fileName to name of FileX as text
				set fileIndex to characters 1 thru 4 of fileName as text
				set folderX to fileIndex & ":PHASE_1:" as string
				move (FileX) to folder folderX of mainFolder replacing no
			end repeat
			
			-- Moves every other Audio Files.
			
			set fileType to every file of mainFolder whose name extension is in {"aiff", "AIFF", "wav", "WAV"}
			repeat with FileX in fileType
				set fileName to name of FileX as text
				set fileIndex to characters 1 thru 4 of fileName as text
				set folderX to fileIndex & ":PHASE_2:" as string
				move (FileX) to folder folderX of mainFolder replacing no
			end repeat
			
			-- Moves every Image Files.
			
			set fileType to every file of mainFolder whose name extension is in {"jpg", "jpeg", "tif", "tiff", "png", "JPG", "JPEG", "TIFF", "TIF", "PNG"}
			repeat with FileX in fileType
				set fileName to name of FileX as text
				set fileIndex to characters 1 thru 4 of fileName as text
				set folderX to fileIndex & ":IMAGES:" as string
				move (FileX) to folder folderX of mainFolder replacing no
			end repeat
			
			-- Moves every other File (if possible).
			
			set fileType to every file of mainFolder
			repeat with FileX in fileType
				set fileName to name of FileX as text
				set fileIndex to characters 1 thru 4 of fileName as text
				set folderX to fileIndex & ":DOCS:" as string
				try
					move (FileX) to folder folderX of mainFolder replacing no
				end try
			end repeat
			
		end tell
	end timeout
end open


If you’re finding that nothing got moved, then I suspect what with 7,000 files it’s choking right here:

set fileType to every file of mainFolder whose name extension is in {"aiff", "AIFF", "wav", "WAV"} and name contains "_Track"

In which case a sufficiently long “with timeout” might make it work. But on the other hand, it could simply be crashing at that step. If it is, you could rewrite the script to work iteratively though the files - just set a list to every file in the folder, then do a repeat loop that goes through every file one at a time and does whatever needs to be done with it.

Whether you get your current approach working by extending the timeout, or go with a more iterative approach, you might want to add a progress bar to any script that takes this long and processes so many separate files:

https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/DisplayProgress.html

Things that can slow down a script like this are the number of commands sent to the external application (in this case the Finder), how “difficult” they are for it (such as thinking about which files have certain name extensions), and the number of times the disk’s accessed for information.

The task here is to perform certain tests on the files’ names and to move the files accordingly. So much of the Finder bottleneck can be removed by using just one Finder command to get all the names without worrying about the extensions and using vanilla AppleScript to analyse the results. This is a lot less work than the Finder scanning the folder four times for files with particular name extensions, returning Finder references for them, and then getting the name of each file again individually. The script below still uses individual commands to move the files.

I don’t know if this is completely jam-proof, but it should work faster where it does work.



on open droppings
	set mainFolder to item 1 of droppings
	
	-- Get the names of all the files in the main folder, using just one easy command.
	local theFileNames
	tell application "Finder" to set theFileNames to name of every file of mainFolder
	
	-- Check them using just vanilla AppleScript.
	-- We'll use text item delimiters to extract the extension from each name.
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "."
	
	repeat with fileName in theFileNames
		set nameExtension to text item -1 of fileName
		set fileIndex to text 1 thru 4 of fileName
		
		if (nameExtension is in {"aiff", "AIFF", "wav", "WAV"}) then
			if (fileName contains "_Track") then
				-- Destination for audio file in first group.
				set folderX to fileIndex & ":PHASE_1:"
			else
				-- Destination for audio file not in first group.
				set folderX to fileIndex & ":PHASE_2:"
			end if
		else if (nameExtension is in {"jpg", "jpeg", "tif", "tiff", "png", "JPG", "JPEG", "TIFF", "TIF", "PNG"}) then
			-- Destination for image file.
			set folderX to fileIndex & ":IMAGES:"
		else
			-- Destination for any other file.
			set folderX to fileIndex & ":DOCS:"
		end if
		
		try
			tell application "Finder" to move file fileName of mainFolder to folder folderX of mainFolder replacing no
		end try
	end repeat
	
	set AppleScript's text item delimiters to astid
end open

THANKS A LOOOOT Nigel & t.spoon!!!

I applied every one of your suggestions and now It works perfectly… with a progress counter! :smiley:

The only problem is the slowness: moving 7000 files took more than an hour.

Maybe you’re interested to know something I noticed: at the beginning, the procedure was extremely slow (more than ONE SECOND :o for every single file to move) but the speed increased regularly (in a “logarithmic” way) every minute approaching the end, where it was very fast. The typical ‘drop’ sound started slow as an old clock and ended fast like a machine gun.

After that, I started the same procedure on other 750 files and it took ‘only’ 1’45"… So, I understood that splitting the mass in smaller pieces could let me spare a lot of time. Not what I hoped, but absolutely better than nothing. :wink:

I don’t know the real reason of that behaviour. I don’t understand why doing a job inside a big directory can be (so much) slower than doing the same thing inside a smaller one… Maybe Folder names aren’t “indexed” in Finder and the search is (a kind of) sequential, comparing name by name, every time? What do you think about it? Maybe the script can be further refined, knowing this…

Anyway, THANK YOU VERY MUCH, AGAIN!!!

And, again, sorry for my poor english. :slight_smile:

Hi.

When I drop a test folder containing 6592 JPEGs (all named in the manner you originally described and with the destination folders already created) onto the droplet in post #8, the machine-gun effect is almost continuous and the script takes just five and a half minutes to complete. It’s a dramatically different story if the folder’s open at the time, of course, because the Finder then has to update the window every time a file’s moved. Displaying and updating a progress bar also adds business to the process, but I don’t know how you’ve implemented that.

That said, I’ve tried using a Finder script to move the items back into the main folder for another run and that seems to be very slow even under optimal conditions. I’ve no idea why. :confused:

In contrast to the post #8 script, the ASObjC version below handles an identical folder in about fifteen seconds ” including creating the destination subfolders. You don’t get any sound effects though. :wink:

use AppleScript version "2.4" -- Mac OS 10.10 (Yosemite) or later.
use framework "Foundation"
use scripting additions

on open droppings
	set |⌘| to current application
	set mainFolder to item 1 of droppings
	set mainFolderPath to |⌘|'s class "NSString"'s stringWithString:(POSIX path of mainFolder)
	set mainFolderURL to |⌘|'s class "NSURL"'s fileURLWithPath:(mainFolderPath)
	
	-- Get NSURLs to all the visible items in the top level of the folder, including their "is directory" flags.
	set fileManager to |⌘|'s class "NSFileManager"'s defaultManager()
	set directoryKey to |⌘|'s NSURLIsDirectoryKey
	set searchOptions to (|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) + (|⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer) + (|⌘|'s NSDirectoryEnumerationSkipsSubdirectoryDescendants as integer)
	set hierarchyEnumerator to fileManager's enumeratorAtURL:(mainFolderURL) includingPropertiesForKeys:({directoryKey}) options:(searchOptions) errorHandler:(missing value)
	local URLArray
	set URLArray to hierarchyEnumerator's allObjects()
	
	-- Preset these NSArrays and individual NSStrings for use in the repeat below.
	set soundFileNameExtensions to |⌘|'s class "NSArray"'s arrayWithArray:({"aac", "aiff", "AIFF", "wav", "WAV"})
	set imageFileNameExtensions to |⌘|'s class "NSArray"'s arrayWithArray:({"jpg", "jpeg", "tif", "tiff", "png", "JPG", "JPEG", "TIFF", "TIF", "PNG"})
	set {|_Track|, |PHASE_1|, |PHASE_2|, |IMAGES|, |DOCS|} to |⌘|'s class "NSArray"'s arrayWithArray:({"_Track", "PHASE_1", "PHASE_2", "IMAGES", "DOCS"})
	
	-- Deal with each URL in turn.
	repeat with thisURL in URLArray
		-- Act if this item's not a directory (and thus not a package either).
		if (not ((thisURL's getResourceValue:(reference) forKey:(directoryKey) |error|:(missing value))'s end as boolean)) then
			-- Get the item's name, first-four-character substring, and name extension.
			set fileName to thisURL's lastPathComponent()
			set fileIndex to (fileName's substringWithRange:({0, 4}))
			set nameExtension to thisURL's pathExtension()
			-- Get the appropriate destination sub-subfolder name.
			if ((soundFileNameExtensions's containsObject:(nameExtension)) as boolean) then
				if ((fileName's containsString:(|_Track|)) as boolean) then
					set folderX to |PHASE_1|
				else
					set folderX to |PHASE_2|
				end if
			else if ((imageFileNameExtensions's containsObject:(nameExtension)) as boolean) then
				set folderX to |IMAGES|
			else
				set folderX to |DOCS|
			end if
			-- Create the destination folder (if it doesn't already exist).
			set destinationFolderURL to (|⌘|'s class "NSURL"'s fileURLWithPathComponents:({mainFolderPath, fileIndex, folderX}))
			tell fileManager to createDirectoryAtURL:(destinationFolderURL) withIntermediateDirectories:(true) attributes:(missing value) |error|:(missing value)
			-- Move the item to the destination folder under its existing name (if an item with the same name doesn't already exist there).
			set destinationURL to (destinationFolderURL's URLByAppendingPathComponent:(fileName))
			tell fileManager to moveItemAtURL:(thisURL) toURL:(destinationURL) |error|:(missing value)
		end if
	end repeat
	say "Finished"
end open

Hi Nigel!

Eheh, that one was a real killer: 12 seconds (TWELVE!!!) to do all the work (and with a progress counter added by me, too)!!! :smiley:

Here’s the definitive script (simply: yours, with that counter):


use AppleScript version "2.4" -- Mac OS 10.10 (Yosemite) or later.
use framework "Foundation"
use scripting additions

on open droppings
	set |⌘| to current application
	set mainFolder to item 1 of droppings
	
	local theFileNames
	tell application "Finder" to set theFileNames to name of every item of mainFolder
	set fileCounter to items in theFileNames
	set progress total steps to fileCounter
	set progress completed steps to 0
	set progress description to "Sto lavorando..."
	set progress additional description to "Preparo i file."
	set a to 0
	
	set mainFolderPath to |⌘|'s class "NSString"'s stringWithString:(POSIX path of mainFolder)
	set mainFolderURL to |⌘|'s class "NSURL"'s fileURLWithPath:(mainFolderPath)
	
	-- Get NSURLs to all the visible items in the top level of the folder, including their "is directory" flags.
	set fileManager to |⌘|'s class "NSFileManager"'s defaultManager()
	set directoryKey to |⌘|'s NSURLIsDirectoryKey
	set searchOptions to (|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) + (|⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer) + (|⌘|'s NSDirectoryEnumerationSkipsSubdirectoryDescendants as integer)
	set hierarchyEnumerator to fileManager's enumeratorAtURL:(mainFolderURL) includingPropertiesForKeys:({directoryKey}) options:(searchOptions) errorHandler:(missing value)
	local URLArray
	set URLArray to hierarchyEnumerator's allObjects()
	
	-- Preset these NSArrays and individual NSStrings for use in the repeat below.
	set soundFileNameExtensions to |⌘|'s class "NSArray"'s arrayWithArray:({"aif", "AIF", "aiff", "AIFF", "wav", "WAV"})
	set imageFileNameExtensions to |⌘|'s class "NSArray"'s arrayWithArray:({"jpg", "jpeg", "tif", "tiff", "png", "JPG", "JPEG", "TIF", "TIFF", "PNG"})
	set {|_Track|, |PHASE_1|, |PHASE_2|, |IMAGES|, |DOCS|} to |⌘|'s class "NSArray"'s arrayWithArray:({"_Track", "PHASE_1", "PHASE_2", "IMAGES", "DOCS"})
	
	-- Deal with each URL in turn.
	repeat with thisURL in URLArray
		
		set a to a + 1
		set progress additional description to "Elaboro elemento " & a & " di " & fileCounter
		
		
		-- Act if this item's not a directory (and thus not a package either).
		if (not ((thisURL's getResourceValue:(reference) forKey:(directoryKey) |error|:(missing value))'s end as boolean)) then
			-- Get the item's name, first-four-character substring, and name extension.
			set fileName to thisURL's lastPathComponent()
			set fileIndex to (fileName's substringWithRange:({0, 4}))
			set nameExtension to thisURL's pathExtension()
			-- Get the appropriate destination sub-subfolder name.
			if ((soundFileNameExtensions's containsObject:(nameExtension)) as boolean) then
				if ((fileName's containsString:(|_Track|)) as boolean) then
					set folderX to |PHASE_1|
				else
					set folderX to |PHASE_2|
				end if
			else if ((imageFileNameExtensions's containsObject:(nameExtension)) as boolean) then
				set folderX to |IMAGES|
			else
				set folderX to |DOCS|
			end if
			-- Create the destination folder (if it doesn't already exist).
			set destinationFolderURL to (|⌘|'s class "NSURL"'s fileURLWithPathComponents:({mainFolderPath, fileIndex, folderX}))
			tell fileManager to createDirectoryAtURL:(destinationFolderURL) withIntermediateDirectories:(true) attributes:(missing value) |error|:(missing value)
			-- Move the item to the destination folder under its existing name (if an item with the same name doesn't already exist there).
			set destinationURL to (destinationFolderURL's URLByAppendingPathComponent:(fileName))
			tell fileManager to moveItemAtURL:(thisURL) toURL:(destinationURL) |error|:(missing value)
		end if
		
		set progress completed steps to a
		
	end repeat
	
	set progress total steps to 0
	set progress completed steps to 0
	set progress description to ""
	set progress additional description to ""
	
	say "Finito"
end open

Almost perfect! :slight_smile:

Back to the old version (and to the speed problem), here’s the script:


on open droppings
	set mainFolder to item 1 of droppings
	
	-- Get the names of all the files in the main folder, using just one easy command.
	local theFileNames
	tell application "Finder" to set theFileNames to name of every file of mainFolder
	
	set fileCounter to length of theFileNames
	set progress total steps to fileCounter
	set progress completed steps to 0
	set progress description to "Sto lavorando..."
	set progress additional description to "Preparo i file."
	set a to 0
	
	-- Check them using just vanilla AppleScript.
	-- We'll use text item delimiters to extract the extension from each name.
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "."
	
	repeat with fileName in theFileNames
		set a to a + 1
		set progress additional description to "Sposto file " & a & " di " & fileCounter
		
		set nameExtension to text item -1 of fileName
		set fileIndex to text 1 thru 4 of fileName
		
		if (nameExtension is in {"aiff", "AIFF", "wav", "WAV"}) then
			if (fileName contains "_Track") then
				-- Destination for audio file in first group.
				set folderX to fileIndex & ":PHASE_1:"
			else
				-- Destination for audio file not in first group.
				set folderX to fileIndex & ":PHASE_2:"
			end if
		else if (nameExtension is in {"jpg", "jpeg", "tif", "tiff", "png", "JPG", "JPEG", "TIF", "TIFF", "PNG"}) then
			-- Destination for image file.
			set folderX to fileIndex & ":IMAGES:"
		else
			-- Destination for any other file.
			set folderX to fileIndex & ":DOCS:"
		end if
		
		try
			tell application "Finder" to move file fileName of mainFolder to folder folderX of mainFolder replacing no
		end try
		
		set progress completed steps to a
		
	end repeat
	
	set AppleScript's text item delimiters to astid
	set progress total steps to 0
	set progress completed steps to 0
	set progress description to ""
	set progress additional description to ""
end open

The problem is obviously NOT the counter: that’s the same implementation I’ve used in the “12 seconds” version.
And it’s not the “open window” case: I’ve thought about that so I’ve closed ALL windows before start.

But, as I said, I’m just a beginner so it is very likely I’m missing something…

Anyway, thank you again: A LOT!!!

Hi Bix.

There’s a mistake in your version of the ASObjC script:

‘items in theFileNames’ should be ‘(count theFileNames)’ or ‘length of theFileNames’.

But in fact you don’t need to fetch the names at all here. You can count the URLArray a bit further down and initialise the progress bar there:

set URLArray to hierarchyEnumerator's allObjects() -- Exisiting line.
	
set fileCounter to URLArray's |count|()
set progress total steps to fileCounter
set progress completed steps to 0
set progress description to "Sto lavorando..."
set progress additional description to "Preparo i file."
set a to 0