Greasemonkey勉強会
ゼミ用資料 関係のない方はスルーしてください
今回の資料:ダウンロード
Greasemonkeyとは
Firefoxでユーザースクリプトを実現するためのエクステンション(拡張機能)の一つで、読み込んだウェブページをクライアント(ユーザー)側でカスタマイズ可能にするもの。
他のブラウザでは、同様の機能が、Opera8では標準で、IEではTrixieを導入することで、SafariではCreammonkeyを導入することで実現できる。
例えば、特定サイトのフォントを変更したり、広告を排除したり、便利なリンクを追加したりすることができるユーザースクリプトがあります。より詳細な内容:http://diveintogreasemonkey.org/toc/ *1
どんなものがあるの
とりあえず使ってみよう。おもしろいスクリプトがいっぱいある→http://userscripts.org/ /人気エントリ
- Autopagerize http://userscripts.org/scripts/show/8551
- 複数のページに分かれているコンテンツをスクロールするだけで移動できる。
- LDRize http://userscripts.org/scripts/show/11562
- j,kでスクロールできる。
- ページを切り分ける部分、操作を定義する部分が別々に定義できる。
- インスタラクション:http://www.heiwaboke.com/ をLDRizeして見に行く
- SBM comment viewer
- はてブとかdel.icio.usでのブックマーク数とかが一度に見れる
- twitterにはてなスターを設置
- Twitterの各発言にはてなスターを設置するGreasemonkey、TwitterStar(愛称はつい☆すた)
- ニコニコ動画にアクセスしている時間をカウントする
- どれだけ廃人か一目瞭然ですね^^^
- ニコニコ動画のコメント熱狂度を可視化する
- 弾幕が張られているのがいつか一目瞭然ですね^^^
- ニコニコ動画のコメントの中から、動画IDやURLっぽいやつを抽出する
- 要参照動画にらくらく移動できてニコニコライフが加速します。大変よかったですね。
- mixiのコメントランキングをグラフで表示するグリモン作ったよ!
- ある人の日記に誰がどれだけくねくねしてるか一目瞭然です。大変よかったですね。
どうやって作るんだぜ
マニュアル:http://diveintogreasemonkey.org/toc/
書いて*.user.jsと名前をつければおk リンクで踏むかドラッグアンドドロップでインストールできる。
// ==UserScript== // @name hello Greasemonkey // @namespace http://omedete.na/ // @include * // @exclude http://www.google.com/* // @exclude http://www.google.co.jp/* // @description ^o^ // ==/UserScript== alert('Hello world!');
冒頭のコメント行は必須。特殊なのはこれくらい
- @include:このスクリプトが有効になるURL
- @exclude:このスクリプトが無効になるURL
日本語はUnicodeエスケープしないといけません。エスケープしてくれるプログラムかエディタを用意するといいでしょう。
初歩
ニコニコ動画の動画リンクがまるで役に立たないので書き換える。
ニコニコは「 短時間での連続アクセスはご遠慮ください」なので自重してsample1.htmlでまず練習(資料)
// ==UserScript== // @name niconico google // @namespace http://omedete.na/ // @include http://www.nicovideo.jp/watch/* // @description ^o^ // ==/UserScript== var h1 = document.getElementsByTagName('h1')[0]; if(!h1) return; h1.firstChild.href='http://www.google.co.jp/search?q=' + h1.firstChild.innerHTML;
GM特有の機能
Greasemonkeyには特別な機能をいくつか用意されています。ニコニコ動画にアクセスしている時間をカウントするスクリプトを例にとって説明。
// ==UserScript== // @name NicovideoTimer // @namespace http://cureblack.com/ // @include http://www.nicovideo.jp/* // ==/UserScript== var field = document.createElement('div'); document.body.appendChild(field); with(field.style) { width = "200px"; backgroundColor = "#FF0000"; position = "fixed"; bottom = 0; right = 0; opacity = '0.5'; textAlign = "right"; }
var time = GM_getValue('nicovideotimer_time', 0);
GM_getValue(key,デフォルト値),GM_setValue(key,値)でGreasemonkeyに値を保存したり取り出したり出来ます。*2
if(window.parent == window){ window.setInterval(function(){ ++time;
GM_setValue('nicovideotimer_time', time);
ここもそう。
var sec = time % 60; var min = Math.floor(time / 60) % 60; var hour = Math.floor(time / (60 * 60)) % 24; var day = Math.floor(time / (60 * 60 * 24)); var str = "累計 "; if(day) str += day + "日"; if(hour) str += hour + "時間"; if(min) str += min + "分"; if(sec) str += sec + "秒"; field.innerHTML = str; }, 1000); }
GM_registerMenuCommand("Reset Nicovideo timer", function(){ time = 0; });
ユーザーメニューに関数を登録できます。*3
ドメイン外との通信にはGM_xmlhttpRequest(details)*4が使えます。
例えばニコニコのコメントXMLにアクセスするのに必要。ニコニコのコメントについては以下を参照
ニコニコ動画を拡張する
ニコニコ動画は動画の長さにより最新のものから250〜1000件のコメントを表示します。短い動画なら250コメント。つまり見えているコメントを書いた人たちとニコニコしているに過ぎない。実際には何人と?
point:
- GM_xmlhttpRequest(外部ドメインとの通信)
- 連想配列(ハッシュ→ユニークキーだけに淘汰できるNE)
- XML解析(.getAttribute())*5
ニコニコは「 短時間での連続アクセスはご遠慮ください」なので自重してsample2.htmlでまず練習(資料)
// ==UserScript== // @name niconico comment unique user // @namespace http://omedete.na/ // @include http://www.nicovideo.jp/watch/* // @description ^o^ // ==/UserScript== (function(){ var h1 = document.getElementsByTagName('h1')[0]; if(!h1) return; var info = document.createElement('span'); info.appendChild(document.createTextNode('unique user...')); if(/watch\/([^/]+)$/.test(location.href)){ var video_id = RegExp.$1; GM_xmlhttpRequest({ method: 'GET', url: 'http://www.nicovideo.jp/api/getflv?v=' + video_id, onload: function(res){ if(/thread_id=(.+?)&.+&ms=(.+?)&/.test(res.responseText)){ var thread_id = decodeURIComponent(RegExp.$1); var url = decodeURIComponent(RegExp.$2); GM_xmlhttpRequest({ method: 'POST', headers: { 'Content-type': 'text/xml' }, url: url, data: '<thread res_from="-1000" version="20061206" thread="' + thread_id + '" />', onload: function(res){ var responseXML = (new DOMParser).parseFromString(res.responseText, "application/xml"); var chats = responseXML.getElementsByTagName('chat'); var unique = new Object(); for(i=0;i<chats.length;i++){ unique[chats[i].getAttribute('user_id')] = 1; } var count=0; for(s in unique){ count++; } info.appendChild(document.createTextNode(count)); }, onerror: function(res){ GM_log(res.status + ':' + res.statusText); } }); } }, onerror: function(res){ GM_log(res.status + ':' + res.statusText); } }); } h1.parentNode.insertBefore(info, h1); })();