新はてなブックマークでもMinibufferBookmarkCommand を使う
なんか、リニューアルされたらMinibufferBookmarkCommand 経由ではてブできなくなった。「100%」とかでるけど、実際にはブックマークされない( ゚д゚)
ブックマークレットだと、タグの[]を打つのが面倒なので、MinibufferBookmarkCommand を修正。一応動くようになりました。
旧はてブとの違いを調査
Web 経由で「ブックマークを追加」ページにいって、ソースみる
- そもそも追加ページのURL が変わった
- 旧:「http://b.hatena.ne.jp/add?mode=confirm&is_bm=1&url=...」
- 新:「http://b.hatena.ne.jp/[ユーザのID]/add.confirm?url=...」
- 当然フォームのポスト先URL も変わった
- 旧:「http://b.hatena.ne.jp/[ユーザのID]/add?mode=enter&is_bm=1&url=...」
- 新:「http://b.hatena.ne.jp/[ユーザのID]/add.edit?url=...」
- 認証キー(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({