I was recently asked by a friend to help him implement the website code part of Brandon Fuller's 'Now Playing' plugin for iTunes. The code Brandon provides is PHP, and I felt that would be limiting if my friends website ever had to move to a non PHP enabled web server. With this in mind I decided to convert and modify his PHP script to be JavaScript only. This article covers the code created to do so.
Below is the javascript file to include on your website.
You will need to set up a few values in the pseudo-constants section of the code first.
The remainder of the constants all declare element IDs or css classes for the elements the javascript creates.
Lastly you will also need to set the _artworkUrl variable to point to the the default artwork url for when album artwork is not available.
/* File: NowPlaying.js Author: Duane Wingett Date: 21st February 2009 Purpose: For use with Brandon Fuller's "Now Playing" iTunes addon, see: http://brandon.fuller.name/archives/hacks/nowplaying/ for more details. Browser Compatability: checked (Tested on) IE 6.0.2 Opera 9.52 Firefox 3.0.5 Netscape 9.0b3 Safari (Windows) 3.2.1 Chrome 1.0 Usage Policy: You are free to use / distribute this code without charge, providing this acknowledgement remains intact ane no profit is gained from use. */ // Constant Declarations var REMOTE_XML_URL = 'http://www.mySite.com/NowPlaying/now_playing.xml'; // Remote location of NowPlaying xml file var DISPLAY_ARTIST = true; var DISPLAY_TITLE = true; var DISPLAY_ALBUM = true; var OUTER_CONTAINER_IDENTITY = 'NowListeningTo'; var IMAGE_CONTAINER_IDENTITY = 'ListeningImageContainer'; var TEXT_CONTAINER_IDENTITY = 'ListeningTextContainer'; var OUTER_CONTAINER_CSS_CLASS = ''; var IMAGE_CONTAINER_CSS_CLASS = 'FloatLeft'; var TEXT_CONTAINER_CSS_CLASS = 'FloatLeft StudioInfoTextContainer RightBorder'; var ARTIST_TEXT_CSS_CLASS = 'StudioInfoText'; var TITLE_TEXT_CSS_CLASS = 'StudioInfoText'; var ALBUM_TEXT_CSS_CLASS = 'StudioInfoText'; var IMAGE_CSS_CLASS = 'NowPlaying'; var CONTENT_DIV_ID = 'x'; // ID of div to insert NowPlaying html into // Declare variables - some with default values var _artist = 'Unknown'; var _title = 'Unknown'; var _album = 'Unknown'; var _artworkUrl = 'http://www.mySite.com/Images/MusicNoImage.gif'; // Remote location of no image file var _isIe = isIe(); var _xmlDoc; // Purpose // Detects if browser is IE // // Returns: // true if it is. // function isIe() { return navigator.appName.indexOf("Microsoft")!=-1; } // Purpose: // Loads the remote XML file into global variable. // function loadXml() { try { if (window.ActiveXObject) { _xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); _xmlDoc.async=false; _xmlDoc.onreadystatechange = populateArtistInfoFromXml; _xmlDoc.load(REMOTE_XML_URL); } else { // Opera, Mozilla, Safari & Chrome var xmlhttp = new window.XMLHttpRequest(); xmlhttp.open("GET",REMOTE_XML_URL,false); xmlhttp.send(null); _xmlDoc = xmlhttp.responseXML.documentElement; _xmlDoc.onload=populateArtistInfoFromXml(); xmlhttp = null; } } catch(e) { alert(e.message); } } // Purpose: // Populates global fields from global xml doc. // function populateArtistInfoFromXml() { try { if(_xmlDoc != null) { if((_xmlDoc.readyState == 4) || (!_isIe)) { //alert('loading values from doc..'); if(getNodeValue(_xmlDoc, "title") != null) { _title = getNodeValue(_xmlDoc, "title"); } if(getNodeValue(_xmlDoc, "artist") != null) { _artist = getNodeValue(_xmlDoc, "artist"); } if(getNodeValue(_xmlDoc, "album") != null) { _album = getNodeValue(_xmlDoc, "album"); } if(getNodeValue(_xmlDoc, "image") != null) { _artworkUrl = getNodeValue(_xmlDoc, "image"); } } } } catch(e) { alert(e.message) } } // Purpose: // Gets and the value from passed in XML document // for the passsed in node name. // // Returns: // value if found or null; // function getNodeValue(xmlDoc, tagName) { var value = null; try { if(_isIe) { value = xmlDoc.getElementsByTagName(tagName)[0].text; // IE } else { value = xmlDoc.getElementsByTagName(tagName)[0].textContent; // Opera, Mozilla, Chrome, Safari } return value; } catch(e) { alert(e.message) } } // Purpose: // Renders the NowPlaying html. // // Inputs: // artist - The artist's name // title - The track name or song title // album - The album name // function renderNowPlaying() { loadXml(); var sb = new StringBuilderEx(); sb.appendFormat("<div id='{0}'>\r\n", OUTER_CONTAINER_IDENTITY); sb.appendFormat(" <div id='{0}' class='{1}' >\r\n", IMAGE_CONTAINER_IDENTITY, IMAGE_CONTAINER_CSS_CLASS); sb.appendFormat(" <img src='{0}' class='{1}' title='{2}' alt='{2}' />\r\n", _artworkUrl, IMAGE_CSS_CLASS, _title); sb.appendFormat(" </div>\r\n"); sb.appendFormat(" <div id='{0}' class='{1}' >\r\n", TEXT_CONTAINER_IDENTITY, TEXT_CONTAINER_CSS_CLASS); if(DISPLAY_ARTIST) { sb.appendFormat(" <p class='{0}' >{1}</p>\r\n", ARTIST_TEXT_CSS_CLASS, _artist); } if(DISPLAY_TITLE) { sb.appendFormat(" <p class='{0}' >{1}</p>\r\n", TITLE_TEXT_CSS_CLASS, _title); } if(DISPLAY_ALBUM) { sb.appendFormat(" <p class='{0}' >{1}</p>\r\n", ALBUM_TEXT_CSS_CLASS, _album); } sb.appendFormat(" </div>\r\n"); sb.appendFormat("</div>\r\n"); var containerDiv = document.getElementById(CONTENT_DIV_ID); containerDiv.innerHTML=sb.toString(); }
// Purpose: // Populates global fields from global xml doc. // function populateArtistInfoFromXml() { try { if(_xmlDoc != null) { if((_xmlDoc.readyState == 4) || (!_isIe)) { //alert('loading values from doc..'); if(getNodeValue(_xmlDoc, "title") != null) { _title = getNodeValue(_xmlDoc, "title"); } if(getNodeValue(_xmlDoc, "artist") != null) { _artist = getNodeValue(_xmlDoc, "artist"); } if(getNodeValue(_xmlDoc, "album") != null) { _album = getNodeValue(_xmlDoc, "album"); } if(getNodeValue(_xmlDoc, "image") != null) { _artworkUrl = getNodeValue(_xmlDoc, "image"); } } } } catch(e) { alert(e.message) } }
You may want to provide a little more error handling and checking for returned null values here and there to.
Below is the HTML for the page to display teh now playing infomation. You need to place an empty div in the page and assign it the same ID that you set in the JavaScript constant "CONTENT_DIV_ID". You need to link to the two JavaScript files "StringBuilderEx.js" and "NowPlaying.js". Include a stylesheet to add your own styling and behaviour to the JavaScript created divs Finally call the "renderNowPlaying()" method after the empty div.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Now Playing Test Page</title> <link href="StyleSheets/BehaviorStyles.css" rel="stylesheet" type="text/css" /> <link href="StyleSheets/AppearanceStyles.css" rel="stylesheet" type="text/css" /> </script src="Javascript/StringBuilderEx.js" type="text/javascript" charset="utf-8"> </script src="Javascript/NowPlaying.js" type="text/javascript" charset="utf-8"> </head> <body> <div id="StudioInfoContainer" > <div id="x"><!-- Now Playing will appear here --></div> <script language="javascript" type="text/javascript"> renderNowPlaying(); </script> </div> </body> </html>
So there you have it a basic web site side implementation of Brandon's Now Playing feature. Feel free to use, alter or extend any of the code in this article.
My the 'NowPlaying.js' JavaScript code has been tested and appears to work on the following browsers:
Full implementation of Brandon Fulller's 'Now Playing' iTunes plugin can be found on his website, the link is below.The JavaScript extended StringBuilder class used in this code is courtesy of Ferreri Gabriele and can be found at the CodePrroject link, below.
Brandon Fuller's PluginFerreri Gabriele's JavaScript StringBuilder
Remember Me
a@href@title, b, blockquote@cite, em, i, strike, strong, sub, sup, u
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.