新はてなブックマークでもMinibufferBookmarkCommand を使う

なんか、リニューアルされたらMinibufferBookmarkCommand 経由ではてブできなくなった。「100%」とかでるけど、実際にはブックマークされない( ゚д゚)
ブックマークレットだと、タグの[]を打つのが面倒なので、MinibufferBookmarkCommand を修正。一応動くようになりました。

はてブとの違いを調査

Web 経由で「ブックマークを追加」ページにいって、ソースみる
  • 認証キー(CSRF 対策かな)が変わった
    • 旧:「rkm=................」
    • 新:「rks=................」
  • 既にはてブしてた際の挙動
    • 旧:「このエントリーは既にブックマークされてます」とでて、編集する場合は「編集」ボタンを押す(こんな感じだった?)
    • 新:以前ブクマした旨を表示しつつ、フォームも出してくれる

MinibufferBookmarkCommand を書き換える

Greasemonkey」>「ユーザスクリプトの管理」から、MinibufferBookmarkCommand を選択し、「編集」。はてブの部分の内容を、以下に書き換える。
結局、POST 先URL は、ユーザ名を引いてくるのが面倒なので、ブックマークレット用のURL を使いました。

タグの補完が効かないというご指摘がありました。調べたところ、class が変わっていましたので修正しました。僕の環境だと補完ができてしまったのだけれど、なんでだろう。
既にid:CoolDriver さんが対応して下さっていました。

	/////////////////////////////////////////////////////////////////
	// hatena bookmark
	var hatenab = new function(){
		var self = this;
		this.checkLogin = function(html){
			var input = $X('//input', html);
			return input.length != 0;
		}
		this.post = function(async, opt){
			var comment = self.comment;
			if (self.tags.length) comment = '[' + self.tags.join('][') + ']' + comment;
			var request = [
				"url=", encodeURIComponent(opt.url),
				"&rks=", encodeURIComponent(opt.rks),
				"&comment=", encodeURIComponent(comment)
				].join('');
			GM_xmlhttpRequest({
			  method: 'POST',
			  url: "http://b.hatena.ne.jp/bookmarklet.edit",
			  headers: {
				  'Content-Type': 'application/x-www-form-urlencoded'
				},
			  onload: function(res){
				  async.ready();
				},
			  onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
			  data: request
			});
		}
		this.getParam = function(async, arg){
			window.Minibuffer.status('bookmark.hatena'+self.time,'Bookmark ' + arg.progress + '%');
			var callback = function(res){
				var html = res.responseText.createHTML();
				if(!self.checkLogin(html)){
					async.error();
					return;
				}
				var inputs = $X('//input', html);
				var res = {};
				inputs.forEach(function(d){
					res[d.getAttribute('name')] = d.getAttribute('value');
				});
			    if($X('//p[@class="bookmarked-confirm"]', html).length){
					// already bookmarked
					var p = $X('//p[@id="title-edit"]', html);
					var text = p[0].textContent;
					window.Minibuffer.message('<small>'+text+'</small><br/> has already bookmarked.', 2000);
					async.ready();
				}else{
					// not yet bookmarked
					self.post(async, res);
				}
			}
			GM_xmlhttpRequest({
			  method: 'GET',
			  url: "http://b.hatena.ne.jp/add?mode=confirm1&url="+encodeURIComponent(arg.url),
			  onload: callback,
			  onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
			});
		}
		this.bookmark = function(urls, tags, comment){
			if(!urls.length) return;
			self.tags = tags;
			self.comment = comment;
			var total = urls.length;
			self.time = new Date().getTime();
			AsyncOrderedList(self.getParam, urls.map(function(url,i){
				return {
				  url: url,
				  progress: Math.floor(i / total * 100)
				}
			})).ready(function(){
				window.Minibuffer.status('bookmark.hatena'+self.time,'Bookmark 100 %', 1000);
			}).error(function(){
				window.Minibuffer.status('bookmark.hatena'+self.time,'Bookmark failed. you are not logging hatena in.', 3000);
			})
		}
		this.getTags = function(){
			// orz
			var a = new Async();
			var callback = function(res){
				var html = res.responseText.createHTML();
				if(!self.checkLogin(html)) {
					a.ready([]);
					return;
				}
				var tags = $X('//a[@class="tag"]', html);
				a.ready(tags.map(function(arg){return arg.textContent}));
			}
			GM_xmlhttpRequest({
			  method: 'GET',
			  url: "http://b.hatena.ne.jp/my",
			  onload: callback,
			  onerror: function(res){a.ready([])},
			});
			return a;
		}
	}

	/////////////////////////////////////////////////////////////////
	// livedoor clip


