Code Snippet: Get Playlist Names From iTunes
I’m working on Locations Pro and adding some new actions. One action I’m adding is ‘Play an iTunes Playlist’. Obviously I need to know what the playlists are so that I can present the user with a nice list to choose from.
If you need to retrieve library information from iTunes there are a couple ways to do it. You can make a request via Applescript but that requires iTunes to be open. Alternately you can use the “iTunes Music Library.xml” file. Below is a method I put together this morning to do that.
While I was putting this together, I came across a link from Jay Tuley. He pointed out that the the library xml file has two possible locations that you have to account for.
He also make a quick reference to the occasional user doing fun things with Finder aliases and moving that XML file. Why you’d want to move that file, I’ve got no idea. I do know that this morning I had no idea how to resolve an alias or do anything with FSRefs. Now I know a little more. The iTunes related code calls a second little function I put together which returns an NSURL with the aliases resolved given a POSIX path.
Enough talking. Here’s the code:
NSMutableArray *playlistNames = [NSMutableArray array];
NSURL *libraryURL;
NSString *normalLibraryPath = [@"~/Music/iTunes/iTunes Music Library.xml" stringByExpandingTildeInPath];
NSString *olderLibraryPath = [@"~/Documents/iTunes/iTunes Music Library.xml" stringByExpandingTildeInPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:normalLibraryPath]) {
libraryURL = [self resolvedFileURLWithPath:normalLibraryPath];
} else if ([[NSFileManager defaultManager] fileExistsAtPath:olderLibraryPath]) {
libraryURL = [self resolvedFileURLWithPath:olderLibraryPath];
} else {
libraryURL = nil;
}
if (libraryURL != nil) { // If an iTunes Library was found
NSDictionary *libraryDictionary = [NSDictionary dictionaryWithContentsOfURL:libraryURL];
NSArray *playlists = [libraryDictionary objectForKey:@"Playlists"];
int i=0;
for (i=0; i<[playlists count]; i++) {
if (![[playlists objectAtIndex:i] objectForKey:@"Visible"]) {
if ([[playlists objectAtIndex:i] objectForKey:@"Name"]) {
[playlistNames addObject:[[playlists objectAtIndex:i] objectForKey:@"Name"]];
}
}
}
}
return playlistNames;
}
- (NSURL *) resolvedFileURLWithPath:(NSString *)path {
CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)path, kCFURLPOSIXPathStyle, NO);
NSString *resolvedPath;
if (url != NULL) {
FSRef fsRef;
if (CFURLGetFSRef(url, &fsRef)) {
Boolean targetIsFolder, wasAliased;
FSResolveAliasFile (&fsRef, true, &targetIsFolder, &wasAliased);
CFURLRef resolvedUrl = CFURLCreateFromFSRef(kCFAllocatorDefault, &fsRef);
if (resolvedUrl != NULL) {
resolvedPath = [NSString stringWithString:
(NSString *)CFURLCopyFileSystemPath(resolvedUrl, kCFURLPOSIXPathStyle)];
CFRelease(resolvedUrl);
}
}
CFRelease(url);
}
if (resolvedPath != nil) {
NSURL *resolvedURL = [NSURL fileURLWithPath:resolvedPath];
return resolvedURL;
}
return nil;
}
Edit: As always, go ahead and use the code however you want, commercially or otherwise. I don’t mind a mention in your about box (and an email if I get one), but I don’t require it.
June 3rd, 2008 at 6:12 am
“Why you’d want to move that [XML] file, I’ve got no idea.”
There are lots of possibilities – you might want to have your iTunes library on an external disk, for example. I did this for a long time, due to a) having a small hard drive and a big music library and b) wanting to listen to my collection on two separate machines at home and at work.
If you hold the option key when starting iTunes, you get the option of choosing where your library is. This is probably stored somewhere in iTunes’s preferences file, so maybe parsing that to find the library’s parent directory would make the code more robust.
June 3rd, 2008 at 7:24 am
If you move the music folder the supported way (by changing it in the iTunes preferences), the index files still end up in the same directory as in the code above. Changing the music folder location only changes where the actual music files are stored.
I hadn’t considered that someone might just alias their entire music directory to another drive. In that circumstance, the alias resolution is actually required. Makes more sense now. I guess I was thinking of it in terms of someone aliasing only that file. Thank you.
-Bob Warwick