昨日に引き続き、Rubyへのポーティング。
Rubyへのポーティング(続き)
昨日やったのは、ログイン処理まで。
元のNicovideo Downloaderは、ログインしたあとに動画のURLにアクセスしているけれど、そのレスポンスでやってるのは動画のタイトル情報を取得しているだけ。
なので、動画のファイル名には動画のIDを使うとした今回は、この処理は省略。
動画情報の取得
動画情報を取得するには、http://www.nicovideo.jp/api/getflv?v=*video_id*&as3=1
にアクセスする。
(video_idは、動画のID)
なので、こんな感じ。
VideoHost = "www.nicovideo.jp" VideoInfoPathFormat = "/api/getflv?v=%s&as3=1" video_id = (動画のID) http = Net::HTTP.new(VideoHost) video_info_path = sprintf(VideoInfoPathFormat, video_id) response = http.get(video_info_path, {'Cookie' => "user_session=#{user_session};")
ただ、このコードを試してみると、レスポンスのボディが空っぽ・・・
どうやら、リダイレクトされてるみたい。
なので、responseがNet::HTTPRedirectionの場合、リダイレクトでなくなるまで改めてGETをするようにした。
リダイレクトの場合、リダイレクト先のURLはHTTPヘッダの'location'フィールドで渡ってくるので、次のような感じ。
while response.is_a?(Net::HTTPRedirection) redirect_uri = URI.parse(response.get_fields('location').first) http = Net::HTTP.new(redirect_uri.host) response = http.get(redirect_uri.request_uri, {'Cookie' => "user_session=#{user_session};") end
こうして取得される動画情報だけど、データがCGIのクエリと同じ形式でエンコードされているので、そのままでは扱いづらい。
そこで、標準添付ライブラリの'cgi'を使って、扱いやすい形にしてあげる。
そして、'url'というフィールドにアクセスして、動画の実際のURLを取得する。
require 'cgi' # これは実際にはもっと前でロードしておく info = CGI.parse(response.body) video_url = info['url'].first video_uri = URI.parse(video_url)
動画のダウンロード
あとは、この動画の実際のURLにアクセスして、データをダウンロードし、ファイルに書き出すだけ。
元のNicovideo Downloaderでは、一度に読み出すブロックサイズを計算したりしているのだけれど、Rubyだとブロックサイズを指定して読み出すというメソッドはないみたい。
けど、Net::HTTP#getのかわりに、Net::HTTP#request_getをブロック付きで呼び出すと、レスポンスのボディを小さく分けて取り出すことが出来る。
なので、これを使ってみた。
output_filename = (出力するファイル名) http = Net::HTTP.new(video_uri.host) http.request_get(video_uri.request_uri, {'Cookie' => "user_session=#{user_session};") do |response| File.open(output_filename, "wb") do |file| response.read_body do |video_block| file.write(video_block) end end end
これでOKのはず。
コード全体としては、以下のようになった。
正しく動かない・・・
さて、これを実際に試してみると、正しく動かない。
具体的には、ファイルは作られるものの、その中身がほぼ空っぽ。
おかしいなと思ってファイルの中身を見てみると、"403 Forbidden"の文字があるだけ。 なぜだ・・・
今日はここまで!