// ==UserScript== // @name Last.fm - Polish the profile // @namespace http://no.name.space/ // @description Display percentage of plays and statistics on user profile // @include http://www.last.fm/user/* // @include http://www.lastfm.fr/user/* // @include http://www.lastfm.de/user/* // @include http://www.lastfm.it/user/* // @include http://www.lastfm.se/user/* // @include http://www.lastfm.es/user/* // @include http://www.lastfm.com.br/user/* // @exclude http://www.last.fm/user/*/group* // @version 0.0.1.20140511024802 // @downloadURL https://update.greasyfork.icu/scripts/774/Lastfm%20-%20Polish%20the%20profile.user.js // @updateURL https://update.greasyfork.icu/scripts/774/Lastfm%20-%20Polish%20the%20profile.meta.js // ==/UserScript== //Changelog: //2005-08-14 arvid.jakobsson@gmail.com 1.0 - Initial version of percentage script //2005-12-16 _m.lenzen@gmail.com - modified version to display more detail and lower threshold //2006-12-29 m.lenzen@gmail.com - Modified to work with the latest last.fm changes // 2007-03-27 snyde1 - fix for Opera // 2007-04-28 snyde1 - merge stats and text colour fix, optimise the math // 2007-04-04 snyde1 - set up comma separation for numbers > 1000 // 2007-08-08 snyde1 - add "landmark" track plays and then album stats and position limits // 2007-08-11 snyde1 - add album section and limits, reorganise // 2007-08-12 snyde1 - add internationalisation (FR, DE, SE, ES, PT, IT) // 2008-01-09 snyde1 - add support for time period used on profile // 2008-09-17 snyde1 - fix for recent format change // 2008-09-20 - remove landmarks, add tracker link, move tracks played around // 2008-09-25 - fix non-English sites // 2009-03-25 - fix header for top tracks // Initiation values // Set the following to zero (0) to disable var noFlip = 1; // Get rid of background images var darkText = 1; // Make text over bar the colour set below (darkTextClr) var doPCTage = 1; // Include percentage of plays for the bars var doStats = 1; // Include monthly/weekly/etc. breakdown of plays var limitCount = 25; // limit line count in artist/track charts ... set to 0 (or over 50) to ignore var squishRecent = 0; // merge lines in recent tracks var squishLibrary = 1; // collapse pictures in Library var addAlbum = 0; // add block for album stats - can be time consuming var useBasis = 0; // Add notation when using weekly stats rather than overall // Colour for dark text var darkTextClr = "#338"; // Change this to the number of decimal places you wish displayed var num_dec = 1; /* BEGIN LICENSE BLOCK Copyright (C) 2005 Arvid Jakobsson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You can download a copy of the GNU General Public License at http://www.gnu.org/licenses/gpl.html or get a free printed copy by writing to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. END LICENSE BLOCK */ var monthStr = new Array(); monthStr[0] = "Jan"; monthStr[1] = "Feb"; monthStr[2] = "Mar"; monthStr[3] = "Apr"; monthStr[4] = "May"; monthStr[5] = "Jun"; monthStr[6] = "Jul"; monthStr[7] = "Aug"; monthStr[8] = "Sep"; monthStr[9] = "Oct"; monthStr[10] = "Nov"; monthStr[11] = "Dec"; // Regexps for languages // English (default) var regDateRE = /since ([^<]*)depuis le ([^<]*)seit ([^<]*)sedan ([^<]*)desde ([^<]*)desde ([^<]*)dal ([^<]*) 0) { panelText = panelPart.snapshotItem(0).innerHTML; tracksplayed = panelText.replace(//ig,""); tracksplayed = tracksplayed.replace(/<.span>/ig,""); if (noFlip == 1) { panelPart.snapshotItem(0).innerHTML = tracksplayed; } tracksplayed = tracksplayed.replace(/[^0-9]/g,""); } else { var panel = document.getElementById("hcard-"+username); panelText = panel.innerHTML+""; panelText = panelText.match(/(.*)<\/span>/i)[1]; var tracksplayed = panelText.match(/([^ ]*) [^0-9]/i)[1]+""; tracksplayed = tracksplayed.replace(/[^0-9]/g,''); } if (!tracksplayed){ return; } var reg_date = panel.innerHTML.match(regDateRE)[1]; if (!reg_date) { return; } if (panel.innerHTML.match(rstDataRE)) { var up_Date = panel.innerHTML.match(rstDateRE)[1]; if (up_Date) { reg_date = up_Date; } } // Language specific date if (! location.href.match(/www\.last\.fm\//)){ reg_date = reg_date.replace(/^ */,""); var fr_date = new Array; fr_date = reg_date.split(/ /); reg_date = fr_date[0]+" "+monthN[fr_date[1]]+" "+fr_date[2]; reg_date = reg_date.replace(/\./g,""); // Just for German } var reg_date_ms = Date.parse(reg_date); var now = new Date(); var now_ms = Date.parse(now); var diff = Math.round((now_ms - reg_date_ms)/1000); // Add tracker link var userText = userData.snapshotItem(0).innerHTML+""; if (userText.match(/\/grapevine[^<]*<\/a>/i)) { var repTrackBack = userText.match(/grapevine[^<]*<.a>/i); repTrackBack += " | "+RTtext+" "; userData.snapshotItem(0).innerHTML = userText.replace(/grapevine[^<]*<\/a>/i,repTrackBack); } // Side panel stuff if ( (doStats != 0) ) { var tps = tracksplayed / diff; // Tracks per second var tph = tps * 3600; var newtph = commatize(tph.toFixed(num_dec),comma,decimal); var tpd = tps * 86400; var newtpd = commatize(tpd.toFixed(num_dec),comma,decimal); var tpw = tps * 604800; var newtpw = commatize(tpw.toFixed(num_dec),comma,decimal); var tpm = tps * 2628000; // Average month length, not 31 days var newtpm = commatize(tpm.toFixed(num_dec),comma,decimal); var tpy = tps * 31536000; commatize(tpy.toFixed(3),comma,decimal); var newtpy = commatize(tpy.toFixed(num_dec),comma,decimal); var paragraph = panel.parentNode; // xpath(".//DIV[@class='c']/P", panel); if (doStats != 0) { var trxText = document.createElement("span"); var parJour = ""; parJour += ""; parJour += ""; parJour += ""; parJour += "
"+prefA+prefB[0]+""+newtph+"
"+prefA+prefB[1]+""+newtpd+"
"+prefA+prefB[2]+""+newtpw+"
"+prefA+prefB[3]+""+newtpm+"
"+prefA+prefB[4]+""+newtpy+"
"; trxText.innerHTML = parJour+"
"; panel.insertBefore(trxText, panel.lastChild.previousSibling); } } // Squish Recents if (squishRecent != 0) { var bars = xpath("//TABLE[@id='recentTracks']/TBODY/TR/TD[@class='subjectCell']"); for (var i=0; i]*>/i," – "); } var bars = xpath("//TABLE[@id='recentTracks']/TBODY/TR/TD[@class='subjectCell featured featuredTrack']"); for (var i=0; i]*>/i," – "); } bars = xpath("//TABLE[@id='recentTracks']/TBODY/TR"); for (var i=0; i0) { var newSection = document.createElement("div"); var xmlhttp=new XMLHttpRequest(); xmlhttp.open("GET", theURL, false); xmlhttp.send(null); var xmlText = xmlhttp.responseText; if (xmlText) { centerField.snapshotItem(0).parentNode.insertBefore(newSection,centerField.snapshotItem(0).nextSibling); xmlText = xmlText+""; var xmlTable = "/)[0]+""; if (xmlTable) { xmlTable = xmlTable.replace(/div style="width:20%;"/g,"div style='width:40%;'"); var addText = albumHDRa+theURL+albumHDRb; addText += '
'+xmlTable+'
'; newSection.innerHTML = addText; } } if (limitCount == 0) {limitCount = 50; } } } // Loop for everything else if ( (doPCTage != 0) || (darkText != 0) || (limitCount != 0) ) { var basis = ""; if ( (doPCTage != 0) && (location.href.match(/charttype=weekly/)) ) { panel = document.getElementById("selectedWeekStats"); tracksplayed = panel.innerHTML.match(/Total Plays:<\/td>([0-9,]+)<\/strong><\/td>/i)[1].replace(/,/, ""); if (useBasis != 0) { basis = " wkly"; } } var bars = xpath("//TD[@class='chartbarCell']/DIV/SPAN"); var poses = xpath("//TD[@class='positionCell']"); var labelz = xpath("//TD[@class='subjectCell']/DIV"); var oldPos = 1000000; var posIndex = 0; for (var i = 0; i < bars.snapshotLength; i++) { var newCell = document.createElement("td"); newCell.setAttribute("Class","myPcnt"); newCell.innerHTML = " "; poses.snapshotItem(i).parentNode.insertBefore(newCell,poses.snapshotItem(i).parentNode.childNodes(poses.snapshotItem(i).parentNode.childNodes.length - 1)); var posCount = poses.snapshotItem(i).innerHTML.replace(/ */g,"")-0; if (posCount < oldPos) { posIndex = 0; } oldPos = posCount+0; posIndex++; if ((limitCount != 0) && (! location.href.match(/charts/)) && (posIndex > limitCount) ) { poses.snapshotItem(i).parentNode.setAttribute("style","display:none;"); } else { var bar = bars.snapshotItem(i); if (doPCTage != 0) { var played = bar.innerHTML; var playedInt = played.replace(/[, \.]/g, ""); var percentage = (playedInt / tracksplayed) * 100; if (percentage >= teninv) { newCell.innerHTML =commatize(percentage.toFixed(num_dec),comma,decimal) + "%" + basis; // labelz.snapshotItem(i).innerHTML += "   -   (" + commatize(percentage.toFixed(num_dec),comma,decimal) + "%" + basis + ")"; } } if (darkText != 0) { // bar.parentNode.parentNode.style.color = darkTextClr; bar.style.color = darkTextClr; } } } } })(); // // Insert "commas" to split number into blocks of 3 digits // function commatize(number,comma,deci) { number = number+""; // Make text if (!comma) { var comma = ","; } if (!deci) { var deci = "."; } var numNeg = 0; if (number.match(/^-/)) { numNeg = 1; number = number.replace(/^-/,""); } var numdp = number.split("."); // Not input decimal symbol - this is from the js stuff if (numdp.length == 2) { var decimal = numdp[1]; } var integer = numdp[0]; if (integer.length < 4) { if (numdp.length == 2) { number = integer + deci + decimal; } if (numNeg == 1) { number = "-" + number; } return(number); } var stubFrnt = integer.length % 3; if (stubFrnt == 0) {stubFrnt = 3;} var newnumber = integer.substr(0,stubFrnt); var oldPos = stubFrnt; while(oldPos < integer.length ) { newnumber = newnumber + comma + integer.substr(oldPos, 3); oldPos = oldPos + 3; } if (numdp.length == 2) { newnumber = newnumber + deci + decimal; } if (numNeg == 1) { newnumber = "-" + newnumber; } return(newnumber); } // line eater fodder