By Andrew Wilkinson
Has 1 other script.
// ==UserScript==
// @name Last.fm Chart Changes
// @author Andrew Wilkinson <andrew@indiegigs.co.uk>
// @namespace http://lastfm.indiegigs.co.uk/
// @version 2.1.2
// @description Show chart changes over a period of time for user charts on Last.fm
// @include http://www.last.fm/user/*
// @include http://beta.last.fm/user/*
// @include http://www.lastfm.*/user/*
// @exclude http://www.last.fm/user/*/tags/*
// @exclude http://www.lastfm.*/user/*/tags/*
// ==/UserScript==
var overall_history = "http://lastfm.indiegigs.co.uk/user.py";
var version_path = "http://lastfm.indiegigs.co.uk/version.txt";
var version = 212;
var chart_limits = new Array();
chart_limits["user"] = 50;
chart_limits["group"] = 10;
var processing = {};
var charttypes = {};
//Regular Expression to strip XML declaration prior to new XML()
var xmlDeclaration = /^<\?xml version[^>]+?>/;
String.prototype.trim = function () {
return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
};
String.prototype.endsWith = function(suffix) {
var startPos = this.length - suffix.length;
if (startPos < 0) {
return false;
}
return (this.lastIndexOf(suffix, startPos) == startPos);
};
function usePlainStyle() {
GM_setValue('style', 0);
document.location.reload();
}
function useColouredStyle() {
GM_setValue('style', 1);
document.location.reload();
}
var outofrange = " ";
var outofrange_class = "delta"; var outofrange_style = "";
var newentry = " ";
var newentry_class = "delta"; var newentry_style = "";
var movedown = "▼ ";
var movedown_end = "";
var movedown_class = "delta"; var movedown_style = "";
var moveup = "▲ ";
var moveup_end = "";
var moveup_class = "delta rise"; var moveup_style = "";
var nonmover = "–";
var nonmover_class = "delta"; var nonmover_style = "";
if(GM_getValue('style') == 1) {
outofrange = " ";
outofrange_class = "delta"; outofrange_style = "";
newentry = "▲ ";
newentry_class = "delta"; newentry_style = "color: #71B7E6;";
movedown = "▼ ";
movedown_end = "";
movedown_class = "delta"; movedown_style = "color: #D51007;";
moveup = "▲ ";
moveup_end = "";
moveup_class = "delta rise"; moveup_style = "color: #66BD30;";
nonmover = "– ";
nonmover_class = "delta"; nonmover_style = "color: #D5D535;";
GM_registerMenuCommand("Use the plain style.", usePlainStyle);
} else {
GM_registerMenuCommand("Use the coloured style.", useColouredStyle);
}
function xpath(query, doc) {
return document.evaluate(query, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
}
function preprocessChart(type, chart) {
var arr = new Array();
for(var i=0; i<chart.length(); i++) {
name = chart[i].url;
postag = chart[i].chartposition;
if(postag.length()) {
arr[name.toLowerCase()] = parseInt(postag);
} else {
arr[name.toLowerCase()] = parseInt(chart[i].rank);
}
}
return arr;
}
function nameArtistChart(pos) {
chart = xpath("//div[contains(@class, 'chart')]/table", document).snapshotItem(pos);
chart.id = "artistchart";
}
function nameTrackChart(pos) {
chart = xpath("//div[contains(@class, 'chart')]/table", document).snapshotItem(pos);
chart.id = "trackchart";
}
function doChart(chartid, user, type, chart, maxsize) {
var i, rows, pos, playbutton, subject, artistcell, multibutton, chartbar, title;
var parent = xpath("//table[@id='"+chartid+"']/../..", document).snapshotItem(0);
for(i = 0; i < parent.childNodes.length; i++) {
if(parent.childNodes[i].className && parent.childNodes[i].className.indexOf("chart") != -1 && parent.childNodes[i].style.display != "none") {
rows = xpath(".//tr", parent.childNodes[i]);
break;
}
}
if(rows.snapshotLength > 0 && rows.snapshotItem(0).cells.length == 6)
{
return false;
}
server = getServer();
for(i=0; i < rows.snapshotLength; i++) {
row = rows.snapshotItem(i);
pos = parseInt(row.cells[0].innerHTML.trim());
if(type == "artist") {
poscell = row.cells[0].innerHTML;
playbutton = row.cells[1].innerHTML;
subject = xpath(".//div/a/@href", row.cells[2]).snapshotItem(0).value;
artistcell = row.cells[2].innerHTML;
multibutton = row.cells[3].innerHTML;
chartbar = row.cells[4].innerHTML;
} else if(type == "track") {
poscell = row.cells[0].innerHTML;
playbutton = row.cells[1].innerHTML;
subject = xpath(".//div/a[2]/@href", row.cells[2]).snapshotItem(0).value;
artistcell = row.cells[2].innerHTML;
multibutton = row.cells[3].innerHTML;
chartbar = row.cells[4].innerHTML;
}
var url = "http://www.last.fm" + subject;
title = row.cells[1].title;
prev = chart[url.toLowerCase()];
if(!prev && maxsize > 0 && pos > maxsize) {
change = outofrange;
chgclass = outofrange_class;
chgstyle = outofrange_style;
} else if(!prev) {
change = newentry;
chgclass = newentry_class;
chgstyle = newentry_style;
} else if(pos > prev) {
change = movedown + (pos - prev) + movedown_end;
chgclass = movedown_class;
chgstyle = movedown_style;
} else if(pos < prev) {
change = moveup + (prev - pos) + moveup_end;
chgclass = moveup_class;
chgstyle = moveup_style;
} else if(pos == prev) {
change = nonmover;
chgclass = nonmover_class;
chgstyle = nonmover_style;
} else {
chgclass = ""; chgstyle = ""; change = "N/A";
}
row.innerHTML = "<td class='"+chgclass+"' style='width: 30px; text-align: left; padding-right: 0px;"+chgstyle+"'>" + change + "</td><td class='positionCell' style='padding-left: 0px;'>" + poscell + "</td><td class='playbuttonCell'>" + playbutton + "<td class='subjectCell' title='"+title+"'>" + artistcell + "</td><td class='multibuttonCell'>" + multibutton + "<td class='chartbarCell'>" + chartbar + "</td>";
}
return true;
}
function doChartDate(chart, chdate, weeks, current) {
var div = xpath("//div[@id='"+chart+"_date']", document);
var new_div = false;
if(div.snapshotLength == 0) {
div = document.createElement("div");
new_div = true;
}
var chart_selector = xpath("//table[@id='"+chart+"']/../../div[position()=last()]", document).snapshotItem(0);
weeks = weeks[0];
div.className = "clearit";
div.id = chart + "_date";
var html = "Comparing to: <b>" + chdate + "</b>. ";
if(weeks.week.length() > 0) {
html += " Compare against ";
for(i=0; i<weeks.week.length(); i++) {
if(parseInt(weeks.week[i]) == parseInt(current)) {
html += "<i>" + weeks.week[i] + "</i>";
} else {
html += "<a style='cursor: pointer; text-decoration: underline;' href='javascript:window.gm_wrapped_setValue(\"compareto\", "+weeks.week[i]+");'>" + weeks.week[i] + "</a>";
}
html += " ";
}
html += " days ago."
}
div.innerHTML = html;
if(new_div) {
xpath("//table[@id='"+chart+"']/../../div[position()=last()-1]", document).snapshotItem(0).style.marginBottom = "0px";
chart_selector.parentNode.insertBefore(div, chart_selector);
}
}
function getChartType(tabs, majortype, chart) {
for(var i = 0; i < tabs.snapshotLength; i++) {
tab = tabs.snapshotItem(i);
if(tab.className.indexOf("current") != -1) {
if(tab.className.indexOf("chartweek") != -1) {
return "week";
} else if(tab.className.indexOf("chart3month") != -1) {
return "threemonths";
} else if(tab.className.indexOf("chart6month") != -1) {
return "sixmonths";
} else if(tab.className.indexOf("chartyear") != -1) {
return "twelvemonths";
} else if(tab.className.indexOf("chartoverall") != -1) {
return "overall";
}
}
}
}
function getOverallChart(majortype, chart, user, type) {
if(processing[chart]) {
return;
}
processing[chart] = true;
var tabs = xpath("//table[@id='"+chart+"']/../../div/ul/li", document);
var charttype = getChartType(tabs, majortype, chart);
if(!charttype)
{
GM_log("Unable to determine the " + type + " chart type.");
return;
}
GM_xmlhttpRequest({
method: 'GET',
url: overall_history + '?user=' + user + '&type=' + type + '&week=' + GM_getValue('compareto', 7) + '&period=' + charttype,
onload: function(responseDetails) {
if(responseDetails["responseText"] == "Invalid period.\n")
{
charttypes[type] = charttype;
}
else
{
var xml = new XML(responseDetails["responseText"].replace(xmlDeclaration, ''));
if(doChart(chart, user, type, preprocessChart(type, eval('xml.' + type)), chart_limits[majortype]))
{
doChartDate(chart, xml.date[0].@text, xml.weeks, xml.used);
charttypes[type] = charttype;
}
}
processing[chart] = false;
}
});
}
function getPageMajorType(server) {
path = window.location.href;
serverlen = server.length;
return path.substr(serverlen, path.substr(serverlen, path.length).indexOf("/"));
}
function getUserName(server, majortype) {
path = window.location.href;
fullpath = server + majortype + "/";
fullpathsize = fullpath.length;
if(path.substr(0, fullpathsize) != fullpath) {
return null;
}
if(path.substr(fullpathsize, path.length).indexOf("/") == -1) {
return path.substr(fullpathsize);
} else {
return path.substr(fullpathsize, path.substr(fullpathsize, path.length).indexOf("/"));
}
}
function getPageType(server, majortype, username) {
path = window.location.href;
fullpath = server + majortype + "/";
size = (fullpath + username).length + 1;
nextslash = window.location.href.substr(size).indexOf("/");
nextampersand = window.location.href.substr(size).indexOf("&");
nextquestion = window.location.href.substr(size).indexOf("?");
if(fullpath + username == window.location.href
|| fullpath + username + "/" == window.location.href
|| (nextquestion != -1 && fullpath + username == window.location.href.substr(0, size+nextquestion))
|| (nextquestion != -1 && fullpath + username + "/" == window.location.href.substr(0, size+nextquestion))) {
return "front";
} else if(majortype == "user") {
var pagetype = path.substr(size, (nextslash == -1 && nextquestion == -1 ? path.length - size : (nextslash == -1 ? nextquestion : nextslash)))
if(pagetype == "charts" && window.location.href.match(/subtype=tracks/)) {
return "trackchart";
} else if(pagetype == "charts" && window.location.href.match(/subtype=albums/)) {
return "albumchart";
} else if(pagetype == "charts") {
return "artistchart";
}
}
}
function getServer() {
path = window.location.href;
slash = path.substr(7).indexOf("/");
return path.substr(0, slash+8);
}
function checkVersion() {
var now = new Date();
if(GM_getValue('last_version_check') == (now.getDay() * 100000 + now.getMonth() * 1000 + now.getYear())) {
return;
}
GM_xmlhttpRequest({
method: 'GET',
url: version_path,
onload: function(responseDetails) {
GM_setValue('latest_version', parseInt(responseDetails["responseText"].trim()));
GM_setValue('last_version_check', (now.getDay() * 100000 + now.getMonth() * 1000 + now.getYear()));
if(GM_getValue('latest_version') > version) {
var profile_box = xpath("//div[@class='leftColWrapper']/div[1]", document).snapshotItem(0);
var div = document.createElement("div");
div.innerHTML = "<p>The Chart Changes Greasemonkey Script has been updated. Click <a href='http://lastfm.indiegigs.co.uk/chartchanges/files/lastfm.user.js'>here</a> to get the latest version.</p>";
profile_box.appendChild(div);
}
}
});
}
function watchForChartChange(majortype, chart, username, type)
{
var tabs = xpath("//table[@id='"+chart+"']/../../div/ul/li", document);
var charttype = getChartType(tabs, majortype, chart);
if(charttype != charttypes[type]) {
getOverallChart(majortype, chart, username, type);
}
}
(function() {
// Give main page access to GM_setValue
unsafeWindow.gm_wrapped_setValue = function (key, value) { window.setTimeout(function () { GM_setValue(key, value); window.location.reload(); }, 0); };
checkVersion();
server = getServer();
if(!server) { return; }
majortype = getPageMajorType(server);
if(!majortype) { return; }
username = getUserName(server, majortype);
if(!username) { return; }
page = getPageType(server, majortype, username);
if(page == "front") {
nameArtistChart(0);
getOverallChart(majortype, "artistchart", username, "artist");
nameTrackChart(1);
getOverallChart(majortype, "trackchart", username, "track");
setInterval(function () { watchForChartChange(majortype, "artistchart", username, "artist");
watchForChartChange(majortype, "trackchart", username, "track"); }, 15000);
} else if(page == "artistchart") {
nameArtistChart(0);
getOverallChart(majortype, "artistchart", username, "artist");
setInterval(function () { watchForChartChange(majortype, "artistchart", username, "artist"); }, 15000);
}else if(page == "trackchart") {
nameTrackChart(0);
getOverallChart(majortype, "trackchart", username, "track");
setInterval(function () { watchForChartChange(majortype, "trackchart", username, "track"); }, 15000);
}
})();