ちょっと時間があったので、tubetopというWebアプリを作ってみた。
tubetop – The hottest viral YouTube videos in the world.
そこで今回は、開発においての技術的な事とか、各国の人気動画を眺めてて思う事なんかをツラツラと書いていこうと思う。
目次
アプリの概要
tubetopとはYouTubeの人気動画を国別に並べてるだけの、それだけと言えばただそれだけのサイト。当初こういったサイトはいくつもあるんだろうと思ってググってみたが、意外にも1つしか見つからなかったので開発することにした。動画に関してはYouTube Data APIというものを利用している。これを使えば人気動画はもちろん、独自の条件で検索した動画情報をJSONとかで受け取ることができる。
使用しているAPIに関しては後述するとして、他の環境周りも一応書いておく。
- バックエンドはRuby on Rails
- PaaSはHeroku
- JSフレームワークはMarionette.js
- CSSフレームワークはSemantic-UI
JS/CSSフレームワークの選定に関しては、多少ひねくれてるのかもしれない。。。
YouTube Data APIについて
国別の人気動画を取得は以下2つのリソースで実現している。
1.I18nRegionsはYouTube上で使用できる地域を取得することができるリソース。地域コードはISO 3166-1 alpha-2で表される。この地域コードを検索条件にして、2.Videosリソースにて人気の動画(chart=mostPopular)の動画を取得している。これをデイリーバッチとして稼働させている。
人気の動画の取得の仕方を探すのにちょっと手こずったけど、それ以外は特に問題なく進んだかな。しかしData APIのドキュメント、目的のものが探しづらいんだよなぁ・・。
ユーザーの地域と使用言語を取得する
tubetopは一応全世界の人に使って欲しかったので、自分に関連性の高い国の動画が上に来るようにした。関連性が高いかどうかは・・
- 自分のいる地域
- 自分の使用している言語
を基に判断している。例えばイギリスに住んでいる日本人がtubetopを開くと、一番目がUnisted Kingdom、2番目の国がJapanになるようになっている。これを実現するために、ユーザーがいる地域と使用言語を取得する方法がある。
◇ ユーザーがいる地域
Javascriptでユーザーがいる地域を判断する方法はいくつかある。ググると参考になるサイトが見つかると思う。一番参考になったサイトはここ。tubetopは「さっさと作る」というのが一つの使命だったため、中でも一番お手軽な方法で実現することにした。GoogleのGeo Location APIである。
実装は本当に簡単で、APIキーも要らない。
📄Google Geo Location API
// headかどこかでapiを読み込んでから <script type="text/javascript" src="//www.google.com/jsapi"></script> # 国コードを取得(万一取れなかったらUSにしとく) # CoffeeScriptでっせ ClientLocation = google?.loader.ClientLocation userRegion = ClientLocation?.address.country_code || 'US'
1行で読み込んで取得は同期処理でサクッとlocation情報が取れるので便利。ただしこのAPI、公式ページもないし、たぶんDeprecatedになってるような気がする・・・。まあこういうことは深く考えてはいけない。
◇ ユーザーが使用している言語
これはブラウザが教えてくれる。
📄ユーザーの使用言語
@getUserLanguage = -> window.navigator.userLanguage || window.navigator.language || window.navigator.browserLanguage
厳密に言うと、この結果イコール使用言語となるわけではないが、今回の要求に対してはこれで充分。なお上記JSの結果はブラウザによって返してくる値が異なる。各ブラウザの設定で言語を選べると思うが、その内容を返してきたのはFirefoxだけだった(Mac)。ChromeとSafariはブラウザの言語設定をどう弄っても「ja」を返してきた。(OSの値を取ってきてんのかな?)
◇ 各国が使用している言語
さて、ブラウザの言語取得ができたからといって、これで終わりでない。各国が使用している言語が分からなければ、言語による優先ソートは実現できない。最初はWikipediaからスクレイピングしてデータ作成しようか・・と思ってたが、探してみると丁度いいのがあった。いやあ、なんとかなるもんですなあ〜。
The GeoNames geographical database covers all countries and contains over eight million placenames that are available for download free of charge.
大雑把に言うと地名に関するデータベースを提供しているサービス。API提供はもちろん、テキストデータでダウンロードすることも可能。こういうのを見るたびにインターネットって偉大なあと思ってしまう。
私が使用したのはcountryInfo.txtという国別データ。ISOの2桁国コードをキーにした簡単統計情報を付加したデータだ。この中に使用言語sが入ってる。こいつをダウンロードしてActiveRecordにしてテーブルにぶち込むrakeを書いてこの問題はクリア。意外と苦労した・・・。
Semantic-UI
さて、CSSフレームワークだけど、お約束のBootstrapではなくてSemantic-UIを使用している。なぜこのフレームワークにしたかというと、国旗を表示するのが簡単だから。
http://semantic-ui.com/elements/flag.html
次のように簡単に国旗アイコンを表示することができる。
📄flag
<i class="jp flag"></i>
jpの部分がISO2桁国コードになってるので、プログラムで出力するには持って来い。この理由だけでこのフレームワークを選んでしまった。まあ新しいことをやるのは新鮮でいいし。
ただSemantic(意味論的な)という名前だけあって、Bootstrap野郎からするとCSSクラスの指定方法が独特。マルチクラス方式になっているのだ。例えば以下はグリッドの例。
four-wide-column
じゃなくて、four
wide
column
とマルチクラスで指定して初めてスタイルが効く。なるほど、セマンティックだ。。。
悪くはないんだろうけど、CSSの定義がネスト+複数クラス定義になるので、あまり好きになれない予感がした。複雑なクラス解析が働くため、僅かかもしれないが描画速度も落ちるはずだし。
📄MyView with Backbone.js
/* こんな感じの定義になる?(LESS/SASS) */ .ui.grid { .four.column { // 定義 } .five.column { // 定義 } .six.column { // 定義 } ... }
なんにせよLESSやSASS必須だろう。
Marionette.js
JSフレームワークにMarionette.jsを使用したのは、以前Backbone.jsを使用したことがあったから。Backboneはシンプルでいいんだけど、本当にシンプル過ぎて、もう少し面倒見てくれよと思う時がある。そんな願いを叶えてくれるのがMarionetteさんだ。
Backbone.jsを理解していれば、基本的につまづくことなくMarionette.jsを使用できると思う。そんなMarionetteの中でも、特に便利だなと思ったことをツラっと書いておこう。
◇ render不要
Backboneでは定形作業としてViewにrender関数を定義してあげる必要があった。典型的なコードは次のような感じ。
var MyView = Backbone.View.extend({ render: function(){ var html = $.templates(MyView.template).render({/* data */}); this.$el.append(html); return this; } }, { template: $('#hoge-template').html() }); new MyView().render();
Marionette.jsなら当たり前のrenderは書かなくてもいい。大したことないように思うかもしれないが、これ非常に楽チン。
📄MyView with Marionette.js
var MyView = Marionette.ItemView.extend({ template: "#hoge-template" }); new MyView().render();
CompositeViewでmodelとcollectionを同時に描画するのなんて、ほんと楽。
◇ uiがイイ
uiを使用するとView内の要素をキャッシュして保持していてくれてアクセスが簡単。
📄ui
var MyView = Marionette.ItemView.extend({ ... // View内の部品を保持しておく ui: { paragraph: 'p', button: '.my-button' }, // こんなふうに指定したり events: { 'click @ui.button': 'clickedButton' }, ... }); var view = new MyView(); view.render(); // こんな感じでjQueryオブジェクトが取得できる view.ui.paragraph.text(); view.ui.button.trigger('click');
ただし、テンプレートを使用しないViewでも必ずrender()を呼び出しておく必要がある。
Marionette.jsを使った感想は、用意されたレールに乗って行くことが可能なら、随分と楽できるなという感じかな。逆にレールに乗れないと結局はjQueryによるDOM弄りまくり地獄になってしまう可能性がある。あと、パフォーマンスを意識して再描画の際に特定箇所のみ再描画したいって場合がよくあるんだが、レールに乗るなら、その描画単位に合わせてViewを作成してやる必要があるなってこと。
例えば下の画像はtubetopのヘッダーメニューなんだけど、
パッと思いつく感じでViewを作成すると、次のような感じで書いちゃう人はいると思う。(自分もそう)
📄HeaderView
HeaderView = Marionette.ItemView.extend template: '#このヘッダー全部を描画するテンプレート' ui: filterFavoriteButton: '#お気に入りトグルボタン' autoScrollButton: '#スクロールボタン' events: 'click @ui.filterFavoriteButton': 'onClickFilterFavorite' 'click @ui.autoScrollButton': 'onClickAutoScroll' ...
しかし、ここでお気に入りボタン(♥)をクリックしたら、ボタン色を変更するような場合
ヘッダーのメニュー丸ごとrenderで再描画しちゃうと、TwitterやらFacebookのソーシャルボタンやら、関係のない部分まで再描画されちゃって困る。かといってjQueryのremoveClass/addClassを駆使してハートの色を変更するのは本末転倒で、これだと何のためにMarionette使ってんのか分かんない。
おそらく正解はViewに切り出すことなんだろう。例えばToggleFavoriteFilterView
のようなものを作るとか。とにかくViewを細分化して、それをLayoutにaddRegionして・・とマメにやっていかないと、Marionetteのレールに乗り続けることは難しい。
まあ、それがあるべき姿なんだろうが。もしくはVirtualDOM系のフレームワークに行っちゃうかね。
MemCachier – Heroku Add-on
tubetopは1日1回しかデータを更新しないので、できあがったビューはキャッシュしとくに越したことないでしょうハイそうですねというわけで、Railsのフラグメント・キャッシュを利用してる。Railsのキャッシュ機構はデフォルトではファイルベースのキャッシュ(だったはず)なので、MemCachierを使用することでメモリベースにすることにした。
Herokuのアドオンに登録されているので使用は簡単。25MBまでなら無料で利用できるようだ。枠内に余裕で収まるのでこいつを使用することに。アドオンインスコするだけで使用できて超楽ちんだったな。
各国の人気動画を眺めてて
ダラダラと技術系のことを書いてきたが、最後にコンテンツの方について思ったことを突然箇条書きで書いてみる。
- やっぱ英語は強い
- いや、アラビア語も強いよ
- いえいえ、スペイン語だってなかなかのものですよ
- Worldwideなアーティスト(例:coldplay)ってYouTubeだけで結構な売上ありそう
- 東/東南アジア諸国は母国語オンリー動画が多い。Worldwideなコンテンツも作り出せていない
- しかしK-PopとかKエロはそれなりに普及してそう
- 意外とイスラム圏の動画がエロい。Yemenが一番エロい気がする(これは戒律ゆえの結果なのだろうか?)
- マインクラフト熱すごい
まあ、こんな感じ。並べてみて分かるということもあるもんだね。日本の動画はほとんど「はじめしゃちょー」と「ヒカキン」が独占してる感じ。しかし残念ながら日本以外でのランクインは全く無い。日本語だから仕方ないんだけど、ちょっと勿体無い気もするな。はじめしゃちょーなんかの動画は外国人にもウケそうだから、せめて字幕だけでも付けたらいいのに、と思ってしまう。
なんやかんや言うとりますが、ネタ探しや暇つぶし、課長に怒られた腹いせなどに、ぜひともtubetopをご利用ください。
関連する記事
- 【Marionette】CompositeViewをCollectionViewで描画するサンプル
- Rails+JSフレームワークでリアルタイム掲示板を作成してみる(Backbone.js編)
- パーシャルをrenderする際のパフォーマンスに関する注意点
- Railsアプリを『浅く』パフォーマンス・チューニングしてみる(その2)
- 久しぶりにRailsで開発して感じたこと