Last.fm - Opera: Sort by time

Sort overall top artists by time played.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name Last.fm - Opera: Sort by time
// @namespace
// @description Sort overall top artists by time played.
// @include http://www.last.fm/user/*
// @include http://www.last.fm/user/*/bytime*
// @version 0.0.1.20140511222853
// @namespace https://greasyfork.org/users/835
// ==/UserScript==

var artDisp = 50;
var statusArea;
var myTempWorkArea;
var username;
var othername;
var theURL;
var timePlayed = new Array();
var nextPtr = new Array();
var prevPtr = new Array();
var XTime = new Array();
var traxPlayed = new Array();
var totalSongs = new Array();
var artistNames = new Array();
var firstLink = 0; var lastLink = 0;
var artLinks;
var trackRows = new Array();
var trackCount = 0;
var periodViewed = "overall";
var tstABC = new Array();
var artistArray = new Object();

// chartDescrip
var chartDescrip = new Object();
chartDescrip["overall"] = "overall";
chartDescrip["year"] = "last 12 months";
chartDescrip["6month"] = "last 6 months";
chartDescrip["3month"] = "last 3 months";
chartDescrip["week"] = "last week";

/* History */
// snyde1:  05/09/2008 First Version
// snyde1:  06/09/2008 Move to 404 page, fix CPU problems
// added track counting
// snyde1:  03.01.2009 fix up tracks, formatting
// snyde1:  10.01.2009 fix sorting
// snyde1:  31-Jul-2009 fix for Opera 10
/* SCRIPT */

