Playlist Sorting at Air America Radio

Advomatic just added user play list functionality for Air America’s player. Users are able to create their own play lists of favorite audio and video clips, and sort them in their preferred order.

To see this functionality in action, you’ll need to go to the Air America site, and create a user account. After doing so, launch their player, by pressing on the big Listen Live button on the top left of every page.

Add two or three audio clips by pressing the “+” next to a clip, then go to the video tab and do the same thing.

Finally, go to the Playlist tab. Here, you can click and drag clips to sort them as desired. Go ahead. It’s all saved, which you can confirm by going to another tab, logging out, logging back in, etc.

Site Recipe

For this functionality, we first used the Views Bookmark as a base. This allows the creation of custom node bookmarks, favorites, etc.

We already embed clips. Clips are a content type that will either reference a local audio file, served by a CDN (using a customized version of the File Field module), or a video clip, using the Embedded Media Field module.

We just created a new bookmark type for the clips as usual.

The player tab is just a view of a user’s custom play list. The tab uses an ajax call to load up a javascript version of the page, which required a custom callback. (This method may become obsolete with the upcoming release of the Embed Widgets module.)

Adding the +/- buttons to the view items was achieved by simply overriding the theme function to add them, with a manual invoke of the nodeapi call in views_bookmark. Having the – button remove an item from the playlist was achieved with custom jQuery that simply removes the element from the DOM after the link’s been clicked.

User Custom Sort

Shuffling the items was two steps. First, after installing jQuery UI, we invoke the following:

  $(‘.view-aar-player-favorite-clips ul’).sortable({cancel:’a’, update: function(e, ui){
    var items = $(this).sortable(‘toArray’);
    var arLen = items.length;
    var output = new Array;
    for ( var i=0, len=arLen; i<len; ++i ) {
      output[i] = $(‘#’+items[i]).children(‘.play’).children(‘a’).attr(‘id’).slice(13);
    $.get(‘/playlist/sort/’ + eval(output));

The cancel:’a’ ensures we can still click the links of the clip area. The update function is called after a drag & drop sort. It will grab the nid’s of the items and send them back to the server. (FYI, we had to override theme_item_list to add unique id’s to the list elements to make the sortable function work. NID’s are stored in the play links of the individual view items, again by overriding the view output.)

Database Updates

The second part was writing a custom page callback, with the following:

*  This takes a newly sorted array of items from a jquery ajax’d JSON array, and changes the timestamp accordingly.
function aar_player_playlist_sort($items = ”, $vbid = 1) {
  global $user;
  if (!$user->uid) {
  $items = explode(‘,’, $items);
  $time = time() – sizeof($items);
  $items = array_reverse($items);
  foreach ($items as $nid) {
    db_query(“UPDATE {views_bookmark_nodes} set timestamp=%d WHERE vbid=%d AND uid=%d AND nid=%d”, $time++, $vbid, $user->uid, $nid);
  print t(‘Completed new sort.’);

We used a custom query, because the Views Bookmark module doesn’t currently offer an API function to do this. But the magic works fine, changing the sort order of our playlist.

The clips of the site may also be viewed at the On Demand page, which deserves a write-up of its own.

Much of the remaining functionality, such as clips automatically progressing and looping after playback, is actually featured in the upcoming Drupal Multimedia book that I’ve nearly completed writing, to be published soon by Packt Publishing. However, I’ll continue writing more site recipes over the next week or three.

I need to thank Marco Carbone (mcarbone at and Jack Haas (jerseycheese at, both developers with Advomatic, for their help with the functionality. Marco built out the On Demand section, and I borrowed some of his javascript for the dynamic ajax of tabs. Jack themed the sucker.

(Cross-posted at