Amazon Seattle Public Library Linky

By Arthaey Angosii Last update Dec 4, 2008 — Installed 36 times. Daily Installs: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0

There are 3 previous versions of this script.

// ==UserScript==
// @name          Amazon Seattle Public Library Linky
// @namespace     http://fatknowledge.blogspot.com
// @description	  v1.4 Search the Seattle Public Library Catalog from Amazon book listings.  
// @include       http://*.amazon.*
// ==/UserScript==

// Based on work by Carrick Mundell http://userscripts.org/scripts/show/1396
// Now handles the case where books are on hold
// Searches by other editions or by title if ISBN match not found (added by Arthaey Angosii)

(function(){
//	GM_log('Amazon Seattle Public Library Linky');	

	var libraryIsbnUrlPattern = 'http://catalog.spl.org/ipac20/ipac.jsp?index=ISBNEX&term='
	var libraryTitleUrlPattern = 'http://catalog.spl.org/ipac20/ipac.jsp?index=PALLTI&term='
	var libraryName = 'the Seattle Public Library';

	createLibraryHTML();

	var title = getTitle();
	var isbn = getIsbn(window.content.location.href);
	var otherEditionIsbns = getOtherEditions();
	var otherEditionIndex = -1;

	var canDoOtherSearches = (title != null || otherEditionIsbns != null);

	//prefer search by ISBN for exact match
	if (isbn!=0){
		updateLibraryHTML('Searching by ISBN in ' + libraryName + '...');
		getBookStatusByIsbn(isbn, title, !canDoOtherSearches, doOtherSearches);
	}
	return;


function doOtherSearches(found){
	if (found) { return; }
	otherEditionIndex++;

	if (otherEditionIsbns != null && otherEditionIndex < otherEditionIsbns.length){
		updateLibraryHTML("Searching by other editions' ISBNs in " + libraryName + '...');
		getBookStatusByIsbn(otherEditionIsbns[otherEditionIndex], title, (title==null), doOtherSearches);
	}
	else if (title != null){
		updateLibraryHTML('Searching by title in ' + libraryName + '...');
		getBookStatusByTitle(isbn, title, true, done);
	}
}


//check if there is a ISBN in the URL
//URL looks like http://www.amazon.com/Liseys-Story-Stephen-King/dp/0743289412/ref=xarw/002-5799652-4968811
function getIsbn(url){
	try { 
		//match if there is a / followed by a 7-9 digit number followed by either another number or an x 
		//followed by a / or end of url 
		var isbn = url.match(/\/(\d{7,9}[\d|X])(\/|$)/)[1]; 
	} catch (e) { return 0; }

	return isbn;
}

function getTitle(){
	var title = getTitleNode();
	if (title==null) { return null; }

	//remove words in parentheses and subtitles (anything after a colon)
	return title.textContent.replace(/\(.+\)/, '').replace(/:.*/, '')
}

function getOtherEditions(){
	var otherEditions = document.getElementById('oeTable');
	if (otherEditions==null) { return null; }

	var urls = [];
	var nodes = document.evaluate(".//table//a[not(contains(@href,'offer-listing'))]", otherEditions, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
	if(!nodes){
		return null;
	}

	var otherEditionLink, isbn;
	for (var i = 0; i < nodes.snapshotLength; i++){
		otherEditionLink = nodes.snapshotItem(i);
		isbn = getIsbn(otherEditionLink.href);
		if (isbn!=0) { urls.push(isbn); }
	}

	return (urls.length > 0 ? urls : null);
}

function getBookStatusByIsbn(isbn, title, updateHtmlIfNotFound, callback){
	getBookStatus(libraryIsbnUrlPattern + isbn, isbn, title, updateHtmlIfNotFound, callback);
}

function getBookStatusByTitle(isbn, title, updateHtmlIfNotFound, callback){
	getBookStatus(libraryTitleUrlPattern + encodeURIComponent(title), isbn, title, updateHtmlIfNotFound, callback);
}

//connect to library server to get book status for isbn and then insert result under the book title
function getBookStatus(libraryUrlPattern, isbn, title, updateHtmlIfNotFound, callback){
	GM_log('Amazon Seattle Public Library Linky Searching');	

	var libraryAvailability = /Checked In/;
	var libraryOnOrder = /On Order/;
	var libraryInProcess = /In Process/;
	var libraryDueBack = /(\d{2}\/\d{2}\/\d{4})/;
	var libraryHolds = /holds /;
	var libraryBrowseResults = /Browsing results matching/;
	var notFound = /We could not find results in the catalog for/;

	GM_xmlhttpRequest
		({
		method:'GET',
		url: libraryUrlPattern,
		onload:function(results) {
			var page = results.responseText;
			if ( notFound.test(page) ) {
				var due = page.match(notFound)[1]
				if (updateHtmlIfNotFound) {
					setLibraryHTML(
						libraryUrlPattern,
						isbn,
						"Not carried",
						"Not in " + libraryName,
						"red"
					);
				}
				callback(false);
			}
			//if there are holds
			else if ( libraryHolds.test(page) ) {
				//23 active, 12 inactive
				var holds = /\d{1,} active, \d{1,} inactive/;
				var holdsStr = page.match(holds);
				setLibraryHTML(
					libraryUrlPattern,
					isbn,
					"Holds!",
					holdsStr + " holds at " + libraryName,
					"#AA7700"  // dark yellow
				);
				callback(true);
			}
			else if ( libraryAvailability.test(page) ) {
				setLibraryHTML(
					libraryUrlPattern,
					isbn,
					"On the shelf now!",
					"Available in " + libraryName,
					"green" 
				);
				callback(true);
			}
			else if ( libraryOnOrder.test(page) ) {
				setLibraryHTML(
					libraryUrlPattern,
					isbn,
					"On order!",
					"On order at " + libraryName,
					"#AA7700"  // dark yellow
				);
				callback(true);
			}
			else if ( libraryInProcess.test(page) ) {
				setLibraryHTML(
					libraryUrlPattern,
					isbn,
					"In process!",
					"In process (available soon) at ",
					"#AA7700"  // dark yellow
				);
				callback(true);
			}
			else if ( libraryDueBack.test(page) ) {
				var due = page.match(libraryDueBack)[1]
				setLibraryHTML(
					libraryUrlPattern,
					isbn,
					"Due back " + due,
					"Due back at " + libraryName + " on " + due,
					"#AA7700"  // dark yellow
				);
				callback(true);
			}
			else if ( libraryBrowseResults.test(page) ) {
				var nodes = document.evaluate("//table//td/a[contains(text(),'" + title + "')]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
				var likelyMatch = (nodes != null && nodes.snapshotLength > 0);
				setLibraryHTML(
					libraryUrlPattern,
					isbn,
					"Browse results for " + title,
					(likelyMatch ?
						"Likely match found in " + libraryName :
						"No exact IBSN match. Browse results in " + libraryName
					),
					(likelyMatch ? "green" : "orange" )
				);
				callback(likelyMatch);
			}
			else {
				if (updateHtmlIfNotFound) {
					setLibraryHTML(
						libraryUrlPattern,
						isbn,
						"Error",
						"Error checking " + libraryName,
						"orange"
						);
				}
				callback(false);
			}
		}
	});
}

//print status of book below book title
function setLibraryHTML(libraryUrlPattern, isbn, title, linktext, color) {
	//GM_log(linktext);	

	var splLinkyDiv = document.getElementById('splLinkyLibraryHTML');
	if (splLinkyDiv == null) { return; }

	var link = document.createElement('a');
	link.setAttribute('title', title );
	link.setAttribute('href', libraryUrlPattern);
	link.style.color = color;

	var label = document.createTextNode( linktext );
	link.appendChild(label);

	//remove existing content
	splLinkyDiv.removeChild(splLinkyDiv.firstChild);
	splLinkyDiv.appendChild(link);
}

function createLibraryHTML() {
	var title_node = getTitleNode();
	var h1_node = title_node.parentNode;

	var br = document.createElement('br');

	var splLinkyDiv = document.createElement('div');
	splLinkyDiv.id = 'splLinkyLibraryHTML';
	//resize to 60% to get out of the enlarged h1 size and return back to normal
	splLinkyDiv.style.fontSize = '60%';
	splLinkyDiv.style.color = 'green';

	//How lame is this javascript DOM syntax?  Instead of having an insertAfter function, you have an insertBefore
	//and then pass in the .nextSibling attribute of the element.  Really inuitive guys.
	h1_node.insertBefore(splLinkyDiv, title_node.nextSibling);
	h1_node.insertBefore(br, title_node.nextSibling);
}

function updateLibraryHTML(text) {
	var splLinkyDiv = document.getElementById('splLinkyLibraryHTML');
	if (splLinkyDiv == null) { return; }

	if (splLinkyDiv.firstChild){
		splLinkyDiv.removeChild(splLinkyDiv.firstChild);
	}
	splLinkyDiv.appendChild(document.createTextNode(text));
}

// Find the node containing the book title
function getTitleNode()
{
	var titleNodeId = 'btAsinTitle';

	var nodes = document.evaluate("//span[@id='" + titleNodeId + "']", document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
	if(!nodes){
		return null;
	}

	var thisNode = nodes.iterateNext(); 
	var titleNode;
	// Get the last node
	while(thisNode){
		//GM_log( thisNode.textContent );
		titleNode = thisNode;
		thisNode = nodes.iterateNext();
	}

	if (titleNode == null) {
        GM_log("can't find title node");
		return null;
	} else {
       // GM_log("Found title node: " + titleNode.textContent);
	}
	return titleNode;
}

function done() {}

}
)();