function xpath(query) {
	return document.evaluate(query, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
}

function doArtists() {
	statusArea.innerHTML="Loading your overall top artists";
	theURL = "/user/" + othername + "/charts?rangetype=overall&subtype=artists";
	if (1 != getPageURL(theURL)) {
		statusArea.innerHTML="Error loading data from chart";
		return;
	}
	var newTable = document.createElement("table");
	newTable.setAttribute("class","candyStriped chart");
	statusArea.parentNode.insertBefore(newTable,statusArea.nextSibling);
	artLinks = xpath("//td[@class='subjectCell']/div/a");
	if (artLinks.snapshotLength < 0) {statusArea.innerHTML="Error loading data from chart - no artists found."; return;}
	var realCount = 0;
	statusArea.innerHTML="<H2 class='heading'>Top overall artists by time</H2>The following are your top artists sorted by time played. Times are in minutes of play, an asterisk (*) shows where times are approximate. The information in parentheses is based on your number of plays for that artist.<P>&nbsp;";
	if (artDisp > artLinks.snapshotLength) { artDisp = artLinks.snapshotLength; }
	for (var i = 0; i < artDisp; i++) {
		var artistName = artLinks.snapshotItem(i).href.match(/\/([^\/]*)$/)[1];
		if (1 != getArtLibrary(artistName)) {
			statusArea.innerHTML="Error loading data from library for "+artistName;
			return;
		}
		artLinks.snapshotItem(i).href = "/user/" + othername + "/library/music/"+artistName+"?sortOrder=desc&sortBy=plays";
		var myTimes = xpath("//td[@class='time border']");
		var myPlays = xpath("//td[@class='playcount border']/a");
		var totalTime = 0; var trackTime = 0; var badFlag = 0; var ttSec = "sec"; traxPlayed[i] = 0;
		for(var j=0; j < myTimes.snapshotLength; j++) {
			myPlays.snapshotItem(j).innerHTML = myPlays.snapshotItem(j).innerHTML.replace(/[, ]/g,"");
			if (myTimes.snapshotItem(j).innerHTML.match(/:/)) {
				var trackMin = myTimes.snapshotItem(j).innerHTML.split(/:/)[0];
				var trackSec = myTimes.snapshotItem(j).innerHTML.split(/:/)[1];
				trackTime = 60*parseInt(trackMin)+parseInt(trackSec);
			} else {
				trackTime = 0;
				badFlag += parseInt(myPlays.snapshotItem(j).innerHTML);
			}
			if (isNaN(parseInt(myPlays.snapshotItem(j).innerHTML))) {myPlays.snapshotItem(j).innerHTML = 0; }
			totalTime += parseInt(myPlays.snapshotItem(j).innerHTML)*trackTime;
			traxPlayed[i] += parseInt(myPlays.snapshotItem(j).innerHTML);
		}
		totalSongs[i] = myTimes.snapshotLength;
		XTime[i] = 0;
		if (badFlag > 0) {
			XTime[i] = badFlag * totalTime / (traxPlayed[i] - badFlag);
			XTime[i] = parseInt(XTime[i]+.5);
			totalTime += XTime[i]; ttSec = "sec*";
		}
		if (isNaN(totalTime)) { totalTime = 0; }
		timePlayed[i] = totalTime;
		artistNames[i] = artistName;
		artistArray[artistName] = new Object();
		artistArray[artistName].url = artLinks.snapshotItem(i).href;
		artistArray[artistName].html = artLinks.snapshotItem(i).innerHTML;
		artistArray[artistName].count = myTimes.snapshotLength;
		artistArray[artistName].position = i;
		artistArray[artistName].time = totalTime;
		tstABC[i] = i;
		// ll
		if ((i < 25) || (4 == (i%5))){newTable.innerHTML = makeTable();}
	}
	newTable.innerHTML = makeTable();
}

function getPageURL(myURL) {
	var xmlhttp=new XMLHttpRequest();
	xmlhttp.open("GET", myURL, false);
	xmlhttp.send(null);
	if (xmlhttp.readyState!=4) { return(0); }
	var xmlText = xmlhttp.responseText;
	if (! xmlText.match(/<tbody>/i)) { return(0); }
	xmlText = xmlText.split(/<tbody>/i)[1];
	xmlText = xmlText.split(/<\/tbody>/i)[0];
	var chartTab = document.createElement("table");
	chartTab.setAttribute("style","display:none; visibility:hidden;");
	chartTab.innerHTML = xmlText;
	document.getElementById("content").insertBefore(chartTab,myTempWorkArea);
	return(1);
}
function getArtLibrary(artist) {
	var theURL = "/user/" + othername + "/library/music/"+artist+"?sortOrder=desc&sortBy=plays";
	var xmlhttp=new XMLHttpRequest();
	xmlhttp.open("GET", theURL, false);
	xmlhttp.send(null);
	if (xmlhttp.readyState!=4) { return(0); }
	var xmlText = xmlhttp.responseText;
	if (!xmlText) {
		return(0);
	}
	if (xmlText.match(/<tbody>/i)) {
		xmlText = xmlText.split(/<tbody>/i)[1];
		xmlText = xmlText.split(/<\/tbody>/i)[0];
	} else {
		return(0);
	}
	myTempWorkArea.innerHTML = "<table id='timeCalcArea'>"+xmlText+"</table>";
	return(1);
}
function makeTable() {
	var j = firstLink; var textBlock=""; var k=1; maxTime = timePlayed[firstLink];
	textBlock = "";
	var tstBCA = tstABC.sort(sortMyArr);
	var maxTime = timePlayed[tstBCA[0]];
	for (var q=0;q<tstBCA.length;q++) { var r = tstBCA[q]; var artNam = artistNames[r];
		var rowType = ""; if (1 == (q%2)) {rowType=" class=\"odd\"";}
		var barWid = parseInt(timePlayed[r]*100/maxTime); if (barWid<20) {barWid = 20;}
		var minuPlay = commatize(parseInt(timePlayed[r]/60));
		var playStr = mTimeStr(timePlayed[r]);
		if (XTime[tstBCA[q]] != 0) {minuPlay += "*";}
		var rankDelta = q - (artistArray[artNam].position); var rankIn = "(&mdash;)";
		if (rankDelta > 0) { rankIn = "<font color=red>&dArr;&nbsp;"+rankDelta+"</font>";}
		if (rankDelta < 0) { rankIn = "<font color=green>&uArr;&nbsp;"+(0-rankDelta)+"</font>";}
		textBlock += "<TR"+rowType+"><TD class=\"positionCell\">"+(q+1)+"</TD><TD class=\"positionCell\">"+rankIn+"</TD>"+
			"<TD class=\"subjectCell\" title=\""+artistArray[artNam].html+", played "+commatize(traxPlayed[r])+" times, for "+playStr+"\"><A HREF='"+artistArray[artNam].url+"'>"+
			artistArray[artNam].html+"</A><span> (#"+(r+1)+" with "+commatize(traxPlayed[r])+" plays)</span></TD>"+
			"<TD class=\"chartbarCell\"><DIV Style=\"width:"+barWid+"%\" class=\"chartbar\"><span>"+minuPlay+"</span></TD></TR>\n";
	}
	return(textBlock);
}
function mTimeStr(newTotTim){
	var secTot = newTotTim % 60; newTotTim = (newTotTim - secTot)/60;
	var minTot = newTotTim % 60; newTotTim = (newTotTim - minTot)/60;
	var hourTt = newTotTim % 24; var dayTot = (newTotTim - hourTt)/24;
	if (hourTt < 10) {hourTt = "0"+hourTt;}
	if (minTot < 10) {minTot = "0"+minTot;}
	if (secTot < 10) {secTot = "0"+secTot;}
	var timPlyStr = dayTot +"d,"+hourTt+":"+minTot+":"+secTot;
	return(timPlyStr);
}
function commatize(number,comma,deci) {
	number = number+"";
	if (!comma) { var comma = ","; }
	if (!deci) { var deci = "."; }
	var numNeg = 0; if (number.match(/^-/)) {numNeg = 1; number = number.replace(/^-/,"");}
	var numdp = number.split(".");
	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);
}
function clearArea(){
	var fourohfour = document.getElementById('fourOhFour');
	fourohfour.innerHTML="";
	statusArea = document.createElement("DIV");
	statusArea.innerHTML = "<H2 class='heading'>Sort by time</H2>";
	fourohfour.insertBefore(statusArea,fourohfour.firstChild);
	var pageTitle = xpath("//title");
	if ( pageTitle.snapshotLength > 0 ) {
		if ( location.href.match(/dotype=artists/i)) {
			var textReplace = "Overall Artists ";
		} else if (location.href.match(/dotype=tracks/i)) {
			var textReplace = "Tracks ";
		}
		pageTitle.snapshotItem(0).innerHTML =
			pageTitle.snapshotItem(0).innerHTML.replace(/users at last.fm/i,textReplace+", sorted by time played.");
	}
	fourohfour.setAttribute("style","width:80%");
	myTempWorkArea = document.createElement("DIV");
	myTempWorkArea.setAttribute("id","myTempWorkArea");
	myTempWorkArea.setAttribute("style","display: none");
	var rightCol = document.getElementById("content");
	rightCol.insertBefore(myTempWorkArea, rightCol.lastChild.nextSibling);
}

