LDRizeのSITEINFOを利用して色んなところに被はてブ数を付けるUserJS
これを読んでて、まあ作るのは大した手間ではないのだけど、いかんせん対応するサイトを全部手動で作るのはアレなのでどうしようか、なんてことを考えていたら、そういえば良いものがあった。
とりあえず os0x さんが簡略化して公開してくれている LDRize の SITEINFO を使って、Amazon と Google にはてなブックマークの数を出すスクリプトを書いた。
「Opera で」ということなので Opera でしか確認してないけど、IE 以外なら動くような気がする。
- HatebuChecker.js (Greasemonkey なら .user.js)
// ==UserScript== // @name HatebuChecker // @namespace http://d.hatena.ne.jp/edvakf/ // @description show hatena bookmark count after some links // @include http://* // @include https://* // ==/UserScript== (function(siteinfo){ var info = null; function HatebuChecker(){ if (siteinfo) { siteinfo.some(function(i){ i = i.data || i; if (!i.domain || !i.paragraph || !i.link || !(new RegExp(i.domain)).test(location.href)) return false; var p = getFirstElementByXPath(i.paragraph); if (!p || !getFirstElementByXPath(i.link, p)) return false; info = i; return true }); siteinfo = null; } if (!info) return; getElementsByXPath(info.paragraph).forEach(function(p){ var a = getFirstElementByXPath(info.link, p); if (!a.getAttribute('href') || a.getAttribute('class') && a.getAttribute('class').indexOf('HatenaBookMarkCountShown') >= 0 ) return; var e = document.createElement('a'); e.setAttribute('href', 'http://b.hatena.ne.jp/entry/'+a.href.replace('#','%23')); var img = document.createElement('img'); img.setAttribute('src', 'http://b.hatena.ne.jp/entry/image/'+a.href.replace('#','%23')); img.setAttribute('alt', ''); img.setAttribute('height', '13'); e.appendChild(img); a.parentNode.insertBefore(e, a.nextSibling); a.setAttribute('class', (a.getAttribute('class') || '') + ' HatenaBookMarkCountShown'); }); } if (window.opera) window.addEventListener('DOMContentLoaded',HatebuChecker ,false); else window.addEventListener('load',HatebuChecker ,false); window.addEventListener('GM_AutoPagerizeNextPageLoaded',HatebuChecker ,false); /* * below is taken from oAutoPagerize.js <http://ss-o.net/userjs/oAutoPagerize.js>: thanks os0x */ function getElementsByXPath(xpath, node) { var nodesSnapshot = getXPathResult(xpath, node, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); var data = []; for (var i = 0; i < nodesSnapshot.snapshotLength; i++) { data.push(nodesSnapshot.snapshotItem(i)); } return data; } function getFirstElementByXPath(xpath, node) { var result = getXPathResult(xpath, node, XPathResult.FIRST_ORDERED_NODE_TYPE); return result.singleNodeValue; } function getXPathResult(xpath, node, resultType) { if (getXPathResult.forceRelative) { xpath = xpath.replace(/id\(\s*(["'])([^"']+)\1\s*\)/g, './/*[@id="$2"]'); xpath = xpath.indexOf('(//') == 0 ? '(.//' + xpath.substring(3) : (xpath[0] == '/' ? '.' : './') + xpath; } var node = node || document; var doc = node.ownerDocument || node; var resolver = doc.createNSResolver(node.documentElement || node); // Use |node.lookupNamespaceURI('')| for Opera 9.5 var isXHTML = document.documentElement.tagName !== 'HTML'; var defaultNS = node.lookupNamespaceURI(window.opera ? '' : null); if (isXHTML) { var defaultPrefix = '__default__'; xpath = addDefaultPrefix(xpath, defaultPrefix); var defaultResolver = resolver; resolver = function (prefix) { return (prefix == defaultPrefix) ? defaultNS : defaultResolver.lookupNamespaceURI(prefix); } } return doc.evaluate(xpath, node, resolver, resultType, null); } function addDefaultPrefix(xpath, prefix) { var tokenPattern = /([A-Za-z_\u00c0-\ufffd][\w\-.\u00b7-\ufffd]*|\*)\s*(::?|\()?|(".*?"|'.*?'|\d+(?:\.\d*)?|\.(?:\.|\d+)?|[\)\]])|(\/\/?|!=|[<>]=?|[\(\[|,=+-])|([@$])/g; var TERM = 1, OPERATOR = 2, MODIFIER = 3; var tokenType = OPERATOR; prefix += ':'; function replacer(token, identifier, suffix, term, operator, modifier) { if (suffix) { tokenType = (suffix == ':' || (suffix == '::' && (identifier == 'attribute' || identifier == 'namespace'))) ? MODIFIER : OPERATOR; } else if (identifier) { if (tokenType == OPERATOR && identifier != '*') { token = prefix + token; } tokenType = (tokenType == TERM) ? OPERATOR : TERM; } else { tokenType = term ? TERM : operator ? OPERATOR : MODIFIER; } return token; } return xpath.replace(tokenPattern, replacer); } })([ { "name":"Amazon bestsellers and others", "paragraph":"//div[contains(concat(\" \", @class, \" \"), \" product \")]/ancestor::td", "domain":"^http://www\\.amazon\\.(?:[^.]+\\.)?[^./]+/gp/(?:bestsellers|mo(?:st-(?:wished-for|gifted)|vers-and-shakers)|new-releases)/ref", "link":".//a" }, { "name":"Amazon yourstore and history", "paragraph":"//h3/ancestor::tr", "domain":"^http://www\\.amazon\\.(?:[^.]+\\.)?[^./]+/gp/(?:history|yourstore)", "link":".//a" }, { "name":"Amazon wishlist", "paragraph":"//form[@name=\"editItems\"]/table/tbody", "domain":"^http://www\\.amazon\\.(?:[^.]+\\.)?[^./]+/gp/registry/wishlist", "link":".//a" }, { "name":"Amazon account home", "paragraph":"//div[contains(concat(\" \", @class, \" \"), \" content \")]//div[contains(concat(\" \", @class, \" \"), \" product \")] | //div[starts-with(@id, \"rhfCell\") or starts-with(@id, \"shvlCell\")]", "domain":"^http://www\\.amazon\\.(?:[^.]+\\.)?[^./]+/gp/yourstore/home", "link":".//a" }, { "name":"Amazon search result", "paragraph":"//div[contains(concat(\" \", normalize-space(@class), \" \"), \" result \")]", "domain":"^http://www\\.amazon\\.(?:[^.]+\\.)?[^./]+/(?:gp/search|s/)", "height":"0", "link":".//div[@class=\"productTitle\"]/a", "view":".//div[@class=\"productImage\"]/a/img | .//div[@class=\"productTitle\"]/a/text()" }, { "name":"Google", "paragraph":"id(\"res\")//li[contains(@class,\"g\")]", "domain":"^http://www\\.(?:l\\.)?google\\.(?:[^.]+\\.)?[^./]+/", "stripe":"1", "link":"descendant::a[contains(concat(\" \",normalize-space(@class),\" \"),\" l \")]", "exampleUrl":"http://www.google.com/" }, /* 追加する場合 { "paragraph":"", "domain":"", "link":"", }, */ ]);
微修正した。
これの良いところは、もっと追加したいサイトがあったら↓から適当に選んでコピペするだけというところ。
あ、そうそう、この前の、Google の検索結果を綺麗にするスクリプトと相性が良くなかったみたいなので、向こうのほうを直した。
↑はちまちま修正している。スパムリストはめっちゃ増えた。