By Sean LeBlanc
—
Last update
Apr 20, 2008
—
Installed
92 times.
// Amazon Douglas 1.2.6 Library Lookup
// Sean LeBlanc
// Modified Josh Staiger's (excellent) code
// to adapt to Douglas County search.
// It will insert a search link on CD, DVD, and VHS items.
// Based on Josh Staiger's Wake County Library Lookup.
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Then restart Firefox and revisit this script.
// Under Tools, there will be a new menu item to "Install User Script".
// Accept the default configuration and install.
//
// To uninstall, go to Tools/Manage User Scripts,
// select "Amazon - Douglas Lookup 1.2.6", and click Uninstall.
//
// ==UserScript==
// @name Amazon - Douglas Lookup 1.2.6
// @namespace http://sean-leblanc.blogspot.com
// @description While viewing a book on Amazon, this script will search for the book in the Colorado Douglas County library. Also, it will try to detect when viewing an item that is a CD, DVD or VHS, and insert a search link into Douglas County Library to use on that page. Based on Josh Staiger's Wake County Library Lookup.
// @include http://*.amazon.*
// @include http://amazon.*
// @version 1.2
// ==/UserScript==
// CHANGELOG:
// 1.2 - First released edition of Amazon - Douglas script.
// 1.2.4 - Small fix for Amazon changes.
// 1.2.6 - Fixed getTitleLocation() for Amazon changes, and updated isDVD() and isVHS().
var dbg = false;
var douglasCountyLibraryName = 'Douglas County Public Library';
var shortLibName = "Douglas";
//var prospectorLibraryName = 'Prospector';
//var worldcatLibraryName = 'WorldCat';
function slog(logthis) {
if (dbg) GM_log(logthis);
}
// Common functions:
function parseTitle(title) {
var firstParens = title.indexOf("(");
var firstBracket = title.indexOf("[");
var firstColon = title.indexOf(":");
var cutOffList = [firstParens, firstBracket, firstColon];
cutOffList.sort(function(a,b) { return a-b; });
for (var i = 0; i<cutOffList.length;i++) {
slog(" " + i + " val: " + cutOffList[i]);
if (cutOffList[i]>0) {
title = title.substring(0, cutOffList[i]);
slog("Title: '" + title + "'");
break;
}
}
var wordArray = title.split(' ');
var newTitle = "";
for (i=0;i<wordArray.length;i++) {
//slog("i= " + i + ", val: '" + wordArray[i] + "'");
var match = wordArray[i].match(/([a-zA-Z0-9]+)/);
if (match) {
if (newTitle.length>0) {
newTitle += " ";
}
newTitle += wordArray[i];
}
}
return newTitle;
}
function isCD() {
var liarray = document.getElementsByTagName('b');
if (liarray.length) {
//slog("bold found - " + liarray.length);
for (i=0;i<liarray.length;i++) {
if (liarray[i].textContent=="Audio CD") {
slog("Bold found. [" + i + "] Text: '" + liarray[i].textContent + "'");
return true;
}
}
}
return;
}
function isDVD() {
//var match = "amazon.com/images/G/01/detail/dvd-gray-medium.gif";
var match = "amazon.com/images/G/01/detail/dvd-gray-medium.";
var query = "//img[contains(@src, '" + match + "')]";
slog("query = '" + query + "'");
var dvdImg = xpathFirst(query);
if (dvdImg) {
return true;
}
else {
return;
}
}
function isVHS() {
//var match = "amazon.com/images/G/01/x-locale/common/icons/vhs-medium.gif";
var match = "amazon.com/images/G/01/x-locale/common/icons/vhs-medium.";
var query = "//img[contains(@src, '" + match + "')]";
slog("query = '" + query + "'");
var vhsImg = xpathFirst(query);
if (vhsImg) {
slog("is vhs.");
return true;
}
else {
slog("is not vhs.");
return;
}
}
function insertItemSearchText(stubDiv, libName, libUrl, itemType) {
clearText(stubDiv);
insertText(stubDiv,
'<a href="' + libUrl + '" title="'+libName+' information for this item">Search for this ' + itemType + ' in ' + libName + ' </a>',
'libraryAvailable');
}
// Simplify making a FIRST_ORDERED_NODE_TYPE XPath call
function xpathFirst(query, node) {
if (!node) {
node = document;
}
var result = document.evaluate(query, node, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null );
if (!result) {
return;
}
return result.singleNodeValue;
}
// Simplify making an UNORDERED_NODE_SNAPSHOT_TYPE XPath call
// Return a snapshot list
function xpathAll(query, node) {
if (!node) {
node = document;
}
return document.evaluate(query, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
}
// Add global style to page
function addGlobalStyle(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) {
throw new Error('Could not get head element.');
}
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
}
// This tries a few different
// ways to get title location:
// This tries a few different
// ways to get title location:
function getTitleLocation() {
var titleXPath1 = "//div[@class='buying']/b[@class='sans']";
var titleXPath2 = "//div[@class='content']//b[@class='sans']";
var titleXPath3 = "//div[@class='buying']/b[@class='asinTitle']";
var titleXPath4 = "//div[@class='content']/b[@class='asinTitle']";
slog("Searching for main title span with: " + titleXPath1);
var mainTitleSpan = xpathFirst(titleXPath1);
if (!mainTitleSpan) {
slog("First search for title failed.");
slog("[2] Searching for main title span with: " + titleXPath2);
mainTitleSpan = xpathFirst(titleXPath2);
if (!mainTitleSpan) {
slog ("Second search for title failed.");
slog ("[3] Searching for main title span with: " + titleXPath3);
mainTitleSpan = xpathFirst(titleXPath3);
if (!mainTitleSpan) {
slog ("Second search for title failed.");
slog ("[4] Searching for main title span with: " + titleXPath4);
mainTitleSpan = xpathFirst(titleXPath4);
if (!mainTitleSpan) {
throw new Error('Could not get main title span.');
}
}
}
}
return mainTitleSpan;
}
// Insert a div into the document that will be used for displaying item availability.
// Return this div.
function getItemAvailabilityDiv() {
//var mainTitleSpan = xpathFirst('//b[@class="sans"]');
var mainTitleSpan = getTitleLocation();
if (!mainTitleSpan) {
throw new Error('Could not get main title span.');
}
var parent = mainTitleSpan.parentNode;
itemAvailabilityDiv = document.createElement('div');
// Amazon uses two different layouts for displaying items.
// Handle both.
switch (parent.nodeName.toUpperCase()) {
case "FORM":
var authorSpan = xpathFirst('span[starts-with(string(normalize-space()), "by")]', parent);
if( !authorSpan ) {
throw new Error('Could not get author span.');
}
var nextBr = xpathFirst('following-sibling::br', authorSpan);
if( !nextBr) {
throw new Error('Could not get next br after author span.');
}
parent.removeChild(nextBr);
parent.insertBefore(itemAvailabilityDiv, authorSpan.nextSibling);
return itemAvailabilityDiv;
break;
case "DIV":
if(parent.lastChild.tagName == 'br') {
parent.removeChild(parent.lastChild);
}
parent.appendChild(itemAvailabilityDiv);
return itemAvailabilityDiv;
break;
default:
throw new Error('Did not recognize the main title span\'s parent\'s nodetype');
}
}
// Insert a new paragraph containing the specified text into the specified div node.
// If present, we set the class attribitue of this div to classAttr.
function insertText(stubDiv, text, classAttr) {
var p = document.createElement('p');
if(classAttr) {
p.setAttribute('class', classAttr);
}
p.innerHTML = text;
stubDiv.appendChild(p);
}
// Clear contents of the specified div node
function clearText(stubDiv) {
stubDiv.innerHTML = '';
}
// Get the isbn for the amazon item we are currently browsing.
// Return null if no isbn can be found.
function getIsbn() {
var match = window.location.href.match(/\/(\d{7,9}[\d|X])\//);
if (!match) {return;}
var isbn = match[1];
return isbn;
}
// Return a function that displays a message within the specified div
// regarding availablility of the current book.
//
// The function returned expects a library url for this item and will
// display a message saying the item is available if passed such a url.
// It will display a message saying the item is unavailable if passed
// a null value.
function getDisplayItemInfoFunction(stubDiv, libName, libUrl) {
clearText(stubDiv);
if(!libUrl) {
insertText(stubDiv, 'Unavailable at ' + libName + '.', 'libraryUnavailable');
return;
}
insertText(stubDiv,
'<a href="' + libUrl + '" title="'+libName+' information for this item">Available at ' + libName + '</a>',
'libraryAvailable');
}
// Return spinner image source
function getSpinnerSrc() {
var spinnerImgSrc = "data:image/gif,GIF89a%10%00%10%00%E6%00%00%FF%FF%FF%FE%FE%FE%A3%A3%A3%FD%FD%FD%E9%E9%E9%B5%B5%B5%F9%F9%F9%FA%FA%FA%F5%F5%F5%FC%FC%FC%AB%AB%AB%ED%ED%ED%C0%C0%C0%B1%B1%B1%C7%C7%C7%E5%E5%E5%F4%F4%F4%B4%B4%B4%F7%F7%F7%C1%C1%C1%CF%CF%CF%E6%E6%E6%03%03%03%E4%E4%E4%DF%DF%DF%C4%C4%C4%EE%EE%EE%9A%9A%9A%C2%C2%C2%D4%D4%D4%E2%E2%E2%3C%3C%3C%A8%A8%A8%B0%B0%B0%F2%F2%F2%AD%AD%AD%B2%B2%B2%DB%DB%DB%AA%AA%AA%D9%D9%D9%D7%D7%D7%BB%BB%BB%26%26%26%CD%CD%CD%D8%D8%D8%B9%B9%B9%9E%9E%9E%CB%CB%CB%AE%AE%AE%FB%FB%FB%EC%EC%ECRRR%EA%EA%EA%85%85%85%F6%F6%F6JJJ%DC%DC%DC%0C%0C%0C%D1%D1%D1%A4%A4%A4)))%E7%E7%E7%5D%5D%5D%BD%BD%BD%A7%A7%A7%CC%CC%CC%B7%B7%B7%F1%F1%F1%D0%D0%D0YYYfff%CA%CA%CA%A6%A6%A6%F0%F0%F0%E0%E0%E0%B8%B8%B8%BF%BF%BF%E8%E8%E8%F3%F3%F3%C8%C8%C8zzz%A5%A5%A5%BE%BE%BENNN%C3%C3%C3%C6%C6%C6%C5%C5%C5%14%14%14jjj%DD%DD%DD%F8%F8%F8%D6%D6%D6%BA%BA%BA%BC%BC%BC%90%90%90nnn%1C%1C%1C%DE%DE%DE%96%96%96%82%82%82%8C%8C%8C%89%89%89aaatttTTT%87%87%87%93%93%93FFF%8E%8E%8EWWW%7F%7F%7F222www%DA%DA%DA%7C%7C%7C666qqqAAAlll%94%94%94xxx%A1%A1%A1%A2%A2%A2---%23%23%23%80%80%80%D2%D2%D2%AC%AC%AC!%FF%0BNETSCAPE2.0%03%01%00%00%00!%F9%04%04%05%00%00%00%2C%00%00%00%00%10%00%10%00%00%07%C8%80%00%82%00%03%82-h%09%83%8A%82%15_%1D%00%1BW%09%07-%25%8B%00Mo%3E%00j%60%00%14%02%3D%8A%15%04%00%11%3C%3Fe%7C%2B%3B%2F%00%07%04%01%03cE%3F%08%3E%5E%3A%05Q!6%15%11%20%12%00%1853p6Z%82%93O%02%05%17%8A%2FQ%85%8A%1D%2C%83)%3BQ%20%1E%97%10%0E%13%0CG%40l%5Eba%97%22-%24%0DR%83%17%3A%01%8B%18%CF%83%12%19%1B%7F1%8B%3F%02T%22%00%01%96%08%08%E2%AD%03%84!J%BA%20%60%01%C4%84%01%00%25*%00%20%20%E0%C4%8B%02%0F%04l%01%90%E4%C44%00%06HD%08%90a%04%00%2BQ4%5C%22%A0%E0%01%00%0E%0A%02%20%80%81%E2R%00a%00V%A4%88g%20%91%A0%40%00!%F9%04%04%05%00%00%00%2C%00%00%00%00%0D%00%0B%00%00%07o%80%00%82%00%03%82%1Bt%85%83%82%17p8%00_s%03Z7L%832%3En%00g%1F%00w%16%0E%00%0F%1A%00%1Ch%1CP7'%16t%84bcA%12r.%3A%0C%20*2%15%00%15%02rb%12%07%82%07%22K%02%83%5B%5C%01%8A%00%1D%2CA%3FB%05%3D%CA%00%10%0E%13%0D%0D%05M%D3%22-%83%0Ba%C9%8A%18%17%00%06%14H!1%CA%3F%02%81%00!%F9%04%04%05%00%00%00%2C%00%00%00%00%10%00%08%00%00%07d%80%00%82%00%03%82%0Ad%85%83%8A%00%3Db%0F%00ef%03N%3E%5D%8B%00Ic.%00lF%9C%3CT%8A%04N%00DP%1D%1BX(%3C5%00%06Y%01%03%11%20q%06%1B%5C%18A%0Dk2%1DE9%1A%00%1A%0C%02%11%061%82%09%10r%16o%05%01%83%17D%D0%8Aiw%83%2B%0C%13U%0B%97M%1BL%0CG%81%00!%F9%04%04%05%00%00%00%2C%03%00%00%00%0D%00%0A%00%00%07g%80%00%01%00%00R%40%03%84%89%002%05%04%00Hi%03%08cD%89%08%26%05%00%20e%00%02S%3A%8A%18z(%23d83.%00%10%18%018%07%5CT%17(Lv2VSu6%02B1%09%84%09%08n%3C3%3F%01%17D%83%8A%1B%40%89U%0B%8A%84%17idb0%05M%D0%008%1F%3C*S%0Ba%C9%89!%5D%89%81%00!%F9%04%04%05%00%00%00%2C%05%00%00%00%0B%00%0E%00%00%07y%80%00%00%3AL%01%82%87%00%0B%00%1C%26%01%12.%1D%87)%00%19%40%00-P8%87%02%1E%0Ey%17r%05%006%1E%01%5C%1428A%5EI%14_%3E61%09%82%03Zb3gA%01%86%88%23%A2%88%88Mc_Xd%C0%00%1EE7k_%BC%87%24%0E%871%88%017%7Cy%8A%0E%1D%10C%2CF%17wWmZ%02'%2F%05%0FzR%00%5B%1B%09%11%01%19%23%00VQ%8A%82%81%00!%F9%04%04%05%00%00%00%2C%08%00%01%00%08%00%0F%00%00%07b%80%0A%01%07-%25%00%87%23%00%14%02%15%87%00!2%3B%2F%00Z%17%01%0FY!Nqjc6%00%03%06%23Pb%2C%8E%00%1CO%A7%87%0B%1Be5.%8E%3DP_ve%8E%05V%AB%01f*gJ%00%17%26m%04%02oo6dK%16%05%00q%24%03%89%3E%7C%04%8E%82%17%60%CD%87)%01%00%22%09%8E%81%00!%F9%04%04%05%00%00%00%2C%06%00%02%00%0A%00%0E%00%00%07m%80%00%19%23%00%14%02%3D%00%89%1E%0E!2%3B%2F%00%07%04%01%142%0FY!6%15%11%20%12%09%89%03%07O%02!%18%89%A7%00G%90%A8%A7%1A%23H%3B%05%AC2%1B%5E%5EH%AC%1C%2B%AC%89%01c3d%0F%00%3BJqBf%04%05EfZ!_m%0E*.%00%1EG%03%03%3ES%00g%3C(%A8hS%01%15kR%A8Pp%03%00%9E%A7%81%00!%F9%04%04%05%00%00%00%2C%03%00%05%00%0D%00%0B%00%00%07r%80%02B1%09%00%00%03%07O%02%05%17%00%17D%01%86%92%1D%2C%92U%0B%92%92%10%0E%13%0CG%05M%99%86%1A%26%0A!R%0B%2C%91%99D(%92Hm%08%99%01zP%202%00-%1EFb%17%18%19n%1AG%7D5Z%00%13%60%11ch%2B3!%00%04D%03%1A%3Cp%03gu%00j3a%96%1F8%00_s%032FU%92%03%B2%00%5EX%85Z%85%86%81%00!%F9%04%04%05%00%00%00%2C%00%00%08%00%10%00%08%00%00%07e%80%13%0D%0D%40(%00%87%88%22-%24%0DR%88%14%02%03%88%87%18%17%93CP9%7B6%93%00)%02T%22%00%09%1F9%1B%04P%1B4%3D%1D%1B%22(%40%26%06%00KY%00G*%0A%1Bg'P%1C%00I'%92%87C7S%03%5Ef%00%23r%15%9D%00%1Ds%13%00d%3E%01Ie%2F%CF%01%10%87%3Bc%92Z%09%88%81%00!%F9%04%04%05%00%00%00%2C%00%00%06%00%0D%00%0A%00%00%07d%80%00%82V%1B%03%82%87%1D%2CP33fA%87%87%10%0E%7DEmE%19%90%82%22-%87%2C%24%86%90%18%17%00Cd%7Bu%12%99%3F%02%03F%7Ce%3Db%7F%0B2(%5D%08%2C%00G%98%1D3K!j%25y%5B%90%10_t%01%20e%00%3FQ%1A%87%17F%2B%00H5%01%220(%87%01%A9%00).%86%06%09%81%00!%F9%04%04%05%00%00%00%2C%00%00%03%00%0B%00%0D%00%00%07r%80%00O%18%00%3A%02%1E%0E!2%3B%03%3EW.%22X%192%0FY!%00Ml%7CsN1%00%00%03%07%9F%00%0Ed%03%A3%9F%5EX_p%1D%A8%9Fxk7hG%AF%A8%25%0C%A7%AF%10HmF%06%AF%03nS.%0B%0D%0CCCJ%5D%00%14%14%00%18P%0EL%05%0F%02%A36%5Ej%01%3F%23%00V%A3%0F5'%00%13%0A%01%08%A3%01%12%9F%2B)%01%00%81%00!%F9%04%04%05%00%00%00%2C%00%00%00%00%08%00%0F%00%00%07a%80%00%82%00%09%82%3A%838o%87%1C%83C%7Cu%00%19%00(%1E%00U%16!%0D%033s%0A%08hP'%93X*h%08%07%83%00%1C%5E%03%82%3Bedj%25%83dXXg(%A9%82%17D%01%83%12)ne%A8%00%03%1BP%05I%19%1D%10%00~q%00%3D%02'%2F%83%06%24%11%01%92%82%04%0A%0F%AA%81%00%3B";
return spinnerImgSrc;
}
// ** In theory this is the only function that needs to be edited to
// ** adapt this script to other libraries.
//
// Search the library for the specified isbn
// if we find it, call fn with the resulting library url
// otherwise call fn with null
function libSearch(isbn, newDiv) {
//var xmlUrlDouglasCo = "http://sable.jefferson.lib.co.us/search/?searchtype=i&searcharg=" + isbn + "&SORT=&searchscope=9";
var xmlUrlDouglasCo = "http://catalog.douglascountylibraries.org/ipac20/ipac.jsp?menu=search&aspect=subtab22&npp=10&ipp=20&spp=20&profile=rem&ri=&term=&index=PALLTI&x=13&y=12&aspect=subtab22&term=&index=PZAUTH&term=&index=PSUBJ&term=&index=PSERIES&term=&index=BSTLLR&term=&index=PAWARD&term=&index=PDVD&term=&index=PVTITL&term=&index=PNMSRTI&term=&index=PMUTITL&term=&index=PCFTITL&term=" + isbn + "&index=ISBNEX&term=&index=LHIS&term=&index=LHISEX";
var successText = 'value="Place a Hold"';
// Search Douglas county, get redirect info:
GM_xmlhttpRequest({
headers: [{'User-Agent': 'dpgm'}],
method:"GET",
url:xmlUrlDouglasCo,
onload:function(res) {
var successStart = res.responseText.indexOf(successText);
if (successStart >= 0) {
// Found, put link in to page:
getDisplayItemInfoFunction(newDiv, douglasCountyLibraryName, xmlUrlDouglasCo);
}
else {
// Not found, search Prospector:
getDisplayItemInfoFunction(newDiv, douglasCountyLibraryName, null);
//prospectorSearch(isbn, newDiv);
}
}
});
}
if (!GM_xmlhttpRequest || !GM_log) {
alert('The Wake County Public Library Lookup script requires Greasemonkey 0.5.3 or higher. Please upgrade to the latest version of Greasemonkey.');
return;
}
addGlobalStyle('.stub { height: 1em; margin: 1em; } .libraryAvailable { font-weight:bold; } .libraryUnavailable { color: rgb(153,0,0)} ');
// CD or DVD?
var mediaUrl1 = "http://catalog.douglascountylibraries.org/ipac20/ipac.jsp?menu=search&aspect=subtab15&npp=10&ipp=20&spp=20&profile=rem&ri=&index=.GW&term=";
var mediaUrl2 = "&oper=and&x=12&y=11&aspect=subtab15&index=.TW&term=&oper=and&index=.AW&term=&oper=and&index=.NW&term=";
var mediaUrl3 = "&ultype=&uloper=%3D&ullimit=&ultype=&uloper=%3D&ullimit=&sort=%20HTTP/1.1";
if (isDVD() || isCD() || isVHS() ) {
var cdTypeUrlAppend = "&limitbox_1=CO01+%3D+co_cdf&limitbox_1=CO01+%3D+co_cdnf&limitbox_1=CO01+%3D+co_cdjf&limitbox_1=CO01+%3D+co_cdjnf&limitbox_1=CO01+%3D+co_cde&limitbox_1=CO01+%3D+co_mcd&limitbox_1=CO01+%3D+co_mcdj&limitbox_1=CO01+%3D+co_mcdy&limitbox_1=CO01+%3D+co_cdyf&limitbox_1=CO01+%3D+co_cdynf";
var vhsTypeUrlAppend = "&limitbox_1=CO01+%3D+co_vf&limitbox_1=CO01+%3D+co_vnf&limitbox_1=CO01+%3D+co_vjf&limitbox_1=CO01+%3D+co_vjnf&limitbox_1=CO01+%3D+co_vynf";
var dvdTypeUrlAppend = "&limitbox_1=CO01+%3D+co_vdf&limitbox_1=CO01+%3D+co_vdnf&limitbox_1=CO01+%3D+co_vdjf&limitbox_1=CO01+%3D+co_vdjnf&limitbox_1=CO01+%3D+co_vdyf&limitbox_1=CO01+%3D+co_vdynf";
slog("This page is probably a DVD or CD.");
var itemAvailabilityDiv = getItemAvailabilityDiv();
if (!itemAvailabilityDiv) {
throw new Error('Could not get item availability stub');
}
itemAvailabilityDiv.setAttribute('class', 'stub');
// Get title:
var titleLocation = getTitleLocation();
if (titleLocation) {
var title = titleLocation.textContent;
// Remove junk from title as best we can:
title = parseTitle(title);
var url = mediaUrl1;
var itemType = "";
// Check to see if it's a DVD or CD:
if (isDVD()) {
slog("Is DVD!");
url += title + mediaUrl2 + dvdTypeUrlAppend + mediaUrl3;
itemType = "DVD";
}
else if (isCD()) {
slog("Is CD!");
url += title + mediaUrl2 + cdTypeUrlAppend + mediaUrl3;
itemType = "CD";
}
else if (isVHS()) {
slog("Is VHS!");
url += title + mediaUrl2 + vhsTypeUrlAppend + mediaUrl3;
itemType = "VHS";
}
slog("Inserting link...");
insertItemSearchText(itemAvailabilityDiv, shortLibName + " Library", url, itemType);
}
else {
slog("Can't find title!");
}
}
// Maybe it's a book?
else {
var isbn = getIsbn();
if(isbn) {
var itemAvailabilityDiv = getItemAvailabilityDiv();
if (!itemAvailabilityDiv) {
throw new Error('Could not get item availability stub');
}
itemAvailabilityDiv.setAttribute('class', 'stub');
insertText(itemAvailabilityDiv, '<img src="' + getSpinnerSrc() + '" alt="Spinner" /> Searching for this edition at ' + douglasCountyLibraryName + '.');
libSearch(isbn, itemAvailabilityDiv);
}
}