Large

Last.fm Compatibilitizer

By Fracture91 Last update Jul 25, 2009 — Installed 376 times.

There are 1 previous version of this script.

Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

// ==UserScript==
// @name			Last.fm Compatibilitizer
// @namespace		http://vestitools.pbworks.com/
// @description		Automatically finds compatibility when you click a last.fm user link, and shows important data with another click
// @include			*
// @exclude			http://www.last.fm/*
// @version			2.0.0
// @copyright		2009+, Andrew Hurle
// ==/UserScript==

//This script is free to use, modify, and freely redistribute for personal use as long as the original author, Andrew Hurle, is credited

//When you click a last.fm profile link, a box will pop up with the usual taste-o-meter
//To visit the link normally, open in another tab (middle mouse button in Firefox 3.5)
//You can highlight the text for easy copying with the highlight button
//Click the more button to see their recent tracks, top artists, top tracks, and Super Eclectic Score
//Hover over a list to see more data
//You must be logged in to last.fm for accurate results

var allUserLinks, thisUserLink;
allUserLinks = document.evaluate(
    '//a[contains(@href, "last.fm/user/")]',
    document.body,
    null,
    XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
    null);
for (var i = 0; i < allUserLinks.snapshotLength; i++) {
    thisUserLink = allUserLinks.snapshotItem(i);
	//make sure it's not a link like http://www.last.fm/user/username/library
	if(thisUserLink.href.replace(/^[ \t]+|[ \t]+$/gim,"").replace(/\/$/,"").indexOf("/", thisUserLink.href.replace(/^[ \t]+|[ \t]+$/gim,"").replace(/\/$/,"").indexOf("last.fm/user/")+13)==-1) {
		thisUserLink.setAttribute("onclick", 'return false;' );
		}
	}
	
var loadingIcon = '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';
	
