Scripting Bridge & iTunes?

Hi, has anyone gotten very far into using Scripting Bridge on Leopard with Python and iTunes? I tried, but got stuck pretty fast. I'm trying to iterate over tracks and (among other things) find out what their file names are.
from ScriptingBridge import *
itunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
lib = itunes.sources()[0].playlists()[0]
tracks = lib.tracks()
print tracks[0].location
This works up until the last line, but then complains "AttributeError: 'ITunesTrack' object has no attribute 'location'". So I thought I would try to ask for a list of "file tracks" instead of "tracks", because that's how appscript seems to work, but no luck.
from ScriptingBridge import *
itunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
lib = itunes.sources()[0].playlists()[0]
tracks = lib.file_tracks()
print tracks[0].location
produces "AttributeError: 'ITunesPlaylist' object has no attribute 'file_tracks'". And then, although I really want to embrace Scripting Bridge, I thought I'd try a last resort and go back to using appscript (that's what I used on Tiger). But that doesn't seem to work on Leopard... while retrieving the list of tracks, it works for a while and then says
Traceback (most recent call last):
File "/Library/Python/2.5/site-packages/appscript-0.17.2-py2.5-macosx-10.5-i386.egg/apps
cript/reference.py", line 372, in _call_
if e.number in [-600, -609] and self.AS_appdata.path: # event was sent to a local app
for which we no longer have a valid address (i.e. the application has quit since this aem.
Application object was made).
AttributeError: AppData instance has no attribute 'path'
even though iTunes hasn't quit. Any suggestions? I know I could read & write XML, but I want this to work while iTunes.app is running. This seems like it ought to be a really basic task, but I'm out of ideas. Thanks in advance.
Message was edited by: dormouse310

