Dribbble Extender

Shows who follows you on your following list

// ==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://gf.qytechs.cn/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());
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址