響 HiBiki Radio Station をaacで録音する

2015/11/10追記

響がリニューアルしたんでこの記事の情報は全く役に立たなくなりました。 新しい仕様についての説明、コードはこちら↓

vector.hateblo.jp

検索用キーワード: Mac, Linux, rtmp, rtmpdump, rtmpe, 保存

まえがき

響で再エンコードなしでaacを取得する方法がわかったんでメモ。

ググるwmaやm3u8で取得する方法は見つかるんだが、wmaだとiOSとかで再生できないし、再エンコードは気分が悪い。m3u8 (HTTP Live Streaming)はなんかファイルがすごい分割されていてパッとググってもffmpegとかでいい感じにmp4などに復元する方法が見つからなかったので遠慮したさがあった。

コード

雑なコードとしては下の2ファイルを見て欲しい

https://github.com/yayugu/net-radio-archive/blob/18d9097df6266f8ece9e026b1414768eb82e26d8/lib/hibiki/scraping.rb

https://github.com/yayugu/net-radio-archive/blob/18d9097df6266f8ece9e026b1414768eb82e26d8/lib/hibiki/downloading.rb

手順

http://hibiki-radio.jp/get_program/$(WEEKDAY)

にアクセスすると曜日ごとの番組情報が取得できる。$WEEKDAYは数字で1-6がそれぞれ月〜金と土日に対応している。

Aタグのonclickが onclick="AttachVideo('garo','1637','1','0')" みたいになっているのでこの関数の1つめと2つめを取り出す。

m = /AttachVideo\('(.+?)','(.+?)','.+?','.+?'\)/.match(onclick_text)
short_name = m[1]
channel_id = m[2]

その情報からURLを生成してアクセスする。

      uri = URI.parse("http://image.hibiki-radio.jp/uploads/data/channel/#{base.short_name}/#{base.channel_id}.xml")

      res = Net::HTTP.get_response(uri)
      unless res.is_a?(Net::HTTPSuccess)
        return nil
      end

      dom = Nokogiri::HTML.parse(res.body)

      protocol = dom.css('protocol').text
      domain = dom.css('domain').text
      dir = dom.css('dir').text
      flv = dom.css('flv').text
      if protocol.blank? || domain.blank? || dir.blank? || flv.blank?
        return nil
      end
      m = /^.+?\:(.+)$/.match(flv)
      filename_query = m[1]
      rtmp_url = "#{protocol}://#{domain}/#{dir}/#{filename_query}"

xmlのような雰囲気のものが取り出せる。404だったり、情報が空のこともある。その場合はその番組はおそらく配信していない。 無事取得できて、以下のようになってたら成功。この情報を組み立てるとrtmpのurlができる。

<data>
        <protocol>rtmpe</protocol>
        <domain>cp209391.edgefcs.net</domain>
        <dir>ondemand</dir>
        <channel type="main">
                <flv>mp4:150101_lovelive_ms_150101_lovelive_ms.mp4?di=910&si=609&pi=2806&gi=6494&gc=3&bi=34236&bc=lovelive_ms&ei=921385&ec=150101_lovelive_ms&vi=4989926&vc=150101_lovelive_ms&msi=516&mc=&ni=1625</flv>
                <thumbnail>http://image.hibiki-radio.jp/uploads/radio_program/flash_image/c7562a9a9a67e099402d472585bcdc5068da0d24.jpg</thumbnail>
        </channel>
</data>

組み立てたurlをrtmpdumpに渡す

`rtmpdump -q -r #{Shellwords.escape(rtmp_url)} -o #{Shellwords.escape(flv_path)}`

うまくいっていればflvファイルがあるはずである。中身はh264の映像とaacの音声である。h264の映像はダミーであるため、ffmpeg(or avconv)でaacだけを取り出す。

`avconv -loglevel error -y -i #{Shellwords.escape(flv_path)} -acodec copy #{Shellwords.escape(aac_path)}`

あとがき

ちなみにrtmpもhls(HTTP Live Streaming)もデータを転送するための方法であり、中身は大抵の場合h264とaacである。 なのでどちらでもmp4が取り出せるはず(方法は知らないけど)