// ==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
// @downloadURL https://update.greasyfork.icu/scripts/22003/Dribbble%20Extender.user.js
// @updateURL https://update.greasyfork.icu/scripts/22003/Dribbble%20Extender.meta.js
// ==/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('✓ '+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('✓ '+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('✓ '+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('✓ '+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('✓ '+title.html());
}
})();