How do I use objc-appscript to create a new playlist in iTunes?

Discussion in 'Mac Programming' started by mlikesit, Nov 3, 2008.

  1. mlikesit macrumors newbie

    Nov 3, 2008
    I am writing an app in Xcode and need to create a new playlist in iTUnes, and add specific tracks to it.

    Here is the code I have so far:

    -(ITunesError *) savePlaylist:(Playlist *) playlist {
    	ITunesError * rv = [[ITunesError new]retain];
            //Get name of playlist we want to create
    	NSString * name = [playlist name];
    	ITReference *playlistRef = [[itunes playlists] byName:name];
            /* Find a unique name for playlist we are creating */
    	if([[[playlistRef exists]send] boolValue]){
    		int i = 1;
    		NSString * n = @"";
    			n = [NSString stringWithFormat:@"%@_%d", name, i];
    			playlistRef = 	[[itunes playlists] byName:n];
    		}while([[[playlistRef exists]send] boolValue]);
    		name = n;
            //Create new playlist in itunes
    	[[[[itunes make] new_: [ITConstant playlist]] withProperties: [NSDictionary dictionaryWithObject: name forKey: [ITConstant name]]] send];
            //Returns the main music library for iTunes
    	ITReference *main = [self getRefToMainPlaylist];
    	ITReference * tracks = [main tracks];
    	//NSArray * trackNames = [[tracks name] getItem];
    	//NSArray * artistNames = [[tracks artist] getItem];
    	NSArray * locations = [[tracks location ] getItem];
    	NSMutableArray *files = [NSMutableArray array];
    	for(int j = 0; j < 10; j++){
    		ASAlias * alias = (ASAlias *) [locations objectAtIndex:j];
    		NSLog([alias path]);
    		NSURL *file = [NSURL fileURLWithPath: [alias path]];
    		[files addObject: file];
            /* At this point here is what we have:
               playlistRef - Reference to playlist we just created in itunes
               files - Array of NSURL objects pointing to files on disk.
    	NSError * error = 0;
    	[[[itunes add: files] to: playlistRef] sendWithError:&error];	
    		[rv setErrorObject:error];
    		NSLog([rv getErrorMessage]);	
            return nil;
    In the code above, i'm not too picky about what tracks I add (I'll worry about that after I can add a track to the playlist) so for now it is just adding the first N tracks from the iTUnes main track library.

    When I run the code above the error message contained in NSError is:
    which comes from when I try to add the files to the playlist.

    Any help here would be greatly appreciated.
  2. hhas macrumors regular

    Oct 15, 2007
    Couple of things:

    1. Take care when casting values returned by application commands, in this case, the (ASAlias*) cast. Some application commands may return different types at different times, e.g. getting a track's location property will return an alias if the file exists, or a 'missing value' constant if it doesn't. If you want to specify the return type, do it when you're constructing the application command, e.g. in this case use [[tracks location] getListOfType: typeAlias error:&error], which will return a coercion error if it encounters a missing track. Alternatively, use -[NSObject isKindOfClass:] to check the returned value's class before using it.

    2. You shouldn't need to re-pack ASAliases as NSURLs if you're only passing them back to iTunes; iTunes should accept either. OTOH, using ASAliases in other Cocoa APIs is a pain as they're not API-compatible with NSURLs (I need to work on this), but you can at least get an NSURL directly via -[ASAlias url], or else you can tell appscript to coerce the values returned by the application command to the desired type for you (in this case typeFileURL).

    3. If you're importing files that aren't already in iTunes, use its 'add' command. In this case though you're wanting to add tracks that already exist in your library playlist to a user playlist, and for that you should use iTunes' 'duplicate' command. Don't have sample code to hand (ask if you need some), but it should be pretty straightforward. iTunes' 'duplicate' command appears to accept either a single-track reference or a multi-track reference (most apps do), though not a list of references (most apps don't), e.g. these work:

    tell application "iTunes"
    	duplicate (track 1 of library playlist 1) to playlist "test"
    end tell
    tell application "iTunes"
    	duplicate (tracks 1 thru 5 of library playlist 1) to playlist "test"
    end tell
    but this doesn't:

    tell application "iTunes"
    	set tracksList to (get tracks 1 thru 5 of library playlist 1)
    	duplicate tracksList to playlist "test"
    end tell
    So if you need to add multiple tracks, either create a single reference that identifies all the tracks you want (e.g. by using a by-test specifier) and use that in the 'duplicate' command, or iterate over a list of references and duplicate them one at a time.


    - You can use ASTranslate (available from the appscript website) to convert the above iTunes commands from AppleScript to ObjC syntax, which is handy if you've got an AppleScript-based example and need some help with translating it into ObjC.

    - Doug's iTunes ( has tons of iTunes-related AppleScripts, many of which can be viewed in Script Editor; also very handy when you're trying to work out how to perform a particular task. As you've probably noticed, iTunes' own scripting documentation (like that of most apps) is very thin and doesn't tell you half the stuff you actually need to know in order to script it effectively - so other folks' scripts can be a valuable source of hints and solutions.
  3. mlikesit thread starter macrumors newbie

    Nov 3, 2008
    Can't create new Playlist

    Thank you for mentioning ASTranslate, wish I would have found out about it when I started this app instead of when I was almost done.

    Using it, I have figured out how to add existing tracks to an existing playlist, but I am still having problems creating a new playlist.

    So i've created this method to simply create a playlist. I got the code from ASTranslate and the only modification I made was to sendWithError.

    Applescript Code
    tell application "iTunes"
    	make new user playlist with properties {name:"DUH"}
    end tell
    Translates to the following Appscript code:
    -(NSError *) createPlaylist:(NSString *) playlist{
    	ITMakeCommand *cmd = [[[itunes make] new_: [ITConstant userPlaylist]] withProperties: [NSDictionary dictionaryWithObject: @"Playlist" forKey: [ITConstant name]]];
    	NSError * rv = 0;
    	[cmd sendWithError:&rv];
    	return rv;
    When I run the Applescript code, it creates a new playlist in iTunes. When I run the objective-c appscript code, I get the following error:

    I have now idea why that happens or what it means and I don't understand why it works when I run the Applescript but not when I run the Appscript.
  4. hhas macrumors regular

    Oct 15, 2007
    Hmm. Wonderfully helpful error message. That you get different behaviour with appscript to AppleScript is a concern, but so far I'm unable to reproduce the problem here (iTunes 8.0.1 on 10.5.5/i386), e.g.:

    #import "ITGlue/ITGlue.h"
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    ITApplication *itunes = [ITApplication applicationWithName: @"iTunes"];
    ITMakeCommand *cmd = [[[itunes make] new_: [ITConstant userPlaylist]] 
    						   withProperties: [NSDictionary dictionaryWithObject: @"DUH"
    																	   forKey: [ITConstant name]]];
    NSError *error;
    id result = [cmd sendWithError:&error];
    NSLog(@"Result = %@", result);
    NSLog(@"Error = %@", error);
        [pool drain];
        return 0;

    2008-11-04 18:23:29.561 itunes-newplaylist[23202:10b] Result = [[[[[ITApplication applicationWithName: @"/Applications/"] sources] byID: [NSNumber numberWithInt: 41]] userPlaylists] byID: [NSNumber numberWithInt: 56496]]
    2008-11-04 18:23:29.563 itunes-newplaylist[23202:10b] Error = (null)
    which makes it hard to troubleshoot the problem at this end without more info.

    A couple things to try:

    - Build the Appscript framework using the latest objc-appscript trunk, regenerate your glue using ASDictionary 0.11.0 and do a clean build of your project to check there isn't a version mismatch between them.

    - Run iTunes with AEDebug enabled and email me the trace for 'make' event sent by AppleScript and the trace for the 'make' event sent by appscript. Also include your OS version, iTunes version and hardware type.

Share This Page