Scripting Aperture - which of these to use?

Hi. Welcome to MacScripter.

I don’t have Aperture myself and I see from Wikipedia that it was discontinued five years ago and won’t run on systems later than Mojave. But looking quickly at the scripts without trying them, it looks as if the first does a full production job with a new folder (or folders) and converting the dates of the individual images, while the second simply renames all (open?) projects assuming they’re named in the default manner. (Edit: italicised text changed from “the project”.)

If Aperture’s default project names are US-format date strings as described, the second script can probably be simplified to this:

tell application "Aperture"
	set ps to projects
	repeat with p in ps
		set nameStr to name of p
		
		set yearNumStr to text -4 thru -1 of nameStr
		set dayNumStr to text 5 thru 6 of nameStr
		
		set monthAbbreviation to text 1 thru 3 of nameStr
		set monthNum to (offset of monthAbbreviation in "JanFebMarAprMayJunJulAugSepOctNovDec") div 3 + 1
		set monthNumStr to text 2 thru 3 of ((100 + monthNum) as text)
		
		set newName to yearNumStr & "-" & monthNumStr & "-" & dayNumStr
		-- The 'log' line below just shows the changes in Script Editor's "Messages" pane. It can be left out if not needed.
		log nameStr & " => " & newName
		set name of p to newName
	end repeat
end tell

Hi Nigel,

Much appreciated - Sadly Aperture’s days are numbered, but there’s a whole bunch of cleaning up I need to do to get my library reorganised to transition to Capture One (which has much better image processing, if not quite so nice image management).

Your version of the script doesn’t seem to do anything (it fails with an error). The second one seems to work, but it goes through the whole library, rather than confining itself to the specific thing selected - which means, having stopped it partway through, I now have a library half done and half not.

So, the second script seems that it works - I guess the question is now how to make it limited to selection, rather than whole library, and perhaps whether another version can be made to change the format from YYYY-MM-DD back to Mon DD, YYYY.

Cheers,

Edit - when I save your script, it’s getting changed: “text” is being changed to “rich text” for example.

Edit Again - The line “set ps to projects”

…is that line likely to be causing the script to target my entire library (for which “projects” is a standard top level section - see on right), rather than the one specific project selected. Is there an alternative “set ps to user-selection” or similar?

Hi metaning. Thanks for the feedback.

I’ve just noticed that the code I inserted into the second script was trying to read a variable named differently from the one actually set! That’s undoubtedly what was causing it to error. Many apologies. :frowning: I’ve now corrected it for posterity….

Hmmm. It looks as if Aperture has hijacked the underlying token for AppleScript’s ‘text’ keyword for its own purposes. I don’t know if it makes any difference. But it’s easily fixed by taking the code containing the word out of the tell application “Aperture” block.

That line supplies a list of your projects to the script. It’s actually the repeat block after that which goes through them, applying the code it contains to each one in turn. Removing the repeat’s easy. It’s just a matter of how to tell the script which particular project you want it to treat. Since projects apparently have names, it should be easy to use a name specifier to identify it — provided that each project’s name’s unique.

set nameStr to text returned of (display dialog "Enter the current name of the project you want to rename:" default answer "Jan 01, 2010")
set yearNumStr to text -4 thru -1 of nameStr
set dayNumStr to text 5 thru 6 of nameStr

set monthAbbreviation to text 1 thru 3 of nameStr
set monthNum to (offset of monthAbbreviation in "JanFebMarAprMayJunJulAugSepOctNovDec") div 3 + 1
set monthNumStr to text 2 thru 3 of ((100 + monthNum) as text)

set newName to yearNumStr & "-" & monthNumStr & "-" & dayNumStr

tell application "Aperture" to set name of project nameStr to newName

To find out how to address a selected or current project regardless of name, it would be necessary to consult Aperture’s scripting dictionary. (Choose “Open Dictionary…” in Script Editor’s “File” menu and select Aperture.app in the dialog which appears. This should open a window called something like “Aperture.sdef”. Enter “application” into the search field at the top and see if selecting any of the hits reveals a term like “selection” or “current project”.)

