2006/11/13 (Mon)
grb+-20061113.user.js
Firefox, Greasemonkey | |
![]()
id:kei-sさんのGoogle Readerでfaviconを表示させるGreasemonkeyスクリプト公開に触発されて、Google Readerにはてなブックマーク件数とブックマークアイコンを表示するGreasemonkeyスクリプトをバージョンアップした。
(重要)インストール後、スクリプト中のconst userの部分を自分のはてなidに変えてください。
主な変更点は以下の通り。
- タイミングによってアイコンが複数表示されてしまうバグを修正
- ブックマーク追加用のアイコンをより適切なものに変更
// ==UserScript==
// @name GR+?B
// @namespace http://d.hatena.ne.jp/nozom/
// @description show ?B button and count in Google Reader
// @include http://www.google.com/reader/view/*
// @include https://www.google.com/reader/view/*
// ==/UserScript==
// original author is id:kusigahama
// see http://d.hatena.ne.jp/kusigahama/20051207#p1
(function() {
const user = 'nozom';
var timerID = null;
var busy = false;
var urlCache = new Object();
function getUrlCache(url) {
if (typeof urlCache[url] == 'undefined')
urlCache[url] = new Object();
return urlCache[url];
}
String.prototype.htmlescape = function() {
return this.replace(/&/g, "&").replace(/</g, "<");
}
function findNode(root, xpath) {
var result = document.evaluate(xpath, root, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
if (! result.snapshotLength) return null;
return result.snapshotItem(0);
}
function getBookmarkCountSpan(node) {
return findNode(node, 'span[@class="hatena-bookmark-count"]');
}
function insertBookmarkCount(targetNode, url, count) {
var a = document.createElement('a');
a.setAttribute('href', "http://b.hatena.ne.jp/entry/" + url);
a.setAttribute('target', '_blank');
var str = (count > 0 ? "" + count : "no") + " user" + (count != 1 ? "s" : "");
a.appendChild(document.createTextNode(str));
with (a.style) {
fontSize = "0.9em";
textDecoration = "none";
if (count >= 5) {
fontWeight = "bold";
backgroundColor = "#fff0f0";
color = "#f66";
}
if (count >= 10) {
backgroundColor = "#ffcccc";
color = "red";
}
}
with (targetNode) {
appendChild(document.createTextNode(" ("));
appendChild(a);
appendChild(document.createTextNode(") "));
}
}
function createBookmarkCount(url, count) {
var node = document.createElement('span');
node.setAttribute('class', 'hatena-bookmark-count');
if (count > 0) {
insertBookmarkCount(node, url, count);
} else {
node.appendChild(document.createTextNode(' '));
}
return node;
}
function setBookmarkCounts(infoArray) {
for (var i = 0; i < infoArray.length; i++) {
var entry = infoArray[i].entry;
var url = infoArray[i].url;
var title = infoArray[i].title;
var entryContainerTitle = infoArray[i].entryContainerTitle;
var collapsedTitle = infoArray[i].collapsedTitle;
var entryActions = infoArray[i].entryActions;
var count = getUrlCache(url).count;
if (typeof count != 'undefined') {
if (typeof collapsedTitle != 'undefined') {
var node = createBookmarkCount(url, count);
collapsedTitle.insertBefore(node, collapsedTitle.childNodes[1]);
}
if (typeof entryContainerTitle != 'undefined') {
var node = createBookmarkCount(url, count);
entryContainerTitle.insertBefore(node, entryContainerTitle.childNodes[1]);
}
}
}
}
function callXmlrpc(requestbody, infoArray) {
const endpoint = "http://b.hatena.ne.jp/xmlrpc";
function onload(response) {
if (response.responseText.match(/<fault>/)) {
clearInterval(timerID);
alert("xmlrpc call failed: " + response.responseText + "\n" + "request: " + requestbody);
} else {
var pattern = /<name>([^<]+)<\/name>\s*<value><int>(\d+)/g;
var m;
while (m = pattern.exec(response.responseText)) {
getUrlCache(m[1]).count = m[2];
}
setBookmarkCounts(infoArray);
}
busy = false;
}
// alert('xmlrpc call');
GM_xmlhttpRequest({ method: "POST", url: endpoint, data: requestbody, onload: onload });
}
function createAddBookmarkIcon(url, title) {
var a = document.createElement('a');
a.setAttribute('href', 'http://b.hatena.ne.jp/add?mode=confirm&is_bm=1&title=' + escape(title) + '&url=' + escape(url));
a.setAttribute('target', '_blank');
var img = document.createElement('img');
img.setAttribute('src', 'http://b.hatena.ne.jp/images/append.gif');
img.setAttribute('alt', 'add bookmark');
img.setAttribute('title', 'add bookmark');
with (img.style) {
borderWidth = '0px';
}
a.appendChild(img);
var node = document.createElement('span');
node.setAttribute('class', 'hatena-bookmark-icon');
node.appendChild(a);
return node;
}
function createBookmarkIcon() {
var img = document.createElement('img');
img.setAttribute('src', 'http://www.hatena.ne.jp/images/user_bookmark.gif');
img.setAttribute('alt', 'bookmarked');
img.setAttribute('title', 'bookmarked');
var node = document.createElement('span');
node.setAttribute('class', 'hatena-bookmark-icon');
node.appendChild(img);
return node;
}
function addBookmarkIcon(currentEntry) {
var entryContainerTitle = findNode(currentEntry, './/div[@class="entry-container"]//h2');
var entryActions = findNode(currentEntry, './/div[@class="entry-actions"]');
if ((entryContainerTitle == null) || (entryActions == null)) return;
var link = entryContainerTitle.firstChild;
var title = link.firstChild.textContent;
function onload(response) {
if (response.responseText != null) {
var responseXML = (new DOMParser()).parseFromString(response.responseText, "application/xml");
if (responseXML != null) {
var channel = responseXML.getElementsByTagName('channel')[0];
if (channel != null) {
var items = channel.getElementsByTagName('items')[0];
if (items != null) {
var lis = items.getElementsByTagName('li');
if (lis.length > 0) {
getUrlCache(link.href).bookmarked = true;
entryActions.appendChild(createBookmarkIcon());
} else {
getUrlCache(link.href).bookmarked = false;
entryActions.appendChild(createAddBookmarkIcon(link.href, title));
}
}
}
}
}
}
var bookmarked = getUrlCache(link.href).bookmarked;
if (typeof bookmarked == 'undefined') {
getUrlCache(link.href).bookmarked = 'loading';
var url = 'http://b.hatena.ne.jp/' + user + '/rss?url=' + escape(link.href);
GM_xmlhttpRequest({ method: "GET", url: url, onload: onload });
} else if (bookmarked == 'loading') {
// skipped
} else if (bookmarked) {
entryActions.appendChild(createBookmarkIcon());
} else {
entryActions.appendChild(createAddBookmarkIcon(link.href, title));
}
}
function timerHandler() {
if (busy) return;
var entries = document.getElementById('entries');
if (entries == null) return;
var currentEntry = document.getElementById('current-entry');
if (currentEntry != null) {
if (findNode(currentEntry, './/span[@class="hatena-bookmark-icon"]') == null) {
addBookmarkIcon(currentEntry);
}
}
busy = true;
var infoArray = new Array();
var reqUrlArray = new Array();
var reqUrlHash = new Object();
for (var i = 0; i < entries.childNodes.length; i++) {
var entry = entries.childNodes[i];
var collapsedTitle = findNode(entry, './/div[@class="collapsed"]//h2');
var entryContainerTitle = findNode(entry, './/div[@class="entry-container"]//h2');
var link = null;
var title = null;
if (entryContainerTitle != null) {
link = entryContainerTitle.firstChild;
title = link.firstChild.textContent;
} else if (collapsedTitle != null) {
link = collapsedTitle.parentNode.parentNode.firstChild;
title = collapsedTitle.textContent;
}
if (link != null) {
var info = { entry: entry, url: link.href, title: title };
if ((collapsedTitle != null) && (getBookmarkCountSpan(collapsedTitle) == null)) {
info.collapsedTitle = collapsedTitle;
}
if ((entryContainerTitle != null) && (getBookmarkCountSpan(entryContainerTitle) == null)) {
info.entryContainerTitle = entryContainerTitle;
}
if ((info.collapsedTitle != null) || (info.entryContainerTitle != null)) {
infoArray.push(info);
if ((getUrlCache(link.href).count == null) &&
(! reqUrlHash[link.href])) {
reqUrlHash[link.href] = true;
reqUrlArray.push(link.href);
}
}
}
}
if (infoArray.length == 0) {
busy = false;
return;
}
if (reqUrlArray.length == 0) {
// all items are found in the cache
setBookmarkCounts(infoArray);
busy = false;
} else {
// avoid xmlrpc call failure in 'too many params' error
reqUrlArray = reqUrlArray.splice(0, 50);
var request = '<?xml version="1.0"?>\n<methodCall>\n<methodName>bookmark.getCount</methodName>\n<params>\n';
for (var i = 0; i < reqUrlArray.length; i++) {
var url = reqUrlArray[i];
request += "<param><value><string>" + url.htmlescape() + "</string></value></param>\n";
}
request += "</params>\n</methodCall>\n";
callXmlrpc(request, infoArray);
}
}
// be careful not to be too busy
timerID = setInterval(timerHandler, 3000);
})();
トラックバック - http://d.hatena.ne.jp/nozom/20061113/1163372094
- Web型RSSリーダ カスタマイズまとめ
- http://d.hatena.ne.jp/nozom/20061113
- http://d.hatena.ne.jp/jiangh/20061128
- http://d.hatena.ne.jp/nozom/20061128
- http://d.hatena.ne.jp/jiangh/20061205
- http://d.hatena.ne.jp/mallowlabs/20070116
- http://d.hatena.ne.jp/ToMmY/20070812
- http://d.hatena.ne.jp/exlair/20070926
- ぎぎ☆にっき【ふぃーばー♪】 - Googleリーダーに乗り換えてみた
- GoogleReaderにはてブ数を表示するグリモンが止まってしまう問題の...
- 光陰矢の如しだから - また少しずつ重くなる
- P’@はてな - はてなブックマーク関連のGreasemonkey
- crow2008の日記 - Googleリーダーとはてブで情報強者になると言って...
- 一詩人の最初の歌 - はてブアドオンとGoogle Readerで快適フィード...
- WebLab.ota - Firefox 設定メモ
- かずめも ラジカル - Debianのある生活 - - RSS Reader
- 医者を志す妻を応援する夫の日記 - はてなブックマークとDelicious...
- 没個性テーマパーク - 馬鹿な俺でも使えたRSSリーダー@Google リー...
- 2009-11-20
- RE:Google Readerにはてなブックマーク件数とブックマークアイコン...
- 後で読まない。 - 1129気になったとこ。
リンク元
- 12811 http://tokuna.blog40.fc2.com/blog-entry-1636.html
- 2084 http://20kaido.com/archives/1213112.html
- 1145 http://google-mania.net/archives/523
- 352 http://www.kagitaku.com/diary
- 338 http://watch.s22.xrea.com/blog/archives/0801290027.html
- 276 http://google-mania.net/webservice/googlereader
- 220 http://d.hatena.ne.jp/
- 190 http://www.google.co.jp/search?q=GR+?B&lr=lang_ja&ie=utf-8&oe=utf-8&rls=org.mozilla:ja-JP-mac:official&client=firefox
- 188 http://watch.s22.xrea.com/blog/archives/0611132052.html
- 133 http://kome-suki.net/archives/3878
カテゴリー
- Diary
- News
- Joke
- Misc
- Novel
- Comic
- Game
- Anime
- TV
- PC
- Linux
- Devel
- Emacs
- Lisp
- Perl
- Admin
- Network
- Security
- Windows
- Web
- Hatena
- Link
- Music
- memo
- Mozilla
- RPM
- Book
- Words
- Ruby
- SQL
- Math
- MS
- AI
- RSS
- ATOK
- SPAM
- Java
- CD
- TeX
- Magazine
- GNU
- XML
- Study
- Movie
- SSH
- Essay
- CVS
- GUI
- Device
- JavaScript
- Brain
- Bookmarklet
- OOP
- Video
- DVD
- Firefox
- Scheme
- C++
- Ajax
- Greasemonkey
- Phone
- Mobile
- SF
- Software
- KAWA
- Gauche
- Dream
- SVN
- OS
- Mono
- Rhino
- C
- Programming
- Fun
- LL
- Haskel
- Lang
- CSS
- Haskell
- Wikipedia
- Amazon
- C#
- Vine
- Photo
- Art
- Unix
- Python
- Hack
- OSS
- Travel
- Bookmark
- Plagger
- Binary
- XPI
- Knoppix
- PHP
- Physics
- Gmail
- Gimp
- Vaio
- PDA
- Puzzle
- Samba
- OCaml
- Apache
- NLP
- Yahoo
- Pylons
- CPAN
- W-ZERO3
- Mac
- WSGI
- TurboGears
- GAE
- Design
- SmallTalk
- QEMU
- Physic












![SUPERMARKET FANTASY [初回限定盤:CD+DVD] SUPERMARKET FANTASY [初回限定盤:CD+DVD]](http://ecx.images-amazon.com/images/I/61vgHoktbfL._SL75_.jpg)

![電撃文庫MAGAZINE (マガジン) 2009年 01月号 [雑誌] 電撃文庫MAGAZINE (マガジン) 2009年 01月号 [雑誌]](http://ecx.images-amazon.com/images/I/61m%2BGzgmC4L._SL75_.jpg)




![絶対可憐チルドレン 02 [DVD] 絶対可憐チルドレン 02 [DVD]](http://ecx.images-amazon.com/images/I/51u8xUXDagL._SL75_.jpg)
![絶対可憐チルドレン 03〈初回限定版〉 [DVD] 絶対可憐チルドレン 03〈初回限定版〉 [DVD]](http://ecx.images-amazon.com/images/I/51XBXRuR2WL._SL75_.jpg)







![音楽と人 2009年 01月号 [雑誌] 音楽と人 2009年 01月号 [雑誌]](http://ecx.images-amazon.com/images/I/51yz930u5iL._SL75_.jpg)
![Talking Rock ! (トーキング・ロック) 2009年 01月号 [雑誌] Talking Rock ! (トーキング・ロック) 2009年 01月号 [雑誌]](http://ecx.images-amazon.com/images/I/51IQAr-3d5L._SL75_.jpg)


ユーザースクリプトの管理画面でGR+?Bをハイライト(選択)した状態で
その画面左下にある「編集」ってボタンをクリックしてください。
この操作が初めてなら編集に使用するアプリを問われますが
次回以降はそれもなく、すんなり編集できるようになります。
以下を追加することで有効になります。
http://www.google.co.jp/reader/view/*