// ==UserScript== // @name Last.fm - Recently Played // @description Adds recently played information in various places around Last.fm // @include http://*.last.fm/* // ==/UserScript== // By BooooooooB - http://www.last.fm/BooooooooB // Version 3.1 /** * Copyright (C) 2008 Robert Wallis * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * */ // Add styles lastFmRecentlyPlayed_addGlobalStyle( 'ul.usersSmall li { width: 100% !important; }' + 'ul.usersSmall span.userImage { margin-left: -78px !important; }' + 'ul.usersSmall li div { padding-left: 78px !important; }' + 'ul.usersSmall span.userImage img { margin-right: 5px !important; }' + 'span.recentlyPlayed_outer { font-size: 0.8em; display: block; padding-left: 80px; color: #555; }' + 'span.recentlyPlayed_inner { font-weight: bold; color: #444; }' ); window.lastFmRecentlyPlayed_init = function() { var usersSmall = document.getElementsByClassName( 'usersSmall' ), i, j, usersSmallImages; for( i = 0 ; i < usersSmall.length ; i++ ) { usersSmallImages = usersSmall[i].getElementsByTagName( 'img' ); for( j = 0 ; j < usersSmallImages.length ; j++ ) { // Replace the small profile picture with a medium sized one if( usersSmallImages[j].className.indexOf( 'subscriber_icon' ) == -1 ) { usersSmallImages[j].src = usersSmallImages[j].src.replace( '\/34s\/', '\/64\/' ).replace( 'default_user_small.png', 'default_user_medium.png' ); usersSmallImages[j].removeAttribute( 'width' ); // The 34x34 ones are square, but the 64 ones might not be, so remove the sizing constraints usersSmallImages[j].removeAttribute( 'height' ); } } } // Add the recently played data window.lastFmRecentlyPlayed_update(); }; window.addEventListener( 'load', window.lastFmRecentlyPlayed_init, true ); window.lastFmRecentlyPlayed_update = function() { var usersSmall = document.getElementsByClassName( 'usersSmall' ), i, j, usersSmallLis, username; for( i = 0 ; i < usersSmall.length ; i++ ) { usersSmalLis = usersSmall[i].getElementsByTagName( 'li' ); for( j = 0 ; j < usersSmalLis.length ; j++ ) { // Get the username try { username = usersSmall[i].getElementsByClassName( 'nickname' )[j].innerHTML; } catch( e ) { username = ( usersSmalLis[j].getElementsByTagName( 'a' )[0].innerHTML ).replace(/\<.*\>/, '' ).replace( ' ', '' ); } console.log('username:'+username); // If we haven't already added the container to ut the recently played stats in, then do so if( usersSmalLis[j].getElementsByClassName( 'recentlyPlayed_' + username )[0] == undefined ) { usersSmalLis[j].innerHTML += ''; } // Add the recently played data for this user to the appropriate target element window.lastFmRecentlyPlayed_updateBlock( username, usersSmalLis[j].getElementsByClassName( 'recentlyPlayed_' + username )[0] ); } } window.setTimeout( window.lastFmRecentlyPlayed_update, 60000*5 ); }; window.lastFmRecentlyPlayed_updateBlock = function( username, target ) { GM_xmlhttpRequest( { method: 'GET', url: 'http://ws.audioscrobbler.com/1.0/user/' + username + '/recenttracks.xml', onload: function( details ) { var username = details.responseText.slice( details.responseText.indexOf( 'user="' ) + 6, details.responseText.indexOf( '"', details.responseText.indexOf( 'user="' ) + 6 ) ); var recentArtist = ''; var recentTrack = ''; var recentTime = 0; var recentHTML = ''; if( ( details.responseText ).indexOf( '' ) != -1 ) { recentArtist = ( details.responseText ).slice( ( details.responseText ).indexOf( '>', ( details.responseText ).indexOf( '' ) ); recentTrack = ( details.responseText ).slice( ( details.responseText ).indexOf( '' ) + 6, ( details.responseText ).indexOf( '' ) ); recentTime = ( details.responseText ).slice( ( details.responseText ).indexOf( '' + recentTrack + '' + 'by: ' + recentArtist + '' + '' + recentDate.toTimeSinceString() + ' ago'; } target.innerHTML = recentHTML; } } ); }; function lastFmRecentlyPlayed_addGlobalStyle( css ) { var head, style; head = document.getElementsByTagName( 'head' )[0]; if( ! head ) { return; } style = document.createElement( 'style' ); style.type = 'text/css'; style.innerHTML = css; head.appendChild( style ); } /* ================================================================================================= * Time Since * January 16, 2004 * * Time Since creates a string which friendly tells you the time since the original date * Based on the original time_since() function by Natalie Downe - http://blog.natbat.co.uk/archive/2003/Jun/14/time_since * * Copyright (c) 2004 Mark Wubben - http://neo.dzygn.com/ * * Usage: date.toTimeSinceString(number nLimit, string sBetween, string sLastBetween) * nLimit: limit the shown time units (year, month etc). default = 2 * sBetween: string between two time units. default = ", " * sLastBetween: string between the second-last and last time unit. default = " and " ==================================================================================================*/ Date.prototype.toTimeSinceString = function( nLimit, sBetween, sLastBetween ) { if(!nLimit){ nLimit = 2; } if(!sBetween){ sBetween = ", "; } if(!sLastBetween){ sLastBetween = " and "; } if(!Date.prototype.toTimeSinceString._collStructs){ Date.prototype.toTimeSinceString._collStructs = new Array( {seconds: 60 * 60 * 24 * 365, name: "year"}, {seconds: 60 * 60 * 24 * 30, name: "month"}, {seconds: 60 * 60 * 24 * 7, name: "week"}, {seconds: 60 * 60 * 24, name: "day"}, {seconds: 60 * 60, name: "hour"}, {seconds: 60, name: "minute"} ); } var collStructs = Date.prototype.toTimeSinceString._collStructs; var nSecondsRemain = ((new Date).valueOf() - this.valueOf()) / 1000; var sReturn = ""; var nCount = 0; var nFloored; for(var i = 0; i < collStructs.length && nCount < nLimit; i++){ nFloored = Math.floor(nSecondsRemain / collStructs[i].seconds); if(nFloored > 0){ if(sReturn.length > 0){ if(nCount == nLimit - 1 || i == collStructs.length - 1){ sReturn += sLastBetween; } else if(nCount < nLimit && i < collStructs.length){ sReturn += sBetween; } } sReturn += nFloored + " " + collStructs[i].name; if(nFloored > 1){ sReturn += "s"; } nSecondsRemain -= nFloored * collStructs[i].seconds; nCount++; } } return sReturn; };