0
votes

I am currently writing an app extension for Spotify that allows me to control the playback. I am using the Spotify AppleScript API in combination with the Scripting Bridge in Objective-C. The first thing I would like to ask,does the Scripting API support Key Value Observing? Because when I add an observer I don't get any notifications from the API and when I try to get data manually from the Scripting API I always get nil values,why? I have the following code:

    -(id)init
    {
        self=[super init];
        if(self)
        {
            spotify=[SBApplication applicationWithBundleIdentifier:@"com.spotify.client"];
            //Not sure if KVO is implemented,so I use this to get data from the API
            timer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(observeValueForKeyPath) userInfo:nil repeats:YES];
            if([self isSpotifyRunning])
            {
                //Useless?
                [spotify addObserver:self forKeyPath:@"currentTrack" options:NSKeyValueObservingOptionNew context:nil];
                [spotify addObserver:self forKeyPath:@"playerPosition" options:NSKeyValueObservingOptionNew context:nil];
                [spotify addObserver:self forKeyPath:@"playerState" options:NSKeyValueObservingOptionNew context:nil];
                [self.playBackSlider setTarget:self];
                [self.playBackSlider setAction:@selector(sliderDidMove:)];
                if(spotify.playerState==SpotifyEPlSPaused||spotify.playerState==SpotifyEPlSStopped)
                {
                    [self.playButton setStringValue:@"Play"];
                }
                else
                {
                    [self.playButton setStringValue:@"Stop"];
                }
            }

        }
        return self;
    }
    -(void)observeValueForKeyPath
    {
            [self.titleTextField setStringValue:spotify.currentTrack.name];
            [self.artistTextField setStringValue:spotify.currentTrack.artist];
            [self.currentPlayBackPositionTextField setStringValue:[self formatTime:spotify.playerPosition]];
            [self.remainingTimeTextField setStringValue:[self formatTime:spotify.currentTrack.duration]];
            [self.playBackSlider setMaxValue:spotify.currentTrack.duration];
            [self.playBackSlider setDoubleValue:spotify.playerPosition];
            [self.playBackSlider setDoubleValue:spotify.playerPosition];
            [self.currentPlayBackPositionTextField setStringValue:[self formatTime:spotify.playerPosition]];
        if(spotify.playerState==SpotifyEPlSPaused||spotify.playerState==SpotifyEPlSStopped)
        {
            [self.playButton setStringValue:@"Play"];
        }
        else
        {
            [self.playButton setStringValue:@"Stop"];
        }
    }
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if([keyPath isEqualToString:@"currentTrack"])
    {
        [self.titleTextField setStringValue:spotify.currentTrack.name];
        [self.artistTextField setStringValue:spotify.currentTrack.artist];
        [self.currentPlayBackPositionTextField setStringValue:[self formatTime:spotify.playerPosition]];
        [self.remainingTimeTextField setStringValue:[self formatTime:spotify.currentTrack.duration]];
        [self.playBackSlider setMaxValue:spotify.currentTrack.duration];
        [self.playBackSlider setDoubleValue:spotify.playerPosition];
    }
    else if([keyPath isEqualToString:@"playerPosition"])
    {
        [self.playBackSlider setDoubleValue:spotify.playerPosition];
        [self.currentPlayBackPositionTextField setStringValue:[self formatTime:spotify.playerPosition]];
    }
    else if([keyPath isEqualToString:@"playerState"])
    {
        if(spotify.playerState==SpotifyEPlSPaused||spotify.playerState==SpotifyEPlSStopped)
        {
            [self.playButton setStringValue:@"Stop"];
        }
        else
        {
           [self.playButton setStringValue:@"Play"];
        }
    }
}

EDIT: I have set a delegate for the SBApplication Object and I get the following error:

Error Domain=NSOSStatusErrorDomain Code=-600 "procNotFound: no eligible process with specified descriptor" UserInfo={ErrorNumber=-600}

What exactly does that mean? Spotify starts when the SBApplication is created,so why is the SBApplication telling me that it didn't found the process? I also took a look at Info.plist in the Spotify Bundle and it is scriptable, so why is it not working?

Thank you in advance for any help!

1
As mentioned in my answer : Get rid of ScriptingBridge!. The error message says, the process associated with the descriptor wasn't found. - vadian
Yes,but it makes no sense because Spotify is started when I execute my code. The Scripting Bridge would probably be the easiest way to achieve that task. Now I have to dig into another documentation about AppleScript as I have to write my use case completely in AppleScript. But I will get rid of ScriptingBridge. Thank you! - ok404

1 Answers

1
votes

The AppleScript scripting dictionary of any application – what you're calling AppleScript API - doesn't support KVO.

Regarding to use the scripting dictionary in Cocoa apps forget ScriptingBridge.

AppleScriptObjC (introduced in 10.6 Snow Leopard) provides a much easier way to interact with AppleScript. You can even write a Cocoa application completely in AppleScriptObjC using AppleScript and a Objective-C like terminology in the same file.