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() {}
}
)();
