// ==UserScript== // @name Douban Book Bar // @namespace DoubanBookBar // @license MIT License // @author ElvisKang // @description 显示书籍的豆瓣评分并进行比价(暂时仅支持Firefox) // @include *://www.amazon.cn/* // @include *://item.jd.com/* // @include *://product.dangdang.com/* // @include *://product.china-pub.com/* // @include *://product.suning.com/* // @version ver 1.0.13 // @grant GM_xmlhttpRequest // @grant GM_addStyle // @downloadURL none // ==/UserScript== (function () { "use strict"; function setBaseCss () { var baseCSS = [ "#bookbar-container a {color:#228A31 !important;text-decoration:none;font-size: 13px;}", "#bookbar-container .bookbar-title {font-size: 15px;}", "#bookbar-container span {margin-right: 5px;display: inline-block;font-size: 13px;font-weight: bold;}", "#bookbar-container ul {padding-left: 0;margin: 4px 0;}", "#bookbar-container li {list-style: none none outside; display: inline;padding: 0 4px;}", "#bookbar-container img{ height:16px; width:16px;}", "#avgScore {color:#DC0000 !important;}" ].join ( "" ); GM_addStyle ( baseCSS ); } function createStarSpan (score) { var starSpan = document.createElement ( "span" ); starSpan.id = "bookbar-star"; var bgPosition = "0 " + (-14) * (10 - Math.floor ( parseFloat ( score ) + 0.8 )) + "px"; var starSpanCSS = [ "#bookbar-star { ", "background :url(http://img3.douban.com/pics/movie/bigstars.gif) no-repeat scroll " + bgPosition + " ; ", "width:75px; height: 14px; position: relative; top: 1px;}" ].join ( "" ); GM_addStyle ( starSpanCSS ); return starSpan; } function createScoreSpan (bookInfo) { var bookID = bookInfo.id, bookRating = bookInfo.rating || {}, numRaters = bookRating.numRaters, averageScore = bookRating.average; var scoreSpan = document.createElement ( "span" ), infoUl = document.createElement ( "ul" ), commentsLink = document.createElement ( "li" ), bookInfoLink = document.createElement ( "li" ); if ( numRaters === 0 ) { commentsLink.innerHTML = "没有人评价这本书"; } else if ( numRaters < 10 ) { commentsLink.innerHTML = "少于10人评价这本书"; } else if ( numRaters >= 10 ) { commentsLink.innerHTML = '(共' + numRaters + '人评价)'; } else { //获取信息出现错误 commentsLink.innerHTML = ""; } if ( commentsLink.innerHTML !== "" ) { var avgLi = document.createElement ( "li" ), starLi = document.createElement ( "li" ), starSpan = createStarSpan ( averageScore ); avgLi.innerHTML = '' + averageScore + ''; avgLi.id="avgScore"; starLi.appendChild ( starSpan ); infoUl.appendChild ( avgLi ); bookInfoLink.innerHTML = '(去豆瓣看这本书)'; infoUl.appendChild ( starLi ); infoUl.appendChild ( commentsLink ); } else { bookInfoLink.innerHTML = '没在豆瓣找到这本书,去豆瓣逛逛?'; } infoUl.appendChild ( bookInfoLink ); scoreSpan.appendChild ( infoUl ); //console.log(scoreLi); return scoreSpan; } function createPriceLi (iconLink, priceData) { var priceLi = document.createElement ( "li" ), link = document.createElement ( "a" ), img = document.createElement ( "img" ); img.src = iconLink; link.href = priceData.href || "#"; link.target = "_blank"; if ( priceData.price === undefined ) { link.textContent = "[没找到]"; } else { link.textContent = "¥" + priceData.price; } priceLi.appendChild ( img ); priceLi.appendChild ( link ); return priceLi; } function createContrastPriceInfo (priceList) { //生成其他网站的价格信息 var contrastPriceInfo = document.createElement ( "span" ), infoContainer = document.createElement ( "ul" ); if ( priceList.length === 0 ) { contrastPriceInfo.innerHTML = "豆瓣上没有购买信息"; } else { for ( var i = 0, len = priceList.length ; i < len ; i++ ) { var matchIndex = sitesContainer.nameList.indexOf ( priceList[i].name ); var priceLi = createPriceLi ( sitesContainer.list[matchIndex].logo, priceList[i] ); infoContainer.appendChild ( priceLi ); } //console.log(contrastPriceInfo); } contrastPriceInfo.appendChild ( infoContainer ); return contrastPriceInfo; } function createBar (infoRow, priceRow, position) { var bar = document.createElement ( "div" ); bar.id = "bookbar-container"; bar.appendChild ( infoRow ); bar.appendChild ( priceRow ); (function insertAfter () { // console.log(bar); var parent = position.parentNode; if ( parent.lastChild === position ) { parent.appendChild ( bar ); } else { parent.insertBefore ( bar, position.nextSibling ); } })(); } function createPriceRowContainer () { var container = document.createElement ( "div" ), label = document.createElement ( "span" ); container.id = "bookbar-priceInfo"; label.innerHTML = "比         价:"; label.className = "bookbar-title"; container.appendChild ( label ); return container; } function createInfoRowContainer () { var container = document.createElement ( "div" ), label = document.createElement ( "span" ); container.id = "bookbar-doubanInfo"; label.className = "bookbar-title"; label.innerHTML = "豆瓣评分:"; container.appendChild ( label ); return container; } // 获取书籍信息的函数 function getBookInfo (isbn) { if ( !isbn ) { return null; } GM_xmlhttpRequest ( { method : "get", url : "http://api.douban.com/v2/book/isbn/" + isbn, onload : function (result) { //console.log(result); var bookInfo = JSON.parse ( result.responseText ); getBookPrice ( bookInfo ); } } ); } function getBookPrice (bookInfo) { var doubanID = bookInfo.id || null; var doubanLink = "http://book.douban.com/subject/" + doubanID + "/buylinks"; var priceList = []; GM_xmlhttpRequest ( { method : "get", url : doubanLink, onload : function (result) { // console.log ( result.responseText ); var container = document.createElement ( "div" ); container.innerHTML = result.responseText; var list = document.evaluate ( '//table[@id="buylink-table"]/tbody/tr', container, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ); //console.log(list); var priceChecker = /[0-9]+(\.[0-9]+)?/; for ( var i = 1, len = list.snapshotLength ; i < len ; i++ ) { //console.log(list.snapshotItem(i)); var part = list.snapshotItem ( i ); var link_info = part.querySelectorAll ( "td.pl2" ); var siteName = link_info[0].textContent.trim (); if ( sitesContainer.nameList.indexOf ( siteName ) !== -1 && siteName !== sitesContainer.curSite.name ) { var priceInfo = { "name" : siteName, "href" : link_info[0].getElementsByTagName ( "a" )[0].href, "price" : priceChecker.exec ( link_info[1].textContent.trim () )[0] }; priceList.push ( priceInfo ); } } //console.log(priceList); sitesContainer.curSite.createDoubanBar ( bookInfo, priceList ); } } ); } // 网站对象 var sitesContainer = { _siteList : [], //可支持的网页,通过Site.list获取 _curSite : null, //当前网页 _siteNameList : [], addSites : function (sitesArray) { if ( Object.prototype.toString.call ( sitesArray ) === '[object Array]' ) { this._siteList = this._siteList.concat ( sitesArray ); for ( var i = 0 ; i < sitesArray.length ; i++ ) { this._siteNameList.push ( sitesArray[i].name ); } } }, get list () { return this._siteList; }, get nameList () { return this._siteNameList; }, get curSite () { return this._curSite; }, set curSite (href) { try { //通过对象中的checker属性匹配网站 for ( var i = 0, len = this._siteList.length ; i < len ; i++ ) { if ( Object.prototype.toString.call ( this._siteList[i].checker ) === "[object RegExp]" ) { if ( this._siteList[i].checker.test ( href ) ) { this._curSite = this._siteList[i]; return this._siteList[i]; } } } } catch (e) { console.log ( "getCurSite() Error : " + e ); return {}; } return {}; } }; function SupportSite (siteInfo) { this.name = siteInfo.name; this.logo = siteInfo.logo; this.checker = siteInfo.checker; this.getISBN = siteInfo.getISBN; this.referencePosition = siteInfo.referencePosition; } SupportSite.prototype.createDoubanBar = function (bookInfo, priceList) { var referencePosition = document.querySelector ( this.referencePosition ); var infoRowContainer = createInfoRowContainer (), priceRowContainer = createPriceRowContainer (); var scoreSpan = createScoreSpan ( bookInfo ), contrastPriceInfo = createContrastPriceInfo ( priceList ); priceRowContainer.appendChild ( contrastPriceInfo ); infoRowContainer.appendChild ( scoreSpan ); setBaseCss (); createBar ( infoRowContainer, priceRowContainer, referencePosition ); }; var Amazon = new SupportSite ( { name : "亚马逊", checker : /(https?:\/\/)?(www)?\.amazon\.(com|cn)\/.*/, logo : "http://www.amazon.cn/favicon.ico", getISBN : function () { var contents = document.querySelectorAll ( "div.content b" ); try { for ( var i = 0 ; i <= contents.length ; i++ ) { var info = contents[i]; if ( info.textContent === "ISBN:" || info.textContent === "条形码:" ) { //console.log(info.nextSibling.data.split(",")[0].substring(1)); return info.nextSibling.data.split ( "," )[0].substring ( 1 ); } } return null; } catch (e) { return null; } }, referencePosition : ".product" } ); var JD = new SupportSite ( { name : "京东商城", checker : /(https?:\/\/)?(www|item)?\.jd\.com\/.*/, logo : "http://www.jd.com/favicon.ico", getISBN : function () { try { var isbnString = document.querySelector ( "li.fore4:nth-child(2)" ).innerHTML; return isbnString.split ( ":" )[1]; } catch (e) { return null; } }, referencePosition : "#name" } ); var Dangdang = new SupportSite ( { name : "当当网", checker : /(https?:\/\/)?(www|product)?\.dangdang\.com\/.*/, logo : "http://www.dangdang.com/favicon.ico", getISBN : function () { var scanItems = document.querySelectorAll ( "div.show_info_left" ); try { for ( var i = 0 ; i < scanItems.length ; i++ ) { if ( scanItems[i].textContent === "ISBN" || scanItems[i].textContent === "ISBN" ) { return scanItems[i].nextElementSibling.innerHTML; } } } catch (e) { return null; } }, referencePosition : ".head" } ); var Chinapub = new SupportSite ( { name : "China-pub", checker : /(https?:\/\/)?(product|www)\.china\-pub\.com\/.*/, logo : "http://www.china-pub.com/favicon.ico", getISBN : function () { var list = document.querySelectorAll ( "#con_a_1 li" ); for ( var i = 0 ; i < list.length ; i++ ) { if ( list[i].innerHTML.split ( ":" )[0] === "ISBN" ) { return list[i].innerHTML.split ( ":" )[1].replace ( /<.*?>/g, "" ).match ( /[0-9]*/g ).join ( "" ); } } return null; }, referencePosition : ".pro_buy_star" } ); var Suning = new SupportSite ( { name : "苏宁易购", checker : /(https?:\/\/)?(product)\.suning\.com\/.*/, logo : "http://www.suning.com/favicon.ico", getISBN : function () { try { var isbn = document.querySelector ( "li.li-b:nth-child(11) > span:nth-child(2)" ); return isbn.innerHTML; } catch (e) { return null; } }, referencePosition : ".product-main-title" } ); //脚本执行 function init () { sitesContainer.addSites ( [Amazon, JD, Dangdang, Chinapub, Suning] ); sitesContainer.curSite = location.href; if ( !!(sitesContainer.curSite) ) { var isbn = sitesContainer.curSite.getISBN (); try { getBookInfo ( isbn ); } catch (e) { throw e; } } } init (); }) ();