Can I programmatically batch-edit iPhoto event titles?

213 Views Asked by At

iPhoto said it had to rebuild its database, and afterwards the previous manual sorting of events was all messed up.

I tried restoring an older database from backup but iPhoto would just rebuild again, messing it up again.

I was able to extract the original order of events from the AlbumData.xml file inside a backup of the iPhoto library (editing this file won't fix the order, sadly).

I can't find a way to change the manual event order with AppleScript or anything else (maybe you could do it with SQLite somehow).

But it seems more feasible to edit iPhoto event titles, adding number prefixes ("1. My first event", "2. My second event") and then sort events by title instead of manually. This also seems less fragile going forward. New events could be named "1.1 My middling event" to go inbetween.

But to achieve this, it would be convenient if I could batch-edit the titles programmatically. Is that possible? I don't see anything useful in the AppleScript Dictionary.

1

There are 1 best solutions below

0
On

I started numbering them manually, then I realized iPhoto has pretty scriptable keyboard shortcuts: when editing one event title you can tab to the next one. So I scripted that.

This is a pretty ugly and hackish mix of Ruby (my weapon of choice) and AppleScript, and it's written to solve my specific problem, but it probably gives a good idea of how you can do this:

def osascript(cmd)
  system "osascript", "-e", cmd
end

def assign(number, name)
  `echo | pbcopy` #  clear out clipboard in case the title is empty and the cmd+c fails
  osascript %{tell app "System Events" to keystroke "c" using command down}  # copy
  actual_name = `pbpaste`
  name_was_empty = actual_name.to_s.chop.empty?  # names generated from dates may show as empty when you try to edit them

  if (actual_name == name) || name_was_empty
    puts "go on"
    osascript %{tell app "System Events" to keystroke (ASCII character 28)}  # left
    osascript %{tell app "System Events" to keystroke "#{number}. "}
    osascript %{tell app "System Events" to keystroke #{name.inspect}} if name_was_empty
    osascript %{tell app "System Events" to keystroke tab}
  else
    puts "Got: #{actual_name.inspect} but expected #{name.inspect} (number: #{number})"
    osascript %{tell app "iPhoto" to display dialog "Not the name I expected. Bailing!"}
    exit 1
  end
end

osascript %{tell app "iPhoto" to activate}
osascript %{tell app "iPhoto" to display dialog "Click the first event title and wait…"}
sleep 3

# You would probably loop over some data structure here.
assign(1, "My first event")
assign(2, "My second event")
# …

Also available as a Gist.