よんちゅBlog

― このブログは自分用のメモや日々の問題などを共有するためのものです ―

20121005185841 お知らせ:  2013/07/17 ブログデザインをリニューアルしました。

Vim Advent Calendar 2012 に"はてブ数"を表示させるグリモンとブックマークレットを作ったよ!

Vim Advent Calendar 2012 の197日目の記事です。

前回(196日目)の記事は @supermomonga さんの homebrewを使ってちょっと新しめのMacVim KaoriYaを使おう - かなりすごいブログ でした。

まえおき

ついに中間発表を終え、後半戦へと突入したVim Advent Calendar 2012

参加者も90人を越え、200日目も目前となって参りました。

しかし!!
あまりにも記事が多すぎて、「どれから読めばいいんだ!」とか「もしかし見逃してるんじゃ?」とか「やだ、私のVim力低すぎ…」などと不安になっている方もいるのではないでしょうか。

そこで、そんな不安を吹き飛ばすため、
Advent Calendar のページにはてなブックマークを表示する Greasemonkey (グリースモンキー) と ブックマークレット を作ってみました。

f:id:yonchu:20130614193818p:plain

Greasemonkey版とブックマークレット版の2種類がありますが、ランキング表示が行えるのはGreasemonkey版のみです

Greasemonkey版のインストール方法

まずスクリプトを以下からダウンロードして下さい。
(Chromeの場合ユーザスクリプトをダウンロードすると警告が出ますが気にしないでください)

続いて各ブラウザにスクリプトをインストールします。

Chromeの場合

