Dribbble Extender

Shows who follows you on your following list

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Dribbble Extender
// @description  Shows who follows you on your following list
// @author       Kos
// @namespace    http://tampermonkey.net/
// @version      0.5
// @license      CC BY-SA 2.0
// @homepage     https://greasyfork.org/scripts/22003-dribbble-extender
// @include      https://dribbble.com/*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// @grant        GM_addStyle
// ==/UserScript==

;(function() {
    'use strict';
    
    // styles for checkmark
    GM_addStyle(
        '.us-follows-you-mark {color:#b3e3bd;font-weight:200}\
        .us-fetch-ready {color:#2cff5a;font-weight:900}'
    );

    var ACCESS_TOKEN = '9eafaa85aba0e22cdd7b7ddaa23181b59c29989dbd27000c78db21f5609110f4',
        followers = [],
        // username
        username = $('.has-sub .profile-name').parent().attr('href').replace('/', ''),
        cacheKey = username,
        curPage = 1,
        perPage = 100,
        repaintDelay = 500,
        waitForAllFetch = false,
        requestPerIteration = 15,
        requestsResponseLeftCount = 0,
        mainIntervalStopped = true,
        lastIntervalFoundFollowers = null,
        justCache = false;

    // if not recognized logged in user, exit
    if (username == '')
    {
        return;
    }
    
    // functions for working with localStorage

    function lsTest()
    {
        var test = 'test';
        try
        {
            localStorage.setItem(test, test);
            localStorage.removeItem(test);
            return true;
        }
        catch(e)
        {
            return false;
        }
    }

    function getLocalStorageArray(name)
    {
        var list = localStorage.getItem(name);
        if (!list)
        {
            return [];
        }
        return JSON.parse(list);
    }

    function saveUpdatedFollowersList(list)
    {
        localStorage.setItem(cacheKey+'_followers_latest', JSON.stringify(list));
    }

    function addFollowerLocalStorage(id)
    {
        var list = getLocalStorageArray(cacheKey+'_followers_latest');

        if (list.indexOf(id) == -1)
        {
            list.push(id);
        }

        saveUpdatedFollowersList(list);
    }

    function saveFinishedAmountOfFollowers()
    {
        var list = getLocalStorageArray(cacheKey+'_followers_latest');

        localStorage.setItem(cacheKey+'_followers', JSON.stringify(list));
        saveUpdatedFollowersList([]);

        // update on page
        followers = list;
        paintFollowed();
    }

    var localStorageAvailable = lsTest();

    $(document).ready(function(){

        if (localStorageAvailable)
        {
            followers = getLocalStorageArray(cacheKey+'_followers');

            // if have previously saved followers, increase delay,
            // update on page only when all users parsed
            if (followers.length)
            {
                waitForAllFetch = true;
                
                // cache results for 5 minutes
                if (localStorageAvailable)
                {
                    var lastFetchTime = localStorage.getItem(cacheKey+'_last_followers_fetch');
                    if (lastFetchTime && new Date().getTime() - lastFetchTime < 5*60*1000)
                    {
                        justCache = true;
                        waitForAllFetch = false;
                    }
                }
            }

            // clear previously parsed data, to parse all new
            saveUpdatedFollowersList([]);
        }

        function finishParse()
        {
            if (mainIntervalStopped)
            {
                return;
            }

            clearInterval(mainInterval);
            mainIntervalStopped = true;
            
            if (localStorageAvailable)
            {
                localStorage.setItem(cacheKey+'_last_followers_fetch', new Date().getTime());
            }
        }
        
        if (!justCache)
        {
            mainIntervalStopped = false;
            
            var mainInterval = setInterval(function(){
                // if there are request we wait to finish, exit
                if (requestsResponseLeftCount > 0)
                {
                    return;
                }
                // if not found any users on last interval
                if (lastIntervalFoundFollowers !== null && lastIntervalFoundFollowers === 0)
                {
                    finishParse();
                    return;
                }
                requestsResponseLeftCount = requestPerIteration;
                lastIntervalFoundFollowers = 0;
                for (var i = 0; i < requestPerIteration; i++)
                {
                    $.ajax({
                        type: 'GET',
                        url: 'https://api.dribbble.com/v1/users/'+username+'/followers/?page='+(curPage++)+'&per_page='+perPage,
                        beforeSend: function(jqxhr)
                        {
                            jqxhr.setRequestHeader('Authorization', 'Bearer ' + ACCESS_TOKEN);
                        },
                        success: function(res)
                        {
                            if (res.length === 0)
                            {
                                finishParse();
                                return;
                            }

                            for (var i = 0; i < res.length; i++)
                            {
                                setFollowed(res[i].follower.id);
                                lastIntervalFoundFollowers++;
                            }

                            // if not full page, assume it last one
                            if (res.length < perPage)
                            {
                                finishParse();
                            }
                        },
                        complete: function(){
                            requestsResponseLeftCount--;
                            // if this is last response of last iteration, save ids for page
                            // in this 'if' fetch ends
                            if (requestsResponseLeftCount === 0 && mainIntervalStopped)
                            {
                                if (localStorageAvailable)
                                {
                                    saveFinishedAmountOfFollowers();
                                }
                            }
                        }
                    });
                }
            }, 100);
        }

        // paint then set repaint with delay
        paintFollowed();
        setInterval(paintFollowed, repaintDelay);
    });
    
    function setFollowed(id)
    {
        id = Math.round(id);

        if (!waitForAllFetch && followers.indexOf(id) == -1)
        {
            followers.push(id);
        }

        if (localStorageAvailable)
        {
            addFollowerLocalStorage(id);
        }
    }

    function paintFollowed()
    {
        paintOnFollowingPage();
        paintOnShotPage();
        paintOnShotsListPage();
        paintOnCommentsPage();
        paintOnUserPage();
    }
    
    function paintOnFollowingPage()
    {
        var following = $('ol.list-of-scrolling-rows').find('.scrolling-row');
        
        if (following.length == 0)
        {
            return;
        }

        for (var i = 0; i < following.length; i++)
        {
            var userId = parseInt(following[i].className.match(/.*?user-row-(\d+).*/)[1]),
                userBlock = $(following[i]),
                title = userBlock.find('.hover-card-parent');

            // if not followed, remove mark if has one
            if (followers.indexOf(userId) == -1)
            {
                userBlock.removeClass('us-follows-you');
                userBlock.find('.us-follows-you-mark').remove();
                continue;
            }

            // if already marked as follower do nothing until all fetched
            if (userBlock.hasClass('us-follows-you'))
            {
                if (mainIntervalStopped)
                {
                    userBlock.find('.us-follows-you-mark').addClass('us-fetch-ready');
                }
                continue;
            }

            // set mark of follower
            userBlock.addClass('us-follows-you');
            title.html('<span title="Follows you" class="us-follows-you-mark'+(mainIntervalStopped ? ' us-fetch-ready' : '')+'">✓ </span>'+title.html());
        }
    }
    
    function paintOnShotsListPage()
    {
        var dribbbles = $('ol.dribbbles > li');
        
        if (dribbbles.length == 0)
        {
            return;
        }

        for (var i = 0; i < dribbbles.length; i++)
        {
            var userBlock = $(dribbbles[i]);
            if (userBlock.find('.attribution-team').length)
            {
                continue;
            }
            
            var avatar = userBlock.find('.attribution-user img');

            // avatar is not loaded yet
            if (!avatar || !avatar.attr('src'))
            {
                return;
            }
            
            
            var userId = parseInt(avatar.attr('src').match(/users\/(\d+)/)[1]),
                title = userBlock.find('.attribution-user a').first();

            // if not followed, remove mark if has one
            if (followers.indexOf(userId) == -1)
            {
                userBlock.removeClass('us-follows-you');
                userBlock.find('.us-follows-you-mark').remove();
                continue;
            }

            // if already marked as follower do nothing until all fetched
            if (userBlock.hasClass('us-follows-you'))
            {
                if (mainIntervalStopped)
                {
                    userBlock.find('.us-follows-you-mark').addClass('us-fetch-ready');
                }
                continue;
            }

            // set mark of follower
            userBlock.addClass('us-follows-you');
            title.html('<span title="Follows you" class="us-follows-you-mark'+(mainIntervalStopped ? ' us-fetch-ready' : '')+'">✓ </span>'+title.html());
        }
    }
    
    function paintOnCommentsPage()
    {
        var dribbbles = $('ol.comments > li');
        
        if (dribbbles.length == 0)
        {
            return;
        }

        for (var i = 0; i < dribbbles.length; i++)
        {
            var userBlock = $(dribbbles[i]),
                userId = parseInt(userBlock.attr('data-user-id')),
                title = userBlock.find('h2');

            // if not followed, remove mark if has one
            if (followers.indexOf(userId) == -1)
            {
                userBlock.removeClass('us-follows-you');
                userBlock.find('.us-follows-you-mark').remove();
                continue;
            }

            // if already marked as follower do nothing until all fetched
            if (userBlock.hasClass('us-follows-you'))
            {
                if (mainIntervalStopped)
                {
                    userBlock.find('.us-follows-you-mark').addClass('us-fetch-ready');
                }
                continue;
            }

            // set mark of follower
            userBlock.addClass('us-follows-you');
            title.html('<span title="Follows you" class="us-follows-you-mark'+(mainIntervalStopped ? ' us-fetch-ready' : '')+'">✓ </span>'+title.html());
        }
    }
    
    function paintOnShotPage()
    {
        var userBlock = $('.user');
        
        if (userBlock.length == 0)
        {
            return;
        }

        var userId = parseInt($('.user > a[rel=contact] img.photo').attr('src').replace(/.*users\/(\d+).*/, '$1')),
            title = userBlock.find('.shot-byline-user a');

        // if not followed, remove mark if has one
        if (followers.indexOf(userId) == -1)
        {
            userBlock.removeClass('us-follows-you');
            userBlock.find('.us-follows-you-mark').remove();
            return;
        }

        // if already marked as follower do nothing until all fetched
        if (userBlock.hasClass('us-follows-you'))
        {
            if (mainIntervalStopped)
            {
                userBlock.find('.us-follows-you-mark').addClass('us-fetch-ready');
            }
            return;
        }

        // set mark of follower
        userBlock.addClass('us-follows-you');
        title.html('<span title="Follows you" class="us-follows-you-mark'+(mainIntervalStopped ? ' us-fetch-ready' : '')+'">✓ </span>'+title.html());
    }
    
    function paintOnUserPage()
    {
        var userBlock = $('.profile-head');
        
        if (userBlock.length == 0)
        {
            return;
        }

        var avatar = $($('.profile-head img.photo')[0]);
        
        // avatar is not loaded yet
        if (!avatar || !avatar.attr('src'))
        {
            return;
        }
        
        var userId = parseInt(avatar.attr('src').replace(/.*users\/(\d+).*/, '$1')),
            title = userBlock.find('.profile-name a');

        // if not followed, remove mark if has one
        if (followers.indexOf(userId) == -1)
        {
            userBlock.removeClass('us-follows-you');
            userBlock.find('.us-follows-you-mark').remove();
            return;
        }

        // if already marked as follower do nothing until all fetched
        if (userBlock.hasClass('us-follows-you'))
        {
            if (mainIntervalStopped)
            {
                userBlock.find('.us-follows-you-mark').addClass('us-fetch-ready');
            }
            return;
        }

        // set mark of follower
        userBlock.addClass('us-follows-you');
        title.html('<span title="Follows you" class="us-follows-you-mark'+(mainIntervalStopped ? ' us-fetch-ready' : '')+'">✓ </span>'+title.html());
    }
})();