function doForm() {
	var formArea = document.createElement("FORM");
	var formText = "";
	formArea.setAttribute("METHOD","GET");
	formText = "<H2 class='heading'>Selection</H2><P>Use this form to select the type and number of items to check. Note that only the \"overall\" period is valid for artists.</P>";
	formText += "Number of entries <INPUT TYPE=\"TEXT\" NAME=\"Number\" Value=\"50\" MAXLENGTH=3>";
	formText += "of type <SELECT NAME=\"DoType\"> <OPTION SELECTED VALUE=\"Artists\"> Artists <OPTION VALUE=\"Tracks\"> Tracks </SELECT>";
	formText += " for the period <SELECT NAME=\"Time\"> <OPTION SELECTED VALUE=\"overall\"> Overall <OPTION VALUE=\"year\"> 12 Month <OPTION  VALUE=\"6month\"> 6 Month <OPTION  VALUE=\"3month\"> 3 Month </SELECT>";
	formText += " <INPUT TYPE='SUBMIT'>";
	formArea.innerHTML = formText;
	document.getElementById('fourOhFour').insertBefore(formArea, document.getElementById('fourOhFour').lastChild.nextSibling)
}

(function() {
	if (!location.href.match(/\/bytime/) ) { // should be on profile
		if (! location.href.match(/user\/[^\/]*$/) ) { return; }
		username = location.href.match(/user\/([^\/]*)$/)[1];
		var addLink = document.createElement("li");
		addLink.innerHTML = "<a href=\"/user/"+username+"/bytime\">Time</a>";
		var addLinkHere = xpath('//ul[@class="visible-menu"]').snapshotItem(0);
		addLinkHere.insertBefore(addLink, addLinkHere.childNodes[5]);
		return;
	}

	username = getLastfmUsername();
	if (username == "") { return; }
	clearArea();
	if (location.href.match(/number=/i)) {
		var numberToGet = location.href.match(/number=([^&$]*)[&$]/i)[1];
		if (! isNaN(parseInt(numberToGet))) {artDisp = parseInt(numberToGet);}
	}
	if (location.href.match(/time=/i)) {
		periodViewed = location.href.match(/time=([^&$]*)$/i)[1];
	}
	othername = location.href.match(/\/user\/([^\/]*)\/bytime/)[1];
	if ( location.href.match(/dotype=artists/i)) {
		doArtists();
	} else if (location.href.match(/dotype=tracks/i)) {
		doTracks();
	}
	if (location.href.match(/\/bytime/i)) {
		doForm();
	}
	return;
})();

function getLastfmUsername() {
	var usernameLink = xpath("//a[contains(@class,'user-badge')]");
	if (usernameLink.snapshotLength > 0) {
		var userNameLoc = usernameLink.snapshotItem(0).innerHTML;
		userNameLoc = userNameLoc.replace(/<[^<>]*>/g,"");
		userNameLoc = userNameLoc.replace(/\s/g,"");
		return(userNameLoc);
	} else {
		return("");
	}
}

