Deviant Statistics

By falexx Last update Apr 4, 2009 — Installed 1,231 times. Daily Installs: 4, 0, 1, 3, 2, 0, 1, 1, 0, 0, 1, 3, 0, 0, 0, 0, 3, 0, 2, 2, 0, 1, 1, 2, 1, 0, 2, 1, 0, 0, 1, 0

There are 7 previous versions of this script.

// ==UserScript==
// @name            Deviant Statistics
// @namespace        falexx.deviantart.com
// @description        Displays additional statistics about a Deviant.
// @include            http://*.deviantart.com/
// @include            http://*.deviantart.com/?*
// ==/UserScript==

/**** COPYRIGHT STUFF GOES HERE
* If you have done some improvements to this script, please let me know :)
****/


var styles = [];
var dialog;

//displaying a friendsmenu while not logged in isn't a good idea
if(!unsafeWindow.deviantART.deviant)
    return;
if(!(dialog=$X('//div[@id="super-secret-stats"]/div/div/div[@class="pbox pppbox"]')[0]))
    return;

var Settings = {
    Version : '3.3',
    Url : {
        updVersion : 'http://da.elexx.org/stats/version.php',
        updScript : 'http://da.elexx.org/stats/deviantstatistics.user.js',
        
        statisticsData : 'http://'+window.location.host+'/stats/gallery/'
    }
}
GM_log(Settings.Url.statisticsData);
/* Install the updater */
if(!$('gmscripts-updater')){
    $('rockdock-message-count').insertAfter($E('span', {id:'gmscripts-updater',style:{position:'relative'}}));
    $('rockdock-message-count').insertAfter($S(' | '));
    
    $('gmscripts-updater').innerHTML = '<a href="#updating" id="gmscripts-updatelink">All scripts are up-to-date.</a><ul id="gmscripts-updatelist"><li>Updatable scripts:</li></ul>';
    
    GM_addStyle('#gmscripts-updatelist { display:none; position:absolute; top:15px; left:0px; background-color:#40534A; border:1px solid #6B8075; list-style:none; margin:0px; padding:0px 5px; }');
    GM_addStyle('#gmscripts-updatelist li:first-child { font-weight:bold; border-bottom:1px solid #707E77; }');

    addEvent($('gmscripts-updatelink'), 'click', function(evt){evt.preventDefault();}, true);
}

if(GM_getValue('timeToUpdate', -1) < Math.floor(new Date().getTime() / 1000 / 60 / 60 / 24))
    get(Settings.Url.updVersion,
        function(e){
            var version=e.replace(/[^a-z0-9.]/g, '');
            var updateLink=$('gmscripts-updatelink');
            
            if(version!=Settings.Version){
                /* We found a different version!! */
                $('gmscripts-updatelist').appendChild($E('li', {}, [$E('a', {href:Settings.Url.updScript}, ['DeviantStatistics'])]));
    
                if(updateLink.innerHTML=='All scripts are up-to-date.')
                    updateLink.innerHTML='1 script is not up-to-date.';
                else
                    updateLink.innerHTML=(parseInt(/^(\d+)/.exec(updateLink.innerHTML)[1])+1) + ' scripts are not up-to-date.'
    
                GM_addStyle('#gmscripts-updatelist:hover { display:block; }');
                GM_addStyle('#gmscripts-updater:hover #gmscripts-updatelist { display:block; }');
            }
            else
                /* Nothing different, let's check tomorrow again */
                GM_setValue('timeToUpdate', Math.floor(new Date().getTime() / 1000 / 60 / 60 / 24));
        }
    );