FWIW, that happens in any app that uses Apple’s Text Suite – you’ll see the same thing in Mail scripts, for example. It was actually a deliberate choice – just incredibly misguided.

Hi Folks,

@Nigel: when I look through the Aperture script dictionary, I can find this:

and this:

Which reads to me like Selection is specific to images, not necessarily “whatever the mouse has selected at this moment”?

Would that be something I’d have to type each time the script runs, or can it be grabbed from the name of the thing selected?

For context, I have over 2000 projects that need renaming, but I need granular control to do them one at a time, or in arbitrary batches. If I have to type anything as a part of the process, then it would seem to be much the same as typing the new names in manually.

@Shane: Is that likely to break scripts (it’s happening in Script Editor upon save)?

Cheers,

Hi metaning.

While doing my own Web searching this morning to see if I could get a handle on this, I came across a link to the original of your “Option 1” script. In the accompanying blurb, adayzdone says to “Select a Project, Folder or Album from the sidebar and run the script.” This suggests that the selection can be a project or projects.

Would you mind selecting a couple of projects in Aperture’s sidebar, running the script below, and posting the contents of Script Editor’s “Result” pane here? It’s just to give me an idea of what the selection looks like scriptwise when projects are selected.

tell application "Aperture"
	set sel to selection
	set par to parent of item 1 of (sel as list)
	
	return {sel, par, class of par}
end tell

Hi Nigel,

Happy to do so, just a question though, so far I’ve been running these scripts from the script menulet, having saved them first in ~/Libary.

Is the other option to have the script open in Script Editor, switch to Aperture, make a selection of a project, then switch back to Script Editor and hit the run button?

Cheers,

That is an option. Either it or Script Menu would be fine with a fully working script. But the test script a couple of posts up should be run in Script Editor so that we can see what values are returned. Hopefully they’ll be something like {{project “blah” of application “Aperture”, project “Blah blah” of application “Aperture”}, application “Aperture”, application}. It should give an idea of what’s in Aperture’s selection property when a couple of projects are selected in the sidebar and how to refer to them in a script.

Just replace text / rich text by string

I do my best to use only the late spelling in all my scripts.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 25 juin 2020 16:06:42

Hi Folks,

@Nigel: the result of having a single project in Aperture selected produces the folowing:

With two projects selected:

Should the script be commanding Finder, or Aperture?

@Yvan: I was more concerned by whether “rich text” would break the script - Script editor forces the change whenever you save a file, so I don’t seem to be able to create a file with “text” in it.

Aperture. Sorry. Since I don’t have Aperture, I had to compile the script for posting against the Finder. I neglected to edit the name in the post itself. Now corrected.

No worries :slight_smile:

With one project selected (but no images selected):

With one project selected (which auto-selects the first image in a project):

With two projects selected (and the first/same image selected):

Hmm. If two projects are selected in the application and there’s only one image in its AppleScript ‘selection’ property, it doesn’t look hopeful for selecting multiple projects in the app and having a script rename them all. :confused:

On the offchance that it’s possible, this script (if I’ve got it right) works through every item in the ‘selection’ and, if that item’s ‘parent’ is a project whose name is in the default format you described, renames that project with a derived name in yyyy-MM-dd format. It doesn’t rename non-projects or projects whose names aren’t in the default format. It may only work with the first projected selected, but the only way to find out is to try it.

