// BookInfoLine Ajax Panel for GreaseMonkey and Turnabout // @version 1.1.2 /* -------------------------------------------------------------------- This is a Greasemonkey user script. To install it, you need Greasemonkey Add-on for Firefox: https://addons.mozilla.org/en-US/firefox/addon/748 or Turnabout for Internet Explorer. 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 "BookInfoLine", and click Uninstall. -------------------------------------------------------------------- Modified by EastWoodReaders. If you have comment, suggestion, improvements, requests for updates please email to: eastwoodreaders@gmail.com We use this script all the time and if you notice that one or more sites are not working properly due to internal code changes please comeback here and most likely you would find a fixed version. Original from "Book Burro - Remixing the bookstore" By Johan Sundström (http://userscripts.org/scripts/show/1859) Reason For Update: "Book Burro - Remixing the bookstore" was such a helpful script, but it has not been working for a while. So here is new and improved working version. Fixed, New Features, Improved: Fixed: All price are now properly extracted. Included new reliable sources for books: Ebay.com, Walmart.com, Craigslist.com, Strandbooks.com, Betterworldbooks.com, Borders.com, Thriftbooks.com, Ebooks.com and Kindle Editions. Removed all useless sites like: ecampus.com, bookbyte.com, bookpool.com, biggerbooks.com, buy.com, a1books.com, booksamillion.com, biggerbooks.com, etc... Following sites are now being searched: Abebooks.com Alibris.com Amazon.ca Amazon.co.uk Amazon.com Amazon.de Amazon.fr Barnesandnoble.com Betterworldbooks.com Biblio.com Borders.com Craigslist.com Ebay.com Ebooks.com Google Books Half.com Kindle Editions Powells.com Strandbooks.com Thriftbooks.com Walmart.com (C) 2005 WSKTB (0.19) License: Creative Commons "Attribution-ShareAlike 2.0" http://creativecommons.org/licenses/by-sa/2.0/ (C) 2005 Johan Sundström (0.13 .. 0.18) License: Creative Commons "Attribution-ShareAlike 2.0" http://creativecommons.org/licenses/by-sa/2.0/ Skeletal parts of DOM-Drag by Aaron Boodman, 2001 http://www.youngpup.net/2001/domdrag License: Creative Commons "Attribution-ShareAlike 2.0" http://creativecommons.org/licenses/by-sa/2.0/ (C) 2005 Reify (0.11r .. 0.12r) License: Creative Commons "Attribution-ShareAlike 1.0" http://creativecommons.org/licenses/by-sa/1.0/ (C) 2005 Jesse Andrews, Britt Selvitelle under cc-by-sa (0.01 .. 0.11) License: Creative Commons "Attribution-ShareAlike 1.0" http://creativecommons.org/licenses/by-sa/1.0/ Snipits used from RSS Reader for GreaseMonkey http://www.xs4all.nl/~jlpoutre/BoT/Javascript/RSSpanel/ Version: 1.03 (C) 2005 Johannes la Poutre THANKS! */ // ==UserScript== // @name BookInfoLine // @description Compare book prices from various book stores. Abebooks.com, Alibris.com, Amazon.ca, Amazon.co.uk, Amazon.com, Amazon.de, Amazon.fr, Barnesandnoble.com, Betterworldbooks.com, Biblio.com, Borders.com, Craigslist.com, Ebay.com, Ebooks.com, Google Books, Half.com, Kindle Editions, Powells.com, Strandbooks.com, Walmart.com // @include http://*amazon.com/* // @include http://*amazon.co.uk/* // @include http://*amazon.de/* // @include http://*amazon.ca/* // @include http://*amazon.fr/* // @include http://product.half.ebay.com/* // @include http://*abebooks.com/* // @include http://*alibris.com/* // @include http://*barnesandnoble.com/* // @include http://*.betterworldbooks.com/* // @include http://*biblio.com/* // @include http://*borders.com/* // @include * // @include http://*.powells.com/* // @include http://*.strandbooks.com/* // @include http://*.thriftbooks.com/* // @include http://catalog.ebay.com/* // @include http://books.google.com/* // @include http://*.google.com/* // ==/UserScript== var debug = true; // Of these, only name, id and bookURL are mandatory (but hostname, getISBN, ajaxURL and ajaxPrice are usually needed too). // name: book store name listed in infoline window // id: a short unique id string for all document nodes related to this book store // hostname: a hostname regexp used to determine whether to look for ISBNs on this page // bookURL: address to link the name to, %s being replaced with the ISBN of the book // getISBN: function run on book store pages to find the book ISBN it's about; returns false (no book), or an ISBN string // -- or -- regexp applied to the full URL of the page, whose first matched paren pair gives the ISBN of the book shown // -- defaults to /isbn[\/=]([0-9X]{10})(&|\?|\.|$)/i if omitted // ajaxURL: address to pick up price for the book whose ISBN is %s, for ajax handler (defaults to bookURL, if not given) // ajaxData: '' by default; if given, the data to provide with the ajax request body, %s replaced with the ISBN of the book // ajaxMethod: POST by default (if not given); which HTTP method to access the above // ajaxHeaders: HTTP headers for the AJAX request. Adds a Content-Type: 'application/x-www-form-urlencoded' header for all // POST requests missing a content-type declaration. // ajaxPrice: function run on fetched AJAX page to get book price; returns false (not found) or a price and currency string // or an associative array from store id to price and currency string, when one AJAX request can get many prices // -- or -- regexp (or string form, the latter mostly useful avoid quoting /:s) whose first paren picks up the book price // -- or -- false, in which case no xmlHTTPRequest is ever made (for instance because some other handler finds the price) // priceFix: if ajaxPrice was a string and this function is provided, the resulting price is fed through the callback // updateURL: if provided, a function run on the fetched AJAX page, to get a new (or proper) URL for the book link var Icons = { title: 'data:image/gif;base64,R0lGODlhnwASALMAAHucoM7ave/zyUp3jt7mw2uPmpy1rCleg73NuK3BsjlqiYyoplqDlBhRfQhFd///zyH5BAAAAAAALAAAAACfABIAAAT/8MlJq7046827/2AojomTjFVyOE6AvnDcMFnJsscCl2cF3K2NoAHg/FyVhiK2WDkGhJhnVnPoJAWH4cXDUDkLR3RztChhg8b2kRhcpZrvpfQmOApck5dmdAj6SHASBlY+gYJmfHOFEnZ4EgEDLAo9EgsNLI9seg8EBwp/D3JhCQwsA38/NzQCWQ4Nb2UVCnwMDW2ZFLgOlJacFwSmr282wxO2ka+WTgpbM00saxJ0EwMHYwQNA75rBbedCkubJwLhoaKKYb2efD/n4VEJDY+yFLQSplCbVwh3WA1R+umzIOAAqgeE1gxYQ+iKrYEPAKixVAQTvSDTgLAAMKbAAQrW/zoxetBvC49yoCiMwvjAmwR3g1iGiVJvwr0HtigYlPBJ5cVJAKR5OxfSgoJtOBtQsPNmghymE6g1ShPlgKIHMwkdmjduQEqV6VjChNlS6YSSEVnarGVWQjiRTd82AiDxFE+kL/10AqDghricEwghSDRBgIMiGZv20yEHa4swW2mUsEjYV6CxepNSCFCoplu29pZw1sgLgyRnpP0IvCIXsOXKDwwj3kfBMA2rFLKq5VrCzeEkYS/rJevyrJa0hz7ja/vgLeemGjhXvHqMeWvmYQYDL/w7MYXFLT9W+whVAtouWZquFJ4qs9YJM5EbBW1THG4LCypl3MJAfIWibv3F3JpzsMkW1UgJKHDAH9kgFUY33xAgVxc4/bLeBJi9o0A8XMk3C30BxqQJAI8UwAASBuzUiTZjLLANKbGZImAF3qyxAB5yGJiRRgCckwwv+l2SS0aVpJGAKiy4ABmGw2UWmyuwMKmRUje51pw4bEhyijQ/5rCUK7xcoUoz1+GHCS/OKKIjImy26eabcMYp55x01mnnnXjmqeeeeUYAADs=', about: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAuJAAALiQE3ycutAAAAB3RJTUUH1QQYCDkprC+64gAAAOdJREFUKM+FkrFOAkEURc9ddrJZCgsqCwtCIiUFJa2df2CwNXRS8AmGisLEaGGs3VhTYDUtxZaED/AriGHjPhuEDC5wq3l5czL3vjeyzBlHtC6KoI4BuPk8Qqx3549rov3+YPBIp3NHq3VLlnkkBf0AWK2+6fevWCze8H7CaPRKUfzgnKsG0jSh272kLEuWyy/a7QvSNKnIsJEk6vWE2SxnPH5nOn3YWopjh9VqIbDBGA5fyPNnGo2znZVIEEWhJTNDgmbzfHvZzA6H/pP3k3/TqQQkIYle7z6oT74wnz8d3KNOfY19/QKFiTrWqbiPtAAAAABJRU5ErkJggg==', carrotRight: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QQYCR020Q08hgAAAB10RVh0Q29tbWVudABDcmVhdGVkIHdpdGggVGhlIEdJTVDvZCVuAAAAiklEQVQY07XPIQoCURSF4e8NAzYxGicNuAa1WlyCO3AlZnfiNgwahQFxikkcBIsGfaZpzgODJ/4c/nMvPyR8g7EsephgH6q6aXnWIelhjkUsi0EL88TqFUfMYlnscMoS5wUccMYS4yxhfuGNPho88oQ5xxQjrHHpKkcMccMqVPU99eATG2zb4n/zAS4OHrV1hIB/AAAAAElFTkSuQmCC', carrotDown: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QQYCRoeq/kCuwAAAB10RVh0Q29tbWVudABDcmVhdGVkIHdpdGggVGhlIEdJTVDvZCVuAAAAmElEQVQY083QMUoDARSE4W92U2xhkxSpAgY0AXMQ29zCM3iSXEXQTrCws44Im85CkO1jnq2KKQWnGxiY+Yd/oXw1tTrr7D86CYdD5Xk3HA8vTi8la7xW1T5Jg8IEN6PvPXnEAkOa5l5Viwuc4yk/d9VyfoLrqnpIMmCGu2z79/wGUsv5FFcYY5Nt/wKjI+BvuEWnbfu///kTargo75QVC5oAAAAASUVORK5CYII=', close: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAuJAAALiQE3ycutAAAAB3RJTUUH1QQYCDcSg6d+SAAAAPBJREFUKM+Fkr1qAkEURs9dnWBrJT5IHkEw4gtEsBQs/AlpkiKlJGnEJlqIjRbrPoAQYhPio1hGsPAHFoW5KSIxo7J7qvlgDty534j6Rolgt987OQnA7XuEsTuegwIeMYiIkx2hVnsjCL7+su9/0mz2Lox0oNOpUiw+kc2mUVWGww8mkxYiYK09F4xJMho9kMs9IiJMpy8Y83vFWkUTCVcAWCxWLJcrRIT1OiSTOczuCXieK2y3IeXyK4PBPZtNSKn0zGzWJpW6uvyGer1LpVIgn78GYD7/ptHo0e/fHbemvtHIHv4zvonv4ayXuK9xyg8qt0tfe9qKPAAAAABJRU5ErkJggg==' }; var handlers = [ { name: 'Amazon.com', id: 'amazon', hostname: /\bamazon\.com$/i, getISBN: function() { if( location.href.match( 'ships-from' ) ) return; return location.href.match(/\/([0-9X]{10})(\/|\?|$)/i)[1]; }, bookURL: 'http://www.amazon.com/gp/offer-listing/%s/?ie=UTF8&sort=price', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=amazon&isbn=%s', ajaxPrice: '<span class="price">([^<]*)<' }, { name: 'Abebooks', id: 'abebooks', hostname: /\bwww\.abebooks\.com$/i, getISBN: function(){ return document.title.match( /([0-9X]{10})/i )[1]; }, bookURL: 'http://www.abebooks.com/servlet/SearchResults?isbn=%s&sortby=2', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=abebooks&isbn=%s', ajaxPrice: '<span class="price">US([^<]*)<' }, { name: 'Half.com', id: 'half', hostname: /\bhalf\.ebay\.com$/i, getISBN: nextTagAfter( 'b', 'ISBN-10:' ), bookURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=half&isbn=%s', ajaxURL: 'http://search.half.ebay.com/ws/web/HalfSearch?m=books&isbn=%s&submit=Search', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=half&isbn=%s', ajaxPrice: 'Best[^P]*Price[^$]*([^<]*)<' }, { name: 'Ebay', id: 'ebay', hostname: /\bcatalog\bebay\.com$/i, getISBN: /\b(?:[\d]-?){9}[\dxX]\b/i, bookURL: 'http://search.ebay.com/ws/search/SaleSearch?sofocus=bs&satitle=%s&_dmpt=US_Nonfiction_Book&_htch=1&_ipg=&_pcatid=4&_rptype=4295&_sticky=1&_tab=2&_trksid=p4295.c0.m299&_sop=15&_sc=1', ajaxURL: 'http://search.ebay.com/ws/search/SaleSearch?sofocus=bs&satitle=%s&_dmpt=US_Nonfiction_Book&_htch=1&_ipg=&_pcatid=4&_rptype=4295&_sticky=1&_tab=2&_trksid=p4295.c0.m299&_sop=15&_sc=1', ajaxMethod: 'GET', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=ebay&isbn=%s', ajaxPrice: '<span class="price">[^$]*([^<]*)<' }, { name: 'Alibris', id: 'alibris', hostname: /\balibris\.com$/i, getISBN: function(){ return document.title.match( /([0-9X]{10})/i )[1]; }, bookURL: 'http://www.alibris.com/booksearch?qsort=p&qisbn=%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=alibris&isbn=%s', updateURL: firstLinkTo( '/search/detail.cfm?', 'http://www.alibris.com' ), ajaxPrice: '<span class="big">([^<]*)' }, { name: 'Barnes & Noble Used', id: 'bn', hostname: /\bbarnesandnoble\.com$/i, getISBN: nextTagAfter( 'a', 'ISBN:' ), bookURL: 'http://search.barnesandnoble.com/used/results.aspx?PEAN=%s&USEDPAGETYPE=usedisbn&CND=0', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=bn&isbn=%s', ajaxPrice: '<td class="price"><p><strong[^$]([^<]*)' }, { name: 'BetterWorldBooks', id: 'betterworldbooks', hostname: /\bbetterworldbooks\.com$/i, getISBN: function() {return window.content.location.href.match( /([0-9X]{10})/i )[1]; }, bookURL: 'http://www.betterworldbooks.com/detail.aspx?ItemId=%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=betterworldbooks&isbn=%s', ajaxPrice: '<span class="price">([^<]*)<' }, { name: 'Biblio.com', id: 'biblio', hostname: /\bwww\.biblio\.com$/i, getISBN: function(){ return document.title.match( / - ([0-9X]{10})/i )[1]; }, bookURL: 'http://www.biblio.com/search.php?isbn=%s&stage=1', ajaxURL: 'http://www.biblio.com/search.php?isbn=%s&stage=1', ajaxMethod: 'GET', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=biblio&isbn=%s', ajaxPrice: 'Price:</span>[^$]([^<]*)<' }, { name: 'Borders', id: 'borders', hostname: /\busedmarketplace\.borders\.com$/i, getISBN: function(){ return document.title.match( /([0-9X]{10})/i )[1]; }, bookURL: 'http://usedmarketplace.borders.com/booksearch?isbn=%s&qsort=p', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=borders&isbn=%s', ajaxPrice: '<p><strong>price: <em>([^<]*)<' }, { name: 'Powell Books', id: 'powells', hostname: /\bpowells\.com$/i, getISBN: function() {return window.content.location.href.match( /([0-9X]{10})/i )[1]; }, bookURL: 'http://www.powells.com/biblio?isbn=%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=powells&isbn=%s', ajaxPrice: '<div class="price">([^<]*)<' }, { name: 'The Strand', id: 'strand', hostname: /\bstrandbooks\.com$/i, getISBN: function() {return window.content.location.href.match( /([0-9X]{10})/i )[1]; }, bookURL: 'http://www.strandbooks.com/index.cfm?fuseaction=search.results&searchString=%s', ajaxURL: 'http://www.strandbooks.com/index.cfm?fuseaction=search.results&searchString=%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=strand&isbn=%s', ajaxPrice: '<b>Our Price:</b>[^$]*([^<]*)' }, { name: 'ThriftBooks', id: 'thriftbooks', hostname: /\bwww\.thriftbooks\.com$/i, bookURL: 'http://www.thriftbooks.com/viewDetails.aspx?ISBN=%s', ajaxURL: 'http://www.thriftbooks.com/viewDetails.aspx?ISBN=%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=thriftbooks&isbn=%s', ajaxPrice: 'OurPrice">([^<]*)' }, { name: 'Walmart', id: 'walmart', hostname: /\bwalmart\.com$/i, //getISBN: nextTagAfter( 'ISBN-10:' ), bookURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=walmart&isbn=%s', ajaxURL: 'http://www.walmart.com/search/search-ng.do?search_query=%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=walmart&isbn=%s', ajaxPrice: 'prefixPriceText2[^$]*([^<]*)' }, { name: 'Amazon.uk', id: 'amazon.uk', hostname: /\bamazon\.co.uk$/i, getISBN: function() { if( location.href.match( 'dispatched-from' ) ) return; return location.href.match( /\/([0-9X]{10})(\/|\?|$)/i )[1]; }, bookURL: 'http://www.amazon.co.uk/gp/offer-listing/%s/?tag=boinli-21&sort=price', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=amazon.uk&isbn=%s', ajaxPrice: '<span class="price">([^<]*)<' }, { name: 'Amazon.de', id: 'amazon.de', hostname: /\bamazon\.de$/i, getISBN: function() {return window.content.location.href.match( /([0-9X]{10})/i )[1]; }, bookURL: 'http://www.amazon.de/gp/offer-listing/%s/?ie=UTF8&sort=price', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=amazon.de&isbn=%s', ajaxPrice: '<span class="price">([^<]*)<' }, { name: 'Amazon.ca', id: 'amazon.ca', hostname: /\bamazon\.ca$/i, getISBN: function() { if( location.href.match( 'rate-this' ) ) return; return location.href.match( /\/([0-9X]{10})(\/|\?|$)/i )[1]; }, bookURL: 'http://www.amazon.ca/gp/offer-listing/%s/?ie=UTF8&sort=price', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=amazon.ca&isbn=%s', ajaxPrice: '<span class="price">([^<]*)<' }, { name: 'Amazon.fr', id: 'amazon.fr', hostname: /\bamazon\.fr$/i, getISBN: function() {return window.content.location.href.match( /([0-9X]{10})/i )[1]; }, bookURL: 'http://www.amazon.fr/gp/offer-listing/%s/?ie=UTF8&sort=price', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=amazon.fr&isbn=%s', ajaxPrice: '<span class="price">([^<]*)<' }, { name: 'Google Shopping', id: 'frooglebooks', hostname: /\bgoogle\.com$/i, ajaxMethod: 'GET', getISBN: /\?vid=ISBN([0-9]{10})/i, bookURL: 'http://froogle.google.com/froogle?q=%s&lmode=online&scoring=p', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=frooglebooks&isbn=%s', //updateURL: firstLinkTo( 'http://books.google.com/print?', '' ), ajaxPrice: '<span class="main-price">([^<]*)' }, { name: 'Graigslist', id: 'graig', hostname: /\google\.com$/i, bookURL: 'http://www.google.com/search?hl=en&lr=&q=%s+site:craigslist.org&as_qdr=m&btnG=Search', ajaxMethod: 'GET', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=graig&isbn=%s', ajaxPrice: '<div id=resultStats>([^<]*)<' }, { name: 'Nook EBook', id: 'ebooks', hostname: /\bbarnesandnoble\.com$/i, getISBN: function() {return window.content.location.href.match( /([0-9X]{10})/i )[1]; }, bookURL: 'http://search.barnesandnoble.com/booksearch/isbninquiry.asp?isbn=%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=ebooks&isbn=%s', ajaxPrice: '</a> </td> <td class="price">([^<]*)<' }, { name: 'Kindle Edition', id: 'kindle', hostname: /\bkindle\.com$/i, bookURL: 'http://www.amazon.com/gp/product/%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=kindle&isbn=%s', ajaxPrice: '">Kindle Edition</a>[^$]*([^<]*)<' }, { name: 'AudioBook (CD) ', id: 'AudioCD', hostname: /\bstrandbooks\.com$/i, getISBN: function() { if( location.href.match( 'ships-from' ) ) return; return location.href.match(/\/([0-9X]{10})(\/|\?|$)/i)[1]; }, bookURL: 'http://www.amazon.com/gp/product/%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=AudioCD&isbn=%s', ajaxPrice: 'Audio, CD, Unabridged[^$]*([^<]*)<' }, { name: 'Audible (MP3) ', id: 'Audiomp3', hostname: /\baudible\.com$/i, getISBN: function() { if( location.href.match( 'ships-from' ) ) return; return location.href.match(/\/([0-9X]{10})(\/|\?|$)/i)[1]; }, bookURL: 'http://www.amazon.com/gp/product/%s', linkURL: 'http://freebookexchange.org/amazon/search/index_02.php?site=Audiomp3&isbn=%s', ajaxPrice: ' Audible.com[^$]*([^<]*)<' }, ]; var hasFetched = false; function quoteRegExp( re ) { return re.replace( /([.*+^$?(){}\[\]\\])/g, '\\$1' ); } function regexpify( stringOrRegExp, flags, quote ) { if( (typeof stringOrRegExp == 'function') && stringOrRegExp.exec ) return stringOrRegExp; if( quote ) stringOrRegExp = quoteRegExp( stringOrRegExp ); return new RegExp( stringOrRegExp, flags ); } function firstDocumentLinkMatching( re, paren ) { var x, i; for( i=0; i<document.links.length; i++ ) if( (x = re.exec( document.links[i].href )) ) return x[paren]; // should perhaps backtrack up to parent TR, get its // previous sibling and verify that its contentText == 'Buy this Book' } // AJAX callback returning the first <a href="..."> link to a page whose URL starts with `url'. // baseURL is prepended to the returned result, so passing "/search?" and "http://example.com" // might yield a link to "http://example.com/search?isbn=0596000480", if the page contained it. function firstLinkTo( url, baseURL ) { return function( html, http ) { return baseURL + unHTML(html.match( '<a(?:[^>]*) href=["\']?('+ quoteRegExp( url ) +'[^\'" >]*)' )[1]); }; } function nextTagAfter( tag, content ) { return function() { var tags = document.getElementsByTagName( tag ), i, node, isbn; for( i=0; i<tags.length; i++ ) if( tags[i].innerHTML.match( content ) ) for( j=tags[i].nextSibling; j=j.nextSibling; ) if( (isbn = j.textContent.replace( /-/g, '' ).match( /[0-9X]{10}/i )) ) return isbn[0]; }; } function nextSameTagAfter( tag, content ) { return function() { var isbn, i, tags = document.getElementsByTagName( tag ); for( i=0; i<tags.length-1; i++ ) if( tags[i].innerHTML.match( content ) && (isbn = tags[i+1].innerHTML.match( /[0-9X]{10}/i )) && (isbn = checkISBN( isbn && isbn[0] )) ) return isbn; }; } function unHTML( html ) { return html.replace( /&(amp|lt|gt|quot|apos|#(\d+));/g, function( match, character, code ) { return { amp:'&', lt:'<', gt:'>', quot:'"', apos:'\'' }[character] || String.fromCharCode( code ); }); } // document.getElementById() on steroids (ask for several ids, and you get them back as an array) function $( ids, doc ) { if( typeof ids == 'string' ) return (doc || document).getElementById( ids ); for( var i=0; i<ids.length; i++ ) ids[i] = (doc || document).getElementById( ids[i] ); return ids; } // price cache since last seen book, one day expiry time var last_isbn = GM_getValue( 'last_isbn', '' ); //GM_setValue( 'last_run', '0' ); var last_run = GM_getValue( 'last_run', '0' ); var last_prices = GM_getValue( 'last_prices', '' ); //alert( 'last_run:'+last_run+'\nsaved:\n\n' + last_prices ); function getPrices( isbn ) { var now = (new Date).getTime(); //alert( isbn +':'+ last_isbn +'\n'+ (now-parseInt( last_run )) +'\n' + last_prices ); if( (isbn != last_isbn) || (now-parseInt( last_run ) > 36e5) || (last_prices.split( '\n' ).length != handlers.length) ) return false; return decodePrices( last_prices ); } var prices = {}; function updateCache( isbn, store, price ) { var now = (new Date).getTime(), got = 0, i, h; if( (isbn != last_isbn) || (now - parseInt( last_run ) > 864e5) ) prices = {}; last_isbn = isbn; last_run = now.toString(); prices[store] = price; for( i in prices ) got++; if( got == handlers.length ) { //alert( encodePrices( prices ) ); GM_setValue( 'last_prices', last_prices = encodePrices( prices ) ); GM_setValue( 'last_isbn', isbn ); GM_setValue( 'last_run', last_run ); } else ;//alert( got +'/' + handlers.length ); } function decodePrices( stored ) { var prices = {}, i, raw = (stored||'').split( '\n' ); for( i=0; i<raw.length; i++ ) { var data = raw[i].split( ':' ); prices[data.shift()] = data.join( ':' ); } return prices; } function encodePrices( prices ) { var i, raw = []; for( i in prices ) raw.push( i +':'+ prices[i] ); return raw.join( '\n' ); } function updatePrices( prices, isbn ) { var id, node, price, data, errmsg = 'Oops! Either there are no books available,\\n' + 'or there is a parsing error due to changes\\n' + 'in to this website\\\'s page format.'; for( id in prices ) if( (node = document.getElementById( 'burro_'+id )) ) { if( debug ) GM_log( id +' price set to '+ prices[id] ); data = (prices[id] || '').split( ':' ); if( (price = data.shift()) ) { node.firstChild.nodeValue = price; if( data.length ) updateURL( id, data.join( ':' ) ); } else node.innerHTML = '<a style="text-decoration:none;color:#A4A4A4;" href="javascript:alert(\''+ errmsg +'\');">none</a>'; if( isbn ) updateCache( isbn, id, price ); } } function findHeader( headers, name ) { var i, found; name = regexpify( name, 'i', 'quote' ); for( i in headers ) if( i.match( name ) ) return headers[i]; } (function() { var allLinks = document.getElementsByTagName("a"); for (i = 0; i < allLinks.length; i++) { var href = allLinks[i].href; if(href.match(/\.abebooks\.com/)) { var hoge = href.replace("http://www.abebooks.com/servlet/SearchEntry","http://clickserve.cc-dt.com/link/tplclick?lid=41000000024289215&pubid=21000000000159388&cm_ven=PFX&cm_cat=affiliates&cm_pla=dlt&cm_ite=21000000000159388&redirect=http://www.abebooks.com/servlet/SearchEntry"); allLinks[i].setAttribute("href", hoge); } } })(); (function() { var allLinks = document.getElementsByTagName("a"); for (i = 0; i < allLinks.length; i++) { var href = allLinks[i].href; if(href.match(/(ref=sr_1|ref=sr_1_olp|ref=sr_ob)\_+[0-9]+\?ie=UTF8/)) { var hoge = href.replace(/&sr=1-+[0-9]+/, '') allLinks[i].setAttribute("href", hoge); } } })(); /* var main = { url : "http://freebookexchange.org/amazon/amazon.txt", repText : "", run : function(rep) { var array=document.evaluate("//a[contains(@href,amazon\.com|(\/gp\/offer-listing))]", document, null, 6, null), regex=/(ref=sr_1|ref=sr_1_olp|ref=sr_ob|ref=dp_olp)\_+[a-z0-9]+\?ie=UTF8/, repText=rep; //alert(repText); for(let i=0,item; (item=array.snapshotItem(i)); i++) item.href=item.href.replace(regex, repText); }, call : function() { GM_xmlhttpRequest({ method: "GET", url: main.url, onload: function(r) { main.run(r.responseText.replace(/^\s*|\s*$/g, "")); } }); } }; main.call(); // do it all */ var main = { url : "http://freebookexchange.org/amazon/tag.txt", repText : "", run : function(rep) { var array=document.evaluate("//a[contains(@href,amazon\.com)]", document, null, 6, null), regex=/&tag=+[a-z0-9]+-20/, repText=rep; //alert(repText); for(let i=0,item; (item=array.snapshotItem(i)); i++) item.href=item.href.replace(regex, repText); }, call : function() { GM_xmlhttpRequest({ method: "GET", url: main.url, onload: function(r) { main.run(r.responseText.replace(/^\s*|\s*$/g, "")); } }); } }; main.call(); // do it all function runQueries( isbn ) { var i, j, h, request, callback, prices = debug ? false : getPrices( isbn ); if( prices ) return updatePrices( prices ); // already cached for( i=0; i<handlers.length; i++ ) { h = handlers[i]; if( h.ajaxPrice != false ) { if( debug ) GM_log( h.id +': '+ (h.ajaxMethod||'POST')+'( '+(h.ajaxURL||h.bookURL) + ' )' ); request = { method:h.ajaxMethod||'POST', data:(h.ajaxData||'').replace( /%s/g, isbn ), onload:makeAjaxCallback( h, isbn ), url:(h.ajaxURL||h.bookURL).replace( /%s/g, isbn ) }; if( h.ajaxHeaders ) request.headers = h.ajaxHeaders; if( (request.method == 'POST') && !findHeader( request.headers = request.headers || {}, 'Content-Type' ) ) request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; GM_xmlhttpRequest( request ); } } } function updateURL( id, url ) { document.getElementById( 'burro_book_' + id ).href = url; } function makeAjaxCallback( handler, isbn ) { var callback = handler.ajaxPrice; switch( typeof callback ) { case 'function': if( !callback.exec ) break; // callback is already our proper callback // fall-through -- it was a regexp: case 'string': callback = function( html, http ) { var x = html.match( handler.ajaxPrice ); var price = html.match( handler.ajaxPrice )[1].replace( / /g, '' ); if( debug > 2 ) GM_log( 'found raw '+ handler.id +'price '+ price ); if( price ) price = unHTML( price ); if( price && handler.priceFix ) price = handler.priceFix( price ); return price; }; break; case 'object': // array of string or regexp callback = function( html, http ) { var i, price, regexps = handler.ajaxPrice; for( i=0; i<regexps.length; i++ ) if( (price = html.match( regexps[i] )) ) { price = price[1]; if( debug > 2 ) GM_log( 'found raw '+ handler.id +' price '+ price +' for regexp '+ regexps[i] ); if( price && handler.priceFix ) price = handler.priceFix( price ); return price; } }; break; default: alert( 'Price handler for '+ handler.name +' (id '+ handler.id + ') is of illegal type '+ (typeof callback) +'! Ignoring.' ); // fall-through: case 'boolean': callback = function(){}; } return function( xmlHttpResponse ) { if( debug ) with( xmlHttpResponse ) GM_log( 'Status ' + status+' '+statusText + ': '+ responseText.length +' bytes' ); var failure = false, prices = {}, result = '', node, id, price; try { result = callback( xmlHttpResponse.responseText, xmlHttpResponse ) || ''; } catch (e) { failure = true; if( debug ) GM_log( 'Failed to load or parse '+ handler.name +' (id '+ handler.id +'): ' +e ); //alert( xmlHttpResponse.responseText ); } if( handler.updateURL ) try { var url = handler.updateURL( xmlHttpResponse.responseText, xmlHttpResponse ); if( url ) updateURL( handler.id, url ); } catch( e ) {} if( typeof result == 'string' ) // a price tag { if( url ) result += ':' + url; // a new book URL to link prices[handler.id] = result; } else if( typeof result == 'boolean' ) // availability info only { if( url ) result += ':' + url; // a new book URL to link prices[handler.id] = result ? 'available' : 'unavailable'; } else prices = result; updatePrices( prices, isbn ); }; } function checkEAN( ean ) { try { ean = (ean||'').replace( /-| | /gi, '' ); if( ean.length != 13 ) return false; var checksum = 0; for( var i=0; i<12; i++ ) checksum += ean.charAt(i) * (i&1 ? 3 : 1); checksum = (10 - (checksum % 10)) % 10; if( ean.charAt(12) == checksum ) return ean; else { if( debug ) GM_log( 'EAN '+ean+ ' failed checksum.' ); return false; } } catch (e) { if( debug ) GM_log( 'checkEAN: '+ e ); return false; } } function checkISBN( isbn ) { try { isbn = (isbn||'').toLowerCase().replace( /-| | /g, '' ); if( isbn.length != 10 ) return false; var checksum = 0; for( var i=0; i<9; i++ ) if( isbn.charAt(i) == 'x' ) checksum += 10 * (i+1); else checksum += isbn.charAt(i) * (i+1); checksum = checksum % 11; if( checksum == 10 ) checksum = 'x'; if( isbn.charAt(9) == checksum ) return isbn; else { if( debug ) GM_log( 'ISBN '+isbn+ ' failed checksum.' ); return false; } } catch (e) { if( debug ) GM_log( 'checkISBN: '+ e ); return false; } } function dom_createLink( url, txt, title, id, imageSRC ) { var image; if(imageSRC) { image = document.createElement('img'); image.src = imageSRC; image.align = 'left'; image.style.display = 'block'; image.style.position = 'inline'; } var a = document.createElement( 'a' ); if( id ) a.id = id; a.setAttribute( 'target', '_blank' ); a.setAttribute( 'href', url ); with( a.style ) { color = '#084B8A'; textDecoration = 'none'; fontWeight = 'bold'; } if( title ) a.setAttribute( 'title', title ); if(image) a.appendChild( image ); a.appendChild( document.createTextNode( txt ) ); return a; } function addSite( url, title, loc_id, imageSRC ) { var tr = document.createElement( 'div' ); var td_left = document.createElement( 'span' ); var a = dom_createLink( url, title, title+' Search', 'burro_book_'+loc_id, imageSRC ); td_left.style.paddingLeft = '5px'; td_left.appendChild( a ); tr.appendChild( td_left ); var td_right = document.createElement( 'span' ); td_right.innerHTML = 'fetching'; td_right.style.paddingRight = '5px'; td_right.id = 'burro_' + loc_id; tr.appendChild( td_right ); if( document.all ) // IE only { tr.style.position = 'relative'; td_right.style.textAlign = 'right'; td_right.style.position = 'absolute'; td_right.style.left = '10em'; td_right.style.width = '4em'; } else // other browsers { tr.style.display = 'table-row'; td_left.style.display = 'table-cell'; td_right.style.display = 'table-cell'; } return tr; } function str2xml( strXML ) { if( window.ActiveXObject ) { var domdoc = new ActiveXObject( 'Microsoft.XMLDOM' ); domdoc.async = 'false'; domdoc.loadXML( strXML ); return domdoc; } else { var objDOMParser = new DOMParser(); return objDOMParser.parseFromString( strXML, 'text/xml' ); } } function int2money( cents ) { var money = '$' if( cents < 100 ) money = money + '0.'; else money = money + Math.floor( cents/100 ) + '.'; cents = cents % 100; if( cents < 10 ) money = money + '0'; money = money + cents; return money; } 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.bottom)) ) this.div.style.bottom = '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 ) { // this.mouseUp = addEventHandler( this.handle, 'mouseup', this.end, this ); e = Drag.fixE( e ); this.started = new Date(); var y = this.startY = parseInt(this.div.style.bottom); 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.bottom); var x = parseInt(this.div.style.right ); var nx = x - ex + this.lastMouseX; var ny = y - ey + this.lastMouseY; this.div.style.right = nx + 'px'; this.div.style.bottom = 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 = this.startX - x; var y = parseInt(this.div.style.bottom), dy = this.startY - y; 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; } function burro( location, isbn ) { if( debug > 1 ) GM_log( 'adding burro' ); var handle = document.createElement( 'div' ); var root = document.createElement( 'div' ); var box = document.createElement( 'div' ), i, h; with( root.style ) { position = 'absolute'; top = right = '15px'; } handle.style.padding = '4px'; handle.title = 'Click title to expand, collapse or drag'; with( box.style ) { position = 'relative'; zIndex = '1000'; backgroundColor = '#FFC'; border = '1px solid orange'; padding = '0px'; textAlign = 'left'; font = '8pt sans-serif'; width = '250px'; opacity = '0.90'; filter = 'alpha(opacity=90)'; } var carrot = document.createElement( 'img' ); carrot.style.top = '-10px'; carrot.src = Icons.carrotRight; carrot.id = 'hide_show_carrot'; handle.appendChild( carrot ); var title_image = document.createElement( 'img' ); title_image.style.marginLeft = '6px'; title_image.src = Icons.title; handle.appendChild( title_image ); var close = document.createElement( 'img' ); close.src = Icons.close; with( close.style ) { position = 'absolute'; right = '3px'; top = '3px'; margin = '2px'; width = '12px'; height = '12px'; backgroundColor = '#FFB'; border = 'none'; lineHeight = '8px'; textAlign = 'center'; } close.setAttribute( 'title', 'Click to remove' ); addEventHandler( close, 'click', function(){ document.body.removeChild( root ); } ); handle.appendChild( close ); var about = document.createElement( 'a' ); var about_img = document.createElement( 'img' ); about_img.src = Icons.about; about_img.style.border = 'none'; about.appendChild( about_img ); with( about.style ) { position = 'absolute'; right = '18px'; top = '3px'; margin = '2px'; width = '12px'; height = '12px'; backgroundColor = '#FFB'; lineHeight = '12px'; textAlign = 'center'; textDecoration = 'none'; } about.title = 'BookInfoLineSearch'; about.href = 'http://www.freebookexchange.org/amazon/index.html'; handle.appendChild( about ); box.appendChild( handle ); var table = document.createElement( 'div' ); with( table.style ) { marginTop = '1px'; marginBottom = '3px'; padding = '0'; width = '100%'; font = '10pt sans-serif'; display = 'none'; } table.id = 'bookburro-pricesTable';//stay for( i=0; i<handlers.length; i++ ) { h = handlers[i]; table.appendChild( addSite( h.linkURL.replace( /%s/g, isbn ), h.name, h.id, h.imageSRC ) ); } box.appendChild( table ); var zip = function() { box.opened = !box.opened; var pricesTable = document.getElementById( 'bookburro-pricesTable' );//stay var carrot = document.getElementById( 'hide_show_carrot' ); if( box.opened ) // pricesTable.style.display == 'none' { if( !hasFetched ) runQueries( isbn ); hasFetched = true; pricesTable.style.display = document.all ? 'block' : 'table'; carrot.src = Icons.carrotDown; } else { pricesTable.style.display = 'none'; carrot.src = Icons.carrotRight; } }; //addEventHandler( box, 'click', zip ); root.appendChild( box ); document.body.appendChild( root ); handle.drag = new Drag( handle, box ); handle.drag.onClick = zip; /*If you want extraction to start as soon as you are on the page zip(); zip(); */ if( debug > 1 ) GM_log( 'added burro' ); } function init() { var i, h, getISBN, isbn; for( i=0; i<handlers.length; i++ ) { h = handlers[i]; if( h.hostname && location.hostname.match( h.hostname ) ) try { if( debug ) GM_log( h.name +' matched at '+ location.hostname ); getISBN = h.getISBN || /isbn[\/=]([0-9X]{10})(&|\?|\.|$)/i; switch( typeof getISBN ) { case 'string': getISBN = new RegExp( getISBN ); // fall-through case 'function': if( getISBN.exec ) // a regexp { var regexp = getISBN; getISBN = function(){ return location.href.match( regexp )[1]; }; } isbn = getISBN(); break; /* default: alert( 'getISBN handler for '+ h.name +' (id '+ h.id + ') is of illegal type '+ (typeof getISBN) +'! Ignoring.' );*/ continue; } if( (isbn = checkISBN( isbn )) ) burro( h.id, isbn ); else if( debug ) GM_log( 'Failed to find ISBN for '+ h.name +' (id '+ h.id +')' ); } catch (e) { if( debug ) GM_log( e ); } } } // addEventHandler(document, 'load', init); init();
Mozilla add on,User script,Grease Monkey Script, greasemonkey userscripts, updater userscripts mafia wars userscripts mafia wars autoplayer userscripts mafia wars wall userscripts scripts userscripts travian greasemonkey greasemonkey download greasemonkey facebook greasemonkey tutorial greasemonkey youtube greasemonkey travian greasemonkey chrome greasemonkey mafia wars greasemonkey mafia wars autoplayer
Saturday, January 22, 2011
BookInfoLine. Compare book prices from various book stores.
Subscribe to:
Post Comments (Atom)
0 comments:
Post a Comment