您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows any tracks on Last.fm artist pages that you've listened to by that artist.
// ==UserScript== // @name Last.fm: Opera - My Top Tracks - July 2008 // @namespace xxx // @description Shows any tracks on Last.fm artist pages that you've listened to by that artist. // @include http://www.last.fm/music/* // @exclude http://www.lastfm.*/music/*/* // @exclude http://www.last.fm/music/*/* // @version 0.0.1.20150227023155 // ==/UserScript== /* CUSTOM VARIABLES */ // chartLimit: Maximum number of songs to display in "My Top Tracks" on // each artist's page. Set to 0 for no limit. var chartLimit = 20; var APIkey = "0d1abf0beae8570e6f8f2441bf561eb3"; // chartType: Which chart to use for data. Options: "overall" "3month" "6month" "12month" "weekly" : 1month is not consistently supported var defChartType = "3month"; var chartList = "+overall+1month+3month+6month+12month+7day+"; var subChartType = "tracks"; // "tracks" or "albums" - can be toggled var doRank = 1; // Include rank data? 1 = yes, 0 =no // chartDescrip var chartDescrip = new Object(); chartDescrip["overall"] = "overall"; chartDescrip["12month"] = "last 12 months"; chartDescrip["6month"] = "last 6 months"; chartDescrip["3month"] = "last 3 months"; chartDescrip["1month"] = "last month"; chartDescrip["7day"] = "last week"; /* History */ // 17-jul-2008: We'll call this a fresh start for the new "beta" Last.fm // 26-Jul-2008: Fix for artist names // 29-Jul-2008: Emergency fix for loading issue // 22-Feb-2015: Massive changes to improve stuff var mychart; var artist, artistENC; var username; /* SCRIPT */ function xpath(query) { return document.evaluate(query, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); } function escape2(str) { var times; if (arguments.length < 2) { times = 1; } else { times = arguments[1]; } for (var i = 0; i < times; i++) { str = str.replace(/\%25 /g, "&pct; "); str = str.replace(/\% /g, "&pct; "); str = encodeURIComponent(str).replace(/\%20/g, "+"); str = str.replace(/\&pct; /g, "%25 "); } return str; } function unescape2(str) { var times; if (arguments.length < 2) { times = 1; } else { times = arguments[1]; } for (var i = 0; i < times; i++) { str = str.replace(/\%25 /g, "&pct; "); str = str.replace(/\% /g, "&pct; "); str = decodeURIComponent(str.replace(/\%26/g, "&")); str = decodeURIComponent(str.replace(/\+/g, "%20")); str = decodeURIComponent(str.replace(/ \& /g, " & ")); // Fix for artist with ampersand for and } return str; } function toggleSubType() { if (subChartType == "albums") { subChartType = "tracks"; } else { subChartType ="albums"; } getTrax(defChartType); } // function unixtimeNow() { // var nowtime = new Date; // return ((nowtime.valueOf() * 0.001)|0); // } function doChart(xmlText, username, chartType, aRank, aPlay) { if ((xmlText.getElementsByTagName("lfm")[0].getAttribute("status")).match(/failed/)) { alert("No such user"); return; } if (subChartType == "albums") { var allArtists = xmlText.evaluate("//lfm/topalbums/album/artist/name",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allAlbums = xmlText.evaluate("//lfm/topalbums/album/name",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allPlays = xmlText.evaluate("//lfm/topalbums/album/playcount",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allURLs = xmlText.evaluate("//lfm/topalbums/album/url",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allMBIDs = xmlText.evaluate("//lfm/topalbums/album/mbid",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allImages = xmlText.evaluate("//lfm/topalbums/album/image[@size='extralarge']",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); } else { var allArtists = xmlText.evaluate("//lfm/toptracks/track/artist/name",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allAlbums = xmlText.evaluate("//lfm/toptracks/track/name",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allPlays = xmlText.evaluate("//lfm/toptracks/track/playcount",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allURLs = xmlText.evaluate("//lfm/toptracks/track/url",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allMBIDs = xmlText.evaluate("//lfm/toptracks/track/mbid",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allImages = xmlText.evaluate("//lfm/toptracks/track/image[@size='extralarge']",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); } var tracks = new Array(); var lastPos = 0; var lastCount; var j = 0; var currCount = 0; myTotalPlays = 0; var metaArray = document.getElementsByName('og'); for (var i = 0; i < allArtists.snapshotLength; i++) { var currArtist = new XMLSerializer().serializeToString(allArtists.snapshotItem(i).firstChild); if (currArtist == artist) { var currName = new XMLSerializer().serializeToString(allAlbums.snapshotItem(i).firstChild); var currCount = new XMLSerializer().serializeToString(allPlays.snapshotItem(i).firstChild); var currURL = new XMLSerializer().serializeToString(allURLs.snapshotItem(i).firstChild); currCount = currCount.replace(/,/g,""); currName = currName.replace(/\?autostart/,""); tracks[j] = new Array(); tracks[j]["name"] = currName; tracks[j]["count"] = currCount; tracks[j]["URL"] = currURL; myTotalPlays = myTotalPlays + parseInt(currCount); if (j == 0) { tracks[0]["pos"] = 1; var maxCount = tracks[0]["count"]; } else { if (tracks[j]["count"] == lastCount) { tracks[j]["pos"] = lastPos; } else { tracks[j]["pos"] = j + 1; } } tracks[j]["width"] = Math.max(20, Math.round(tracks[j]["count"] / maxCount * 98)); lastPos = tracks[j]["pos"]; lastCount = tracks[j]["count"]; j++; } } if (chartLimit < 1) { chartLimit = 500; } var HTML = ""; if (!navigator.userAgent.match(/Opera/)) { HTML += "<span>Use the menu options to select the time period and chart type.</span>"; } // Fancy toggler HTML += "<span class=\"horizontalOptions clearit\"><ul>"; HTML += "<li class=\""+((chartType=="7day")?"current ":"")+"first chartweek\"><a "+((chartType=="7day")?"name=\"\"":"href=\"javascript:getTrax(\'7day\')\"")+">Last week</a></li>"; // HTML += "<li class=\""+((chartType=="1month")?"current ":"")+"chart1month\"><a "+((chartType=="1month")?"name=\"\"":"href=\"javascript:getTrax(\'1month\')\"")+">Last month</a></li>"; HTML += "<li class=\""+((chartType=="3month")?"current ":"")+"chart3month\"><a "+((chartType=="3month")?"name=\"\"":"href=\"javascript:getTrax(\'3month\')\"")+">Last 3 months</a></li>"; HTML += "<li class=\""+((chartType=="6month")?"current ":"")+"chart6month\"><a "+((chartType=="6month")?"name=\"\"":"href=\"javascript:getTrax(\'6month\')\"")+">Last 6 months</a></li>"; HTML += "<li class=\""+((chartType=="12month")?"current ":"")+"chartyear\"><a "+((chartType=="12month")?"name=\"\"":"href=\"javascript:getTrax(\'12month\')\"")+">Last 12 months</a></li>"; HTML += "<li class=\""+((chartType=="overall")?"current ":"")+"chartoverall\"><a "+((chartType=="overall")?"name=\"\"":"href=\"javascript:getTrax(\'overall\')\"")+">Overall</a></li>"; HTML += "<li class=\"current chartoverall\"><a name=NULLandVOID)\"> </a></li>"; HTML += "<li class=\""+((subChartType=="tracks")?"current ":"")+"chartoverall\"><a "+((subChartType=="tracks")?"name=\"\"":"href=\"javascript:toggleSubType()\"")+">Tracks</a></li>"; HTML += "<li class=\""+((subChartType=="albums")?"current ":"")+"chartoverall\"><a "+((subChartType=="albums")?"name=\"\"":"href=\"javascript:toggleSubType()\"")+">Albums</a></li>"; HTML += "</ul></span>"; // Table HTML += "<table class=\"candyStriped chart\"><tbody>"; var candyRowClass; if (tracks.length < 1) { HTML += "<tr class=\"first odd\"><td>I have no suitable "+subChartType+" for this artist / period</td></tr>"; if (doRank == 1) { HTML += "<tr class=\"\" ><td align=center><i>"+artist+"</i> is ranked number "+aRank+" this period, with "+aPlay+" plays.</td></tr>"; } } else { for (var k = 0; k < tracks.length && k < chartLimit; k++) { if ((k % 2) == 0) { candyRowClass = "odd "; if (k == 0) {candyRowClass = "first odd ";} } else { candyRowClass = ""; } HTML += "<tr class=\""+candyRowClass+"\"><td class=\"positionCell\">"+tracks[k]["pos"]+"</td><td class=\"subjectCell\" title=\""+unescape2(tracks[k]["name"], 2)+ ", played "+ commatize(tracks[k]["count"]) +" times\"><div><span class=\"text\"><a title=\""+unescape2(tracks[k]["name"], 2)+ "\" href=\""+ tracks[k]["URL"] +"\">"+unescape2(tracks[k]["name"])+"</a></span></div></td><td class=\"chartbarCell\" ><div class=\"chartbar\" style=\"width: "+tracks[k]["width"]+"\%;\"><span>"+ commatize(tracks[k]["count"]) +"</span></div></td></tr>"; } HTML += "<tr class=\"\"><td colspan=3 align=center>Total of "+tracks.length+" "+subChartType+" ("; notShown = tracks.length - chartLimit; if (notShown > 0) { HTML += "" + notShown + " not"; } else { HTML += "all"; } HTML += " shown), played "+myTotalPlays+" times.</td></tr>"; if (doRank == 1) { HTML += "<tr class=\"odd\"><td colspan=3 align=center><i>"+artist+"</i> is ranked number "+aRank+" this period, with "+aPlay+" plays.</td></tr>"; } } HTML += "<tr class=\"\"><td colspan=3 align=center><span id=\"TopTraxActive\" style=\"display: none;\">Reloading - please wait</span></td></tr>"; HTML += "</tbody></table><span class=\"moduleOptions\"><a href=\"/user/"+escape2(username)+"/charts/?rangetype="+chartType+"&subtype="+subChartType +"\" title=\"\">See more</a></span>"; mychart.innerHTML = HTML; } function getTrax(chartType) { var myFlash = document.getElementById("TopTraxActive"); defChartType = chartType; if (myFlash) {myFlash.setAttribute("style", "display: inline; color: red;");} if (artist.match(/\%27/)) { artist=artist.replace(/\%27/g,"'"); } var artRank = 0; var artPlay = 0; if (doRank == 1) { var xmlhttp=new XMLHttpRequest(); var theURL = "http://ws.audioscrobbler.com/2.0/?method=user.gettopartists&limit=1000&user="+username+"&api_key="+ APIkey + "&period=" + chartType; xmlhttp.open("GET", theURL, false); xmlhttp.send(null); var xmlText = xmlhttp.responseXML; if (!xmlText) { alert("Can't load artist list"); return; } var allArtists = xmlText.evaluate("//lfm/topartists/artist/name",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var allPlays = xmlText.evaluate("//lfm/topartists/artist/playcount",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < allArtists.snapshotLength; i++) { var currName = new XMLSerializer().serializeToString(allArtists.snapshotItem(i).firstChild); if (currName == artist) { artPlay = new XMLSerializer().serializeToString(allPlays.snapshotItem(i).firstChild); artRank = (i+1)+" (of "+allArtists.snapshotLength+") "; break; } } } var xmlhttp=new XMLHttpRequest(); var theURL = "http://ws.audioscrobbler.com/2.0/?method=user.gettop"+subChartType+"&limit=1500&user=" + escape2(username) + "&api_key=" + APIkey + "&period=" + chartType; xmlhttp.open("GET", theURL, true); xmlhttp.send(null); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { var xmlText = xmlhttp.responseXML; if (!xmlText) { alert("no data - toptracks"); return; } doChart(xmlText, username, chartType, artRank, artPlay); } } } function initNewPanel(oldPanel) { var newPanel = document.createElement("div"); newPanel.setAttribute("class", "myTopTrax"); newPanel.setAttribute("id", "myTopTraxPan"); newPanel.setAttribute("style", "width: 100%;"); oldPanel.parentNode.insertBefore(newPanel,oldPanel.parentNode.firstChild); myPan = document.getElementById("hiLightPan"); newPanel.innerHTML = "<H2 class='heading'><span class='h2Wrapper'>My Top Trax & Wax for "+artist+"</SPAN></H2>"; newPanel.innerHTML += "<div class=\"module-body chart chartweek current\" id=\"divMyTopTrax\">"; newPanel.innerHTML += "</div><hr />"; } function getLastfmUsername() { var usernameLink = document.evaluate("//a[contains(@class,'user-badge')]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); if (usernameLink.snapshotLength > 0) { var userNameLoc = usernameLink.snapshotItem(0).innerHTML; userNameLoc = userNameLoc.replace(/<[^<>]*>/g,"").replace(/[ \n]+/g,""); return(userNameLoc); } else { return(""); } } (function() { var artistName; username = getLastfmUsername(); if (username == "") { return; } artistENC = location.href.match(/\/music\/([^\/\?]*)/)[1]; if (!artistENC) { return; } if (artistENC.match(/\&/)) { artistENC = artistENC.replace(/\&/g,"%26"); } var theURL = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist="+artistENC+"&api_key="+APIkey; var xmlhttp=new XMLHttpRequest(); xmlhttp.open("GET", theURL, false); xmlhttp.send(null); var xmlText = xmlhttp.responseXML; if (!xmlText) { alert("no data - no artist"); return; } artistName = xmlText.evaluate("//lfm/artist/name",xmlText, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); artist = "" + new XMLSerializer().serializeToString(artistName.snapshotItem(0).firstChild); var shtPanel = xpath('//div[contains(@class,"artist-listening-trend")]/h2').snapshotItem(0); if (!shtPanel){ return; } initNewPanel(shtPanel); mychart = document.getElementById("divMyTopTrax"); if (!mychart) { alert("Can't open chart element"); return; } if (!navigator.userAgent.match(/Opera/)) { defChartType = GM_getValue("defChartType", defChartType); GM_registerMenuCommand("TopTrax: Select chart", promptForChart); GM_registerMenuCommand("TopTrax: Toggle album/track",toggleSubType); } if (!defChartType) { defChartType = "6month"; } getTrax(defChartType); })(); // // Insert commas to split number into blocks of 3 digits // Assumes POSTIVE number // function commatize(number) { var numdp = number.split("."); if (numdp.length == 2) { var decimal = numdp[1]; } var integer = numdp[0]; if (integer.length < 4) { 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 + "," + integer.substr(oldPos, 3); oldPos = oldPos + 3; } if (numdp.length == 2) { newnumber = newnumber + "." + decimal; } return(newnumber); } function promptForChart() { GM_setValue("chartType", prompt("What chart do you want to use? (overall, 7day, 12month, 6month, 3month)", getForChart())); if (!chartDescrip[GM_getValue("chartType")]){ GM_setValue("chartType", "overall"); defChartType = "overall"; } defChartType=GM_getValue("chartType"); getTrax(defChartType); } function getForChart() { return GM_getValue("chartType", "overall"); }