on renameSelectedProjects()
	tell application "Aperture"
		set theSelection to selection
		-- Repeat with every object in Aperture's 'selection' property.
		repeat with thisItem in theSelection
			set parentObject to thisItem's parent
			if (parentObject's class is project) then
				-- If an object's 'parent' is a project, get the project's current name.
				set projectName to parentObject's name
				-- Does the name conform to Aperture's default format for project names (MMM dd, yyyy)?
				set nameIsDefaultFormat to my checkNameFormat(projectName)
				-- If so, derive a new name in yyyy-MM-dd format and set the project's name to that.
				if (nameIsDefaultFormat) then
					set newName to my reformatName(projectName)
					set parentObject's name to newName
				end if
			end if
		end repeat
	end tell
end renameSelectedProjects

on checkNameFormat(nameStr)
	-- Check that the supposed numeric parts can be coerced to number, that the name's the right length, and that the other characters have allowed values.
	try
		(text 5 thru 6 of nameStr) as integer
		(text 9 thru 12 of nameStr) as integer
		considering case
			return (((count nameStr) is 12) and ¬
				(text 1 thru 4 of nameStr is in {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "}) and ¬
				(text 7 thru 8 of nameStr is ", "))
		end considering
	on error
		return false
	end try
end checkNameFormat

on reformatName(nameStr)
	set yearNumStr to text -4 thru -1 of nameStr
	set dayNumStr to text 5 thru 6 of nameStr
	
	set monthAbbreviation to text 1 thru 3 of nameStr
	set monthNum to (offset of monthAbbreviation in "JanFebMarAprMayJunJulAugSepOctNovDec") div 3 + 1
	set monthNumStr to text 2 thru 3 of ((100 + monthNum) as text)
	
	return yearNumStr & "-" & monthNumStr & "-" & dayNumStr
end reformatName

renameSelectedProjects()

Another idea would be for the script to get the names of all your projects — which is apparently possible without resorting to the selection — and to present those conforming to the default format in a ‘choose from list’ dialog so that you could select in that. But it could be problematic if the project names aren’t unique. I’ll work on it this afternoon.

Here’s a stab at the ‘choose from list’ idea. When run, it should display a ‘choose’ dialog showing the names of all your projects whose names conform to the default format. The numbers in front of the names are to help the script associate the names you choose with the projects from which they were taken. Be careful if you have more than one project with the same name. The names are shown in the order that Aperture returns the projects to the script.

on renameChosenProjects()
	tell application "Aperture"
		activate
		set allProjects to projects
		
		-- Collect those projects whose names match the default format and prepare a list of numbered choices from their names.
		set defaultlyNamedProjects to {}
		set choiceList to {}
		set i to 0
		repeat with thisProject in allProjects
			set thisName to thisProject's name
			if (my hasDefaultFormat(thisName)) then
				set end of defaultlyNamedProjects to thisProject
				set i to i + 1
				set end of choiceList to (i as text) & ". " & thisName
			end if
		end repeat
	end tell
	
	-- If no projects' names match the default format, show a message and stop.
	if (choiceList is {}) then display dialog "No projects found with names matching the default format." with title "Reformat Aperture Project Names" buttons {"Finish"} default button 1 cancel button 1 with icon note
	-- Otherwise invite the user to choose from the numbered choices.
	set theChoice to (choose from list choiceList with prompt "Select the project(s) you want renamed:" with title "Reformat Aperture Project Names" with multiple selections allowed)
	if (theChoice is false) then error number -128 -- The dialog's "Cancel" button was clicked
	
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to ". "
	-- Work through the chosen names.
	repeat with thisItem in theChoice
		-- Separate the choice number and the project name.
		set i to (text item 1 of thisItem) as integer
		set oldName to text from text item 2 to end of thisItem
		-- Derive a new name from the original.
		set newName to reformatName(oldName)
		-- Retrieve the corresponding project from the list and apply the new name to it.
		set thisProject to item i of defaultlyNamedProjects
		tell application "Aperture" to set thisProject's name to newName
	end repeat
	set AppleScript's text item delimiters to astid
	
	display dialog "Finished" with title "Reformat Aperture Project Names" buttons {"OK"} default button 1 with icon note
end renameChosenProjects

-- Check a passed project name for conformity to Aperture's default format.
on hasDefaultFormat(nameStr)
	try
		-- Can what should be the numeric parts be coerced to number?
		(text 5 thru 6 of nameStr) as integer
		(text 9 thru 12 of nameStr) as integer
		-- If no error, check the name's length and other contents.
		considering case
			set nameLength to (count nameStr)
			-- The name must be either 12 characters long or follow the 12th with a space and parentheses containing at least one character,
			-- and must begin with a month abbreviation and have a comma and a space after the day number.
			return (((nameLength is 12) or ((nameLength > 15) and (text 13 thru 14 of nameStr is " (") and (nameStr ends with ")"))) and ¬
				(text 1 thru 4 of nameStr is in {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "}) and ¬
				(text 7 thru 8 of nameStr is ", "))
		end considering
	on error
		return false
	end try
end hasDefaultFormat

-- Return a new name derived from the passed default project name,
-- with the date part in yyyy-MM-dd format instead of MMM dd, yyyy.
on reformatName(nameStr)
	-- Extract the year and day numbers.
	set yearNumStr to text 9 thru 12 of nameStr
	set dayNumStr to text 5 thru 6 of nameStr
	
	-- Extract the month abbreviation and work out the corresponding month number
	set monthAbbreviation to text 1 thru 3 of nameStr
	set monthNum to (offset of monthAbbreviation in "JanFebMarAprMayJunJulAugSepOctNovDec") div 3 + 1
	-- Coerce the month number to text, with a leading zero if necessary.
	set monthNumStr to text 2 thru 3 of ((100 + monthNum) as text)
	
	-- Assemble the new date format.
	set newName to yearNumStr & "-" & monthNumStr & "-" & dayNumStr
	-- If anything follows the date in the original name, append that as is.
	if ((count nameStr) > 12) then set newName to newName & text 13 thru -1 of nameStr
	
	return newName
end reformatName

renameChosenProjects()

Edit: checkNameFormat() and reformatName() handlers modified to recognise and deal with default names having parenthesised numbers. What’s in the parentheses isn’t actually checked. As long as it’s something.

Hi Nigel,

Wow! Those scripts work wonderfully. As you predicted, the first script only changes the first project selected, but the second does a marvellous job - If that intermediate step of the list window is necessary from an engineering point of view, the ability to just (command)A then hit enter in its popup window is really nice.

Aperture stops you having projects with the same name - appending a (1), (2) etc on the name if there’s multiples of the same date. e.g:

  • Aug 01, 2013
  • Aug 01, 2013 (1)

Is that something you can take into account with the script?

Would it be difficult to create a reversing version to go from YYYY-MM-DD to Mon DD, YYYY?

Cheers,

Hi metaning.

Good to know we’re getting somewhere.

The reason for the ‘choose from list’ dialog is to allow you to select which projects to rename, which is where the conversation had been going. But it’s perfectly possible to do without it, albeit with less user control.

That only requires a minor change in the code. Let me know if you want to keep the ‘choose’ dialog. I’d recommend keeping it, but it’s entirely up to you. :slight_smile:

OK. Further to the post above, I’ve now updated the script in post #15 to handle default project names with parenthesised numbers

Hi Nigel,

It’s working beautifully, and the parenthesis-added project names work exactly as expected. :slight_smile:

The reason I was asking about the “choose from list” step, is that I guess the platonic ideal of how I imagined it would function, would be that you select one, or many projects from the sidebar, and then run the script, and it operates on whatever you had selected in the first place. You select three projects, it does all three. You select 100 projects, it does that 100. You select one project, etc, so that chooser window requiring you to select them again seemed like a redundant extra step.

Is the intermediate list-window step necessary for it to work on multiple projects, which is why your earlier script would only actually change the name of the first project selected? If so, I can live with it - it’s the least of the hoops I’ll be jumping through in migrating over to Capture One. :lol:

What would be involved in a script to change the naming back again? Changing a project name with a script doesn’t register as an undo-able event (as I discovered to my horror when I tried that original github version).

Cheers,

If Aperture’s project names really are unique, and you simply want to reformat all those having the default format without bothering to select particular ones, I suspect that the renameChosenProjects() handler in the post #15 script could be replaced with this:

on renameChosenProjects()
	-- Get the names of all the projects in Aperture.
	tell application "Aperture"
		activate
		set projectNames to name of projects
	end tell
	
	-- Work through the list of names.
	repeat with thisName in projectNames
		-- If a name matches Aperture's default format, rename the corresponding project with a reformatted name.
		if (hasDefaultFormat(thisName)) then
			set newName to reformatName(thisName)
			tell application "Aperture" to set name of project thisName to newName
		end if
	end repeat
	
	display dialog "Finished" with title "Reformat Aperture Project Names" buttons {"OK"} default button 1 with icon note
end renameChosenProjects

If that works, the full reverse process would look something like this:

on unrenameChosenProjects()
	-- Get the names of all the projects in Aperture.
	tell application "Aperture"
		activate
		set projectNames to name of projects
	end tell
	
	-- Work through the list of names.
	repeat with thisName in projectNames
		-- If a name matches the yyyy-MM-dd format set by the name reformatting script,
		-- rename the corresponding project with the probable original default.
		if (hasISODateFormat(thisName)) then
			set oldName to unreformatName(thisName)
			tell application "Aperture" to set name of project thisName to oldName
		end if
	end repeat
	
	display dialog "Finished" with title "Unreformat Aperture Project Names" buttons {"OK"} default button 1 with icon note
end unrenameChosenProjects

-- Check a passed project name for conformity to yyyy-MM-dd names derived from Aperture's default format.
on hasISODateFormat(nameStr)
	try
		-- Can what should be the numeric parts be coerced to number?
		(text 1 thru 4 of nameStr) as integer
		(text 6 thru 7 of nameStr) as integer
		(text 9 thru 10 of nameStr) as integer
		-- If no error, check the name's length and other contents.
		set nameLength to (count nameStr)
		return (((nameLength is 10) or ((nameLength > 13) and (text 11 thru 12 of nameStr is " (") and (nameStr ends with ")"))) and ¬
			(character 5 of nameStr is "-") and (character 8 of nameStr is "-"))
	on error
		return false
	end try
end hasISODateFormat

-- Return a name beginning with a date in MMM dd, yyyy format
-- derived from a passed name beginning with a date in yyyy-MM-dd format.
on unreformatName(nameStr)
	-- Extract the year and day numbers.
	set yearNumStr to text 1 thru 4 of nameStr
	set dayNumStr to text 9 thru 10 of nameStr
	
	-- Extract the month number and use it to get the month abbreviation (plus a space).
	set monthNum to (text 6 thru 7 of nameStr) as integer
	set monthAbbreviation to item monthNum of {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "}
	
	-- Reconstitute the date in the default MMM dd, yyyy format.
	set oldName to monthAbbreviation & dayNumStr & ", " & yearNumStr
	-- If anything follows the date in the passed name, append that as is.
	if ((count nameStr) > 10) then set oldName to oldName & text 11 thru -1 of nameStr
	
	return oldName
end unreformatName

unrenameChosenProjects()

Hi Nigel,

OK, playing around with permutations of how this works. I think I wasn’t testing things properly, so I wasn’t seeing the full consequences of how the scripts work.

The way the scripts need to work, is that they only effect the projects you’ve manually selected before firing the script off, what’s happening currently is that the script is going through the entire library, and grabbing every project to populate that popup window (or just processing every project in the un-naming version), which is a problem because project names are only unique within a folder. So your library might have multiple copies of the same project name, but in different folders for different cameras, with different contents. The current popup list method doesn’t show the folder hierarchy.

If you imagine the situation, I have 2000+ projects in my library, I want to rename just 5 of them from one camera (each camera has a folder in the library, where its projects live), and those five have the same names as projects from other cameras. Then after doing that, I want to undo just two of those project re-namings to go back to their older format.

So it all needs to function based on manual selections in Aperture’s Library panel.

The first script you created, which did only one project, but limited itself to just the selected project, had the sort of behaviour I need, but something about it makes it unable to process more than one project - as in if you select 3 projects, run the script, it only renames the first one.

So I guess that’s the question at this stage - is there a way to get a list of all currently selected projects, and then run that first script against them, or was getting that list the missing link?

Cheers,