Google Books - Peninsula Library System Lookup

By Al's scripts Last update Mar 6, 2008 — Installed 595 times. Daily Installs: 0, 5, 2, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 2, 1, 0, 0, 0, 1, 4, 0
// ==UserScript==
// @name          Google Books - Peninsula Library System Lookup
// @namespace     http://www.japaninyourpalm.com
// @description   Display the availability of Google Books search result in the San Francisco Peninsula Library System and add hyperlinks to maps & hours on Peninsula Library results page
// @include       http://books.google.com/books?vid*
// @include       http://books.google.com/books?id*
// @include       http://catalog.plsinfo.org/search/i?SEARCH*

// ==/UserScript==
// Version 1.7 - altered amazon isbn search pattern
// Version 1.6 - indicate if book is avail as on online book - Jan 2008
// Version 1.5 - Updates to find book title on google - December 2007
// Version 1.4 - updated ISBN finder again - now just seeks any amazon ink 
// Version 1.3 - updated my ISBN finder on google's book page
// Version 1.2 - improved the book DUE reg expression & looser books.google url test

// Version 1.1 - tidy and remove GM_log statements
// Version 1.0 -
// Integrated into Google Print book search results to let you know if the book you're paging through is 
// available at a San Francisco Peninsula library.  The script puts a small yellow box in the corner of 
// your Google Print book search. Box includes job title. The script also linkifies the library names, 
// on the library lookup results page, to point to the library's streetmap, hours and phone.
// (this GM script acts on 2 completely seperate pages)
// 
// Based on Junk Blocker's Peninsula Library System Amazon Lookup
// http://userscripts.org/scripts/show/1072
// which is based on...
// Library Lookup
// http://userscripts.org/scripts/source/886
//
// Note:
// Google Print has a "Find this book in a library" link, which I found often uses an ISBN number 
// which  doesn't match the book I'm looking at.
// The floating div approach used here is much nicer anyway in that it tells me immediately if the
// book is avalable locally.
//
// To Do: 
// - add Santa Clara County library lookup to the same div
// - add web service xISBN to search on alternate ISBN #s, since libraries usually carry older
//   hard cover versions of the more recent book/ISBN you find on google print. 