ダウンロードしたスクリプトを拡張機能の管理ページ(chrome://extensions/)にドラッグ&ドロップして下さい。
(関係ないけど、拡張機能の管理ページをブックマークバーに追加しておくとすぐにアクセスできるのでおすすめです。)

FireFoxの場合

FireFoxの場合は、Greasemonkeyを使用するために以下のAdd-On が必要になります。
インストールしていない方はまずそちらをインストールしてください。

それから、ダウンロードしたスクリプトをFireFoxへドラッグ&ドロップし、Greasemonkeyの管理画面で有効化を行います。

ブックマークレット版のインストール方法

以下のリンクをブックマークに追加してください。
もしくは、コードをコピーして手動で新しいブックマークを作成して下さい。

javascript:(function(){var s=document.createElement("script");s.charset="UTF-8";s.src="https://github.com/yonchu/atnd-hatena-bookmarks/raw/master/atnd-hatebu-min.user.js";document.body.appendChild(s)})();


スクリプトをサーバから読み込まないバージョンも用意しました。

javascript:(function(){var t,e,n,r,a,i,o,d,l,c,u,m,f,h,p,s,y;try{if(top!==self){throw 0}}catch(b){i=b;return}t=function(t){var e,n;if(typeof GM_addStyle!=="undefined"&&GM_addStyle!==null){GM_addStyle(t);return}n=document.createElement("style");n.setAttribute("type","text/css");n.setAttribute("media","screen");n.appendChild(document.createTextNode(t));e=document.getElementsByTagName("head")[0];return e.appendChild(n)};r=function(){var t,e;t="http://b.st-hatena.com/entry/image/";e=document.createElement("img");e.className="hatebu";return function(n){var r;r=e.cloneNode();r.setAttribute("src",t+n);return r}}();a=".hatebu{padding-bottom: 2px !important; margin-left: 5px !important;}";t(a);u=document.querySelectorAll("#post-body table tr");for(f=0,p=u.length;f<p;f++){c=u[f];e=null;y=c.children;for(h=0,s=y.length;h<s;h++){l=y[h];n=l.firstChild;if(!n){continue}d=n.tagName;if(!(d&&d==="a"||d==="A")){continue}e=n;break}if(!e){continue}m=e.href;if(!m){continue}o=r(m);l.appendChild(o)}})();


インストール作業はこれだけです。

あとは Vim Advent Calendar 2012 のページを開き、
Greasemonkey版なら何もしなてくも、ブックマークレット版ならブックマークレットを実行すれば、ブックマーク数が表示されます。
ランキング表示は若干時間がかかります。
(ランキングの同一順位を考慮してないのでそこは多めに見てほしい。)

ちなみに、ATNDの他のイベントページでも Vim Advent Calendar と同じようなテーブルレイアウトを使用している場合はブックマーク数を表示することができます。
Vimmer以外の方もインストールしておけば幸せになれるかもしれません。

※ 動作確認は、Chrome/FireFox/Safari にて行いました。IEは知りません。

注意

ブックマークレット版では、一部の記事でブクマ数が正常に表示されません。

記事執筆後に "はてなダイヤリー" から "はてなブログ" へ移行したが、VACのURLがはてなダイヤリーのままになっているためと思われます。はてなブックマークAPIはリダイレクトに対応していないようです。

Greasemonkey版ではリダイレクトの解決を自身で行うよう対応しています。
インストールが面倒でなければGreasemonkey版をお使い下さい。

技術的な話

ソースコードは以下にて公開しています。
不具合報告などありましたらよろしくお願いします。

制作時間は、ブックマークレット版が 約15分。
Greasemonkey版は3時間ぐらい。(リダイレクト関連で結構悩みました)
JavaScript は CoffeeScript で書いています。

Greasemonkeyはひな形を用意しておくことで、比較的短時間で作成することができます。
Chrome Extension なんかより簡単に作れるのでおすすめです。

しかし、欠点としてGreasemonkeyは自動更新が行えません。この縛りは結構つらいです。
幸いGreasemonkeyChrome拡張に変更するのは非常に簡単なので、今回のGreasemonkeyも、もし需要があるようならChrome拡張版を用意しようかと思います。

ブックマークレット版は、あらかじめGreasmonkey版を作り、動作確認を行なっておくことで、スムーズに作成することができます。
サーバ読み込みバージョンは、サーバ上のGreasemonkeyを読み込んでいるだけです。
非サーバ読み込みバージョンは、GreasemonkeyUglifyJSを使ってMinify(圧縮)しただけです。
簡単ですね。

Vimは関係ありませんが、思いついたちょっとしたアイディアをすぐに形にできるよう、
みなさんも Greasemonkeyブックマークレット のひな形を用意してはいかがでしょうか。


以上、
Vim Advent Calendar 2012 197日目の記事でした。
(Vim script が1行も出てこなくてごめんなさい。)

明日 198日目は、 @deris0126 さんです。

Chrome拡張では、Background pages よりも Event pages を使用したほうが良い

これからChrome拡張を作る方には是非知っておいて欲しい機能、Event pages についての話です。

Event pages は、作成したChrome拡張によっては、必ずしも使用できるわけではありませんが、もし可能なら積極的に使用してほしいと思います。

公式ドキュメントでも、Background pages のページ冒頭には、以下の様な注意書きがなされています。

Caution: Consider using event pages instead. Learn more. via: Background Pages - Google Chrome

なぜ Event pages なのか

理由を詳しく説明すると、
Background pages を使用している拡張は、Chrome起動時にプロセスが起動され、以降Chromeが終了するまで生き続けます。
よって、例え Background pages が何もしていなくてもメモリその他のリソースを専有し続けることになります。

Chrome拡張が起動しているかどうかは、Chromeの Task Manager を見ることで簡単に確認することができます。
実際に見てもらえれば分かりますが、このメモリ消費が結構ばかになりません。

また、Background pages が起動しているかどうかは、Chrome拡張の一覧 (chrome://extensions/) で確認することができます。
(以下は英語表記ですが、日本語にしていれば日本語が表示されると思います。)

f:id:yonchu:20130509190710p:plain
f:id:yonchu:20130509190715p:plain

Chrome拡張 Vimmers follow status の場合

先日私が作ったChrome拡張 Vimmers follow status でも Background pages を使用していました。
(現在のバージョンでは Event pages 対応になっています)


この拡張は、一見すると Content script のみで実現できそうなのですが、Oauth認証を実装するためにどうしても Background pages を用意する必要がありました。
ですが、Oauth認証も常時使用しているわけではありません。
Vimmersページ にアクセスして "Show All!" ボタンをクリックしたときしか使用していません。
それ以外のときは、Background pages では何も行なっておらず、ただメモリだけが専有され続けていました。
ひどいですね。自分で作っといてなんですが、こんな拡張使えたものじゃありません。

そこで、Event pages の出番です。
Backgroud pages とほぼ同じ機能を持ちながら、必要な時だけ起動され、不要になると自動的に終了してくれるという、まさに今回のようなケースに適したものとなっています。

Chrome拡張 ニコ生アリーナ の場合

しかし冒頭でも述べたとおり、必ずしも Event pages が使えるわけではありません。

例えば、Vimmers follow status よりも前にリリースしたChorome拡張 ニコ生アリーナ では、Background pages 内で番組情報などのデータを持っており、バックグランドで定期的に新しい番組のチェックなどを行なっています。

定期的なチェックぐらいなら、alarms API を使用することでなんとかなりますが、番組情報をキャッシュとして持っていなければ、ポップアップを開くたびに取得しなければならず、非常に使いづらいものとなってしまいます。
(他にも極力無駄な通信が発生しないような工夫を施したりしています)

こういった拡張では Event pages を使用することは難しいでしょう。

Background pages を Event pages に移行する方法

では、実際にどうすれば Background pages を Event pages に変更できるか。
そのための指針は公式ドキュメントに示されています。


対象となるChrome拡張がどのような機能を有するかによって修正内容が違ってくるため、まずは Vimmers follow status で行った変更を説明していきます。
といっても大した変更ではありません。

手順1(共通): Manifest(manifest.json)の変更

Manifestを以下のように変更します。

{
  "name": "Vimmers follow status",
  "version": "0.1.0",
  "manifest_version" : 2,
  "description": "VimmersページにTwitterのフォロー状態を表示します。",
  "background" : {
    "page": "background.html"
  },
  // .... 以下省略
}

{
  "name": "Vimmers follow status",
  "version": "0.1.0",
  "manifest_version" : 2,
  "description": "VimmersページにTwitterのフォロー状態を表示します。",
  "background" : {
    "scripts": [
      "js/lib/chrome_ex_oauthsimple.js",
      "js/lib/chrome_ex_oauth.js",
      "js/eventPage.js",
      "js/lib/ga.js"
    ],
    "persistent": false
  },
  // .... 以下省略
}

この変更は Event pages 使用時に必須の変更です。

backgroud.html が不要になったので削除し、background.html 内で読み込んでいたjsファイルを全て scripts に書き出しています。
さらに、"persistent": false を設定することで、Background pages の非永続化を行い、Event pages 方式に変更しています。

手順2: chrome.extension.sendRequest -> chrome.runtime.sendMessage

これは私が知らなかっただけなのですが、
chrome.extension.sendRequest が Chrome ver.20 から deprecated となっていました。
それでも通常の Background pages では使用できていたんですが、Event pages では使用できなくなっていました。

誤って使用すると以下のようなエラーが出ます。

Uncaught Error: sendRequest and onRequest are obsolete. Please use sendMessage and onMessage instead.

親切ですね。おかげで気づけました。

また、Background pages でもいつ使用できなくなるか分かりませんので、使用している方は早めに移行した方が良いかと思います。


新方式の chrome.runtime.sendMessage については以下を参照下さい。


私が対応した限りでは、引数などは変わっていなかったため、リネームするだけで対応できました。

以上が、今回 Vimmers forllow status で修正した点になります。

これで、Vimmers follow status も無駄にメモリを専有しなくなり、経済的な拡張となりました。

以下に diff があるので良ければ参考にして下さい。

Background pages -> Event pages のまとめ

公式ページの Event pages へ移行するためのチェックリスト migrating existing background pages の日本語訳がどこにもないようでしたので意訳してみました。
参考にどうぞ。

background page から event page への変更

background page から event page 変更する場合は、以下のチェックリストに従って下さい。

  1. Manifest に "persistent": false を追加する。
  2. Event page 読み込み時に、毎回必要な受信eventを登録する。event page はChrome拡張をバージョンアップしたときにも一度だけ読み込まれ、登録したイベントの処理が行われる。
  3. Install時、またはUpgrade時のみ必要な初期化処理がある場合は、runtime.onInstalled をイベントを使用する。
  4. もし実行状態をメモリに保持しておく必要が有るなら、storage API または IndexdDB を使用する。event page は長時間ロードされていないため、実行状態を保持するのに global変数 は使用しないほうが良い。
  5. 必要なら、イベント通知を抑制するために event filters を使用する。例えば、tabs.onUpdated イベントを使用したい場合、代わりに filter 付きの webNavigation.onCompleted イベントを使用する (tabs API には filter がありません)。そうすることで、必要なイベントでのみ event page を読み込むことができる。
  6. runtime.onSuspend event を使用することで、event page 終了直前に処理を行うことができる。しかし、それよりも定期的な実行を推奨する。そうすることで、onSuspend イベントを受け取れずにChrome拡張がクラッシュした場合にも、データが失われません。
  7. window.setTimeout() または window.setInterval() の代わりに、alarms API を使用する。もし event page が途中でが終了してしまうような場合、このような DOM-based timers は使用出来ない。
  8. extension.getBackgroundPage の代わりに runtime.getBackgroundPage を使用する。このメソッドは、必要時に event page を起動するため、非同期で実行される。
  9. message passing を使用する場合、不要になった message ports は閉じなければならない。message ports が閉じられるまで、event page は終了することができません。
  10. context menu API を使用する場合、contextMenus.create に String型の id パラメータを設定(idは通常optional)する必要がある。また、onclick パラメータの代わりに contextMenus.onClicked を使用してlistener を登録する。

via: Event Pages - Google Chrome

誤りなどがありましたら、ご指摘頂ければと思います。

また、公式のサンプルアプリも非常に参考になるので、見ておくと良いかと思います。

以上、Event pages の説明でした。

VimmersページにTwitterのフォロー状態を表示するChrome拡張を作った

GWも終わり、新入社員の方々はそろそろ研修が終わって本格的に業務をこなしはじめる頃ではないでしょうか。
そして、今後どのエディタと付き合っていくかも、決めなければならない時期なのではないでしょうか。

まだ決まっていな方、そしてもう決めてしまった方も、今なら vim がおすすめですよ。

ところでみなさま、 vim-jp » Vimmers というページをご存知でしょうか?
このページでは、vimmer の中でも特に vim に詳しい方々や vim を愛してやまない方々が紹介されています。

これから vim をはじめようという方、まだはじめたばかりの方、
Vimmersページで紹介されている有名 vimmerTwitterでフォローしてみてはいかがでしょうか。
とても刺激になりますよ。


前置きが長くなりましたが、
今回はこの Vimmersページ をもっと活用していくために、Twitterのフォロー状態を表示するChrome拡張 Vimmers follow status を作ってみました。
(いったい何を作ってるんだと苦笑されそうですが…)

使い方

Vimmers follow status をインストール後、Vimmersページにアクセスし、"Show All!" ボタンをクリックすると、Twitterのフォロー状態が表示されるようになります。

f:id:yonchu:20130508205808p:plain

フォロー状態に応じて、Borderカラーが変わるようになっています。
また、フォローしている人数やフォローされている人数なども表示されます。

※ 初回アクセス時はTwitterアプリケーションの認証を行う必要があります。

ちなみに、私のフォロー状況はスクリーンショットの通りです。
うーん、まだまだですね。

みなさんもこれを期に、Vimmersページの方々をフォローして vim力 を高ためるきっかけを作ってみてはいかがでしょうか。
私もまだまだ未熟なので、もっともっと精進していきたいですね。
そしていつかは、このVimmersページに載せて頂けるような vimmer になりたいものです。

それと、私はVimmersページには載っていませんが、ついでに私のこともフォローして頂けたら、それはとってもうれしいなって。


追記 2013/05/08:
なんとVimmersページに追加されました。たった1時間たらずの ”いつか” でした…w
こういうこともあるので、みなさんもマサカリを恐れず積極的にアウトプットしていくと良いことがあるかも?

技術的な話も少し

開発期間は約1日で、
js は coffeescript で css は less で書きました。

Chrome拡張本体には coffeescript や less は含まれていませんが、以下にてソースコードを公開していますので、そちらを参照下さい。

実装は非常に簡単なものなので、はじめてChrome拡張を作るという方にも参考になるのではないでしょうか。

Browser Action と Options page はありませんが、Background と Content script を使用しているので、これらの連携方法や、Oauth認証の実装方法などが参考になるかと思います。

また、Chrome拡張をはじめて作る場合は、まずはドットインストールをやってみることをオススメします。
ひと通り見てみましたが、非常に分かりやすくてよかったです。

さらに詳しく知りたい場合は、公式ドキュメントを見ると良いでしょう。
内容も分かりやすく、量も実は思ったほど多くありません。
逆にネットの情報はChromeのバージョンやmanifestのバージョンが最新ではない場合が多いため気をつける必要があります。
困ったときはまず公式ドキュメントを見るほうが、変なつまづきがなくて良いかと思います。

以上。

バグ報告や要望、pull request などありましたらお気軽にどうぞ。


あと、まだアイコンがないので募集中です (^_^;)

追記: 2013/05/09
syui (PSP_T)さん にアイコンを作って頂きました。
ありがとうございます。

f:id:yonchu:20130509192249p:plain

まさか募集一日目で作って頂けるとは。