The problem here is that Scripting Bridge is just a bit too arrogant and nit-picky for its own (or its users') good.
i.e. Unlike appscript, which carefully mimics the way that AppleScript works in order to ensure maximum compatibility with existing applications - all of which have for the last 14 years been designed and tested against AppleScript - Scripting Bridge tries to impose its own particular ideas of how application scripting should operate. The result is that applications which work fine with AppleScript but don't precisely behave in the way that Scripting Bridge thinks they should behave can end up being partially or even completely inaccessible to Scripting Bridge users (at least not without resorting to klunky low-level workarounds).
(Incidentally, I did caution Apple a year ago about the compatibility problems that the Scripting Bridge-style approach would cause - I made some of the same mistakes myself in early versions of appscript - but unfortunately they went ahead and did it anyway.)
In this case, it's Scripting Bridge's insistence on enforcing the object model structure defined in iTunes' dictionary that's causing the problem, since iTunes' dictionary is rather inconsistent in declaring the types of elements each class supports. For example, if you look up the 'playlist' class's definition, you'll see that it forgets to list 'file track' as an element. This doesn't bother AppleScript (or appscript), but it trips up the rather less tolerant Scripting Bridge, as you can see here:
from ScriptingBridge import *
itunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
lib = itunes.sources()[0].playlists()[0]
filetracks = lib.fileTracks() # this line raises an AttributeError: 'ITunesPlaylist' object has no attribute 'fileTracks'
print filetracks[0].location()
Not that this excuses the iTunes developers for their sloppy documentation, mind (and you should definitely file a bug report on it), but it isn't much consolation to users who just want to do things that they know worked fine in AppleScript or appscript.
Anyway, it is possible to work around this particular limitation in Scripting Bridge by resorting to raw AE codes; in this case:
import struct
from ScriptingBridge import *
itunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
lib = itunes.sources()[0].playlists()[0]
filetracks = lib.elementArrayWithCode_(struct.unpack('>L', 'cFlT')[0]) # filetracks = lib.fileTracks()
print filetracks[0].location()
To obtain the raw codes, use ASDictionary's plain text export option, Smile's 'copy translate' feature, Script Debugger's advanced dictionary viewer, or save the dictionary as an sdef file in Script Editor. And don't forget to take account of endianness issues when converting four-char-code strings to ints as shown above.
As for the error you're getting with appscript:
Appscript identifies local applications by their process numbers, so if you quit and relaunch an application after you've created an 'app' object for it and then use that app object to send the application another command, appscript will deliberately raise an error (-609) to tell you the process number used by that app object is no longer valid. (Note: you should actually get a CommandError, not AttributeError, here - the error message you're actually seeing is caused by a bug in 0.17.2's error handling/reporting code that's since been fixed - but the general explanation still holds.)
In your case, however, it sounds as if iTunes is running throughout, so that isn't what's causing appscript to error. I suspect the actual cause is a timeout error; unfortunately this gets wrongly reported in appscript as error -609 instead of -1712 (timeout error) as it should be. Obviously, getting the wrong error message when an error occurs is rather confusing for users, and fixing this problem is on my TODO list for the next release, although I've yet to figure out why the Apple Event Manager should be giving appscript the wrong error number in the first place. In the meantime, you should be able to confirm that it's a timeout error by running the equivalent command in AppleScript within a 60 second timeout block (which is, IIRC, the default timeout used by appscript 0.17.2).
As to why it can take so long to get file tracks in iTunes - I'm not an iTunes guru, but you could try asking on the AppleScript-users mailing list to see if anyone there has any suggestions. As for avoiding timeout errors in the first place, you can increase the timeout delay for your appscript command via its 'timeout' argument (this is equivalent to AS's 'with timeout' block, except that it only affects the command it's used in) - see ch.11 of the appscript manual for details.
HTH
has
(p.s. If you've any questions or problems with Python appscript, best place to post them is the PythonMac-SIG mailing list at python.org, or mail me directly if you prefer.)

Similar Messages

  • Scripting Bridge for iTunes

    I'm trying to do something simple and efficient with scripting bridge and iTunes, which is to display the number of the track currently playing in the playlist (aka "get index of current track"), so here's my try:
    // initialization
    iTunes = \[ SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes" \] ;
    // repeat this on a timer
    iTunesTrack* currentTrack = \[ iTunes currentTrack \] ;
    iTunesPlaylist* currentPlaylist = \[ iTunes currentPlaylist \] ;
    SBElementArray* currentTracks = \[ currentPlaylist tracks \] ;
    NSInteger index = \[ currentTracks indexOfObject: currentTrack \] ;
    but this doesn't work because currentTracks and currentTrack are references that haven't been evaluated (and indexOf doesn't persuade them to evaluate). This can be fixed by:
    NSInteger index = \[ \[ currentTracks get \] indexOfObject: \[ currentTrack get \] \] ; // leaks mem!
    and while the index is now correct, this leaks memory (about 1K bytes per call - alot more after some time!). Am I doing something wrong? Does Scripting Bridge have a memory leak? Is there a better way to get this index, or am I stuck going back to AppleScript (I promised myself I'd quit if it got messy). Thx, -L.

    Thanks again for your collective guidance - per your advice, I've tried allocating and releasing an autorelease pool every get/loop. In fact, I've tried many variations of draining and releasing pools, as well as variable assignments and releases. No change in the memory leak.
    I'm starting to suspect that the leak is lower-level than anything Objective-C is doing, but please correct me!
    I've distilled the problem into just a few lines of code inserted into the generic Cocoa app template generated by Xcode. Please take a look below and see how one might change it to not leak memory - Activity Monitor says it ticks up .01MB (about 10K) in RSS memory usage every few seconds.
    Thanks for your continued guidance, -Lance.
    // generated a skeletal Cocoa app (just removed generic copyright comments, added startTrackWatcher)
    // generate iTunes.h with sdef /Applications/iTunes.app | sdp -fh --basename iTunes
    // and add ScriptingBridge framework to project
    #import <Cocoa/Cocoa.h>
    int main(int argc, char *argv[])
    void startTrackWatcher() ; // added these two lines
    startTrackWatcher() ; // for watching mem leak
    return NSApplicationMain(argc, (const char **) argv);
    // added lines below for startTrackWatcher
    #import <ScriptingBridge/ScriptingBridge.h>
    #import "iTunes.h"
    @interface Status : NSObject {
    @public
    NSTimer* timer ;
    iTunesApplication* iTunes ;
    - (void)doit:(NSTimer*)timer;
    - (Status*)initWithTime:(int)time;
    @end
    @implementation Status
    - (void)doit:(NSTimer*)t
    // NSAutoreleasePool* pool = [[ NSAutoreleasePool alloc ] init ] ;
    iTunesTrack* currentTrack = [ iTunes currentTrack ] ;
    iTunesPlaylist* currentPlaylist = [ iTunes currentPlaylist ] ;
    SBElementArray* currentTracks = [ currentPlaylist tracks ] ;
    // NSInteger index = [ currentTracks indexOfObject: currentTrack ] ; // wrong because items aren't evaluated
    NSInteger index = [ [ currentTracks get ] indexOfObject: [ currentTrack get ] ] ; // leaks memory (check Activity monitor)!
    printf( "%d
    ", index ) ;
    // [ pool drain ] ;
    // [ pool release ] ;
    - (Status*)initWithTime:(int)time {
    /NSAutoreleasePool pool =*/ [[NSAutoreleasePool alloc] init];
    timer = [NSTimer scheduledTimerWithTimeInterval:time
    target:self
    selector:@selector(doit:)
    userInfo:timer
    repeats:YES] ;
    iTunes = [ SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes" ] ;
    return self ;
    @end
    void startTrackWatcher() {
    [[ Status alloc ] initWithTime:0.1 ] ;

  • Scripting Bridge and iTunes

    I'm trying to add a playlist to iTunes via some Obj-C code. (Yeah I know AppleScript would be simpler, but part of this is for me to learn coding with Cocoa.) I'm not new to coding, just the Mac flavor of it, and I suspect I'm missing something simple. Anyway, the procedure in question (from a button's click handler):
    <pre>
    iTunesApplication *iTApp;
    SBElementArray *thePlaylists;
    NSDictionary *newPlaylistProps;
    iTunesPlaylist *newPlaylist;
    iTApp = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
    if ([iTApp isRunning]) {
    thePlaylists = [(iTunesSource*)[[iTApp sources] objectAtIndex:0] playlists];
    newPlaylistProps = [NSDictionary dictionaryWithObject:@"foobar" forKey:@"name"];
    newPlaylist = (iTunesPlaylist*)[[[iTApp classForScriptingClass:@"playlist"] alloc] initWithProperties:newPlaylistProps];
    [thePlaylists addObject:newPlaylist];
    </pre>
    I've got iTunes.h created and #imported like the ADC guide showed. The code above works fine until the addObject call, at which point I get an Apple event error -10014. This seems to mean I sent in a list when the handler wanted a single object. I thought newPlaylist counted as just an object.
    Also regarding populating the thePlaylists var - I've resorted to grabbing the first source solely to simplify things. Until I hit this wall, I was iterating the sources to find the library one.
    Any help would be appreciated - thanks!

    Short answer: Scripting Bridge's design is flawed. See the 'jumpstart me with the scripting bridge' thread over on AppleScript-implementors for an explanation of this particular defect:
    http://lists.apple.com/archives/Applescript-implementors/2007/Nov/index.html
    Your options are:
    1. Work around Scripting Bridge's brokenness by sending your own 'make' Apple event via -[SBObject sendEvent:id:parameters:]. (Or even via AEBuildAppleEvent or NSAppleEventDescriptor and AESendMessage if you're particularly masochistic.) You'll need to know the raw AE codes for the 'make' command to do this; e.g. Script Editor can save an application's dictionary to .sdef (XML) file, or ASDictionary [1] can export it in a more readable plain text format.
    2. Use AppleScript via NSAppleScript. Somewhat defeats the purpose of the exercise, but AppleScript knows how to speak Apple events properly so at least you know it'll work.
    3. Use a third-party bridge that speaks Apple events the same way as AppleScript does. For ObjC, use objc-appscript [2]:
    ITApplication *itunes = [[ITApplication alloc] initWithName: @"iTunes.app"];
    NSDictionary *properties = [NSDictionary dictionaryWithObject:@"my playlist" forKey:[ASConstant name]];
    ITMakeCommand *cmd = [[[itunes make] new_: [ITConstant playlist]]
    withProperties: properties];
    ITReference *playlist = [cmd send];
    [itunes release];
    HTH
    [1] http://appscript.sourceforge.net/download.html
    [2] http://appscript.sourceforge.net/objc-appscript.html

  • Scripting Bridge: how to set current iTunes playlist

    I know how to get the current iTunes playlist using Scripting Bridge, but how do I set the current playlist?

    This is the answer:
    1. Dig into iTunesApplication's "sources" to find iTunesSource "Library"
    2. Dig into iTunesSource "Library" to find iTunesPlaylist "Party Shuffle"
    3. Do a reveal.

  • How to use AS's "make new" command in Scripting Bridge?

    Anybody know how to rewrite this line of Applescript in Cocoa using the Scripting Bridge?
    tell application "iTunes" to make new playlist with properties {name:"Some Name"}
    I'd hate to have to embed AS into my app just for this thing.
    Is there maybe some page in the documentation on Applescript object allocation in Scripting Bridge that I'm missing?
    Thanks in advance.

    If you have the Time Capsule setup in Bridge Mode as you indicate, the ethernet ports are all equal and they will behave just like a normal ethernet "switch".
    If you've double checked to make sure that you have a good ethernet cable and you don't have a connection at the WAN port, but do on the other LAN ports, unfortunately the WAN port is defective.

  • Problem Running App with Scripting Bridge on MAC OS X TIger

    Hi,
    I have an application which link with Scripting Bridge Frame work, use XCODE 3.0 and SDK 10.5. I use Scripting Bridge, to control some functionality of ITune from Objective-C. This Application run fine on Leopard and behave as expected. When I Run this application on Tiger this does not load.
    Considering that scripting Bridge was first released om Leopard.
    Can my Above Application Run on Tiger. If not how do I interface ITune from Objective-C, on both Tiger and Leopard? IS there update which suppose to fix this?
    Thanks
    Akhilesh

    webdevcda wrote:
    Considering that scripting Bridge was first released om Leopard.
    Can my Above Application Run on Tiger.
    No.
    If not how do I interface ITune from Objective-C, on both Tiger and Leopard? IS there update which suppose to fix this?
    There will be no update for old products like Tiger. What there is is all you will ever get. For Tiger, you will have to dig into sending Apple Events to iTunes manually. Or it might be easier to define your Apple Scripts as string resources in your application an execute them via a system() call.

  • Compiling code generated for Scripting Bridge

    Hi,
    I have generated code for iTunes on MAC OS X leopard, I added the generated header file in my project, and imported (#import "Itunes.h") in my implementation file of Objective 'C'. I also linked my project with Scripting Bridge. (/System/Library/Frameworks/ScriptingBridge.framework.)
    But when I build my project I get following error,
    "error ScriptingBridge/ScriptingBridge.h no such file or directory".
    MY project link with other framework, cocoa, AppKit, WebKit fine, and it has been working fine as a web kit plug-in.
    I am new to MAC and Objective 'C' programming, could some one help solve this problem.
    Thanks,
    kumar
    Sample Code from I Tunes.h
    ++++++++++++++++++++++++++++
    #import <AppKit/AppKit.h>
    #import <ScriptingBridge/ScriptingBridge.h>
    @class ITunesPrintSettings, ITunesApplication, ITunesItem, ITunesArtwork, ITunesEncoder, ITunesEQPreset, ITunesPlaylist, ITunesAudioCDPlaylist, ITunesDevicePlaylist, ITunesLibraryPlaylist, ITunesRadioTunerPlaylist, ITunesSource, ITunesTrack, ITunesAudioCDTrack, ITunesDeviceTrack, ITunesFileTrack, ITunesSharedTrack, ITunesURLTrack, ITunesUserPlaylist, ITunesFolderPlaylist, ITunesVisual, ITunesWindow, ITunesBrowserWindow, ITunesEQWindow, ITunesPlaylistWindow;
    typedef enum {
    ITunesEKndTrackListing = 'kTrk' /* a basic listing of tracks within a playlist */,
    ITunesEKndAlbumListing = 'kAlb' /* a listing of a playlist grouped by album */,
    ITunesEKndCdInsert = 'kCDi' /* a printout of the playlist for jewel case inserts */
    } ITunesEKnd;
    typedef enum {
    ITunesEnumStandard = 'lwst' /* Standard PostScript error handling */,
    ITunesEnumDetailed = 'lwdt' /* print a detailed report of PostScript errors */
    } ITunesEnum;

    Hi,
    Could you provide some more details on the entity bean? Like, part of ejb-jar,the implementation code?
    Does your bean use any field by name 'dirty'?
    There was some discussion on a similar problem here - http://forums.oracle.com/forums/message.jsp?id=906659
    Hope this helps,
    Neelesh
    OTN Team @IDC

  • This new "Scripting Bridge"

    I've been reading up about this beat, but I was wondering how you implement it after you do something like;
    NSString * currentTrackName = [[iTunes currentTrack] name];
    Or is that the declaration and implementation in one?
    Thanks,
    Ricky.

    Right.
    So If I was to slap more code on top to make it look like this, would that work?
    iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
    NSString * currentTrackName = [[iTunes currentTrack] name];
    I'm really unsure of what I need to put in my header file. This is what I have;
    #import <Cocoa/Cocoa.h>
    #import <ScriptingBridge/SBApplication.h>
    @interface songGrab : SBApplication {
    IBOutlet id display;
    - (void) currentTrack;
    @end
    I've imported the Scripting Bridge class and added SBApplication like that page showed. songGrab is the name of my class.
    What would I do in the instance if I wanted to use the 'delay' handler? What does that belong to?
    Thanks,
    Ricky.

  • How do I get automator scripts into iTunes? Very frustrated.

    This is one of those questions that probably has a very simple answer unless you haven't worked with Automator or applescripts.
    I found Automator, created a script for iTunes to change settings for audiobooks that I import from CD so that it remembers it's place in a "song", makes it so that it doesn't show up in shuffle lists, and doesn't have a gap between songs. Yippee for me.
    I click on File, Save, name the file and save it and ... it doesn't show up under iTunes. It only took me 45 minutes to get it so that the scroll icon shows up under iTunes (I'm so confused now that I don't even know which thing I did caused that to happen) but my script I created doesn't show up.
    I did find one place that said to place the file in (myname\library\scripts\programname) So I went to my home folder, find the library folder, found the scripts folder, and found only one application under there (Safari) but no iTunes. I created a folder called iTunes and saved my script there but ... it doesn't show up under iTunes.
    I did try quitting iTunes and opening it back up and ... it still isn't there.
    Is this even the right place to ask this question?

    It seems at this point the Script menu in iTunes doesn't recognize Automator files. A quick and dirty fix is to save the workflow as an application and then make an AppleScript that says:
    tell application "NameofApp" to launch
    save that script as a script and put it in the appropriate folder (/Users/username/Library/iTunes/Scripts). That script should show up in iTunes and running that will run your application which should do what you want.
    Hope this helps.

  • Button for iTunes scripts and iTunes Plug-Ins is gone in 7.3.x

    In iTunes 7.3.x I am missing the upper button for iTunes scripts and ITunes Plug-Ins for the little add on programs like iTunes-BPM and iTunes-Lame.
    Does anybody know a trick how I get this button to show up again?
    I am talking about this button:
    /___sbsstatic___/migration-images/505/5054148-1.jpg

    No idea why it's not working. Never seen this problem before.
    Only thing I can think of is make sure the name of the Scripts folder is spelled correctly (not an extra space) /usr/library/iTunes/Scripts/.
    Post over here -> AppleScripts for iTunes (Mac)

  • Scripting Bridge equivalent to AppleScript "every"

    Hi
    What is the Scripting Bridge equivalent in Ruby to the following AppleScript:
    tell application "Microsoft Entourage" to set allContacts to every contact in anAddressBook
    Thanks
    Praful

    Praful wrote:
    Having browsed various group, I concluded that rb-appscript was my best bet. However, I've had an issue with it, which I've posted to the rb-appscript mailing list.
    Hmm, doesn't seem to have appeared there yet. (I posted a message to it on Sat. and it hasn't appeared either - could be an issue with the RubyForge mailing lists, or an overzealous spam filter somewhere inbetween.)
    This works in rb-appscript with a small address book but not with a large one:
    addressbook.contacts.get.findall do |c|
    p "#{c.first_name.get} #{c.last_name.get}"
    end
    The error message is:
    OSERROR: -1708
    MS applications' scripting support can be rather cranky, and prone to compatibility problems with Apple event bridges other than AppleScript's. My first guess is that Entourage may not like one of appscript's extra performance optimisations, as I've already heard of it causing some problems with Excel. Fortunately, appscript's very open and flexible by design, so can generally be tweaked to work with awkward applications. Try adding the following patch to your script and let me know if that fixes it:
    require 'appscript'
    include Appscript
    class AppData # disable caching feature
    def unpackobjectspecifier(desc)
    return Reference.new(self, @referencecodecs.fully_unpack_objectspecifier(desc))
    end
    end
    Entourage = app('Microsoft Entourage')
    (I'd test it here, but I've only got Office X and the version of En'rage that comes with that seems to be buggy as it's not returning any contacts at all.)
    Running address_book.contacts.get as you suggested returns successfully for a small address book but not a large one (>5000 contacts). The error message is:
    /Library/Ruby/Gems/1.8/gems/rb-appscript-0.5.1/lib/appscript.rb:540:in `sendcommand': CommandError (Appscript::CommandError)
    OSERROR: -609
    MESSAGE: Connection is invalid.
    COMMAND: app("/Applications/Microsoft Office 2004/Microsoft Entourage").address_books.ID(403).contacts.get()
    from /Library/Ruby/Gems/1.8/gems/rb-appscript-0.5.1/lib/appscript.rb:642:in `method_missing'
    Perhaps it's timing out?
    Could be; either that or Entourage is crashing. (Error -609 normally means it's crashed, but there's a glitch in Apple's APIs that cause timeouts to sometimes raise error -609 instead of the usual -1712.) It's odd that the equivalent AppleScript seems to work - appscript is designed to mimic AppleScript as closely as possible for compatibility's sake - but you could try increasing the timeout delay to see if that helps, e.g.:
    app("/Applications/Microsoft Office 2004/Microsoft Entourage").address_books.ID(403).contacts.get(:timeout => 10000)

  • Scripting Bridge confusion

    Note that this is not about scripting "Bridge", the Adobe product, but rather the Mac OS X technology "Scripting Bridge"...*that* has made googling for an answer quite difficult!
    Anyway, I'm trying to use Mac's Scripting Bridge technology to do a little bit of control of Photoshop from my Cocoa app.  All I'm really trying to do at this point is to save all files currently open in PS (CS3) as JPEGs with quality = 12.
    I've run the 'sdef ... | sdp ...' tool to generate the header for Scripting Bridge.  I get a handle to the application, get all the open documents, and start looping over them using this code:
    AdobePhotoshopCS3Application *psApp = [SBApplication applicationWithBundleIdentifier:@"com.adobe.Photoshop"];
    SBElementArray *docs = [psApp documents];
    NSUInteger index ;
    AdobePhotoshopCS3Document *doc, *savedDoc = nil;
    AdobePhotoshopCS3JPEGSaveOptions *options = [[[psApp classForScriptingClass:@"JPEG save options"]
                                                 alloc] init];
    for (index = 0; index < [docs count]; index++) {
      doc = [[docs objectAtIndex:index] get];
    I now wish to add in a call to -saveIn:as:copying:appending:withOptions: with options.quality=12;,  but am confused on how to use the options object.  I can create the it just fine, but  I can't set the quality property.  The docs say "Immediately after creating the object, insert it in the appropriate element array. The object is not “viable” in the application until it has been added to its container. Consequently, you cannot set or access its properties until it’s been added."  Add it to what?  Isn't it just a parameter to the -saveIn: method?
    Can anyone clear up my confusion on this?
    Thanks!
    randy

    I'm bumping this because I've been looking into this myself.  I've been trying to simply open a file using Scripting Bridge. What it boils down to is that Photoshop really isn't Scripting Bridge-savvy. Here's the deal...
    Apple's docs really spell it out like it is. Most classes have a container, which is a mutable array, that they need to be added to before they can be acted upon, as shown in the generated header...
    @interface photoshopCS4Application : SBApplication
    - (SBElementArray *) documents;
    - (SBElementArray *) fonts;
    - (SBElementArray *) notifiers;
    ...and that is the complete list of top-level containers available to us. Because we don't have an array made available to us to store the newly created photoshopCS4OpenOptions object, we can't use the object and by extension can't make a document. Therefore, we can't use the open command in Scripting Bridge. The punchline here is that the same can be said of all the commands that require some kind of options object. Now I'm going to investigate the possibility of just sending an AppleEvent of some kind and bypass Scripting Bridge entirely, but my hopes are dim and I'll have to revert back to Applescript for individual commands.
    If I'm wrong (and I'm praying someone will have a way to prove me exactly that), then I will be happy to edit or amend my answer here. And if I could find where to submit a bug report or feature request to Adobe in their voluminous website, I would.

  • Getting Safari document title/location via Scripting Bridge fails

    I'm trying to get the URL and document title from the topmost Safari document/tab. I have an AppleScript and an objective-c version using the Scripting Bridge framework.
    Both versions work fine for most web pages, however when I open a Youtube video in full-screen mode, the Scripting Bridge based version fails (error below). The Apple Script works fine for "normal" and full-screen Safari windows.
    Can anyone see what is wrong with the Scripting Bridge code below to cause it to fail for full-screen Safari windows?
    Here the code (I omitted error checking for brevity):
    AppleScript:
    tell application "Safari"
    # Give us some time to open video in full-screen mode
    delay 10
    do JavaScript "document.title" in document 0
    end tell
    Scripting Bridge:
    SafariApplication* safari = [SBApplication applicationWithBundleIdentifier:@"com.apple.Safari"];
    SBElementArray* windows = [safari windows];
    SafariTab* currentTab = [[windows objectAtIndex: 0] currentTab];
    // This fails when in full-screen mode:
    id result = [safari doJavaScript: @"document.title" in: currentTab];
    NSLog(@"title: %@", result);
    Scripting Bridge error (with added line breaks):
    Apple event returned an error. Event = 'sfri'\'dojs'{
    '----':'utxt'("document.title"),
    'dcnm':'obj '{ 'want':'prop',
    'from':'obj '{ 'want':'cwin',
    'from':'null'(),
    'form':'indx',
    'seld':1 },
    'form':'prop',
    'seld':'cTab' }
    Error info = {
    ErrorNumber = -1728;
    ErrorOffendingObject = <SBObject @0x175c2de0:
    currentTab of SafariWindow 0 of application "Safari" (238)>;
    I could not find details about the given error code. It complains about 'currentTab' which shows that the JavaScript event at least made it all the way to Safari. I assume that the current tab receives the event, but refuses to run the JS code, because it is in full-screen mode. However, why does this work for an AppleScript? Don't they use the same code path eventually?
    Thanks!
    Rico

    1) I have not yet looked into Apple events, but have read elsewhere that it is not the most fun thing to deal with. I might give it a shot after having tried 2 + 3
    Not really, but your command isn't too complicated so it'd be quite doable using the AEBuild* functions/NSAppleEventDescriptor and AESendMessage. If you go the AEBuild* route, you can use AEDebug to sniff Apple events sent from AppleScript for clues - the AEPrint syntax is similar to that used by AEBuild* functions. Mostly it's just tedious; first learning to use the lower-level APIs, then writing the code for them.
    2) Using NSAppleScript was actually my first approach, but having to compile each script before I run it seems a waste. Maybe I can try a pre-compiled script and hand in the JavaScript as a parameter.
    That's the safe and efficient way to parameterize AppleScripts. Although unless you're doing this to support user-supplied scripts, by the time you've packed what you need into an NSAppleEventDescriptor, a bit more code and you could probably send it directly to Safari yourself.
    3) I had tried ASTranslate in the past. I have not actually compiled the generated code, but seeing this makes me wonder about the difference between the Apple Script and Scripting Bridge.
    I've written about that in various places, e.g.:
    http://stackoverflow.com/questions/1309958/avoiding-applescript-through-ruby-rb- appscript-or-rubyosa/1316563#1316563
    Basically, Apple event IPC is RPC plus first-class queries, not OO as a lot of folks assume. AppleScript's OO-like syntax is a bit of a red herring, and the AS interpreter uses various tricks (e.g. implict gets) to further this illusion. So it looks and feels like OO, but only up to a point, and beyond that folks get totally confused when it does something decidedly un-OO. Hence AppleScript's reputation amongst professional programmers as being confusing and unpredictable. (It's actually reasonably straightforward and predictable one you know how it really works; it's just that figuring it out for yourself takes a lot of time and effort, since it's completely messed with your preconceptions by then. Ugh.)
    Apple had an opportunity to learn their lessons from AS's approach, but whether due to politics, hubris or naivety they decided to dress up SB to look even more Cocoa-/OO-like. Which just means there's a bigger impedance mismatch between the SB API and the AE API hidden beneath the surface. So the abstractions are thicker and leakier, and the obfuscations more impenetrable when you do run into problems. By comparison, objc-appscript minimizes the syntactic sugar and wears much of Apple events' inherent weirdness on its sleeve. So while it takes a bit of getting used to if you're from an OO background, once you do get the hang of it it (nearly always) just works.

  • Scripting Bridge Fully Undocumented

    I was excited to find javascript amongst the languages supported by Apple's new Scripting Bridge...
    http://www.apple.com/applescript/features/scriptingbridge.html
    ...where javascript is featured boldly in the announcement.
    But I was then immediately disappointed to find there seems no way to actually use javascript with the scripting bridge.
    Searching Apple's resources turns up nothing. Indeed on the main page, they left off the javascript example, and documented only the other two featured languages - python and ruby. What's going on?
    Does anyone know where I can start since Apple's developer resources for using Javascript with the scripting bridge seem even worse than their AppleScript documentation. A single documented example would be a beginning.

    I was excited to find javascript amongst the languages supported by Apple's new Scripting Bridge...
    http://www.apple.com/applescript/features/scriptingbridge.html
    ...where javascript is featured boldly in the announcement.
    But I was then immediately disappointed to find there seems no way to actually use javascript with the scripting bridge.
    Searching Apple's resources turns up nothing. Indeed on the main page, they left off the javascript example, and documented only the other two featured languages - python and ruby. What's going on?
    Does anyone know where I can start since Apple's developer resources for using Javascript with the scripting bridge seem even worse than their AppleScript documentation. A single documented example would be a beginning.

  • Can anyone spot the error in this script for iTunes?

    This AppleScript is designed to copy the Name and Artist of an iTunes track, then populate the Album Artist field with both, separated with an oblique. But when I run the script in iTunes, it only pastes the Artist name in to the Album Artist field and not the whole string.
    tell application "iTunes"
    if selection is not {} then -- if tracks are selected...
    set sel to selection
    set numTracks to (length of sel)
    set s to "s"
    if numTracks is 1 then set s to ""
    display dialog "Adds the name of the track and the name of the artist to the Album Artist field." & return & return & (numTracks & " track" & s & " selected.") buttons {"Cancel", "Continue"} default button 2 with title "Create Album Artist" giving up after 30
    if gave up of result is true then return
    repeat with t from 1 to numTracks
    tell contents of item t of sel
    set {album artist} to ({get artist} & " / " & {get name})
    end tell
    end repeat
    else
    display dialog "No tracks have been selected." buttons {"Cancel"} default button 1 with icon 0 giving up after 30
    end if -- no selection
    end tell

    Hello
    Try -
    tell item t of sel
    set album artist to (get artist) & " / " & (get name)
    end tell
    instead of -
    tell contents of item t of sel
    set {album artist} to ({get artist} & " / " & {get name})
    end tell
    In your original code, the left and right value of assignment are both list, i.e. -
    left value = {album artist}
    right value = {get artist, "/", get name}
    Consequently 'album artist' is assigned to the 1st item of the list at right, which is the result of 'get artist'.
    In order to avoid this, don't use list assingment, which is not necessary at all here.
    Also, I think you may just tell item t of sel, not contents of item t of sel.
    Hope this may help,
    H

Maybe you are looking for