(function() {
  var Drag = function(){ this.init.apply( this, arguments ); };

  Drag.fixE = function( e ) {
    if( typeof e == 'undefined' ) e = window.event;
    if( typeof e.layerX == 'undefined' ) e.layerX = e.offsetX;
    if( typeof e.layerY == 'undefined' ) e.layerY = e.offsetY;
    return e;
  };
  

  Drag.prototype.init = function( handle, dragdiv ) {
    this.div = dragdiv || handle;
    this.handle = handle;
    if( isNaN(parseInt(this.div.style.right)) ) this.div.style.right  = '0px';
    if( isNaN(parseInt(this.div.style.top)) ) this.div.style.top = '0px';
    this.onDragStart = function(){};
    this.onDragEnd = function(){};
    this.onDrag = function(){};
    this.onClick = function(){};
    this.mouseDown = addEventHandler(this.handle, 'mousedown', this.start, this);
  };

  Drag.prototype.start = function(e) {
    e = Drag.fixE(e);

    this.started = new Date();
    var y = this.startY = parseInt(this.div.style.top);
    var x = this.startX = parseInt(this.div.style.right);
    this.onDragStart(x, y);
    this.lastMouseX = e.clientX;
    this.lastMouseY = e.clientY;
    this.documentMove = addEventHandler(document, 'mousemove', this.drag, this);
    this.documentStop = addEventHandler(document, 'mouseup', this.end, this);
    if (e.preventDefault) e.preventDefault();
    return false;
  };

  Drag.prototype.drag = function( e ) {
    e = Drag.fixE(e);
    var ey = e.clientY;
    var ex = e.clientX;
    var y = parseInt(this.div.style.top);
    var x = parseInt(this.div.style.right);
    var nx = -ex + x + this.lastMouseX;
    var ny = ey + y - this.lastMouseY;
    this.div.style.right = nx + 'px';
    this.div.style.top  = ny + 'px';
    this.lastMouseX = ex;
    this.lastMouseY = ey;
    this.onDrag(nx, ny);
    if (e.preventDefault) {
      e.preventDefault();
    }
    return false;
  };

  Drag.prototype.end = function() {
    removeEventHandler( document, 'mousemove', this.documentMove );
    removeEventHandler( document, 'mouseup', this.documentStop );
    var time = (new Date()) - this.started;
    var x = parseInt(this.div.style.right),  dx = x - this.startX;
    var y = parseInt(this.div.style.top), dy = y - this.startY;
    this.onDragEnd( x, y, dx, dy, time );
    if( (dx*dx + dy*dy) < (4*4) && time < 1e3 ) {
      this.onClick( x, y, dx, dy, time );
    }
  };

  function removeEventHandler( target, eventName, eventHandler ) {
    if( target.addEventListener ) {
      target.removeEventListener( eventName, eventHandler, true );
    } else if( target.attachEvent ) {
      target.detachEvent( 'on' + eventName, eventHandler );
    }
  }

  function addEventHandler( target, eventName, eventHandler, scope ) {
    var f = scope ? function(){ eventHandler.apply( scope, arguments ); } : eventHandler;
    if( target.addEventListener ) {
      target.addEventListener( eventName, f, true );
    } else if( target.attachEvent ) {
      target.attachEvent( 'on' + eventName, f );
    }
    return f;
  }

  // Define library search URL/API and book status regular expressions
  var libraryUrlPattern = 'http://catalog.plsinfo.org/search/i?SEARCH=';
  var libraryUrlPatternSuffix = '&searchscope=1';
  var libraryName = 'Peninsula Library System';
  var libraryAvailability = /In Library|Check Shelf/i;
  var libraryRecentlyReturned = /Recently Returned/i;
  var libraryRecentAvailability = /Recent Checkin/i;
  var libraryStorage = /Storage/i;
  var libraryOnHold = /(On Hold Shelf|[Bb]eing [Hh]eld|holds? on \w+ copy returned of \d+ cop|In transit \+\d+ hold)/i;
  var libraryTransit = /In Transit/i;
//  var libraryDueBack = /(\d{2} [A-Z][A-Z][A-Z] \d{2}|DUE \d{2}-\d{2}-\d{2})/i;  
  var libraryDueBack = /DUE (\d{2}-\d{2}-\d{2})/i;
  var libraryReordered = /REORDERED/i;
  var libraryInternet = /INTERNET/;  
  var notFound = /No matches found; nearby STANDARD NOS are/

  var libraryLookup = {
    insertLink: function(isbn, titleText, hrefTitle, aLabel, color ) {
      var body = document.getElementsByTagName('body')[0];
      var div = document.createElement('div');
      div.setAttribute('style','right:92px;top:2px;width=170px;z-index:999;padding:3px 3px 3px 3px; background-color:#FFC; text-align:center;border:1px solid green;color:#000000;opacity:0.86;font-family:san-serif;font-size:small;position: absolute;');
                 
      var title = document.createElement('div');
      var label = document.createTextNode( 'Peninsula Library System' );
      title.appendChild(label);
      title.setAttribute('style','background:#008000;cursor:move;color:white;');
      div.appendChild(title);

      var divStyled=document.createElement('div');
	  divStyled.setAttribute('style','border:0px;padding:1em; background:#FFC');


      var bookTitleShort = titleText.substring(0,26) + " ...";
      var bookTitle = document.createTextNode(bookTitleShort);	    
      var link = document.createElement('a');
      link.setAttribute ( 'title', hrefTitle );
      link.setAttribute('href', libraryUrlPattern + isbn + libraryUrlPatternSuffix);
      link.setAttribute('target','_blank');
      link.setAttribute('style','color: ' + color);

      var label = document.createTextNode( aLabel );

      link.appendChild(label);
      divStyled.appendChild(bookTitle);
      divStyled.appendChild(document.createElement("br"));      

      divStyled.appendChild(link);
      
      div.appendChild(divStyled);
      body.appendChild(div);

      title.drag = new Drag(title, div);
    },

    doLookup : function (isbn, titleText) {
      GM_xmlhttpRequest ({
        method : 'GET', url : libraryUrlPattern + isbn + libraryUrlPatternSuffix, onload : function(results) {
          page = results.responseText;
          if (notFound.test(page)) {
            var due = page.match(notFound)[1];
            libraryLookup.insertLink (isbn, titleText, "Not carried", "Not in Library", "red");
          } else if (libraryAvailability.test(page)) {
            libraryLookup.insertLink (isbn, titleText, "On the shelf now!", "In Library", "green");
          } else if (libraryRecentAvailability.test(page)) {
            libraryLookup.insertLink (isbn, titleText, "Recent Checkin", "New In Library", "green");
          } else if ( libraryRecentlyReturned.test(page) ) {
            libraryLookup.insertLink (isbn, titleText, "Recently Returned", "Recently Returned", "green");
          } else if ( libraryStorage.test(page) ) {
            libraryLookup.insertLink (isbn, titleText, "In Storage", "In Storage", "green");
          } else if ( libraryOnHold.test(page) ) {
            libraryLookup.insertLink (isbn, titleText, "Being Held", "On Hold", "green");
          } else if ( libraryTransit.test(page) ) {
            libraryLookup.insertLink (isbn, titleText, "In Transit", "In Transit", "#AA7700");
          } else if ( libraryDueBack.test(page) ) {
            var due = page.match(libraryDueBack)[1];
            libraryLookup.insertLink ( isbn, titleText, "Due back " + due, "Due back " + due, "#AA7700");
          } else if ( libraryReordered.test(page) ) {
            libraryLookup.insertLink (isbn, titleText, "Reordered", "Reordered", "#AA7700");
          } else if ( libraryInternet.test(page) ) {
            libraryLookup.insertLink (isbn, titleText, "Internet Book", "Available as an online book", "#AA7700");            
          } else {
            libraryLookup.insertLink (isbn, titleText, "Error: Click for library page", "Error checking " + libraryName + " Library", "orange");
					}
        }
      });
    }
  }

  
  try { 	
  	// note this script only runs on Google Print results or Peninsula library system results pages
  	
  	// OLD var isbnPattern = /books.google.com\/books\?vid\=ISBN(\d+)[A-Z]*/;  // Google Print's ISBN pattern
  	var booksGooglePattern = /books.google.com\/books\?id/; //Google Print's URL
  	
  	// Check if we're on Google Print
  	if (booksGooglePattern.test(document.location)) {  // find Amazon link's ISBN #
  		// var isbnXPath = "/html/body/table[@id='viewport_table']/tbody/tr[2]/td[@id='menu_td']/div[@id='menu_container']/div[@id='menu']/div[8]/div/div[@id='buy_content']/div[@id='buy_v']/table/tbody/tr[1]/td/div/a";
  		var isbnXPath = "//a[contains(@href, 'amazon')]";

        var isbnNode = document.evaluate(isbnXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue;  		
  		
  		var isbnPatternAmazonURL = /ASIN\/([A-Z0-9]+)&/;  // find isbn at end of amazon url

        var isbn = isbnNode.href.match(isbnPatternAmazonURL)[1];

        // 12/13/2007, i noticed Google changed the page's structure a little
        // so I'll start using the html page title for extracting a book title
           
        var pageTitleText =  document.title;
        var titleExpression = /(.*?)\s- Google/;
        var titleRE = titleExpression.exec(pageTitleText);
        var titleText = titleRE[1];
        libraryLookup.doLookup(isbn, titleText);  
          
  	}
  	else { // We must be on Peninsula library results page
  	
        var library_id = new Array(); // library name and id hash table - for building url later
        
        library_id["Atherton"] = 18;
        library_id["Belmont"] = 19;
        library_id["Bookmobile"] = 44;
        library_id["Brisbane"] = 20;
        library_id["Burlingame"] = 5;
        library_id["Burlingame Easton"] = 6;
        library_id["CaƱada College"] = 36;
        library_id["College of San Mateo"] = 37;        
        library_id["Daly City Bayshore"] = 8;
        library_id["Daly City John D. Daly"] = 9;
        library_id["Daly City - Serramonte"] = 7;
        library_id["Daly City - Westlake"] = 10;
        library_id["East Palo Alto"] = 21;        
        library_id["Foster City"] = 22;
        library_id["Half Moon Bay"] = 23;
        library_id["Menlo Park"] = 11;
        library_id["Menlo Park, Belle Haven"] = 12;
        library_id["Millbrae"] = 24;
        library_id["Pacifica-Sanchez"] = 26;
        library_id["Pacifica-Sharp Park"] = 25;
        library_id["Portola Valley"] = 27;
        library_id["Redwood City"] = 13;
        library_id["Redwood City, Fair Oaks"] = 14;
        library_id["Redwood City, Redwood Shores"] = 16;
        library_id["Redwood City, Schaberg"] = 15;
        library_id["San Bruno"] = 17;
        library_id["San Carlos"] = 28;
        library_id["San Mateo Main"] = 30;
        library_id["San Mateo - Hillsdale"] = 31;
        library_id["San Mateo - Marina"] = 32;
        library_id["Skyline College"] = 38;
        library_id["South San Francisc, Grand Avenue"] = 41;
        library_id["South San Francisco"] = 33;
        library_id["South San Francisco Community Learning Center"] = 34;
        library_id["Woodside"] = 29;
        
       
        var xpathLibraryNameCells = "//tr[@class='bibItemsEntry']/td[1]";               
        var libraryNameElems = document.evaluate(xpathLibraryNameCells, 
                   document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

        for (var k = 0; k < libraryNameElems.snapshotLength; k++) { // iterate thru each library name table cell
            var libraryNameElem = libraryNameElems.snapshotItem(k);
            var libraryName = libraryNameElem.innerHTML;
            var namePattern;
            for (var nameKey in library_id) {
                namePattern = new RegExp(nameKey);
                var result;
                if ( (result = namePattern.exec(libraryName)) !=null ) {
                    var libName = result[0]
                    var newName = libraryName.replace(namePattern, "<a href='http://www.plsinfo.org/library/library.asp?libraryid=" + library_id[nameKey] + "' style='background-color:#FFC'>" + libName + "</a>");
        	        libraryNameElem.removeChild(libraryNameElem.firstChild);
                    libraryNameElem.innerHTML = newName;

            	    break;
                }
            }

        }
        
  	} // end else on Peninsula library page
  	
  } catch (e) {
      // window.alert("Could not locate ISBN or something else not right");
    return;
  }


}
)();