NicoCastの仕組み
ニコニコ動画をChromeCastで再生するものを作った。
早いところ書こうと思っていたけど、忘れてた。 適当に記しておく。
簡潔に書くとこんな感じ。
詳しくは下に徒然なるままにそこはかとなく書き綴っているが、長いのし読みづらいので本当に興味がある人以外は読まない方がいい。
まず、Chromecastの実体は恐らくChromeWebBrowserそのものだ。OSはわからない。 GoogleOSとかもあるし、そこら辺かもしれない。
つまり、WebBrowserでニコニコ動画を表示できればいい。 実際、HTML5のプレイヤーは公式のスマートフォンサイトにあるので、実装は可能だと踏んだ。 (ソースコードとか読んでない。多分自分には読めない)
ニコニコ動画の動画URLはAPIを叩けば簡単に手に入る。 問題は、試聴する方法だ。 ニコニコ動画の動画にアクセスするにはCookieが必要なのである。
Google先生に助言を仰ぐと、Cookieの取得方法には次のものがあるらしい。
- ログインした状態で flapi.nicovideo.jp/api/getflv?v=[動画ID]
- ログインした状態で www.nicovideo.jp/watch/[動画ID] (動画視聴ページ)
- ext.nicovideo.jp/thumb_watch?v=[動画ID]&k=[Key] (外部プレイヤー用)
つまり、これらの方法でCookieを取得すれば視聴できるわけである。
方針はたった。あとは組むだけなのだが、ここでいくつか弊害が出てくる。
ひとつは、ログイン情報の送信だ。 自分はセキュリティに関してはさっぱり知見がない為、今回はログインしない方向で組んだ。
次は、クロスドメイン問題だ。 WebBrowserはセキュリティ的な観点から他ドメインのアクセスに制限がある。 簡単にいえば、他ドメインのデータを取得できない。 動画のURLはAPIから取得しなければならないし、Cookieももらってくる必要がある。 Cookie自体は何らかの方法でアクセスすると他ドメインでももらえるのでなんとかなった。 (アクセスするのと、アクセスしたデータを取得するのは少し違うらしい。よくわからん) 動画URLは開発当初GAS(Google Apps Script)でAPIから取得するスクリプトを組んで送っていた。 (無論GASはWebBrowserでないので、クロスドメイン問題は起きない)
さて、これでクロスドメインはなんとかなりそうだ。 しかし、外部プレイヤーのkeyとやらを手に入れる必要がある。 外部プレイヤーのkeyは動的に作られ、ext.nicovideo.jp/thumb_watch?v=[動画ID] にアクセスしたときに返されるJavaScript(外部プレイヤーをブログに貼るコード)の中に書いてある。 アクセスして取ってくればいい?そうは行かない。 先ほどのクロスドメイン問題が健在である。
そのkeyこそGASで取得すればいいではないか。 それも上手くいかない。 アクセス元を記録しているのか、他の端末で得たkeyではエラーを返してくる。 万事休すのように思えるが、まあなんとかなる方法がある。 実際にblogに貼ってある外部プレイヤーのHTMLを見てみる。
<embed type="application/x-shockwave-flash" id="external_nico_0" name="external_nico_0" src="http://ext.nicovideo.jp/swf/player/thumbwatch.swf?ts=1401689792" width="240" height="180" allowscriptaccess="always" allowfullscreen="true" bgcolor="#000000" quality="high" flashvars="thumbWatch=1&thumbPlayKey=1402840276.0.1.KGUJYPPfYnx0hQG7SpYNqWXUD5Q.aHR0cDovLzM4NDZtYXNhLndlYi5mYzIuY29tL25pY29UaHVtYldhdGNoLw%3D%3D..&playerTimestamp=1402382800&player_version_xml=1402382797&player_info_xml=1397103121&translation_version_json=1401689833&v=sm9&videoId=sm9&thumbTitle=%E6%96%B0%E3%83%BB%E8%B1%AA%E8%A1%80%E5%AF%BA%E4%B8%80%E6%97%8F%20-%E7%85%A9%E6%82%A9%E8%A7%A3%E6%94%BE%20-%20%E3%83%AC%E3%83%83%E3%83%84%E3%82%B4%E3%83%BC%EF%BC%81%E9%99%B0%E9%99%BD%E5%B8%AB&thumbDescription=%E3%83%AC%E3%83%83%E3%83%84%E3%82%B4%E3%83%BC%EF%BC%81%E9%99%B0%E9%99%BD%E5%B8%AB%EF%BC%88%E3%83%95%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%A9%E3%82%B9%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%EF%BC%89&thumbImage=http%3A%2F%2Ftn-skr2.smilevideo.jp%2Fsmile%3Fi%3D9&movie_type=flv&wv_id=sm9&language=ja-jp&iee=1&noAdSense=1&category=%E9%9F%B3%E6%A5%BD%20%E3%82%B2%E3%83%BC%E3%83%A0&leaf_switch=2&accessFromHash=1402753876%3Aedca82cd658c480acad3e0d41d26f7e51ef3db64aec348585de996428b32d6ab">
なにが書いてあるのかわけがわからない。 そんな文字列を読んでいる人もいるもので、Google先生に尋ねると答えが返ってきた。
重要なのは、flashvars属性の文字列だという。 整形したものを載せておく。
thumbWatch=1 thumbPlayKey=1402840276.0.1.KGUJYPPfYnx0hQG7SpYNqWXUD5Q.aHR0cDovLzM4NDZtYXNhLndlYi5mYzIuY29tL25pY29UaHVtYldhdGNoLw==.. playerTimestamp=1402382800 player_version_xml=1402382797 player_info_xml=1397103121 translation_version_json=1401689833 v=sm9 videoId=sm9 thumbTitle=新・豪血寺一族 -煩悩解放 - レッツゴー!陰陽師 thumbDescription=レッツゴー!陰陽師(フルコーラスバージョン) thumbImage=http://tn-skr2.smilevideo.jp/smile?i=9 movie_type=flv wv_id=sm9 language=ja-jp iee=1 noAdSense=1 category=音楽 ゲーム leaf_switch=2 accessFromHash=XXXXXXXXXXX
HTMLエスケープを元に戻して、&で区切るとこんな感じだ。 (accessFromHashだけは何なのかわかってないので一応隠しておく) 必要なのは、thumbPlayKeyであり、これを先ほどのURLのkに入れる。 外部プレイヤーに関しては全てGoogle先生からの受け売りだ。
実はこの外部プレイヤーは厄介者で、ここで結構手こずっている。 上記の対策だけではChromeCast再生は無理なのだ。 それはChromeCastの仕様と外部プレイヤーの仕様の両方が問題になる。
ChromeCastのアプリはGoogleに登録しなければならないのだが、アプリサイトを固定URLで登録する。 つまり、動的にWebページを作るのはJavascriptのみしか使えない。 外部プレイヤーの仕様で、Javascriptから動的に作られた外部プレイヤーは生成されない。 さて、どうしたものか。
ここでChromeCastが実質何であるかを思い出して欲しい。 そう、WebBrowser。リンクが飛べる。 これを使うと他リンクにGETを投げられるので、Javascript以外の方法で動的にページが作れる。 GASを使った。
さて、どこまで書いたか.... そうそうここまでの知識はNicoThumbWatch4HTML5を作る際に知った。 作ってページもあるが、特に面白くもなかったのでひっそりと公開されている。
で、話を戻すと これで動画再生はできる。
【ニコニコ動画】ニコニコ動画をChromeCastに対応させてみた
実はこの動画より前に再生はできていたのだが...
さて、続いてコメントだがコメントも当初はGASから取得していた。 コメントの表示も重なりを極力避けたり、Google先生に仕様を聞いたりして作った。 のが過去にあったので流用。
【ニコニコ動画】ニコニコ動画(RC)に戻るChrome拡張を作ってみた
結局基盤は過去に作ってあったのである。 早く公開できたのにはこういう理由がある。
これで通常の動画は再生できるようになった。
アニメ見たい。 そう思うだろう。思ったんだ。 試してみると、公式動画が再生できない現象に陥った。 問題はGASだ。
GASはGoogleのサービスで、そのサーバは日本にないらしい。(おそらく、たぶん、めいびー) 公式動画のアニメは日本国内からしかアクセス出来ない。 APIはアクセス元の国を見て、外国からのアクセスにはエラーを返してくるようだ。 つまり、動画URLとコメントの両方が取得できない。
この問題は、解決法を考えるのに時間はかからなかった。 要はChromeから動画URLとコメントデータを送ればいいのだ。 ついでに、一般動画のコメントデータはCookieも必要なかったことがここで判明したため、Chromecastから取得するように変更する。
さてはて、これにて再生ができるわけである。
再生はできた。満足。 ...他の人にも使って欲しい。 リリースするには?
そう、一時停止とシークバー、音量調整、コメント非表示の機能が必要だ。 これが結構に大変だった。
通信ができない。 これはChromeCastアプリのリンクを飛んでいるためだと思われる。 サイトが飛ぶと、実行中のスクリプトは止まる。つまり通信が切断される。 サイトを飛ばさず、取得したHTMLをdocument.writeした。 (ちなみに、最初のChromeCastサイトとリンク先は共にGoogleサーバなので、クロスドメインにはならない)
動画の再生位置はGoogleの用意したChromeCastAPIを使うと取れるらしいが、英語ワカリマセンの私には厳しかった。 適当に0.5秒間隔でChromeにJSONで送信する。(送信にGoogleの用意したChromeCastAPI使ってるのは読めたから) 他の操作もChromeCastAPIでJSONを送信する。
これで配布できるかな? ぐらいには完成したので配布。 【ニコニコ動画】ニコニコ動画をChromeCastに対応させてみたを配布してみた 動画しっかりつくる気力はなかった。解説、書かなくてごめんなさい。
もっと色々やってるけど、とりあえずここまで。 コメント重いとか、有料動画サポートとか、プレミアム回線とか改善したいけど難しい.... 有料動画サポートとプレミアム回線はログイン必要だし、コメント重いのはどうにも自分には難しい。
【後日談】
Googleからこんなメールが届く。
Dear Developer, Your Google Chrome item, "nicoCast," with ID: XXXXXXXXX did not comply with our policies and was removed from the Google Chrome Web Store. Your App is in violation of branding guidelines found here: https://developers.google.com/chrome/web-store/branding If you'd like to re-submit your item, please make the appropriate changes to the item so that it complies with our policies, then re-publish it in your developer dashboard. Please reply to this email for issues regarding this item removal.
このロゴがよくなかったらしい。
かなりお気に入りなのだけど... 仕方がないですね...
【さらに後日談】
公開してから色々な情報サイトに取り上げられて、嬉しい限り。 と思っていたら、
Chromecastでニコ動を見たいなら『nicoCast』を使おう 週アスPLUS #chromecast http://weekly.ascii.jp/elem/000/000/229/229749/
まさかの週アス!?
現時点では、連続再生ができない、再生中にコメントを書き込めない、ニコ生が見られないなど、まだまだベータ版といった感じですがこれからに期待ですね。
これからに期待されました(; ・`ω・´)
コメントカクカク=>改善法募集
連続再生=>自分の気力次第
コメント書き込み=>やり方はあるので搭載できそう
ニコ生対応=>仕組み的に厳しい
こんなところですか。