I am trying to create a new user playlist using the cocoa scripting bridge, but cannot seem to get it to work. I have so far:
iTunesApplication *iTunes = [SBApplication
applicationWithBundleIdentifier:@"com.apple.iTunes"];
SBElementArray *iSources = [iTunes sources];
iTunesSource *library = nil;
for (iTunesSource *source in iSources) {
if ([[source name] isEqualToString:@"Library"]) {
library = source;
break;
}
}
// could not find the itunes library
if (!library) {
NSLog(@"Could not connect to the iTunes library");
return;
}
// now look for our playlist
NSString *playlistName = @"new playlist";
SBElementArray *playlists = [library userPlaylists];
iTunesUserPlaylist *playlist = nil;
for (iTunesUserPlaylist *thisList in playlists) {
if ([[thisList name] isEqualToString:playlistName]) {
playlist = thisList;
break;
}
}
// if the playlist was not found, create it
if (!playlist) {
playlist = [[[iTunes classForScriptingClass:@"playlist"] alloc] init];
[playlist setName:playlistName];
[[library userPlaylists] insertObject:playlist atIndex:0];
}
When I try and add a name for the playlist, I get the error message:
iTunesBridge[630:80f] *** -[SBProxyByClass setName:]: object has not been added to a container yet; selector not recognized
Can anyone point me in the correct direction?
Making new application objects is dreadfully obfuscated in SB. The pseudo-Cocoa-ish alloc-init-insert procedure bears no resemblance to what's actually going on underneath. While the alloc-init appears to create a regular object that you can manipulate with subsequent method calls, the result is actually a shim whose only function is to be 'inserted' into an 'array', at which point SB sends an actual
make
event to the target process. (See also here and here for SB criticisms.)IIRC, the only point you can actually specify initial properties is in
-initWithProperties:
. You can set them after the object has been 'inserted', but that is a completely different operation (manipulating an object that already exists rather than specifying initial state for an object being created) so can easily have unintended consequences if you aren't careful.At any rate, here's how you'd normally create a new playlist if one doesn't already exist:
And, FWIW, here's how I'd do it in ObjC, using objc-appscript (which I wrote so I wouldn't have to use SB, natch):
(The downside of objc-appscript is that you have to build and embed a copy of the framework in your application bundle. The benefits are that it's more capable, less prone to application compatibility issues, and much less obfuscated. Plus you can use appscript's ASTranslate tool to convert the Apple events sent by the above AppleScript into ObjC syntax - very handy when figuring out how to construct your references and commands.)