var eqIcon = 'R0lGODlhDAAMALMLAIyMjP///5SUlK2trZycnKWlpbW1tc3NwP/92+Df09rZzf/8yQAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBQALACwAAAAADAAMAAAEOXAlQytNS409KC9KIXKbKBIoUQRBigqwQLAxDAh0HgA8wPq7X+9H3A2DSJ6gx+wJDs3mYXFYNp+LCAAh+QQFBQALACwCAAMACAADAAAECnDJUuQKweotRAQAIfkEBQUACwAsAgADAAgABAAABAxwyRDkEsJarLsFQAQAIfkEBQUACwAsAgACAAgABQAABAtwyRCkvThjCsClEQAh+QQFBQALACwCAAIACAAFAAAEC3DJMaS9OGMhQsgRACH5BAUFAAsALAIAAwAIAAQAAAQLcMlSpL0yBMwXABEAIfkEBQUACwAsAgAEAAgAAwAABAkwhEXIujjrKyMAIfkEBQUACwAsAgADAAgAAwAABAowhEWrpbIKsWQEACH5BAUFAAsALAIAAwAIAAMAAAQJkJBFq6VC3JUjACH5BAUFAAsALAUABQAFAAEAAAQEMIQlIwAh+QQFBQALACwCAAQACAACAAAECFAIEoK8ot4IADs=';
	
	
document.addEventListener('click', function(event) {

	//left mouse button
	if(event.which==1) {

		for (var i = 0; i < allUserLinks.snapshotLength; i++) {
			thisUserLink = allUserLinks.snapshotItem(i);

			if(event.target==thisUserLink) {
			
				//replace trailing whitespace, then trailing /
				var user = event.target.href.substr(event.target.href.indexOf("/user/")+6).replace(/^[ \t]+|[ \t]+$/gim,"").replace(/\/$/,"");
				
				//make sure it's a valid last.fm username
				if(user.search(/[\s!@#$%&*[()+={}|;:'"<,>.?\/~`\\\^\]]/gi)==-1) {
				
					if(!document.getElementById("compatBox" + user)) {
						
						var compatBox = document.createElement("div");
						compatBox.id = "compatBox" + user;
						compatBox.style.position = "absolute";
						
						compatBox.style.top = event.pageY + 2 + "px";
						compatBox.style.backgroundColor = "#ffffff";
						compatBox.style.border = "2px solid #ababab";
						compatBox.style.fontSize = "11px";
						compatBox.style.fontFamily = '"Lucida Grande",Arial,Helvetica,Verdana,sans-serif';
						compatBox.style.color = '#1B1B1B';
						compatBox.style.lineHeight = "1.18182em";
						compatBox.style.padding = "1px";
						compatBox.style.MozBorderRadius = "4px";
						//compatBox.style.MozBoxShadow = "0px 0px 2px 1px rgba(0,0,0,0.25)";
						compatBox.innerHTML = '<img src="data:image/gif;base64,' + loadingIcon + '">';
						document.body.appendChild(compatBox);
						compatBox = document.getElementById("compatBox" + user);
						compatBox.style.left = event.pageX + "px"; //center
						
						getCompat(user);
						
						}
						
					else document.body.removeChild(document.getElementById("compatBox" + user));
					
					}
			
				}
			
			}
			
			if(event.target.id=="highlightButton") {
				var r1 = document.createRange();
				r1.setStartBefore(event.target.parentNode.parentNode.getElementsByTagName("p")[0]);
				r1.setEndAfter(event.target.parentNode.parentNode.getElementsByTagName("p")[1]);
				window.getSelection().addRange(r1);
				}
				
			else if(event.target.id=="highlightRTButton") {
				var r1 = document.createRange();
				r1.setStartBefore(event.target.parentNode.parentNode.getElementsByTagName("p")[0]);
				r1.setEndAfter(event.target.parentNode.parentNode.getElementsByTagName("ul")[0]);
				window.getSelection().addRange(r1);
				}
				
			else if(event.target.id=="highlightTAButton") {
				var r1 = document.createRange();
				r1.setStartBefore(event.target.parentNode.parentNode.getElementsByTagName("p")[0]);
				r1.setEndAfter(event.target.parentNode.parentNode.getElementsByTagName("table")[0]);
				window.getSelection().addRange(r1);
				}
				
			else if(event.target.id=="highlightTTButton") {
				var r1 = document.createRange();
				r1.setStartBefore(event.target.parentNode.parentNode.getElementsByTagName("p")[0]);
				r1.setEndAfter(event.target.parentNode.parentNode.getElementsByTagName("table")[0]);
				window.getSelection().addRange(r1);
				}
				
			else if(event.target.id=="moreButton") {
			
				event.target.id = "lessButton";
				event.target.innerHTML = "Less";
				if(event.target.parentNode.parentNode.lastChild.tagName!="DIV") {
				
					getRT(event.target.parentNode.parentNode.getElementsByTagName("strong")[0].innerHTML);
					getTA(event.target.parentNode.parentNode.getElementsByTagName("strong")[0].innerHTML);
					getTT(event.target.parentNode.parentNode.getElementsByTagName("strong")[0].innerHTML);
					getSES(event.target.parentNode.parentNode.getElementsByTagName("strong")[0].innerHTML);
				
					event.target.parentNode.parentNode.innerHTML += '<div id="moreContent">' +
					'<div id="recentTracks" style="text-align: center;"><img src="data:image/gif;base64,' + loadingIcon + '"></div>' +
					'<div id="topArtists" style="text-align: center;"><img src="data:image/gif;base64,' + loadingIcon + '"></div>' +
					'<div id="topTracks" style="text-align: center;"><img src="data:image/gif;base64,' + loadingIcon + '"></div>' +
					'<div id="superEclecticScore" style="text-align: center; padding-bottom: 0px;"><img src="data:image/gif;base64,' + loadingIcon + '"></div>' +
					'</div>';
					
					
					
					
					}
					
				else event.target.parentNode.parentNode.lastChild.style.display = "inline";
				
			
				}
				
			else if(event.target.id=="lessButton") {
			
				event.target.id = "moreButton";
				event.target.innerHTML = "More";
				event.target.parentNode.parentNode.lastChild.style.display = "none";
			
				}
				
			else if(event.target.id=="refreshButton") {
			
				getRT(event.target.parentNode.parentNode.getElementsByTagName("strong")[0].innerHTML);
				event.target.style.display = "none";
				event.target.parentNode.innerHTML += '<img src="data:image/gif;base64,' + loadingIcon + '" style="height: 10px; width: 10px;">';
			
				}
		
		}

	}, true);
	
function hideOtherInfo(except) {

	if(typeof except!="string") except = "none";

	if(except!="recentTracksList") {
	
		var allLi = document.getElementById("recentTracksList").childNodes;
		
		for(var i=3; i < allLi.length; i++) {
	
			allLi[i].style.display = "none";
			
			}
	
		}
	
	if(except!="topArtistsList") {
	
		var allTb = document.getElementById("topArtistsList").childNodes;
		
		for(var i=5; i < allTb.length; i++) {
	
			allTb[i].firstChild.style.display = "none";
			
			}
	
		}
		
	if(except!="topTracksList") {
	
		var allTb = document.getElementById("topTracksList").childNodes;
		
		for(var i=5; i < allTb.length; i++) {
	
			allTb[i].firstChild.style.display = "none";
			
			}
	
		}

	}
	
//mouseover listener for showing full info
	
document.addEventListener('mouseover', function(event) {
	
	if((event.target.tagName=="LI") && (event.target.parentNode.id=="recentTracksList")) {
	
		var allLi = event.target.parentNode.childNodes;
		
		for(var i=0; i < allLi.length; i++) {
	
			allLi[i].style.display = "block";
			
			}
			
		hideOtherInfo("recentTracksList");
	
		}
		
	if((event.target.tagName=="TD") && (event.target.parentNode.parentNode.parentNode.id=="topArtistsList")) {
	
		var allTb = event.target.parentNode.parentNode.parentNode.childNodes;
		
		for(var i=0; i < allTb.length; i++) {
	
			allTb[i].firstChild.style.display = "table-row";
			
			}
			
		hideOtherInfo("topArtistsList");
	
		}
		
	if((event.target.tagName=="TD") && (event.target.parentNode.parentNode.parentNode.id=="topTracksList")) {
	
		var allTb = event.target.parentNode.parentNode.parentNode.childNodes;
		
		for(var i=0; i < allTb.length; i++) {
	
			allTb[i].firstChild.style.display = "table-row";
			
			}
			
		hideOtherInfo("topTracksList");
	
		}

	}, false);
	
	
function getRT(_user) {

	GM_xmlhttpRequest({
		method: 'GET',
		url: 'http://ws.audioscrobbler.com/2.0/user/' + _user + '/recenttracks.xml',
		headers: {
			'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
			'Accept': 'text/xml',
			},
		onload: function(details) {
			var myCompatBox, myRTBox; 
			//make sure the compatBox is still there
			if( (myCompatBox = document.getElementById("compatBox" + _user)) && (myRTBox = myCompatBox.lastChild.firstChild) ) {
			
				details.responseXML = new DOMParser().parseFromString(details.responseText, "text/xml");
				myRTBox.style.textAlign = "left";
				myRTBox.innerHTML = '<div style="position: absolute; right: 6px; -moz-user-select: none;">' +
				'<a id="highlightRTButton" style="cursor: pointer;">Highlight</a> | <a id="refreshButton" style="cursor: pointer;">Refresh</a>' +
				'</div>' +
				'<p style="margin-bottom: 4px;"><strong>' + _user + "</strong>'s" + ' <a href="http://www.last.fm/user/' + _user + '/tracks">Recent Tracks</a></p>';
				var myList = document.createElement("ul");
				myList.id = "recentTracksList";
				myList.style.width = "100%";
				myList.style.padding = "0px";
				myList.style.margin = "0px";
				myList.style.listStyle = "none";
				myList.style.borderTop = "1px solid rgb(221, 221, 221)";
					
				function parseUTS(uts) {
				
					var currentTime = new Date();
					var currentUTS = currentTime.getTime(); currentUTS = currentUTS / 1000;
					var diff = currentUTS - uts;
					
					if(diff >= 63072000) return (Math.floor(diff/31536000)) + " years ago";
					else if(diff >= 31536000) return "a year ago";
					else if(diff >= 5256000) return (Math.floor(diff/2628000)) + " months ago";
					else if(diff >= 2628000) return "a month ago";
					else if(diff >= 1209600) return (Math.floor(diff/604800)) + " weeks ago";
					else if(diff >= 604800) return "a week ago";
					else if(diff >= 172800) return (Math.floor(diff/86400)) + " days ago";
					else if(diff >= 86400) return "a day ago";
					else if(diff >= 7200) return (Math.floor(diff/3600)) + " hours ago";
					else if(diff >= 3600) return "an hour ago";
					else if(diff >= 120) return (Math.floor(diff/60)) + " minutes ago";
					else if(diff >= 60) return "a minute ago";
					else if(diff > 0) return "seconds ago";
					else if(diff >= -120) return "now";
					else if(diff < -120) return "in the future";
					else return "sometime";
				
					}
					
				//need to make sure all tags/children exists, especially <album>
				
				var tracks = details.responseXML.getElementsByTagName("track");
				for(var i=0; i < tracks.length; i++) {
				
					var npString = "", defaultDisplay = "", artistURL = "http://www.last.fm/", trackURL = "http://www.last.fm/", artist = "someone", name = "something", album = "that has no name", date = "sometime", time = 9999999999;
				
					if(i>2) defaultDisplay = " display: none;";
				
					//have to put all this stuff in try/catch statement because the node may not exist or may have no content
				
					try {
						if(tracks[i].getAttribute("nowplaying")=="true") npString = ' background: url(data:image/gif;base64,' + eqIcon + ') no-repeat rgb(255, 252, 201) 3px 3px;';
						}
						catch(e) {}
					
					try{
						artistURL = tracks[i].getElementsByTagName("url")[0].firstChild.nodeValue.split("/_/")[0];
						}
						catch(e) {}
					
					try{
						trackURL = tracks[i].getElementsByTagName("url")[0].firstChild.nodeValue;
						}
						catch(e) {}
					
					try{
						artist = tracks[i].getElementsByTagName("artist")[0].firstChild.nodeValue;
						}
						catch(e) {}
					
					try{
						name = tracks[i].getElementsByTagName("name")[0].firstChild.nodeValue;
						}
						catch(e) {}
					
					try{
						album = tracks[i].getElementsByTagName("album")[0].firstChild.nodeValue;
						}
						catch(e) {}
					
					try{
						date = tracks[i].getElementsByTagName("date")[0].firstChild.nodeValue;
						}
						catch(e) {}
					
					try{
						time = parseInt(tracks[i].getElementsByTagName("date")[0].getAttribute("uts"));
						}
						catch(e) {}
					
				
					myList.innerHTML += '<li style="background-color: rgba(235,235,235,' + (i/10) + ');' + npString + defaultDisplay + '"><a href="' + artistURL + '">' + artist + '</a> - <a href="' + trackURL + '" title="On the album ' + album + '">' + name + '</a><div style="position: absolute; right: 10px; display: inline; color: #999999;" title="' + date + ' UTC">' + parseUTS(time) + '</div></li>';
				
					}
					
				myRTBox.appendChild(myList);
				
				myCompatBox.style.left = ((1 - (myCompatBox.offsetWidth / window.innerWidth))*50) + "%"; //recenter
				
				}
			
			}
			
		});
			
	}
	
function getTA(_user) {

	GM_xmlhttpRequest({
		method: 'GET',
		url: 'http://ws.audioscrobbler.com/2.0/user/' + _user + '/topartists.xml',
		headers: {
			'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
			'Accept': 'text/xml',
			},
		onload: function(details) {
			var myCompatBox, myTABox;
			//make sure the compatBox is still there
			if( (myCompatBox = document.getElementById("compatBox" + _user)) && (myTABox = myCompatBox.lastChild.childNodes[1]) ) { 
			
				details.responseXML = new DOMParser().parseFromString(details.responseText, "text/xml");
				myTABox.style.textAlign = "left";
				myTABox.innerHTML = '<div style="position: absolute; right: 6px; -moz-user-select: none;">' +
				'<a id="highlightTAButton" style="cursor: pointer;">Highlight</a>' +
				'</div>' +
				'<p style="margin-bottom: 4px;"><strong>' + _user + "</strong>'s" + ' <a href="http://www.last.fm/user/' + _user + '/charts?rangetype=overall&subtype=artists">Top Artists</p>';
				var myList = document.createElement("table");
				myList.id = "topArtistsList";
				myList.style.width = "100%";
				myList.style.padding = "0px";
				myList.style.margin = "0px";
				myList.align = "left";
				myList.style.borderSpacing = "0";
				myList.style.borderTop = "1px solid rgb(221, 221, 221)";
				
				
			
				var artists = details.responseXML.getElementsByTagName("artist");
				var modLength = artists.length; if(modLength > 15) modLength = 15;
				var topCount = 1;
				for(var i=0; i < modLength; i++) {
				
					var defaultDisplay = "", rank= (i+1), artistURL = "http://www.last.fm/", artist = "someone", playcount = "0";
					
					if(i>4) defaultDisplay = " display: none;";
				
					//have to put all this stuff in try/catch statement because the node may not exist or may have no content
					
					try{
						rank = artists[i].getAttribute("rank");
						}
						catch(e) {}
					
					try{
						artistURL = artists[i].getElementsByTagName("url")[0].firstChild.nodeValue;
						}
						catch(e) {}
					
					try{
						artist = artists[i].getElementsByTagName("name")[0].firstChild.nodeValue;
						}
						catch(e) {}
					
					try{
						playcount = parseInt(artists[i].getElementsByTagName("playcount")[0].firstChild.nodeValue);
						if(topCount==1) topCount = playcount;
						}
						catch(e) {}
					
				
					myList.innerHTML += '<tr style="background-color: rgba(235,235,235,' + (i/10) + ');' + defaultDisplay + '"><td title="' + (i+1) + '">' + rank + '</td><td><a href="' + artistURL + '">' + artist + '</a></td><td style="color: #999999;"><div class="chartBar" style="width: ' + ((playcount/topCount) * 100) + '%;"><span>' + playcount + '</span></div></td></tr>';
				
					}
					
				myTABox.appendChild(myList);
				
				myCompatBox.style.left = ((1 - (myCompatBox.offsetWidth / window.innerWidth))*50) + "%"; //recenter
				
				}
			
			}
			
		});
			
	}
	

function getTT(_user) {

	GM_xmlhttpRequest({
		method: 'GET',
		url: 'http://ws.audioscrobbler.com/2.0/user/' + _user + '/toptracks.xml',
		headers: {
			'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
			'Accept': 'text/xml',
			},
		onload: function(details) {
			var myCompatBox;
			//make sure the compatBox is still there
			if( (myCompatBox = document.getElementById("compatBox" + _user)) && (myTTBox = myCompatBox.lastChild.childNodes[2]) ) { 
			
				details.responseXML = new DOMParser().parseFromString(details.responseText, "text/xml");
				myTTBox.style.textAlign = "left";
				myTTBox.innerHTML = '<div style="position: absolute; right: 6px; -moz-user-select: none;">' +
				'<a id="highlightTTButton" style="cursor: pointer;">Highlight</a>' +
				'</div>' +
				'<p style="margin-bottom: 4px;"><strong>' + _user + "</strong>'s" + ' <a href="http://www.last.fm/user/' + _user + '/charts?rangetype=overall&subtype=tracks">Top Tracks</p>';
				var myList = document.createElement("table");
				myList.id = "topTracksList";
				myList.style.width = "100%";
				myList.style.padding = "0px";
				myList.style.margin = "0px";
				myList.align = "left";
				myList.style.borderSpacing = "0";
				myList.style.borderTop = "1px solid rgb(221, 221, 221)";
				
				
			
				var tracks = details.responseXML.getElementsByTagName("track");
				var modLength = tracks.length; if(modLength > 15) modLength = 15;
				var topCount = 1;
				for(var i=0; i < modLength; i++) {
				
					var defaultDisplay = "", rank = (i+1), artistURL = "http://www.last.fm/", artist = "someone", trackURL = "http://www.last.fm/", name = "something", playcount = "0";
					
					if(i>4) defaultDisplay = " display: none;";
				
					//have to put all this stuff in try/catch statement because the node may not exist or may have no content
					
					try{
						rank = tracks[i].getAttribute("rank");
						}
						catch(e) {}
					
					try{
						artistURL = tracks[i].getElementsByTagName("artist")[0].getElementsByTagName("url")[0].firstChild.nodeValue;
						}
						catch(e) {}
					
					try{
						artist = tracks[i].getElementsByTagName("artist")[0].getElementsByTagName("name")[0].firstChild.nodeValue;
						}
						catch(e) {}
						
					try{
						trackURL = tracks[i].getElementsByTagName("url")[0].firstChild.nodeValue;
						}
						catch(e) {}
						
					try{
						name = tracks[i].getElementsByTagName("name")[0].firstChild.nodeValue;
						}
						catch(e) {}
					
					try{
						playcount = parseInt(tracks[i].getElementsByTagName("playcount")[0].firstChild.nodeValue);
						if(topCount==1) topCount = playcount;
						}
						catch(e) {}
					
				
					myList.innerHTML += '<tr style="background-color: rgba(235,235,235,' + (i/10) + ');' + defaultDisplay + '"><td title="' + (i+1) + '">' + rank + '</td><td><a href="' + artistURL + '">' + artist + '</a> - <a href="' + trackURL + '">' + name + '</a></td><td style="color: #999999;"><div class="chartBar" style="width: ' + ((playcount/topCount) * 100) + '%;"><span>' + playcount + '</span></div></td></tr>';
				
					}
					
				myTTBox.appendChild(myList);
				
				myCompatBox.style.left = ((1 - (myCompatBox.offsetWidth / window.innerWidth))*50) + "%"; //recenter
				
				}
			
			}
			
		});
			
	}
	
function findScore(content) {

	var x = content.indexOf('<center><font size="18"><b>') + 27;
	if(x <= 26) return "0";

	var y = content.indexOf('/', x); 
	if(y == -1) return "0";

	return content.slice(x, y);

	}
	
function getSES(_user) {

	GM_xmlhttpRequest({
		method: 'GET',
		url: 'http://anthony.liekens.net/pub/scripts/last.fm/supereclectic.php?user=' + _user,
		headers: {
			'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
			'Accept': 'text/html, text/plain',
			},
		onload: function(details) {
			var myCompatBox;
			//make sure the compatBox is still there
			if( (myCompatBox = document.getElementById("compatBox" + _user)) ) { 
			
				var score = findScore(details.responseText);
			
				myCompatBox.lastChild.lastChild.innerHTML = '<p><strong>' + _user + '</strong>' + "'s" + ' <a href="http://anthony.liekens.net/pub/scripts/last.fm/supereclectic.php?user=' + _user + '" title="A measurement of a user' + "'s" + ' musical diversity">Super Eclectic Score</a> is <strong><span style="color: hsl(' + (0.255 * parseInt(score) - 20) + ', 90%, ' + ((0.1 * parseInt(score)) / 2 + 30) + '%);">' + score + '</span>/1000</strong></p>';
				
				}
			
			}
			
		});
			
	}
	
	
function getCompat(_user) {

	GM_xmlhttpRequest({
		method: 'GET',
		url: 'http://www.last.fm/user/' + _user + '/tasteomatic',
		headers: {
			'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
			'Accept': 'text/plain, text/html',
			},
		onload: function(details) {
			var myCompatBox;
			//make sure the compatBox is still there, and make sure the response text isn't the error page
			if((myCompatBox = document.getElementById("compatBox" + _user)) && (details.responseText.indexOf("<div")==-1)) { myCompatBox.innerHTML = details.responseText +
			'<div style="position: absolute; top: 5px; right: 6px; -moz-user-select: none;">' +
			'<a id="highlightButton" style="cursor: pointer;">Highlight</a>' +
			' <span style="position: relative; bottom: 1px;">|</span> ' +
			'<a id="moreButton" style="cursor: pointer;">More</a>' +
			'</div>';
			
			//have to fix the library links underneath the compatibility bar
			var allLibraryLinks, thisLibraryLink;
			allLibraryLinks = document.evaluate(
				"//div[@id='compatBox" + _user + "']//a[@href]",
				document.body,
				null,
				XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
				null);
			for (var i = 0; i < allLibraryLinks.snapshotLength; i++) {
				thisLibraryLink = allLibraryLinks.snapshotItem(i);
				thisLibraryLink.href = "http://www.last.fm/user/" + thisLibraryLink.href.substr(thisLibraryLink.href.indexOf(_user + "/"));
				}
			
			}
			else myCompatBox.innerHTML = 'Error: User not found';
			//add the style to the div
			var myStyle = document.createElement("style");
			myStyle.type = "text/css";
			myStyle.innerHTML = '#' + myCompatBox.id + ' span.bar {' +
			'-moz-background-clip:border;' +
			'-moz-background-inline-policy:continuous;' +
			'-moz-background-origin:padding;' +
			'-moz-border-radius-bottomleft:3px;' +
			'-moz-border-radius-bottomright:3px;' +
			'-moz-border-radius-topleft:3px;' +
			'-moz-border-radius-topright:3px;' +
			'background:#CCCCCC none repeat scroll 0 0;' +
			'display:block;' +
			'height:8px;' +
			'margin:5px 0;' +
			'overflow:hidden;' +
			'width:100%;' +
			'position:relative;' +
			'}' +
			'#' + myCompatBox.id + ' span.bar span {' +
			'-moz-border-radius-bottomleft:3px;' +
			'-moz-border-radius-bottomright:3px;' +
			'-moz-border-radius-topleft:3px;' +
			'-moz-border-radius-topright:3px;' +
			'display:block;' +
			'height:8px;' +
			'}' +
			'#' + myCompatBox.id + ' span.verylow span {' +
			'-moz-background-clip:border;' +
			'-moz-background-inline-policy:continuous;' +
			'-moz-background-origin:padding;' +
			'background:#9A9A9A none repeat scroll 0 0;' +
			'}' +
			'#' + myCompatBox.id + ' span.low span {' +
			'-moz-background-clip:border;' +
			'-moz-background-inline-policy:continuous;' +
			'-moz-background-origin:padding;' +
			'background:#453E45 none repeat scroll 0 0;' +
			'}' +
			'#' + myCompatBox.id + ' span.medium span {' +
			'-moz-background-clip:border;' +
			'-moz-background-inline-policy:continuous;' +
			'-moz-background-origin:padding;' +
			'background:#5336BD none repeat scroll 0 0;' +
			'}' +
			'#' + myCompatBox.id + ' span.high span {' +
			'-moz-background-clip:border;' +
			'-moz-background-inline-policy:continuous;' +
			'-moz-background-origin:padding;' +
			'background:#05BD4C none repeat scroll 0 0;' +
			'}' +
			'#' + myCompatBox.id + ' span.veryhigh span {' +
			'-moz-background-clip:border;' +
			'-moz-background-inline-policy:continuous;' +
			'-moz-background-origin:padding;' +
			'background:#E9C102 none repeat scroll 0 0;' +
			'}' +
			'#' + myCompatBox.id + ' span.super span {' +
			'-moz-background-clip:border;' +
			'-moz-background-inline-policy:continuous;' +
			'-moz-background-origin:padding;' +
			'background:#FF0101 none repeat scroll 0 0;' +
			'}' +
			'#' + myCompatBox.id + ' p {' +
			'margin: 1px;' +
			'padding: 0' + 
			'}' +
			'#' + myCompatBox.id + ' a {' +
			'color:#0187C5;' +
			'outline-color:-moz-use-text-color;' +
			'outline-style:none;' +
			'outline-width:medium;' +
			'text-decoration:none;' +
			'}' +
			'#' + myCompatBox.id + ' #recentTracksList li {' +
			'padding: 2px 3px 3px 17px;' +
			'border: 1px solid rgb(221, 221, 221);' +
			'border-top-width: 0px;' +
			'}' +
			'#' + myCompatBox.id + ' table td {' +
			'padding: 2px 3px 3px 3px;' +
			'border: 1px solid rgb(221, 221, 221);' +
			'border-top-width: 0px;' +
			'}' +
			'#' + myCompatBox.id + ' table td:first-child {' +
			'border-right-width: 0px;' +
			'padding-right: 3px;' +
			'padding-left: 2px;' +
			'text-align: right;' +
			'width: 11px;' +
			'}' +
			'#' + myCompatBox.id + ' table td:nth-child(2) {' +
			'border-left-width: 0px;' +
			'border-right-width: 0px;' +
			'padding-left: 0px;' +
			'width: 5%;' +
			'white-space: nowrap;' +
			'}' +
			'#' + myCompatBox.id + ' table td:last-child {' +
			'border-left-width: 0px;' +
			'padding-left: 20%;' +
			'padding-bottom: 1px;' +
			'padding-top: 1px;' +
			'}' +
			'#' + myCompatBox.id + ' div .chartBar {' +
			'background-color: #71b7e6;' +
			'-moz-border-radius: 0px 3px 3px 0px;' +
			'height: 17px;' +
			'}' +
			'#' + myCompatBox.id + ' div .chartBar span {' +
			'background-color: #71b7e6;' +
			'color: white;' +
			'padding: 0px;' +
			'margin: 2px 3px 0px 3px;' +
			'font-size: 10px;' +
			'position: relative;' +
			'top: 2px;' +
			'-moz-border-radius: 0px 3px 3px 0px;' +
			'}' +
			'#' + myCompatBox.id + ' a:hover {' +
			'text-decoration: underline;' +
			'}' +
			'#' + myCompatBox.id + ' li:hover {' +
			'background-color: #d0f4e0 !important;' +
			'}' +
			'#' + myCompatBox.id + ' tr:hover {' +
			'background-color: #d0f4e0 !important;' +
			'}' +
			'#' + myCompatBox.id + ' #moreContent > div {' +
			'border-width: 0px;' +
			'border-top-width: 1px;' +
			'border-style: dotted;' +
			'border-top-color: #cccccc;' +
			'margin-top: 4px;' +
			'padding: 4px 0px 4px 0px;' +
			'overflow: auto;' +
			'}';
			
			myCompatBox.style.padding = "4px";
			myCompatBox.style.minWidth = "445px";
			
			myCompatBox.appendChild(myStyle);
			myCompatBox.style.left = ((1 - (myCompatBox.offsetWidth / window.innerWidth))*50) + "%"; //recenter

			}
		});

	}