Last.fm - Observe your friends

By myoclonia Last update Nov 1, 2006 — Installed 956 times.
// ==UserScript==
// @name          Last.fm - Observe your friends
// @description	  observe what somebody's friends have recently been playing
// @include       http://*.last.fm/*
// ==/UserScript==
// 
// Made by myoclonia - http://www.last.fm/user/myoclonia/
// 
// Version 1.0
//  - First release - output the most recent tracks based on the friends list
//    on http://www.last.fm/user/<username>/friends/
//    This works for anybody's friend list!
//  - Heavily based on BooooooooB's Last.fm - Recently Played script (v1.6b)
//    http://www.last.fm/BooooooooB
//    Thanks for giving me a great start!
//
// Description
//    The "observe friends" option that used to be located 
//    at http://www.last.fm/user/<username>/observe  has been broken 
//    for some weeks now. That's why I decided to fix it myself ;-)
//
//    This script will display the 10 most recent tracks, using  
//    the friends list of any given user located on 
//    http://www.last.fm/user/<username>/friends/
//


// Script requires GM_xmlhttpRequest
if( ! GM_xmlhttpRequest ) {
	alert( 'Please upgrade to a newer version of Greasemonkey for the Last.fm recently played script to work.' );
}

// Caching things...
var nowTime = new Date();
var cacheTimeout = 4;

// Append the needed styles to the page
GM_addStyle( 'span.recentlyPlayedPanelArtist { display: block; padding-left: 5px; font-size: 0.9em; }' );
GM_addStyle( 'span.recentlyPlayedPanelTrack { display: block; padding-left: 5px; font-size: 0.9em; }' );
GM_addStyle( 'hr.recentlyPlayedHr { margin: 0; padding: 0; visibility: hidden; clear: both; }' );
GM_addStyle( '.lastPanel ul.i li a { height: auto !important; min-height: 60px !important; }' );

// Check if panel exists, and add most recently played tracks for each user
if( document.getElementById( 'friendslist' ) ) {
	lastFm_nowPlaying( document.getElementById( 'friendslist' ) );
}


// Goes through the panel and gets each block
function lastFm_nowPlaying( panel ) {
	// Get an array of all the user blocks in the panel
    var userBlocks = document.evaluate(
        "//li[@class='uName']",
        panel,
        null,
        XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
        null);

	// For each one...

    for (var i = 0; i < userBlocks.snapshotLength; i++) {

        var username = userBlocks.snapshotItem(i).getElementsByTagName( 'a' )[0].innerHTML;
		//username = ( username.replace(/^\W+/, '' ) ).replace(/\W+$/, '' );
		if( username ) {
			// Get and place data
			lastFm_nowPlaying_do( username, userBlocks.snapshotItem(i) );
		}
	}
}

// Gets the XML data for a block
function lastFm_nowPlaying_do( username, block ) {

	// Check the timestamp on the cache
	var cacheTime = GM_getValue( username + '_timeout', 0 );
	if( parseInt( nowTime.getTime() / 10000 )  <= cacheTime ) {
		// If this cache hasn't timed out yet, we can use it
		recentTracks = GM_getValue( username + '_recent', 0 );
		if( recentTracks ) {
			// Go use the stuff
			lastFm_nowPlaying_place( block, recentTracks, username );
			return;
		}
	}

	// If the cache has timed out...
	// Request the XML of the user's recent tracks
	GM_xmlhttpRequest( {
		method: 'GET',
		url: 'http://ws.audioscrobbler.com/1.0/user/' + username + '/recenttracks.xml',
		onload: function( details ) {
			// Put it into the cache
			var username = details.responseText.slice( details.responseText.indexOf( 'user="' ) + 6, details.responseText.indexOf( '"', details.responseText.indexOf( 'user="' ) + 6 ) );
			GM_setValue( username + '_recent', details.responseText );
			GM_setValue( username + '_timeout', parseInt( nowTime.getTime() / 10000 ) + ( cacheTimeout * 6 ) );
			// Go use the stuff
			lastFm_nowPlaying_place( block, details.responseText, username );
			return;
		}
	} );
}

// Parses the XML data and puts it in the block
function lastFm_nowPlaying_place( block, data, user ) {

	// If I was being tidy, I'd turn the XML string into a DOM, but I'm not sure it's worth it, so it's left as a string
	if( block && data ) {
		var recentArtist = '';
		var recentTrack = '';
		var recentTime = 0;

            var theplace = document.evaluate(
                "//li[@class='delete']",
                document,
                null,
                XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
                null);

		
		// Check that the user has actually listened to anything recently
		if( data.indexOf( '<name>' ) != -1 ) {

        var parser = new DOMParser();
        var dom = parser.parseFromString(data, "application/xml");
        var tracks = dom.getElementsByTagName('track');
        var artist, name, date;

		for (var i = tracks.length-1; i >= 0; i--) {

			artist = tracks[i].getElementsByTagName('artist')[0].textContent;
            name = tracks[i].getElementsByTagName('name')[0].textContent;
            date = tracks[i].getElementsByTagName('date')[0].textContent;

			// place data on page
			var main;
            // old version of last.fm (23rd oct 2006)
            //main = document.getElementById('widget');
            // for the october beta:
			main = document.getElementById('widgetHolder');
            var thisDiv = document.createElement("div");

            if (i == 0) {
                thisDiv.innerHTML = '<b>' + user + '</b>';
            }

			thisDiv.innerHTML += '<div style="float: left; text-align: left; width: 79%;">' + artist + ' - ' + name + '</div>';
            thisDiv.innerHTML += '<div style="float: right; text-align: right; width: 19%;">' + date + '</div>\n';

            // whitespace as a separator to the next block
			if (i == tracks.length-1) {
                thisDiv.innerHTML += '<div style="clear: right;"><br></div>\n';
			}
  
            if (main) {
                //main.parentNode.insertBefore(thisDiv, main);
                main.parentNode.insertBefore(thisDiv, main.nextSibling);
            }

		}			
		// end of for-block

		}			
	}
}