class Hibiki

Public Class Methods

new(url, options) click to toggle source
Calls superclass method WebRadio::new
# File lib/hibiki.rb, line 10
def initialize(url, options)
        super
        @url = @url.sub(%r|/detail\Z|, '')
end

Public Instance Methods

download() click to toggle source
# File lib/hibiki.rb, line 15
def download
        hibiki_download(@label, Pathname(@url).basename.to_s)
end
dump() click to toggle source
# File lib/hibiki.rb, line 19
def dump
        tag = Pathname(@url).basename.to_s.gsub(%r|[-/]|, '_')
        agent = Mechanize.new
        media_info = hibiki_media_info(agent, tag)

        return {
                tag => {
                        'desc' => media_info[:name],
                        'url' => @url,
                        'label' => tag
                }
        }
end

Private Instance Methods

find_cover(media_info) click to toggle source
# File lib/hibiki.rb, line 44
def find_cover(media_info)
        media_info[:episode][:episode_parts].map{|s|s[:pc_image_url]}.reject(&:empty?)[0]
end
header() click to toggle source
# File lib/hibiki.rb, line 34
def header
        {'X-Requested-With' => 'XMLHttpRequest'}
end
hibiki_download(name, program_id) click to toggle source
# File lib/hibiki.rb, line 48
def hibiki_download(name, program_id)
        begin
                agent = Mechanize.new
                media_info = hibiki_media_info(agent, program_id)
                @cover = find_cover(media_info) unless @cover
                serial = media_info[:episode][:name].scan(/([\d\.]+)/).flatten.first
                video_id = media_info[:episode][:video][:id]

                video_info = JSON.parse(agent.get("https://vcms-api.hibiki-radio.jp/api/v1/videos/play_check?video_id=#{video_id}").body,{:symbolize_names => true})
                playlist_url = video_info[:playlist_url]
                m3u8_url = URI(agent.get(playlist_url).body.scan(/http.*/).flatten.first)

                # choice the max size element from multi-part m3u8 file
                m3u8 = agent.get(m3u8_url).body.split("EXT-X-KEY").sort{|m,n|m.size <=> n.size}.last

                key_url = m3u8.scan(/URI="(.*)"/).flatten.first

                tses = m3u8.scan(/^.*ts_.*\.ts/)
                key = agent.get_file(key_url)
                iv = m3u8.scan(/IV=0x(.*)$/).flatten.pack("H*")
        rescue NoMethodError
                $stderr.puts $!
                raise NotFoundError.new("no radio program in #{program_id}.")
        end

        ts_file = "#{name}##{serial}.ts"
        mp3_file = "#{name}##{serial}.mp3"

        decoder = OpenSSL::Cipher.new('aes-128-cbc')
        decoder.key = key
        decoder.iv = iv

        decoder.decrypt

        mp3nize(ts_file, mp3_file) do
                open(ts_file, 'wb:ASCII-8BIT') do |ts|
                        tses.each do |file|
                                ts.write(decoder.update(agent.get_file(m3u8_url.merge(file))))
                        end
                        ts.write(decoder.final)
                end
        end
end
hibiki_media_info(agent, program_id) click to toggle source
# File lib/hibiki.rb, line 38
def hibiki_media_info(agent, program_id)
        agent.request_headers = header
        json = agent.get("https://vcms-api.hibiki-radio.jp/api/v1/programs/#{program_id}").body
        JSON.parse(json, symbolize_names: true)
end