BirdPlaydar

BirdPlaydar Resolving

Birdplaydar exposes the Playdar music content resolver service to Songbird add-ons via the sbIPlaydarService XPCOM service. The Birdplaydar search page lets you search for tracks using Playdar resolvers, which search your computer, your local network, and internet sources like Last.fm. It doesn’t matter where the track actually is; if Playdar can find it, you can listen.

Download the add-on here.

The sbIPlaydarService is intended to be reusable. It provides a simple interface for Songbird add-ons to interact with Playdar. If you want to build a Songbird add-on that uses Playdar, or if you just want to know how it all works, read on…

Resources

The examples on this page will walk you through the process of connecting to Playdar, but if you need more information you can check out these links. You’ll need the XPCOM source for your add-on.

Birdplaydar source code

sbIPlaydarService interface definition

sbIPlaydarServiceListener interface definition

Playdar resources

Songbird developer resources

Setting Up the Playdar Service

After dropping the sbIPlaydarService and sbIPlaydarServiceListener folders into your source tree, you’re ready to start coding. First, get the Playdar Service.

var playdar = Cc['@repeatingbeats.com/playdar/playdar-service;1']
                .getService(Ci.sbIPlaydarService);

If there is no existing Playdar library, the Playdar Service will automatically create a library for Playdar results. A Playdar folder will be added to the service pane.

Playdar Service Pane

For your add-on to listen to Playdar’s responses to your queries, you need to implement the sbIPlaydarServiceListener interface.

// implement the sbIPlaydarServiceListener interface
var playdarListener = {

  onStat : function(detected) {
    // gets called when Playdar responds to a stat() query
    if (detected) {
      alert("Playdar detected");
    } else {
      alert("Playdar could not be detected!");
    }
  },

  onResults : function(response,finalAnswer) {
    // gets called when Playdar responds to a resolve() query
    // response is a JSON string
    var responseObj = JSON.parse(response);
    alert("Playdar response for qid: " + responseObj.qid);
    // see Playdar HTTP API for more details
    // track info is in responseObj.results
    if (finalAnswer) {
      // last response for this qid
      alert("final response for qid: " + responseObj.qid);
    }
  }
};

Next, register your listener with the Playdar Service. The client registration method returns a Client ID string that is unique to your client. You will need this Client ID for future calls to the Playdar Service. The client registration method looks like this:

/* sbIPlaydarService */
AString registerClient(in sbIPlaydarServiceListener aListener,
                       in boolean aHideTracks);

The aHideTracks parameter controls how your Playdar results are handled by the Playdar library in Songbird. If true, the tracks returned by the Playdar Service will be hidden. If false, all resolved Playdar tracks will immediately be visible in the Playdar library.

Your client registration will look something like this:

var cid = playdar.registerClient(playdarListener,false);

During registration, the Playdar Service creates a new MediaList in the Playdar Library. This list is unique to your Client ID. Use this method to get your list:

var clientList = playdar.getClientList(cid);

All tracks resolved by Playdar are automatically added to your Client List. If all you want to do is listen for Playdar’s resolved tracks, implement the sbIMediaListListener interface and attach the listener to your Client List. This example shows how you can call an arbitrary function on resolve:

// get a reference to your controller script
var controller = this;

// implement sbIMediaListListener interface
var clientListListener = {
  onItemAdded : function(list,item,i) {
    controller.onResolvedTrack(item);
  }
};

// attach the listener to your client list
clientList.addListener(clientListListener, false,
    LibraryUtils.mainLibrary.LISTENER_FLAGS_ITEMADDED);

Resolving Tracks

Once you’ve set up your listeners and registered your client, querying Playdar for tracks is simple. Just call the Playdar Service’s resolve method. Here’s the API:

/* sbIPlaydarService */
/**
 * \brief query playdar to resolve a track
 *
 * \param aCid Client ID
 * \param aArtist Track artist
 * \param aAlbum Track album
 * \param aTrack Track name
 * \param aQid Query ID
 */
 void resolve(in AString aCid,
              in AString aArtist,
              in AString aAlbum,
              in AString aTrack,
              [optional] in AString aQid);

Query Playdar for a song:

playdar.resolve(cid,'LCD Soundsystem','','All My Friends');

If Playdar can find the track, it will be added to the Client MediaList. Now that you have a Playdar resolved track instantiated as an sbIMediaItem, your add-on should do something interesting with it! This simple function shows how you can access two custom Playdar MediaItem properties:

onResolvedTrack : function(track) {

  // where did Playdar find the track?
  var source = track.getProperty(playdar.sourcePropID);
  alert("Track: " + track.getProperty(SBProperties.trackName) +
          "\nSource: " + source);

  // what is the Playdar score for the track?
  var score = track.getProperty(playdar.scorePropID);
  alert("Score: " + score);
}

Remember that onResolvedTrack is an arbitrary function defined in the listener above. Note that your sbIPlaydarServiceListener’s onResults function will also be called every time Playdar responds to a query.

As a general guideline, getting your Client List and attaching an sbIMediaListListener is the simple way to listen to Playdar. Use onResults for more advanced Playdar response parsing. You must implement an sbIPlaydarServiceListener for client registration. If you don’t want to deal with onResults, just leave it empty.

Hidden or Visible?

Because every single track that Playdar resolves is automatically added to your client’s MediaList, the Playdar library can get cluttered and disorganized quickly. You have three options for controlling the visibility of your Playdar results.

  1. Hidden list, hidden tracks – Your client list and all resolved tracks will remain hidden if register your client with aHideTracks being true:

     :::javascript
     var cid = playdar.registerClient(playdarListener,true);
  2. Hidden list, visible tracks – Your client list will be hidden, but all resolved tracks will be visible in the Playdar library if you register your client with aHideTracks being false:

     :::javascript
     var cid = playdar.registerClient(playdarListener,false);
  3. Visible list, visible tracks – For your playlist to show up in the service pane, you can tell the Playdar Service to make it visible and give it a name:

     :::javascript
     playdar.showClientListInServicePane(cid,"myPlaylistName");

Your track and playlist visibility settings will probably be influenced by the features of your add-on. Just remember that other add-ons might be using the Playdar Library too.

Cleaning Up

When your playdar client no longer needs the service, you should use the unregisterClient method to clean up. This method will help you clean up hidden tracks and playlists in the Playdar Library.

/* sbIPlaydarService */
/**
 * \brief cleanup when client no longer needs service
 *
 * \param aCid Client ID
 * \param aRemoveClientList If true, client playlist is removed
 *                          from library
 * \param aRemoveAllTracks If true, all tracks resolved for this
 *                         client are removed from the library
 * \param aRemoveHiddenTracks If true, only hidden tracks for
 *                            this client are removed
 */
void unregisterClient(in AString aCid,
                      in boolean aRemoveClientList,
                      in boolean aRemoveAllTracks,
                      [optional] in boolean aRemoveHiddenTracks);

Summary

You now know everything you need to get up and running with Playdar in a Songbird extension. The sbIPlaydarService interface will likely evolve as Playdar grows, so you might want to keep an eye on the the source code. Feel free to contact me to suggest improvements. All the better if you want to help make the improvements.

Birdplaydar