shwango! blog
life, love and some other stuff…

Archive for December, 2004

iTunes and a “Now Playing” feature

[UPDATED - see below!]

Here’s some cool code I hacked together from the iTunes Windows COM SDK docs and some other sites - Dan Crevier’s Blog and ajc.

I had already posted how I did something like this in WinAmp, but I’ve been using iTunes a lot now and really like it. There are a few plugins and such out there to post the current track info to a file or site, but the main thing other scripts didn’t do was to post the stream info if iTunes was playing a stream.

Basically it’s some JavaScript that runs in the background listening for events from the iTunes applications. Currently I’m just using OnPlayerPlayEvent and OnQuittingEvent, but some of the other events might be cool to use. I just create a little XML and post it to the web server - this one’s real time, where my WinAmp one was polled.

I don’t know how good or efficient this code is, but it hasn’t crashed my box yet! I also am posting a simple cgi I hacked up in Perl to snag the bits of XML and output an HTML file that is included in my main page via SSI.

I just start iTunes, then run my script. When I exit iTunes, the JavaScript code exits as well - and it tells you it’s closing.

iTunes JavaScript code: (I think I got the html escaped - I need a better way to post code!)

var iTunesApp = WScript.CreateObject("iTunes.Application");
var iTunesIsRunning = true;

function ITEventTest_OnPlayerPlayEvent(iTrack) {
   getCurrentTrackInfo();
}

function ITEventTest_OnPlayerPlayingTrackChangedEvent(iTrack) {
   getCurrentTrackInfo();
}

function ITEventTest_OnQuittingEvent() {
   iTunesIsRunning = false;
}

function getCurrentTrackInfo() {
   var current = iTunesApp.CurrentTrack;
   var stream = iTunesApp.CurrentStreamTitle;

   var trackType = "";
   var trackName = "";
   var trackArtist = "";
   var trackAlbum = "";

   if (stream != "") {
      streamURL = iTunesApp.CurrentStreamURL;
      trackType="stream";
      trackName=stream;
      trackArtist=current.Name;
      trackAlbum=streamURL;
   } else {
      trackType="file";
      trackName=current.Name;
      trackArtist=current.Artist;
      trackAlbum=current.Album;
   }

   var response = postTrack(trackType, trackName, trackArtist, trackAlbum);
}

function postTrack(trackType, trackName, trackArtist, trackAlbum) {
   var xmlTrack = new ActiveXObject("MSXML2.DOMDocument.4.0");
   xmlTrack.loadXML(’<?xml version="1.0" ?><track/>’);
   var root = xmlTrack.documentElement;
   root.setAttribute("type", trackType);

   var textNode = xmlTrack.createElement("name");
   textNode.text = trackName;
   root.appendChild(textNode);
   var textNode = xmlTrack.createElement("artist");
   textNode.text = trackArtist;
   root.appendChild(textNode);
   var textNode = xmlTrack.createElement("album");
   textNode.text = trackAlbum;
   root.appendChild(textNode);

   var xmlhttp = new ActiveXObject("MSXML2.XMLHTTP.4.0");
   xmlhttp.open("POST", "http://[cgi url]",false);
   xmlhttp.send(xmlTrack);
   if (xmlhttp.status != "200") {
      WScript.Echo("Error posting to server. Code is: " + xmlhttp.status);
   }
}

WScript.ConnectObject(iTunesApp, "ITEventTest_");
WScript.Echo("Waiting for changes…");
getCurrentTrackInfo();

while (iTunesIsRunning) {
   WScript.Sleep(1000);
}

var response = postTrack("OFFLINE", "offline.", "", "");

WScript.DisconnectObject(iTunesApp);
WScript.Echo("iTunes was closed, iTunesListener exiting.");

Perl CGI on the server: (Beware: I’m not a great Perl coder!)

#!/usr/bin/perl

use XML::LibXML;

local $/;

my $parser = XML::LibXML->new();

my $request = <STDIN>;
my $xmlRequest = $parser->parse_string($request);

my $root = $xmlRequest->getDocumentElement;
my $type = $root->getAttribute("type");

my @nodes = $root->findnodes("name");
my $name = $nodes[0]->string_value();

@nodes = $root->findnodes("artist");
my $artist = $nodes[0]->string_value();

my @nodes = $root->findnodes("album");
my $album = $nodes[0]->string_value();

open(file,">[path writable by web server]/current_song.html");
print file $name;
print file "<br />";
print file $artist;
print file "<br />";
print file $album;
print file "\n";
close(file);

print "Content-type: text/html\n\n";
print "ok";

And the simple Server Side Include in my html:

<!–#include virtual=”../includes/iTunes/current_song.html” –>

Works for me and it’s pretty cool hack I think! I’m thinking about some other possiblities… If I can use iTunes to publish a stream, then I could have some playlist posting and even playlist manipulation - that could be cool.

Also I found a somewhat cool plugin for iTunes on Windows called “multi plugin”. I only really use the plugin for controlling iTunes with my laptop’s multimedia buttons when iTunes is minimized - iTunes should automatically do this like WinAmp did. I can’t figure out how to uninstall it though!

UPDATE:

Seems I deleted some code that is needed so that the getCurrentTrackInfo() function is called when listening to a stream. The “OnPlayerPlayEvent” event is not called when the track a stream is playing changes. You need to trap for “OnPlayerPlayingTrackChangedEvent”, so just add this:

function ITEventTest_OnPlayerPlayingTrackChangedEvent(iTrack) {
   getCurrentTrackInfo();
}

I’ve updated my code above to reflect this. The full title of the stream sometimes isn’t present when you first connect - just reconnect if that bothers you.

Also, I need to add some more error trapping too. The script crashes if you start the script and iTunes isn’t playing anything - at least this happens to me!

Enjoy!

Merry Christmas 2004!

Merry Christmas to my three, ok two, blog readers! But I still have another Christmas coming! We’re heading up to Chagrin Falls for New Years and to celebrate Christmas with Jen’s family.

The first Christmas was pretty cool. Jen got me a telescope! Jen says it’s not a great one, but I’m not an expert at telescopes, so I just think it’s great. I’ve always loved looking at the stars, so it should be really cool. It was a cool surprise since it was something I never would have thought to ask for, but would have liked! Those are usually the coolest presents.

She also got me a wireless outside temperature sensor. Being a gadget freak, I thought this was cool. Now… can I hack it and hook it up to my computer? ;-)
I’ll report more next year! (I was going to post some Cincinnati snow pics, but I grabbed the wrong SDRAM card from the camera!)

Firefox

I have to say Firefox is really great. I’ve been trying to use it for most of my browsing and it’s doing a great job. So far only a few sites have had problems. I got Jen using it a while ago when something wasn’t working right with IE and she hasn’t had too many problems either - maybe something with PDF’s, but I haven’t looked into it yet.

I really love that they’ve incorporated the base functionality of MSXML. That’s a great thing! Currently our web app at work is only for IE, but maybe we’ll see that change. We are using MSXML a lot, but think we can do the same stuff in Firefox - maybe Safari too. I’d like to get us back to working on the Mac platform at some stage and didn’t like the thought of a fully installed client.

The theme-ability is cool - not a pain like IE. And there are some cool extensions out there, but I haven’t played around with them much yet.

I still need to get some of my CSS code working in Firefox, but for the most part, it works like a charm!

Anyway… sorry for not posting more. Between work, life, Christmas… ok, just excuses, but oh well…