// ==UserScript== // @name hateBUZZ // @namespace http://d.hatena.ne.jp/snaka72/ // @description Show buzz of current page with Hatena Bookmarkers. // @include http://* // @require http://gist.github.com/raw/128813/e31dba7e13521499c0284c8b1af0bc4d553886d6/json2.js // @require http://gist.github.com/raw/128816/3890f29e5a215777a17765a928e8acae01662b69/GrowlMonkey.js // ==/UserScript== var HateBuzz = function(){ // CONFIGURATION /////////////////////////////////////////////////////////// const DEBUG = false; var MAX_ITEMS = GM_getValue('max-items', 5); var AND_MORE = GM_getValue('and-more', true); var BUZZ_ONCE = GM_getValue('buzz-once', true); // CLASS ///////////////////////////////////////////////////////////////// function Hatebu(url) { this.url = url; } Hatebu.getUserIcon = function(user) { return "http://www.hatena.ne.jp/users/" + user.substr(0, 2) + "/" + user + "/profile.gif"; }; Hatebu.prototype = { eachBookmark: function(proc) { var cachedData = eval(GM_getValue(currentURL(), null)); if (cachedData) { debug("キャッシュがヒット! : " + currentURL()); this._processForBookmarks(cachedData.bookmarks, proc); GM_setValue(currentURL(), cachedData.toSource()); return; } debug("キャッシュにヒットしなかったのでリクエストします:" + currentURL()); var that = this; GM_xmlhttpRequest({ method: "GET", url: "http://b.hatena.ne.jp/entry/json/"+ currentURL(), onload: function(data) { var json = eval(data.responseText); if (!json.bookmarks) return; that._processForBookmarks(json.bookmarks, proc); GM_setValue(currentURL(), json.toSource()); } }); }, _processForBookmarks: function(bookmarks, proc) { shuffle(MAX_ITEMS, bookmarks, function(bookmark) { if (bookmark.comment.length > 0) { proc(bookmark); } }); } }; // PRIVATE ///////////////////////////////////////////////////////////////// function MAX_ITEMS() { return 5; } function currentURL() { return window.top.location.href; } function shuffle(count, arr, func) { arr = BUZZ_ONCE ? arr : arrayCopy(arr); for(var i = 0; arr.length > 0 && i < count;) { var index = Math.floor(Math.random() * arr.length); var pick = (arr.splice(index, 1))[0]; if (pick.comment.length == 0) continue; setTimeout(func, i++ * 1000, pick); } } function arrayCopy(arr) { return arr.slice(); } // growl ... function register() { GrowlMonkey.register( HateBuzz.appname, "http://www.hatena.ne.jp/images/top/side_b.gif", [{ name: "buzz", displayName: "Buzz!!", enabled: true }] ); } function notify(title, message, icon){ GrowlMonkey.notify(HateBuzz.appname, "buzz", title, message, icon); } function debug(msg) { DEBUG && notify("debug", msg); } // PUBLIC ////////////////////////////////////////////////////////////////// var self = { appname : "hateBUZZ", hatebu : null, main : function(){ register(); this.hatebu = new Hatebu(currentURL()); this.hatebu.eachBookmark(function(bookmark) { notify( bookmark.user, bookmark.comment || "", Hatebu.getUserIcon(bookmark.user) ); }); }, clearCache : function() { GM_setValue(currentURL(), ''); notify("HateBUZZ", currentURL() + "のキャッシュをクリアしました"); }, setMaxItems : function() { var max_items = prompt( "表示する人数を入力してください。(デフォルト:5)", GM_getValue('max-items', 5) ); if (!max_items || max_items == "") { GM_setValue("max-items", ''); return; } GM_setValue("max-items", max_items); }, setBuzzAlways : function() { BUZZ_ONCE = false; GM_setValue("buzz-once", false); self.clearCache(); }, setBuzzOnce : function() { BUZZ_ONCE = true; GM_setValue("buzz-once", true); } } GM_registerMenuCommand("hateBUZZ!! - キャッシュクリア", self.clearCache); GM_registerMenuCommand("hateBUZZ!! - 最大人数の設定", self.setMaxItems); if (BUZZ_ONCE) GM_registerMenuCommand("hateBUZZ!! - 何度でもBUZZる", self.setBuzzAlways); else GM_registerMenuCommand("hateBUZZ!! - 一度っきりBUZZる", self.setBuzzOnce); return self; }(); // initialize the whole works window.addEventListener("load", function(e) { window.setTimeout(HateBuzz.main, 1000); }, false); // vim: sw=4 ts=4 et si