オリジナルとのdiff はこんな感じ。

--- /Users/luke/Desktop/minibufferbookmarkcommand.user.js       2008-12-05 02:03:45.000000000 +0900
+++ /Users/luke/Desktop/minibuffer_bookmark_comm.user.js        2008-12-05 02:02:51.000000000 +0900
@@ -64,17 +64,13 @@
                        var comment = self.comment;
                        if (self.tags.length) comment = '[' + self.tags.join('][') + ']' + comment;
                        var request = [
-                               "mode=enter",
-                               "&eid=", opt.eid,
-                               "&url=", encodeURIComponent(opt.url),
-                               "&rkm=", encodeURIComponent(opt.rkm),
-                               "&is_bm=", opt.is_bm,
-                               "&title=", encodeURIComponent(opt.title),
+                               "url=", encodeURIComponent(opt.url),
+                               "&rks=", encodeURIComponent(opt.rks),
                                "&comment=", encodeURIComponent(comment)
                                ].join('');
                        GM_xmlhttpRequest({
                          method: 'POST',
-                         url: "http://b.hatena.ne.jp/add",
+                         url: "http://b.hatena.ne.jp/bookmarklet.edit",
                          headers: {
                                  'Content-Type': 'application/x-www-form-urlencoded'
                                },
@@ -98,10 +94,10 @@
                                inputs.forEach(function(d){
                                        res[d.getAttribute('name')] = d.getAttribute('value');
                                });
-                               if(keys(res).length == 1){
+                           if($X('//p[@class="bookmarked-confirm"]', html).length){
                                        // already bookmarked
-                                       var a = $X('//ul[@class="entry"]/li[1]/a', html);
-                                       var text = a[0].textContent;
+                                       var p = $X('//p[@id="title-edit"]', html);
+                                       var text = p[0].textContent;
                                        window.Minibuffer.message('<small>'+text+'</small><br/> has already bookmarked.', 2000);
                                        async.ready();
                                }else{
@@ -111,7 +107,7 @@
                        }
                        GM_xmlhttpRequest({
                          method: 'GET',
-                         url: "http://b.hatena.ne.jp/add?mode=confirm&is_bm=1&url="+encodeURIComponent(arg.url),
+                         url: "http://b.hatena.ne.jp/add?mode=confirm1&url="+encodeURIComponent(arg.url),
                          onload: callback,
                          onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
                        });
@@ -142,7 +138,7 @@
                                        a.ready([]);
                                        return;
                                }
-                               var tags = $X('//a[@class="tag-latest"]', html);
+                               var tags = $X('//a[@class="tag"]', html);
                                a.ready(tags.map(function(arg){return arg.textContent}));
                        }
                        GM_xmlhttpRequest({
感想

Firebug++。まともに使ったのは初めてな気がする・・・。

  • 1. HTML 確認
  • 2. 調べたい要素のXPath をコピー(時々冗長なXPath になる)
  • 3. コンソールで$x
  • 4. コンソールの結果をクリックして、プロパティとかみる
  • 5. プロパティの値も見れるので、欲しい物をみっける
  • 6. コンソールでためす
  • 7. ソースに反映


この流れで結構いけますね。楽しい丶(´▽`)ノ