.Net Code Monkey RSS 2.0
 Sunday, February 22, 2009

Background

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.

The Solution

Below is the javascript file to include on your website.

Javascript Code

You will need to set up a few values in the pseudo-constants section of the code first.

  • REMOTE_XML_URL - is the remote url for the 'now_playing.xml' published by Barndon's ITunes plugin.
  • DISPLAY_ARTIST, DISPLAY_TITLE and DISPLAY_ALBUM  - are flags for if to display these element.

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(); }

You may want to provide a little more error handling and checking for returned null values here and there to.

Html Code

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>

Summary

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.

Compatability

My the 'NowPlaying.js' JavaScript code has been tested and appears to work on the following browsers:

  • IE 6.0.2
  • Opera 9.52
  • Firefox 3.0.5
  • Netscape 9.0b3
  • Safari (Windows) 3.2.1
  • Chrome 1.0

Note

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.

Links

Brandon Fuller's Plugin
Ferreri Gabriele's JavaScript StringBuilder

Sunday, February 22, 2009 10:28:09 AM (GMT Standard Time, UTC+00:00)  #    Comments [2] -
Html | JavaScript | iTunes
 Wednesday, December 03, 2008

Today I realised it was my poor coding that had created a subltle bug that the test team spotted yesterday.

The Bug

The bug was that Excel itself would crash if there was more than one instance of Excel open with my workbook application in one instance and another workbook application in the other and the user attempted to close my workbook via the grey [X].

The Cause

It turned out to be beacuse I had lazily shown and hidden some form objects rather than creating instances of the forms and opening and closing them and clearing up properly by setting these instances to nothing via a call in the "Workbook_BeforeClose" event when the workbook is finished with.

The solution

Once I re-wrote the form handling to be carried out within a "Dialog Manager" module, to work like a static class in C#, with private fields for each form and public properties to access them, the bug seemed to disappear.

Discussions here indicated it would probably be due to undisposed of form refences being present when the workbook is closed. If you have anything further you can add to this issue, please comment below.

Wednesday, December 03, 2008 12:38:34 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] -
Excel | VBA | Bug
 Tuesday, December 02, 2008

I have recently been lumped with quite a bit of Excel based tasks to do at work, and there is one function that I keep needing that does not appear to be in VBA. "AverageIf"

Knowing that you can perform the equivelant of an AverageIf with combination of SumIf() and CountIf(), I thought I'd wrap these up in a function.

'Purpose:
'   Like Excel's sum if function put performs an average, rather than a sum.
'
Public Function AVGIF(ByVal checkRange As Range, ByVal criteria As Variant, ByVal avgRange As Range) As Variant

    Dim sumIfResult As Double
    Dim countIfResult As Double

    sumIfResult = Application.WorksheetFunction.SumIf(checkRange, criteria, avgRange)
    countIfResult = Application.WorksheetFunction.CountIf(checkRange, criteria)

    If countIfResult = 0 Then
        AVGIF = 0
    Else
        AVGIF = sumIfResult / countIfResult
    End If

End Function

I hope some one finds this as useful as I have.

 

Tuesday, December 02, 2008 5:01:14 PM (GMT Standard Time, UTC+00:00)  #    Comments [4] -
VBA | Excel
 Sunday, November 30, 2008

Mixing with one deck using Serato Scratch Lives Input reverse function

Below is a clip of a simple demonstration to show how you can use the Input Reverse function in Serato Scratch Live to mix with just one deck.

It may be useful if you can you break a needle during a set, or one deck is off for repair / servicing, or you have completely ruined one of the TCVs, There are any number of reasons that may lead you to have just one serviceable deck!

I hope it may help someone out of a sticky situation. sometime. Thank you for watching.

Tracks played:
Stir Fry - Breakin on the streets
The Soul of Man  -Scatterbox
Plump DJs - Weighed Down

You Tube Clip Link

Sunday, November 30, 2008 9:58:03 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] -
Scratch Live | Serato
Archive
<February 2009>
SunMonTueWedThuFriSat
25262728293031
1234567
891011121314
15161718192021
22232425262728
1234567
Blogroll
 Clemens Vasters
 Harry Pierson
Passion * Technology * Ruthless Competence
 Joshua Flanagan
A .NET Software Developer
 Michael Schwarz's Blog
Developing applications on the Microsoft platform since Windows 3.1!
 Omar Shahine
Yet another Microsoft blogger
 Scot GU
Scott Guthrie lives in Seattle and builds a few products for Microsoft
 Scott Hanselman
Programming Life and the Zen of Computers
 Tom Mertens
Tom's corner
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2012
Duane Wingett
Sign In
Statistics
Total Posts: 39
This Year: 4
This Month: 0
This Week: 0
Comments: 39
Themes
Pick a theme:
All Content © 2012, Duane Wingett
DasBlog theme 'Business' created by Christoph De Baene (delarou)