[firefox][備忘録] ニコニコ動画のflvファイルを保存するfirefoxエクステンションを作成
javascriptの勉強がてらfirefoxのエクステンションを初めて作ってみた。車輪の再(再々…)発明なのはみのがして。いろいろハマったので誰かの何かの足しになるかも、というわけで作り方とかを掲載してみることにする。
ちなみに当方の環境はDebian(lenny) + FireFox(Iceweasel) 2.0.0.6
firefoxのエクステンションに関して参考にしたのは以下のサイト
Firefoxエクステンションの書き方
Firefox拡張機能(extension)の作り方
ニコニコ動画からのflvファイル取得については以下のサイトを参考にした。
ニコニコ動画のFLVをダウンロードするGreasemonkey
仕様はこんな感じで。
- ステータスバー(ウィンドウの右下にあるやつ)にそれっぽいアイコンを表示
- 動画の再生ページでアイコンをクリックすると動画のflvファイルを取得
パッケージ名は安易に「nicoget」としてみた。
作ったファイルはこれだけ。
~/work/nicoget/chrome.manifest /install.rdf /chrome/content/nicoget/nicogetOverlay.xul /chrome/content/nicoget/nicoget.js /chrome/content/nicoget/nicoget.css /chrome/content/nicoget/nico.ico /chrome/content/nicoget/contents.rdf
各ファイルの説明
chrome.manifest
パッケージをインストールするときにはインストーラが勝手に作ってくれるので、xpiを作る際には必要ないけど開発用firefoxで実行するときには必要。
以下開発用chrome.manifes
content nicoget chrome/content/nicoget/ overlay chrome://browser/content/browser.xul chrome://nicoget/content/nicogetOverlay.xul
フォーマットや役割について詳しくは以下のサイトにある。
http://developer.mozilla.org/ja/docs/chrome.manifest
content行はURI(chrome://...)とパッケージの実際のパスとの関連付けをするものだけど、パスの最後が"/"で終らないとダメということを知らずにそうとうハマった。
install.rdf
ここにあるやつをほぼ丸写し。
異なるのは
<?xml version="1.0"?> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <em:id>{a58fa49f-acb8-43f8-b3b5-e69f552f6a7d}</em:id> <!-- 拡張機能ごとにUUIDを生成(*) --> <em:version>0.1</em:version> <!-- 拡張機能のバージョン --> <em:type>2</em:type> <!-- 2:拡張機能、4:テーマ、8:ロケール、16:プラグイン、32:... --> <em:file> <Description about="urn:mozilla:extension:file:nicoget.jar"> <em:package>content/nicoget/</em:package> </Description> </em:file> <!-- Target Application this extension can install into, with minimum and maximum supported versions. --> <em:targetApplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox固有のUUID --> <em:minVersion>1.5</em:minVersion> <em:maxVersion>2.0.0.*</em:maxVersion> </Description> </em:targetApplication> <!-- Front End MetaData --> <!-- 拡張機能の説明(人間用) --> <em:name>nicoget</em:name> <em:description>get smilevideo extension</em:description> <em:creator>test@test</em:creator> <!--em:homepageURL>http://localhost/</em:homepageURL--> </Description> </RDF>
nicogetOverlay.xul
こいつがbrowser.xulを上書き(Overlay)してステータスバーにアイコンを表示させる。
<?xml version="1.0"?> <?xml-stylesheet href="nicoget.css" type="text/css"?> <overlay id="sample" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/x-javascript" src="nicoget.js"/> <statusbar id="status-bar"> <statusbarpanel class="statusbarpanel-iconic" id="nico-panel" label="nicoget" onclick="getflv()"/> </statusbar> </overlay>
見ての通りステータスバーをクリックするとgetflv()が呼ばれる。
nicoget.js
DL処理の本体。エコノミーならファイル名にlowが付くようにしてみた。
function getflv(){ try{ getnicoflv() }catch(e){ alert(e); } } function getnicoflv(){ var href = window.content.location.href; // 動画IDの取得 try{ var vid = /http:\/\/www\.nicovideo\.jp\/watch\/(.*)$/.exec(href)[1]; }catch(e){ throw Error("not smile video URL."); } var apiurl = "http://www.nicovideo.jp/api/getflv?v="+vid; var req = new XMLHttpRequest(); req.open("GET", apiurl, false); req.send(null); if(req.status != 200){ throw Error(req.responseText); } try{ var tid=unescape(/thread_id\=(.*?)\&l/.exec(req.responseText)[1]); var url=unescape(/\&url\=(.*?)\&/.exec(req.responseText)[1]); }catch(e){ throw Error("get flv failed: " + vid); } // エコノミーモードの判定 var bEconomy = /low$/.test(url); // ファイル選択ダイヤログの作成 const nsIFilePicker = Components.interfaces.nsIFilePicker; const FP = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker); FP.init(window, "get flv file", Components.interfaces.nsIFilePicker.modeSave); var file_name = vid + (bEconomy? "_low" : "") + ".flv"; FP.defaultString = file_name; // ダイヤログ表示 var result = FP.show(); if( result == Components.interfaces.nsIFilePicker.returnCancel) { return; } var sourceUri = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService).newURI(url, null, null); // ダウンロードマネージャ var dm = Components.classes["@mozilla.org/download-manager;1"].getService(Components.interfaces.nsIDownloadManager); var PERSIST = Components.classes['@mozilla.org/embedding/browser/nsWebBrowserPersist;1'].createInstance(Components.interfaces.nsIWebBrowserPersist); // キャッシュを利用するためのコード var postData = null; try { var SH = getWebNavigation().sessionHistory; var entry = SH.getEntryAtIndex(SH.index, false).QueryInterface(Components.interfaces.nsISHEntry); postData = entry.postData; } catch (e) {} // ダウンロードマネージャに情報を登録 var download = dm.addDownload(0, sourceUri, FP.fileURL, file_name, null, null, null, null, PERSIST); // ダウンロード進捗のリスナを設定 PERSIST.progressListener = download; // ファイル取得開始 PERSIST.saveURI(sourceUri, postData, null, null, null, FP.file); return; }
nico.ico
ステータスバーに表示するアイコンにはニコニコ動画サイトのfaviconを使用することにした。再配布する予定はないから問題ないよね。もちろん別の画像でも可。
今回は以下のコマンドで取得した。
$ wget http://www.nicovideo.jp/img/favicon.ico
nicoget.css
ここではstatusbarpanelとnico.icoを関連付けるために必要
statusbarpanel#nico-panel { list-style-image: url("nico.ico"); }
contents.rdf
オーバーレイ情報を記述するものらしい。パッケージインストール時にinstall.rdfやこいつをみてchrome.manifestを作っているのだろうか?
<?xml version="1.0"?> <RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:chrome="http://www.mozilla.org/rdf/chrome#"> <RDF:Seq RDF:about="urn:mozilla:package:root"> <RDF:li RDF:resource="urn:mozilla:package:nicoget"/> </RDF:Seq> <RDF:Seq RDF:about="urn:mozilla:overlays"> <RDF:li RDF:resource="chrome://browser/content/browser.xul"/> </RDF:Seq> <RDF:Seq RDF:about="chrome://browser/content/browser.xul"> <RDF:li>chrome://nicoget/content/nicogetOverlay.xul</RDF:li> </RDF:Seq> <RDF:Description RDF:about="urn:mozilla:package:nicoget" chrome:displayName="nicoget" chrome:author="papamitra" chrome:authorURL="papamitra@hoge" chrome:name="nicoget" chrome:extension="true" chrome:description="get smile video flv file"> </RDF:Description> </RDF:RDF>