{ "translatorID": "3e684d82-73a3-9a34-095f-19b112d88bbf", "label": "Google Books", "creator": "Simon Kornblith, Michael Berkowitz and Rintze Zelle", "target": "^https?://(books|www)\\.google\\.[a-z]+(\\.[a-z]+)?/(books(?:\\/.*)?\\?(.*id=.*|.*q=.*)|search\\?.*?(btnG=Search\\+Books|tbm=bks))|^https?://play\\.google\\.[a-z]+(\\.[a-z]+)?\\/(store\\/)?(books|search\\?.+&c=books)", "minVersion": "2.1.9", "maxVersion": "", "priority": 100, "inRepository": true, "translatorType": 4, "browserSupport": "gcsb", "lastUpdated": "2014-06-01 17:47:45" } /* The various types of Google Books URLs are: Search results - List view http://books.google.com/books?q=asimov&btnG=Search+Books Search results - Cover view http://books.google.com/books?q=asimov&btnG=Search%20Books&rview=1 Single item - URL with "id" http://books.google.com/books?id=skf3LSyV_kEC&source=gbs_navlinks_s http://books.google.com/books?hl=en&lr=&id=Ct6FKwHhBSQC&oi=fnd&pg=PP9&dq=%22Peggy+Eaton%22&ots=KN-Z0-HAcv&sig=snBNf7bilHi9GFH4-6-3s1ySI9Q#v=onepage&q=%22Peggy%20Eaton%22&f=false Single item - URL with "vid" (see http://code.google.com/apis/books/docs/static-links.html) http://books.google.com/books?printsec=frontcover&vid=ISBN0684181355&vid=ISBN0684183951&vid=LCCN84026715#v=onepage&q&f=false Personal play store book lists https://play.google.com/books (no test) Play Store Individual Books https://play.google.com/store/books/details/Adam_Smith_The_Wealth_of_Nations?id=-WxKAAAAYAAJ Play Store Book Searches https://play.google.com/store/search?q=doyle+arthur+conan&c=books */ var singleRe = /^https?:\/\/(?:books|www|play)\.google\.[a-z]+(?:\.[a-z]+)?(?:\/store)?\/books(?:\/.*)?\?(?:[^q].*&)?(id|vid)=([^&]+)/i; function detectWeb(doc, url) { if(singleRe.test(url)) { return "book"; } else { return "multiple"; } } var itemUrlBase; function doWeb(doc, url) { // get local domain suffix var psRe = new RegExp("https?://(books|www|play)\.google\.([^/]+)/"); var psMatch = psRe.exec(url); var suffix = psMatch[2]; var prefix = "books"; //Where is it not books? psMatch[1]; itemUrlBase = "http://"+prefix+".google."+suffix+"/books?id="; var m = singleRe.exec(url); if(m && m[1] == "id") { ZU.doGet("http://books.google.com/books/feeds/volumes/"+m[2], parseXML); } else if (m && m[1] == "vid") { var itemLinkWithID = ZU.xpath(doc, '/html/head/link[@rel="canonical"]')[0].href; var m = singleRe.exec(itemLinkWithID); ZU.doGet("http://books.google.com/books/feeds/volumes/"+m[2], parseXML); } else { var items = getItemArrayGB(doc, doc, 'google\\.' + suffix + '/books\\?id=([^&]+)', '^(?:All matching pages|About this Book|Table of Contents|Index)'); //Zotero.debug(items); // Drop " - Page" thing for(var i in items) { items[i] = items[i].replace(/- Page [0-9]+\s*$/, ""); } Zotero.selectItems(items, function(items) { if(!items) Z.done(); var baseurl = url.match(psRe)[0]; var newUris = []; for(var i in items) { //the singleRe has the full URL - we may only be getting the URL w/o host correct for that. if (i.search(psRe)===-1){ i = baseurl.replace(/\/$/, "") + i; } var m = singleRe.exec(i); newUris.push("http://books.google.com/books/feeds/volumes/"+m[2]); } ZU.doGet(newUris, parseXML); }); } } function parseXML(text) { //Z.debug(text) // Remove xml parse instruction and doctype var parser = new DOMParser(); var xml = parser.parseFromString(text, "text/xml").documentElement; var ns = {"dc":"http://purl.org/dc/terms", "atom":"http://www.w3.org/2005/Atom"}; var newItem = new Zotero.Item("book"); var authors = ZU.xpath(xml, "dc:creator", ns); for (var i in authors) { newItem.creators.push(Zotero.Utilities.cleanAuthor(authors[i].textContent, "author")); } var pages = ZU.xpathText(xml, "dc:format", ns); const pagesRe = /(\d+)( pages)/; var pagesMatch = pagesRe.exec(pages); if (pagesMatch!=null) { newItem.numPages = pagesMatch[1]; } else { newItem.numPages = pages; } var ISBN; const ISBN10Re = /(ISBN:)(\w{10})$/; const ISBN13Re = /(ISBN:)(\w{13})$/; var identifiers = ZU.xpath(xml, "dc:identifier", ns); for (var i in identifiers) { var ISBN10Match = ISBN10Re.exec(identifiers[i].textContent); var ISBN13Match = ISBN13Re.exec(identifiers[i].textContent); if (ISBN10Match != null) { ISBN = ISBN10Match[2]; } if (ISBN13Match != null) { ISBN = ISBN13Match[2]; } } newItem.ISBN = ISBN; newItem.publisher = ZU.xpathText(xml, "dc:publisher", ns); newItem.title = ZU.xpathText(xml, "dc:title", ns, ": "); newItem.language = ZU.xpathText(xml, 'dc:language', ns); newItem.abstractNote = ZU.xpathText(xml, 'dc:description', ns); newItem.date = ZU.xpathText(xml, "dc:date", ns); var url = itemUrlBase + identifiers[0].textContent; newItem.attachments = [{title:"Google Books Link", snapshot:false, mimeType:"text/html", url:url}]; var subjects = ZU.xpath(xml, 'dc:subject', ns); for(var i in subjects) { newItem.tags.push(subjects[i].textContent); } newItem.complete(); } /** * Grabs items based on URLs, modified for Google Books * * @param {Document} doc DOM document object * @param {Element|Element[]} inHere DOM element(s) to process * @param {RegExp} [urlRe] Regexp of URLs to add to list * @param {RegExp} [urlRe] Regexp of URLs to reject * @return {Object} Associative array of link => textContent pairs, suitable for passing to * Zotero.selectItems from within a translator */ function getItemArrayGB (doc, inHere, urlRe, rejectRe) { var availableItems = new Object(); // Technically, associative arrays are objects //quick check for new format var bookList = ZU.xpath(doc, '//ol[@id="rso"]/li|//ol[@id="rso"]/div/li'); if(bookList.length) { Z.debug("newFormat") for(var i=0, n=bookList.length; i-elements, scrape title from alt-attribute, href-link from parent -element for(var i=0; i