BlindWanderer / Overdrive Libraries

// ==UserScript==
// @name           Overdrive Libraries
// @namespace      http://home.comcast.net/~mailerdaemon
// @include        https://*.libraryreserve.com/*/SignIn.htm*
// @include        *
// @version        1.0
// ==/UserScript==

var server = document.location.host;
var page;
//http://digitallibrary.delcolibraries.org/1BC4F70D-19D8-4384-BF95-472FEE9144FE/10/374/en/ContentDetails.htm?ID={0889499B-ECE8-41DF-A725-258B93037B2C}
//http://search.overdrive.com/TitleInfo.asp?TitleReserveID={0889499B-ECE8-41DF-A725-258B93037B2C}&TitleFormatID=25
//TitleFormatID
//	25 - OverDrive WMA Audiobook
//	30 - OverDrive Music
//	35 - OverDrive Video
// 40 - OverDrive Video (mobile)
//	50 - Adobe PDF eBook
//	410 - Adobe EPUB eBook
//	425 - OverDrive MP3 Audiobook
//	900 - Mobipocket eBook

var domains = {
		values:null,
		setup:function(){
			if(this.values == null)
			{
				var me = this.values = {};
				var stored = GM_getValue("domains", "");
				if(stored)
					stored.split("/").forEach(function(f){ me[f]=true;});
			}
		},
		prod:function(host, bool){
			this.setup();
			if(bool === true || bool === false)
			{
				this.values[host] = bool;
				var me = this.values;
				var out = "";
				
				var next = function(f){return "/" + f;}
				var first = function(f){go = next; return f;}
				var go = first;
				
				for(var a in me)
					if(me[a] === true)
						out += go(a);
				GM_setValue("domains", out);
				return bool;
			}
			else
				return (this.values[host] === true);
		}
	};

if(/^search\.overdrive\.com$/.test(server))
{
	GM_addStyle("a.subscribed {background-color: rgba(0,255,0, 0.5);} a.not-subscribed {background-color: rgba(255,0,0, 0.25);}");
	Array.forEach(document.links, function(a){
			switch(domains.values[a.host])
			{
				case true:
					a.className += " subscribed";
					break;
				case false:
					a.className += " not-subscribed";
					break;
			}
		});
}
else
{
	if(/^secure\d+\.libraryreserve\.com$/.test(server))
	{//it could be a config page ^_^
		rConfig = /^\/(([^\/]+)\/[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\/\d+\/\d+\/en\/)([^.]+)\.htm$/
		if(m = rConfig.exec(document.location.pathname))
		{
			server = m[2];
			page = m[4];
			if(m[3] == "SignIn")
			{
				var checkbox = document.createElement("input");
				{
					var form = Array.filter(document.forms, function(f){return f.getAttribute("action") == "BANGAuthenticate.dll";})[0];
					var submit = Array.filter(form.elements, function(f){return f.type == "submit";})[0];
					var row = GetParentNodeByTag(submit, "tr");
					var tr = document.createElement("tr");
						tr.appendChild(document.createElement("td"));
						tr.appendChild(document.createElement("td"));
					var td = tr.appendChild(document.createElement("td"));
					var label = td.appendChild(document.createElement("label"));
					label.appendChild(checkbox);
					label.htmlFor = checkbox.id = "add";
					label.appendChild(document.createTextNode(" Include this library"));
					checkbox.type="checkbox";
					checkbox.checked = domains.prod(server);
					insertAfter(tr, row);
				}
				addEvent(checkbox, "click", function(event){
					domains.prod(server, this.checked);
					GM_setValue(server, m[1]);
				});
			}
		}
	}

	if(domains.prod(server))
	{
		var node = {
			ContentDetails:function(){
				$Z("//tr[td[text()='Release date:\xa0\xa0']]", function(r,i,p){
						var tr = document.createElement("tr");
							tr.vAlign="top";
						var title = tr.appendChild(document.createElement("td"));
							title.appendChild(document.createTextNode("Other libraries:\x0a\x0a"));
						var td = tr.appendChild(document.createElement("td"));
						
						{
							var id = document.location.search.match(/(?:^\?ID=|&ID=)([^&]+)/)[1];
							var szFormatType = $X("../script[contains(text(), 'szFormatType')]", r).textContent.match(/szFormatType = "([^"]*)"/)[1];
							var a = td.appendChild(document.createElement("a"));
							
								a.href = "http://search.overdrive.com/TitleInfo.asp?TitleReserveID="+id+"&TitleFormatID="+szFormatType;
								a.appendChild(document.createTextNode("search.overdrive.com"));
							td.appendChild(document.createElement("br"));
						}
						//var next = false;
						//log(domains);
						for(var d in domains.values)
						{
							if((d != server) && (p = GM_getValue(d, "")))
							{
								var a = td.appendChild(document.createElement("a"));
									a.href = "http://"+p + "ContentDetails.htm"+document.location.search;
									a.appendChild(document.createTextNode(d));
								td.appendChild(document.createElement("br"));
			//					next = true;
							}
						}
						//if(next)
							insertAfter(tr, r);
					});
			},
		}

		if(!page)
			page = /\/([^.\/]+)\.htm$/.exec(document.location.pathname)[1];
		if(typeof(node[page]) == "function")
			node[page]();
		//log(page);
	}
}

function $X(_xpath, node){return document.evaluate(_xpath, node?node:document, null,	XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);}
function $Y(_xpath, node){return document.evaluate(_xpath, node?node:document, null,	XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);}
function $Z(_xpath, func, node, payload, j){
	var res = document.evaluate(_xpath, node?node:document, null,	XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
	var i;
	if(j == null) j = 0;
	for (i = j = 0; link = res.snapshotItem(i); ++i)
		j += func(link, i, payload);
	return j;
}
function GetParentNodeByTag(child, tag, bad) {
	tag = tag.toUpperCase();
	while((child = child.parentNode) && child.tagName != tag);
	return child?child:bad;
}
function insertAfter(insert, after){return after.parentNode.insertBefore(insert, after.nextSibling);}
function insertBefore(insert, before){return before.parentNode.insertBefore(insert, before);}

function addEvent( obj, type, fn, capture ) {
 	obj.addEventListener( type, fn, capture?capture:false );
}
function removeEvent( obj, type, fn, capture ) {
 	obj.removeEventListener( type, fn, capture?capture:false );
}
function getFirstNonTextChild(obj){
	if(obj.firstChild.nodeName != "#text") return obj.firstChild;
	return getNextNonTextSibling(obj.firstChild);
}
function getNextNonTextSibling(obj){
	while((obj=obj.nextSibling) && (obj.nodeName == "#text"));
	return obj;
}

function log(){
	var arg;
	switch(arguments.length)
	{
		case 1:
			arg = arguments[0];
			break;
		case 0:
			arg = null;
			break;
		default:
			arg = arguments;
			break;
	}
	
	if(JSON && JSON.stringify)
		arg = JSON.stringify(arg);
	if(typeof(unsafeWindow.console) != "undefined" && typeof(unsafeWindow.console.log) != "undefined")
		unsafeWindow.console.log(arg);
	else if(typeof(GM_log) != "undefined")
		GM_log(arg);
	return arg;
}