Last.fm Artist Playcount/Chart Position Graph

By Abhinav Sarkar Last update Jan 3, 2008 — Installed 1,788 times. Daily Installs: 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0
// ==UserScript==
// @name           Last.fm Artist Playcount/Chart Position Graph
// @namespace      http://abhin4v.myinfo.ws
// @include        http://www.last.fm/artist/*
// @include        http://www.last.fm/music/*
// @exclude        http://www.last.fm/music/*/+*
// @exclude        http://www.last.fm/artist/*/+*
// @exclude        http://www.last.fm/music/*/*/+*
// @exclude        http://www.last.fm/artist/*/*/+*
// @exclude        http://www.last.fm/music/*/*/*/+*
// @exclude        http://www.last.fm/artist/*/*/*/+*
// ==/UserScript==



(function() {
    lastfmPlaycountsVariation = {
        $x: function(p, context) {
            if (!context) context = document;
            var i, arr = [], xpr = document.evaluate(p, context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
            for (i = 0; item = xpr.snapshotItem(i); i++) arr.push(item);
            return arr;
        },
        
        getUser: function() {
            if (this.$x("/html/body/div/div/div[2]/ul/li[2]/a")[0].innerHTML == "Log in")
                return '';
            
            return this.$x("/html/body/div/div/div/div/a[2]")[0].innerHTML;
        },
        
        getArtist: function() {
            return this.$x("/html/body/div[2]/div[3]/h1/a")[0].innerHTML;   
        },
        
        getData: function(url, cb) {
            //GM_log("url = "+url);
            GM_xmlhttpRequest({
                method: "GET",
                url: url,
                onload: function(xhr) {
                    if (xhr.status == 200) cb("(" + xhr.responseText + ")");
                }    
            });
        },
        
        parseData: function(data) {
            //GM_log(data);
            data = eval(data);
            
            window.setTimeout(function() {}, 1000);
            var chartData = {'from':[],'playcount':[],'chartposition':[],'x':[],'y1':[],y2:[], 'ex':'','ey1':'',ey2:''};
            var maxPlaycount = 0;
            var maxChartposition = 0;
            var maxFrom = parseInt(data.value.items[data.value.items.length-1].from);
            var minFrom = parseInt(data.value.items[0].from);
            
            beginDate = new Date(minFrom*1000);
            endDate = new Date(maxFrom*1000);
            
            var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
            beginMonth = beginDate.getMonth();
            endMonth = endDate.getMonth();
            beginYear = beginDate.getFullYear();
            endYear = endDate.getFullYear();
            
            //GM_log(months[beginMonth]+ " " + beginYear);
            //GM_log(months[endMonth]+ " " + endYear);
            
            monthsCount = (endYear - beginYear)*12 + (endMonth - beginMonth);
            chartMonths = [];
            chartYears = [];
            
            for (var i = 0; i < monthsCount; i++) {
                if (i%3 == 0) chartMonths.push(months[(beginMonth + i)%12]);
                else chartMonths.push('');
                if (i%12 == 0) chartYears.push(beginYear + Math.floor(i/12));
                else chartYears.push('');
                
            }
                
            chartMonths.push('');
            chartYears.push('');
            //GM_log(chartMonths);
            
            
            
            data.value.items.forEach(
                function(item) {
                    chartData.from.push(parseInt(item.from));
                    chartData.x.push(parseInt(item.from)-minFrom);
                    if (item.playcount != null) {                        
                        chartData.playcount.push(parseInt(item.playcount));
                        chartData.chartposition.push(parseInt(item.chartposition));
                        chartData.y1.push(parseInt(item.playcount));
                        if (maxPlaycount < parseInt(item.playcount)) maxPlaycount = parseInt(item.playcount);
                        if (maxChartposition < parseInt(item.chartposition)) maxChartposition = parseInt(item.chartposition);
                    }
                    else {
                        chartData.playcount.push(-1);
                        chartData.chartposition.push(-1);
                        chartData.y1.push(-1);
                    }
                }
            );
            
            for (var i = 0; i < chartData.chartposition.length; i++) {
                if (chartData.chartposition[i] != -1)
                    chartData.y2[i] = maxChartposition -(chartData.chartposition[i] - 1);
                else
                    chartData.y2[i] = -1;
            }
            
            chartData.ex = lastfmPlaycountsVariation.simpleEncode(chartData.x, maxFrom-minFrom);
            chartData.ey1 = lastfmPlaycountsVariation.simpleEncode(chartData.y1, maxPlaycount);
            chartData.ey2 = lastfmPlaycountsVariation.simpleEncode(chartData.y2, maxChartposition);
            //GM_log(chartData.ex);
            //GM_log(chartData.ey1);
            //GM_log(chartData.ey2);
            /*chartData.cx = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
            chartData.cy = lastfmPlaycountsVariation.compressData(chartData.ex, chartData.ey);
            
            cmaxPlaycount = 0;
            for (var i=0; i < chartData.cy.length; i++) {
                var playcount = chartData.cx.indexOf(chartData.cy.charAt(i));
                if (playcount > cmaxPlaycount) cmaxPlaycount = playcount;
            }*/
            
            //GM_log(chartData.cx);
            //GM_log(chartData.cy);
            insertHere = lastfmPlaycountsVariation.$x('/html/body/div[2]/div[5]/div/div[2]/div[2]/div/h3')[0];
            maxHeight = (maxChartposition > maxPlaycount) ? maxChartposition : maxPlaycount;
            //GM_log(maxPlaycount + " " + maxChartposition + " " + maxHeight);
            width = parseInt(insertHere.offsetWidth) - 10;
            height = Math.round(width/3) + 5;
            chartImgUrl = 'http://chart.apis.google.com/chart?' +
                'chs=' + width + 'x' + height + '&' +
                'chd=s:' + chartData.ex + ',' + chartData.ey1 + ',' + chartData.ex + ',' + chartData.ey2 + '&' +
                //'chtt=Playcount+over+time&' +
                'cht=lxy&' +
                'chm=r,E5ECF9,0,' + Math.round((1-10/maxChartposition)*100)/100 + ',1.00&' +
                'chxt=x,x,y,r&' +
                'chco=FF9933,6666CC,E5ECF9&' +
                'chdl=Playcount|Chart Position|Top 10&' +
                'chxl=' + '0:|' + chartMonths.join('|') +
                '|1:|' + chartYears.join('|') + 
                '|2:|0|' + Math.floor(maxPlaycount/5) + '|' + Math.floor(2*maxPlaycount/5) + '|' + Math.floor(3*maxPlaycount/5) + '|' + Math.floor(4*maxPlaycount/5) + '|' + maxPlaycount +
                '|3:|' + maxChartposition + '|' + Math.floor(4*maxChartposition/5) + '|' + Math.floor(3*maxChartposition/5) + '|' + Math.floor(2*maxChartposition/5) + '|' + Math.floor(maxChartposition/5) + '|1';
                
            //GM_log(chartImgUrl);
                        
            d = document.createElement('div');
            i = document.createElement('img');
            h3 = document.createElement('h3');
            h3.innerHTML = 'Artist Playcount/Chart Position Graph';
            i.src = chartImgUrl;
            i.style.padding = "2px";
            i.style.backgroundColor = "#FFFFFF";
            d.appendChild(h3);
            d.appendChild(i);
            insertHere.parentNode.insertBefore(d, insertHere);
            
        },
        
        simpleEncode: function(values,maxValue) {
            var simpleEncoding = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
            var chartData = [];
            for (var i = 0; i < values.length; i++) {
                var currentValue = values[i];
                if (!isNaN(currentValue) && currentValue >= 0) {
                    chartData.push(simpleEncoding.charAt(Math.round((simpleEncoding.length-1) * currentValue / maxValue)));
                } else {
                    chartData.push('_');
                }
            }
            return chartData.join('');
        },
        
        compressData: function(x, y) {
            var cy = [];
            var simpleEncoding = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
            for (var i = 0; i < simpleEncoding.length; i++) {
                cy[i] = [];
            }
            for (var i = 0; i < x.length; i++) {
                idx = simpleEncoding.indexOf(x.charAt(i));
                cy[idx].push(simpleEncoding.indexOf(y.charAt(i)));
            }
            
            for (var i = 0; i < cy.length; i++) cy[i] = lastfmPlaycountsVariation.avg(cy[i]);
            //GM_log(uneval(cy));
            return(lastfmPlaycountsVariation.simpleEncode(cy, simpleEncoding.length-1));
        },
        
        avg: function(nums) {
            sum = 0;
            flag = 1;
            for (var i = 0; i< nums.length; i++)
                if (nums[i] != -1) {
                    sum += nums[i];
                    flag = 0;
                }
            
            if (flag) return(-1);
            return(Math.round(sum/nums.length));
        }    
    };
    
    //insertHere = lastfmPlaycountsVariation.$x("/html/body/div/div[4]/div/div[2]/div[2]/div/h3")[0];
    //insertHere.parentNode.insertBefore(document.createElement('div'), insertHere).innerHTML = "<canvas id='canvas' height='300' width='400'></canvas>";
    
            
    user = lastfmPlaycountsVariation.getUser();
    //GM_log("user = "+user);
    if (user != '') {
        artist = lastfmPlaycountsVariation.getArtist();
        //GM_log("artist = "+artist);
        dataURL = "http://pipes.yahoo.com/pipes/pipe.run?_id=DPyk_K9E3BGNzxTTDtXErg&_render=json&artist="+artist+"&user="+user;
        lastfmPlaycountsVariation.getData(
            dataURL,
            lastfmPlaycountsVariation.parseData
        );
    }
})();