// ==UserScript== // @name Bloglines meets Hatena Bookmark // @namespace http://www.m4i.jp/ // @include http://www.bloglines.com/myblogs_display?* // @include http://www.bloglines.com/public_display?* // @version 1.0.2 // ==/UserScript== (function(){ Function.prototype.bind = function(object) { var __method = this; return function() { return __method.apply(object, arguments); }; }; function XMLRPC() { this.calls = []; this.called = 0; this.chunk = 0; } XMLRPC.prototype = { proxy: function(endPoint) { this.endPoint = endPoint; return this; }, call: function(method, params) { this.parts = this.chunk ? Math.ceil(params.length / this.chunk) : 1; for (var i = 0; i < this.parts; i++) { var call = {method} ; var param = this.chunk ? params.slice(this.chunk * i, this.chunk * (i + 1)) : params; for (var j = 0; j < param.length; j++) { call..params.appendChild( {param[j]} ); } this.calls.push(call); } return this; }, result: function(callback) { this.callback = callback; for (var i = 0; i < this.parts; i++) { GM_xmlhttpRequest({ method: 'post', url: this.endPoint, data: this.calls[i].toString(), onload: this._loadHandler.bind(this) }); } return this; }, split: function(chunk) { this.chunk = chunk; return this; }, _loadHandler: function(res) { var response = new XML(res.responseText.replace(/^<\?xml.*?\?>/, '')); if (this.response) { this.response..struct.appendChild(response..member); } else { this.response = response; } if (++this.called == this.parts) { this.callback(this.response); } } }; var entryURI = 'http://b.hatena.ne.jp/entry/'; var endPoint = 'http://b.hatena.ne.jp/xmlrpc'; var item_expr = '//div[starts-with(@id, "siteItem.")]'; var uris = []; var hrefs = document.evaluate( item_expr + '/h3/a/@href', document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); var href; while (href = hrefs.iterateNext()) { uris.push(href.nodeValue); } new XMLRPC() .split(50) .proxy(endPoint) .call('bookmark.getCount', uris) .result(function(response) { var members = {}; for each (var member in response..member) { members[member.name] = member..int; } var items = document.evaluate( item_expr, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < items.snapshotLength; i++) { var uri = document.evaluate( './h3/a/@href', items.snapshotItem(i), null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.nodeValue; var ul = document.evaluate( './div/ul[@class="item_nav"]', items.snapshotItem(i), null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; var users = members[uri]; if (!Number(users)) continue; var a = document.createElement('a'); var li = document.createElement('li'); a.setAttribute('href', entryURI + uri.replace(/#/, '%23')); a.setAttribute('target', '_blank'); a.setAttribute('class', users >= 10 ? 'hottest' : users >= 5 ? 'hotter' : 'hot'); a.appendChild(document.createTextNode( '?B: ' + users + (users == 1 ? ' user' : ' users'))); li.appendChild(a); ul.appendChild(li); } }); var style = document.createElement('style'); style.setAttribute('type', 'text/css'); style.innerHTML = '.hotter' + '{' + ' color: #ff6666 !important;' + ' background-color: #fff0f0;' + ' font-weight: bold;' + ' font-style: normal;' + '}' + '.hottest' + '{' + ' color: red !important;' + ' background-color: #ffcccc;' + ' font-weight: bold;' + ' font-style: normal;' + '}'; document.getElementsByTagName('head')[0].appendChild(style); })();