/* Get, calculate and display the statistics */
var Cache = {
    
    top : {fullviews:null, views:null, favourites:null, comments:null, cat:{name:'',count:0}, caty:{name:'',count:0}},
    total : {given:{comments:0, favourites:0, watches:0}, received:{comments:0, favourites:0, watches:0}, categories:0, pageviews:0, views:0, deviations:0, scraps:0, shouts:0, forumposts:0},
    average : {day:{given:{comments:0, favourites:0, watches:0}, received:{comments:0, favourites:0, watches:0}, uploads:0, pageviews:0, views:0}, deviation:{comments:0, favourites:0, views:0}},
    other : {username:null},
    
    getData : function(){
        var sSpan = $X('//div[@class="blues-bar-ctrl"]/span[@class="bb bb-with-sep"]/a/span[@class="tight"]')[0];
        sSpan.innerHTML += '<br /><span id="dsStatus">Loading ...</span>';
        get(Settings.Url.statisticsData, function(e){
            e = e.substring(e.indexOf('deviantART.pageData=')+20);
            e = e.substring(0, e.indexOf('\n</script>'));
    
            eval('var gFeed = ' + e.replace(/\\'|\\\\"/g, '\'') + ';');
            Cache.checkAndCalcData(gFeed);
            window.setTimeout(function(){ $('dsStatus').remove(); GM_addStyle('div.blues-bar span.bb span.tight { font-size:7pt !important; top:-0.1em !important; }');}, 3000);
        });
    },
    
    checkAndCalcData : function(feed){
        if(!feed.userstats){
            if(window.location.host.substring(0, window.location.host.indexOf('.')) == unsafeWindow.deviantART.deviant.username)
                dialog.parentNode.appendChild($E('div',{className:'pbox pppbox'},['Make sure you checked the "Accept thir-party cookies" in your Firefox Preferences => Privacy => Cookies. Or add an exception for "deviantart.com" on the right side of the preference window!']));
            if($X('//div[@class="gruserbadge"]/h1')[0].innerHTML.indexOf('!')>=0)
                dialog.parentNode.appendChild($E('div',{className:'pbox pppbox'},['No additional statistics, because this Deviant got banned.']));
            else
                dialog.parentNode.appendChild($E('div',{className:'pbox pppbox'},['This user doesn\'t allow you to access the statistics.']));
            
            $('dsStatus').innerHTML = 'An error occurred';
            return;
        }
    
        if(feed.devstats.length==0){
            dialog.parentNode.appendChild($E('div',{className:'pbox pppbox'},['No additional statistics, because the gallery is empty.']));
            $('dsStatus').innerHTML = 'An error occurred';
            return;
        }

        $('dsStatus').innerHTML = 'Calculating ...';
        
        /* Copy copy copy */
        this.other.username = feed.userstats.username;
        
        this.total.given.comments = feed.userstats.comments;
        this.total.given.favourites = feed.userstats.favourites;
        this.total.given.watches = feed.userstats.friends;
        
        this.total.received.watches = feed.userstats.friendswatching;
        
        this.total.pageviews = feed.userstats.pageviews;
        this.total.deviations = feed.userstats.deviations;
        this.total.scraps = feed.userstats.scraps;
        this.total.shouts = feed.userstats.shouts;
        this.total.forumposts = feed.userstats.forum_posts;
        
        /* Now calculate the rest */
        var cat = [];
        var caty = [];
        for(i in feed.devstats){
            var D = feed.devstats[i];
            
            $('dsStatus').innerHTML = D.title;
            
            this.total.received.comments += D.comments;
            this.total.received.favourites += D.favourites;
            this.total.views += D.views;
            
            if(!this.top.fullviews || D.fullviews > this.top.fullviews.fullviews) this.top.fullviews = D;
            if(!this.top.views || D.views > this.top.views.views) this.top.views = D;
            if(!this.top.favourites || D.favourites > this.top.favourites.favourites) this.top.favourites = D;
            if(!this.top.comments || D.comments > this.top.comments.comments) this.top.comments = D;
            
            
            D.cat = D.category.split('/')[0];

            if(cat[D.cat]) cat[D.cat]++;
            else cat[D.cat] = 1;
            
            if(cat[D.cat] > this.top.cat.count){
                this.top.cat.name = D.cat;
                this.top.cat.count = cat[D.cat];
            }
    
            if(caty[D.category]) caty[D.category]++;
            else{
                caty[D.category] = 1;
                this.total.categories++;
            }
            if(caty[D.category] > this.top.caty.count){
                this.top.caty.name = D.category;
                this.top.caty.count = caty[D.category];
            }
        
        }
        
        var daysSinceJoined = Math.floor((new Date().getTime() - new Date(feed.userstats.since).getTime()) / 1000 / 60 / 60 / 24);
        this.average.day.given.comments = this.total.given.comments / daysSinceJoined;
        this.average.day.given.favourites = this.total.given.favourites / daysSinceJoined;
        this.average.day.given.watches = this.total.given.watches / daysSinceJoined;
        this.average.day.received.comments = this.total.received.comments / daysSinceJoined;
        this.average.day.received.favourites = this.total.received.favourites / daysSinceJoined;
        this.average.day.received.watches = this.total.received.watches / daysSinceJoined;
        this.average.day.uploads = (this.total.deviations + this.total.scraps) / daysSinceJoined;
        this.average.day.pageviews = this.total.pageviews / daysSinceJoined;
        this.average.day.views = this.total.views / daysSinceJoined;
        
        this.average.deviation.comments = this.total.received.comments / (this.total.deviations + this.total.scraps);
        this.average.deviation.favourites = this.total.received.favourites / (this.total.deviations + this.total.scraps);
        this.average.deviation.views = this.total.views / (this.total.deviations + this.total.scraps);
        
        Cache.displayData();
    },
    
    displayData : function(){
        /* Ereasing the original displayed data */
        dialog.innerHTML = ''; // :-)
        
        dialog.newInfo(this.total.deviations, 'Deviation#');
        dialog.newInfo(this.total.scraps, 'Scrap#');
        dialog.newInfo(this.total.pageviews, 'Pageview#');
        dialog.newInfo(this.total.views, 'View#');
        dialog.newInfo(this.total.shouts, 'Shout#');
        dialog.newInfo(this.total.forumposts, 'Forum Post#');
        dialog.newInfo(this.total.categories, 'Different Categories');
        dialog.newSpacer();
        dialog.newInfo(this.total.given.comments, 'Comment# given');
        dialog.newInfo(this.total.received.comments, 'Comment# received');
        dialog.newInfo(this.total.given.favourites, 'Favourite# given');
        dialog.newInfo(this.total.received.favourites, 'Favourite# received');
        dialog.newInfo(this.total.given.watches, 'Friend#');
        dialog.newInfo(this.total.received.watches, 'Watcher#');
        dialog.newSpacer();
        dialog.newInfo(this.average.day.given.comments, 'Comment# given per day');
        dialog.newInfo(this.average.day.received.comments, 'Comment# received per day');
        dialog.newInfo(this.average.day.given.favourites, 'Favourite# given per day');
        dialog.newInfo(this.average.day.received.favourites, 'Favourite# received per day');
        dialog.newInfo(this.average.day.given.watches, 'Friend# added per day');
        dialog.newInfo(this.average.day.received.watches, 'Watche# received per day');
        dialog.newSpacer();
        dialog.newInfo(this.average.day.uploads, 'Submission# per day');
        dialog.newInfo(this.average.day.pageviews, 'Pageview# per day');
        dialog.newInfo(this.average.day.views, 'View# per day');
        dialog.newSpacer();
        dialog.newInfo(this.average.deviation.comments, 'Comment# received per Deviation');
        dialog.newInfo(this.average.deviation.favourites, 'Favourite# received per Deviation');
        dialog.newInfo(this.average.deviation.views, 'View# received per Deviation');
        dialog.newSpacer();
        dialog.newUrl(this.top.views.views, 'Most viewed Deviation', this.top.views.id, this.top.views.title);
        dialog.newUrl(this.top.fullviews.fullviews, 'Most fullviewed Deviation', this.top.fullviews.id, this.top.fullviews.title);
        dialog.newUrl(this.top.favourites.favourites, 'Most favoured Deviation', this.top.favourites.id, this.top.favourites.title);
        dialog.newUrl(this.top.comments.comments, 'Most commented Deviation', this.top.comments.id, this.top.comments.title);
        dialog.newSpacer();
        dialog.innerHTML += 'Most used gallery: <a href="http://'+this.other.username+'.deviantart.com/gallery/#_browse/'+this.top.cat.name+'/" class="a">'+this.top.cat.name.replace(/\//g,' > ')+'</a> (<strong>'+comma(this.top.cat.count)+' Deviations</strong>)<br />';
        dialog.innerHTML += 'Most used category: <a href="http://'+this.other.username+'.deviantart.com/gallery/#_browse/'+this.top.caty.name+'/" class="a">'+this.top.caty.name.replace(/\//g,' > ')+'</a> (<strong>'+comma(this.top.caty.count)+' Deviations</strong>)<br />';
        //dialog.newCat(this.top.cat.count, 'Most used gallery', this.top.cat.name);
        //dialog.newCat(this.top.caty.count, 'Most used category', this.top.caty.name);

        $('dsStatus').innerHTML = 'Finished';
        GM_addStyle('body div.popup2-gruser-stats { width:auto; white-space:nowrap; }');
    }
}

/* Now start it!!! */
Cache.getData();


/* Do the prototyping!! */
String.prototype.trim = function(){
    return this.replace(/^\s+|\s+$/g, '');
}
dialog.newInfo = function(num, txt){
    txt = num==1 ? txt.replace(/#/,'') : txt.replace(/#/,'s');
    this.innerHTML += '<strong>'+comma(num)+'</strong> '+txt + '<br />';
}
dialog.newUrl = function(num, txt, url, urlTxt){
    this.innerHTML += txt+': <a href="http://www.deviantart.com/deviation/'+url+'/" class="a">'+urlTxt+'</a> (<strong>'+comma(num)+'</strong>)<br />';
}
dialog.newCat = function(num, txt, url){
    this.innerHTML += txt+': <a href="http://browse.deviantart.com/'+url+'/" class="a">'+url.replace(/\//g,' > ')+'</a> (<strong>'+comma(num)+' Deviations</strong>)<br />';
}
dialog.newSpacer = function(){
    this.innerHTML += '<hr />';
}

function $(id){
    var el =(typeof(id)=='string'?document.getElementById(id):false);
    if(el){
        el.remove=function(){
            this.parentNode.removeChild(this);
        }
        el.insertAfter=function(newElement) {
            if(this.parentNode.lastchild == this)
                this.parentNode.appendChild(newElement);
            else
                this.parentNode.insertBefore(newElement, this.nextSibling);
        }
    }
    return el;
}

function $X(xpath,root){
    var got=document.evaluate(xpath,root||document,null,null,null), result=[];
    while(next=got.iterateNext()) result.push(next);
    return result;
}

function $E(tag, attributes, children){
    var e=document.createElement(tag);
    
    function applyObj(to, obj){
        for(prop in obj) if(obj.hasOwnProperty(prop))
            if(typeof(obj[prop])=='object')
                applyObj(to[prop], obj[prop]);
            else
                to[prop]=obj[prop];
    }

    applyObj(e, attributes);
    for(var c in children)
        if(typeof(children[c])=='string') e.appendChild($S(children[c]));
        else e.appendChild(children[c]);

    return e;
}

function $S(str){
    return document.createTextNode(str);
}

function comma(flo) {
    if(!flo) return 'none';
    
    flo = new String(Math.floor(flo*100)/100);
    var integer = flo.split('.')[0];
    
    if(integer.length>3) {
        var start = integer.length-3;
        return comma(integer.substring(0,start))+','+integer.substring(start);
    }
    else if(flo.split('.').length > 1)
        return integer+'.'+flo.split(".")[1];
    else
         return integer;
}

function addEvent(obj, evType, fn, useCapture){
    if(!obj) return;
    if(typeof(evType)=='string') evType=[evType];
    evType.forEach(
        function(evnt, idx, ary){
            obj.addEventListener(evnt, fn, useCapture);
        }
    )
}

/* get post data */
function get(url,cb){GM_xmlhttpRequest({method:"GET", url:url, headers:{'User-Agent':'Firefox / GreaseMonkey / deviantFriends'}, onload:function(xhr){cb(xhr.responseText,xhr.status)}})}

styles.push('body div.popup2-gruser-stats { height:auto !important; }');  
styles.push('.pppbox hr { margin-top:15px; }');
styles.push('div.blues-bar span.bb span.tight { font-size:6pt !important; top:-0.5em !important; }');
GM_addStyle(styles.join('\n'));