I'm writing an applescript to automate some tedious work in Aperture, and I'm having a hell of a time understanding some of the peculiarities of the language. In particular, I'm having a really difficult time dealing with collections (lists and elements). I'm stumped by object specifiers that include collections and applying commands to elements in a collection. Moreover, I'm confused by strange differences in object specifiers that seem to behave differently when referring to object elements by their class within a class versus, well, let me show you.
Here's the beginning of a script.
prop Movies : {}
tell Application "Aperture"
set Movies to every image version whose name of every keywords contains "Movie"
end tell
length of Movies -- result => 601
The application
object in Aperture contains an elements collection of image version
s. image version
objects contain an elements collection of keyword
s. keyword
s are objects/lists with a name
and id
property.
So the global script property Movies
now contains all of the image version
objects in my Aperture library that are actually videos. Now, when I try to do this:
repeat with movie in Movies
log ("Movie name is '" & name of movie & "'.")
log (" the class of this object is '" & class of movie & "'.")
end
the output, as expected, is:
Movie name is 'MOV03510.MPG'.
the class of this object is 'image version'.
Movie name is 'MOV00945'.
the class of this object is 'image version'.
Movie name is 'MOV03228.MPG'.
the class of this object is 'image version'.
Movie name is 'MOV02448'.
the class of this object is 'image version'.
...
However, I'm stuck with how to access an elements collection within those image version
s. When I do this:
repeat with movie in Movies
log ("Movie name is '" & name of movie & "'.")
log (" the class of this object is '" & class of movie & "'.")
set kwnamelist to name of every keyword in movie
if kwnamelist contains "Movie"
log (" Yes, '" & name of movie & "' is indeed a video.")
end if
end
gives me
find_videos.applescript:1089:1096: script error: Expected class name but found identifier. (-2741)
The error, to me, sounds like applescript is confused by the object specifier name of every keyword in movie
. BUT, the reason I'm so confused about this is that if I write this code:
tell Application "Aperture"
repeat with imageind from 1 to 1000
set img to item imageind of image versions
tell me to log ("Image name is '" & name of img & "'.")
tell me to log (" the class of this object is '" & class of img & "'.")
set kwnamelist to name of every keyword in img
if kwnamelist contains "Movie"
tell me to log (" '" & name of img & "' is actually a video!")
end if
end
end tell
then I get the expected output:
...
Image name is 'DSC_4650'.
the class of this object is 'image version'.
Image name is '104-0487_IMG'.
the class of this object is 'image version'.
Image name is 'MOV02978.MPG'.
the class of this object is 'image version'.
'MOV02978.MPG' is actually a video!
Image name is '108-0833_IMG'.
the class of this object is 'image version'.
...
Can anyone tell me what's wrong with my object specifier? Why is it that I can essentially apply get name
to every keyword in img
when the image version
is in one context, but I can't in a different context? Is there something I'm missing here? Is it that the keyword
class is internal to the Aperture application
object? How would I specify something like application::keyword
if that's the case?
UPDATE:
I've solved this particular problem, but I'd really appreciate it if someone could explain exactly why this solves it. I did this:
tell Application "Aperture"
repeat with movie in Movies
tell me to log ("Movie name is '" & name of movie & "'.")
tell me to log (" the class of this object is '" & class of movie & "'.")
set kwnamelist to name of every keyword in movie
if kwnamelist contains "Movie"
tell me to log (" Yes, '" & name of movie & "' is indeed a video.")
end if
end
end tell
gives the expected output:
...
Movie name is 'IMG_0359'.
the class of this object is 'image version'.
Yes, 'IMG_0359' is indeed a video.
Movie name is 'MOV02921.MPG'.
the class of this object is 'image version'.
Yes, 'MOV02921.MPG' is indeed a video.
Movie name is 'MOV02249'.
the class of this object is 'image version'.
开发者_StackOverflow Yes, 'MOV02249' is indeed a video.
...
It seems like there's a very peculiar scope issue at work here. Could someone explain to me how keyword
objects are in scope in this new version, but out of scope in the previous version where we weren't in a tell
block? I thought that tell
blocks were just for directing commands without direct parameters? Do they determine type scope as well? Or is there a command hidden somewhere here in the construction/execution of the object specifier that depends on getting sent to the Application "Aperture"
object?
If I understand the core of your question correctly - because you have solved the practical part, screwy dereferencing, which is a bit of an old chestnut for applescripters - you must only use terminology inside the relevant tell blocks, so if your application (Aperture) supplies the terminology "keyword", you can't refer to "keyword" unless you are inside a tell application "Aperture"
block.
OR if for some reason you want to use terminology from a given app without using a tell block, you can wrap your code like this:
using terms from application "Aperture"
-- blah blah about 'keyword' and other Aperture terminology
end using terms from
Applescript is rather funny like this unfortunately and often times it's hit or miss. In this case repeat with item in list
, item is a reference to the contents, not the contents itself. Often times AppleScript will dereference this for you, but not always. Typically I always use the repeat with x from 1 to count
method to avoid this problem.
About scripting Aperture keywords
Keyword scripting in Aperture 3 is quite unintuitive. Here's what Ive learned:
- A keyword's
id
is a string with the path from the keyword name up to its top-level parent, with each parent's name preceded by a tab. - The value of the
parents
property is just the id without the name and, if the keyword is not at the top-level, the tab following the name. - Keywords don't compare equal even if their values are the same; in fact,
keyword 1 of animage != keyword 1 of anImage
. - An image may have multiple keywords with the same name if they have different parents. However, the name will only appear once wherever the image's metadata is displayed.
- The way to add a keyword to
anImage
with nameaName
and parentstheParents
istell anImage to make new keyword with properties {name:aName, parents:theParents, id:aName&tab&theParents}
See my entry here for a fuller explanation plus add and remove handlers.
精彩评论