function doTracks() {
	var trackArray = new Object();
	statusArea.innerHTML="Loading your top tracks";
	theURL = "/user/" + othername + "/charts?rangetype="+periodViewed+"&subtype=tracks";
	if (1 != getPageURL(theURL)) {
		statusArea.innerHTML="Error loading data from chart";
		return;
	}
	var artistNames = new Array();
	var trackNames = new Array();
	var newTable = document.createElement("table");
	newTable.setAttribute("class","candyStriped chart");
	statusArea.parentNode.insertBefore(newTable,statusArea.nextSibling);
	artLinks = xpath("//td[@class='subjectCell']/div/a");
	var trkLinks = xpath("//td[@class='chartbarCell']/div/a/span");
	if (artLinks.snapshotLength < 0) {statusArea.innerHTML="Error loading data from chart - no artists found."; return;}
	var realCount = 0;
	artDisp = 2*artDisp;
	if (artDisp > artLinks.snapshotLength) { artDisp = artLinks.snapshotLength; }
	for (var i = 0; i < artDisp; i++) {
		var artistName = artLinks.snapshotItem(i).innerHTML;
		i++;
		var trackName = artLinks.snapshotItem(i).innerHTML;
		if (!trackArray[artistName]) {
			trackArray[artistName] = new Object();
			trackArray[artistName].url = "url";
			trackArray[artistName].tracks = new Object();
			trackArray[artistName].tracks[trackName] = new Object();
			trackArray[artistName].tracks[trackName].url = artLinks.snapshotItem(i).href;
			trackArray[artistName].tracks[trackName].count = trkLinks.snapshotItem((i-1)/2).innerHTML.replace(/,/g,"");
			trackArray[artistName].tracks[trackName].position = (i-1)/2;
			trackArray[artistName].tracks[trackName].time = 0;
		} else{
			trackArray[artistName].tracks[trackName] = new Object();
			trackArray[artistName].tracks[trackName].url = artLinks.snapshotItem(i).href;
			trackArray[artistName].tracks[trackName].count = trkLinks.snapshotItem((i-1)/2).innerHTML.replace(/,/g,"");
			trackArray[artistName].tracks[trackName].position = (i-1)/2;
			trackArray[artistName].tracks[trackName].time = 0;
		}
		realCount++;
	}
	statusArea.innerHTML = "";
	for( var i in trackArray) {
		statusArea.innerHTML = "Loading artist: <font color='blue'>"+i+"</font>";
		getArtLibrary(i);
		var myTimes = xpath("//td[@class='time border']");
		var myPlays = xpath("//td[@class='playcount border']");
		var myTrcks = xpath("//td[@class='subject']/span[@class='name']/a");
		for (var j in trackArray[i].tracks ) {
			var k = -1;
			do { k=k+1; } while ((k<myTrcks.snapshotLength) && (j != myTrcks.snapshotItem(k).innerHTML))
			if (k >= myTrcks.snapshotLength) {trackArray[i].tracks[j].time = "0:00";}
			else {trackArray[i].tracks[j].time = myTimes.snapshotItem(k).innerHTML;}
			var trackMin = trackArray[i].tracks[j].time.split(/:/)[0];
			var trackSec = trackArray[i].tracks[j].time.split(/:/)[1];
			trackArray[i].tracks[j].time = 60*parseInt(trackMin)+parseInt(trackSec);
			if (isNaN(trackArray[i].tracks[j].time)) {trackArray[i].tracks[j].time = 0;}
			trackArray[i].tracks[j].totaltime = trackArray[i].tracks[j].time * parseInt(trackArray[i].tracks[j].count);
			trackRows[trackCount] = "<td Class='subjectCell' title=\""+j+", played "+commatize(trackArray[i].tracks[j].count)
			+" times, for "+mTimeStr(trackArray[i].tracks[j].totaltime)+"\"><A HREF="+trackArray[i].tracks[j].url+">"+i+" - "+j+"</A></td>";
			timePlayed[trackCount] = trackArray[i].tracks[j].totaltime;
			trackCount++;
		}
	}
	statusArea.innerHTML = "<H2 class='heading'>Top tracks by time for "+chartDescrip[periodViewed]+"</H2><table>";
	for (var q=0;q<trackCount;q++){
		tstABC[q] = q;
	}
	var tstBCA = tstABC.sort(sortMyArr);
	var maxTime = timePlayed[tstBCA[0]];
	for (var q=0;q<trackCount;q++) {
		var rowType = ""; if (1 == (q%2)) {rowType=" class=\"odd\"";}
		var barWid = parseInt(timePlayed[tstBCA[q]]*100/maxTime); if (barWid<20) {barWid = 20;}
		var minuPlay = commatize(parseInt(timePlayed[tstBCA[q]]/60));
		newTable.innerHTML += "<tr"+rowType+"><td class=\"positionCell\">"+(q+1)+"</td>"+trackRows[tstBCA[q]]
		+ "<TD class=\"chartbarCell\"><DIV Style=\"width:"+barWid+"%\" class=\"chartbar\"><span>"+minuPlay+"</span></TD></TR>\n";
	}
}

function sortMyArr(a, b){
	return( timePlayed[b] - timePlayed[a]);
}