Serve up iTunes with Apple's media browser
Give your software some soul
Mac Secrets Let's stay with the iLifeMediaBrowser.framework, which we looked at last time. Previously, I showed how to use Apple's built-in media browser using virtually no code.
Following on from that, a number of folks have asked me if it's possible to use classes in the iLifeMediaBrowser library to access your iTunes library without displaying the Apple browser? Indeed it is, and this is the subject of this article.
First off, why would you want to do this? From a developer's point of view, there are lots of good reasons. Maybe you've written an alarm-clock utility and you want the user to be able to choose a "wake-up" song from her iTunes library. Or maybe you're writing an app to backup, consolidate or repair the song library. Or maybe you want multiple iTunes libraries - whatever.
If you browse the net, you'll find various techniques for interrogating the library, ranging from using iTunes with AppleScript to parsing the associated XML file. But to the best of my knowledge, the techniques used here have never been documented outside of Apple.
The key class that I'm using here is called ILiTunesMediaManager. As the name suggests, this class is the media manager for iTunes. If your interest lies elsewhere, there are equivalent classes that handle the media for other iLife applications, such as ILiMovieMediaManager and ILiPhotoMediaManager.
Instantiating an ILiTunesMediaManager object is dead easy. We simply call the sharedMediaManager class method like this:
ILiTunesMediaManager * tunesManager = [ILiTunesMediaManager sharedMediaManager];
As before, I've provided the necessary header files as part of this month's sample project. The header files were created using class-dump as described in previous articles.
Load your data
Once we've got an instance of ILiTunesMediaManager, we need to load it with data from the iTunes library: this doesn't happen automatically. To do this, you need to call the loadData method. This is asynchronous - it works away in the background - so we need some way of knowing when the job's done.
From our perspective, the simplest way of doing this is to set up a timer to periodically query the media manager to ask if it's ready yet. This can be done via the isLoaded and isLoading methods: I check them both just to make sure the media manager really is ready. If you're worried about long delays here, don't be: I've got over 1,600 songs in my library, and it loads almost instantly.
Once ILiTunesMediaManager is ready to roll, we can start having some fun. The list of available playlists is accessed, counter-intuitively, via a method called playlists.
This returns an array of ILMediaGroup objects corresponding to the available playlists. An ILMediaGroup object encapsulates all sorts of different groups such as albums, recently played, recently added, and so on. If you want to filter this stuff, the simplest thing to do is use the type method to figure out what kind of group you're looking at. Turn on the DEBUG flag in my code - below - and you'll see all the different type numbers after each group name.
While on the subject of groups, it's also worth pointing out that one group can potentially contain subgroups. This functionality isn't directly supported by the iTunes user interface, but it is programmatically accessible.
OK, so we've got a list of playlists. Via the mediaObjects method, ILMediaGroup provides access to another array containing all the media objects in the group. Each object is of type ILMediaObject. Here's where things get really interesting: different methods give you access to information such as the name (song title), artist, play duration, and the fully qualified path of the media file itself.
Methods access music information
Play it again...
For the sake of completeness, my demo application includes the ability to play a track: just double-click an item in the right-hand list and it will start playing. This is done by making use of the ILMediaBrowserAudioPlayer class that, once again, forms a part of the iLifeMediaBrowser library: it's what's used by the Apple browser when previewing a selected audio file. In essence, this class is a simple wrapper around QTMovie that forms part of the QuickTime framework.
If you want to make more sophisticated use of ILMediaBrowserAudioPlayer, you should be aware that it posts a number of undocumented notifications while it's working. These notifications - the meaning of each should be obvious from the name - are listed here:
MediaBrowserAudioPlayerWillBeginPlaying MediaBrowserAudioPlayerDidBeginPlaying MediaBrowserAudioPlayerDidBeginNextSong MediaBrowserAudioPlayerDidFinishPlaying
You can listen out for these notifications in the usual way and take the appropriate action as required. In fact, even if you don't use any of the classes mentioned but simply use the standard media browser as described last time, these notifications will still be generated and can be exploited in the host application.
That's all we've got room for this time. You can download the demo application and source code that I mentioned earlier here. More undocumented naughtiness next time.®