Source for "Tumblr - Check New Followers"

By brasil
Has 24 other scripts.


// ==UserScript==
// @name           Tumblr - Check New Followers
// @namespace      http://userscripts.org/scripts/show/9436
// @include        http://www.tumblr.com/dashboard
// ==/UserScript==

// 2007/11/28 DOM Storage (for browser crash)
// 2007/11/04 Tumblr v3

var CHECK_LEAVER = false;
var CHECK_INTERVAL = 24*60*60*1000;
var ID = 'CNF_'+$x('//li[@class="post is_mine with_avatar"]//div[@class="username"]/a/@href');


var lastChecked = storage(ID+'lastChecked') || 0;
var now = (new Date()).getTime();
if((now - lastChecked) > CHECK_INTERVAL)
	checkNewFollower(true);


function checkNewFollower(quiet){
	getUsers('followers', function(current){
		var old = storage(ID + 'followers');
		storage(ID+'lastChecked', (new Date()).getTime());
		storage(ID+'followers', current);
		if(!old){
			if(!quiet) alert('Initialized!');
			return;
		}
		
		var comers = diff(current, old);
		var leavers = CHECK_LEAVER? diff(old, current) : {};
		
		if(isEmpty(comers) && isEmpty(leavers)){
			if(!quiet) alert("There is no change in the followers.");
			return;
		}
		
		if(!confirm([
			(isEmpty(comers) ? '' : '[+] New Followers\n\n' + keys(comers).join(' / ')),
			(isEmpty(leavers) ? '' : '[-] Leaved Followers\n\n' + keys(leavers).join(' / ')),
			'Are you sure you want to open tabs?'
		].join('\n\n'))){
			return;
		}
		
		for(var name in comers){
			GM_openInTab(comers[name]);
		}
	})
}

GM_registerMenuCommand('Check New Followers', checkNewFollower);

GM_registerMenuCommand('Open OPML(Followers)', function(){
	getUsers('followers', openOPML);
});

GM_registerMenuCommand('Open OPML(Friends)', function(){
	getUsers('following', openOPML);
});

// ----[Application]-------------------------------------------------
function openOPML(ps){
	var opml = <opml version="1.0">
		<body>
			<outline title="Subscriptions" />
		</body>
	</opml>
	
	for(var p in ps)
		opml.body.outline.outline += <outline type="rss" title={p} htmlUrl={ps[p]} xmlUrl={ps[p]+"rss"} />
	
	GM_openInTab('data:application/xml;charset=utf-8,' + opml.toXMLString());
}

function getUsers(type, callback){
	getText('http://www.tumblr.com/' + type, function(text){
		var doc = convertToHTMLDocument(text);
		var res = {};
		map(
			function(link){
				res[link.textContent]=link.getAttribute('href');
			}, 
			$x('//div[@class="username"]/a', doc));
		callback(res);
	});
}

function diff(a, b){
	var res = {};
	for(var prop in a)
		if(!(prop in b))
			res[prop] = a[prop];
	return res;
}

// ----[Utility]-------------------------------------------------
function storage(key, value){
	var map = globalStorage.wrappedJSObject[document.domain];
	return (storage = function(key, value){
		if(arguments.length == 1)
			return eval('('+map[key]+')');
		
		if(value!=null){
			map[key] = uneval(value);
			return value;
		}
		
		delete map[key];
	}).apply(null, arguments);
}

function isEmpty(obj){
	if(obj==null)
		return true;
	
	for(var i in obj)
		return false;
	return true;
}

function keys(obj){
	var res=[];
	for(var key in obj)
		res.push(key);
	return res;
}

function map(){
	var fn = Array.shift(arguments);
	var res = [];
	while(arguments[0].length){
		var args = Array.map(arguments, Array.shift);
		res.push(fn.apply(null, args));
	}
	return res;
}

// cho45 - http://lowreal.net/
function $x(exp, context) {
	var Node = unsafeWindow.Node;
	if (!context) context = document;
	var resolver = function (prefix) {
		var o = document.createNSResolver(context)(prefix);
		return o ? o : (document.contentType == "text/html") ? "" : "http://www.w3.org/1999/xhtml";
	}
	var exp = document.createExpression(exp, resolver);
	
	var result = exp.evaluate(context, XPathResult.ANY_TYPE, null);
	switch (result.resultType) {
		case XPathResult.STRING_TYPE : return result.stringValue;
		case XPathResult.NUMBER_TYPE : return result.numberValue;
		case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
		case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: {
			result = exp.evaluate(context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			var ret = [];
			for (var i = 0, len = result.snapshotLength; i < len ; i++) {
				var item = result.snapshotItem(i);
				switch (item.nodeType) {
				case Node.ELEMENT_NODE:
					ret.push(item);
					break;
				case Node.ATTRIBUTE_NODE:
				case Node.TEXT_NODE:
					ret.push(item.textContent);
					break;
				}
			}
			return ret;
		}
	}
	return null;
}

function convertToHTMLDocument(html) {
	var xsl = (new DOMParser()).parseFromString(
		'<?xml version="1.0"?>\
			<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform">\
			<output method="html"/>\
		</stylesheet>', "text/xml");
	
	var xsltp = new XSLTProcessor();
	xsltp.importStylesheet(xsl);
	
	var doc = xsltp.transformToDocument(document.implementation.createDocument("", "", null));
	doc.appendChild(doc.createElement("html"));
	
	var range = doc.createRange();
	range.selectNodeContents(doc.documentElement);
	doc.documentElement.appendChild(range.createContextualFragment(html));
	
	return doc
}

function getText(url, onload, onerror){
	GM_xmlhttpRequest({
		method : 'GET',
		url : url,
		onload : function(res){
			if(res.status!=200)
				return onerror(res);
			onload && onload(res.responseText);
		},
		onerror : onerror || function(){},
	})
}