Advertisement
riocampos

gogakuondemand.rb (v3.3)

Aug 6th, 2013
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 5.82 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2. # coding: utf-8
  3.  
  4. # 全講座DLで約20分、約557MB(mp4からmp3への変換はPC能力に依存)
  5.  
  6. require 'nokogiri'
  7. require 'net/https'
  8. require 'fileutils'
  9. require 'kconv'
  10.  
  11. def check_ffmpeg_status
  12.   IO.popen('ffmpeg -version 2>&1') do |pipe|
  13.     status = pipe.inject('') { |total, line| total << line }
  14.     true if status =~ /openssl|gnutls/
  15.   end
  16. end
  17.  
  18. def load_pref
  19.   set_script_dir
  20.   load_pref_file
  21.   load_subjects_file
  22.   set_save_file_dest_dir
  23. end
  24.  
  25. def set_script_dir
  26.   @script_dir = File.dirname(File.expand_path(__FILE__))
  27.   push_dir(@script_dir)
  28. end
  29.  
  30. def load_pref_file
  31.   load 'pref.rb'
  32.   @select_subjects_jp = []
  33.   pref.each do |k,v|
  34.     @select_subjects_jp << k if v
  35.   end
  36. end
  37.  
  38. def load_subjects_file
  39.   load 'subjects.rb'
  40.   @select_subjects = []
  41.   @subject_urls = subject_urls
  42.   @subjects_jp  = subjects_jp
  43.   @select_subjects_jp.each do |sub_jp|
  44.     @select_subjects << @subjects_jp[sub_jp]
  45.   end
  46. end
  47.  
  48. def set_save_file_dest_dir
  49.   if save_file_dest_dir
  50.     working_dir = File.expand_path(File.path(save_file_dest_dir))
  51.   else
  52.     working_dir = File.expand_path(File.dirname('.'))
  53.   end
  54.   Dir.mkdir(working_dir) unless File.directory?(working_dir)
  55.   push_dir(working_dir)
  56. end
  57.  
  58. def is_win?
  59.   RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|cygwin|bccwin/ ? true : false
  60. end
  61.  
  62. def print_download_subjects
  63.   download_subjects = @select_subjects_jp * "、"
  64.   print "ダウンロードする語学講座:#{download_subjects}\n"
  65. end
  66.  
  67. def https_body(url)
  68.   uri = URI.parse(url)
  69.   https = Net::HTTP.new(uri.host, uri.port)
  70.   https.use_ssl = true
  71.   https.ssl_version = :TLSv1
  72.   https.verify_mode = OpenSSL::SSL::VERIFY_NONE
  73.   if uri.query
  74.     https.get(uri.path + '?' + uri.query).body
  75.   else
  76.     https.get(uri.path).body
  77.   end
  78. end
  79.  
  80. def get_source_urls
  81.   data_hash ={}
  82.   @select_subjects.each do |sub|
  83.     url = "https://cgi2.nhk.or.jp/gogaku/#{@subject_urls[sub]}/listdataflv.xml"
  84.     doc = Nokogiri.XML(https_body(url))
  85.     data_array = doc.xpath("/musicdata/music")
  86.     date = data_array.map { |d| d["hdate"].scan(/(\d+)(\d+)/)} \
  87.           .map{ |dt| "#{record_year(dt[0][0].to_i)}_%02d_%02d" % dt.flatten}
  88.     data_hash[sub] = {kouza: data_array[0].values[2]}
  89.     data_array.each_with_index do |d, i|
  90.       data_hash[sub][{date: date[i]}] = data_array[i].values[4]
  91.     end
  92.   end
  93.   data_hash
  94. end
  95.  
  96. def record_year(record_month)
  97.   now = Time.now
  98.   this_month = now.month
  99.   this_year = now.year
  100.   @record_year = this_month - record_month < 0 ? this_year - 1 : this_year
  101. end
  102.  
  103. def prepare_download_each_subject(key, value)
  104.   @subject = value[:kouza]
  105.   print "\n講座名:#{@subject}\n"
  106.   subject_dir = File.join(current_dir, key.to_s + "/")
  107.   Dir.mkdir(subject_dir) unless File.directory?(subject_dir)
  108.   subject_dir
  109. end
  110.  
  111. def each_date_process(key, value)
  112.   value.each do |k, v|
  113.     next if k == :kouza
  114.     @metadata = {}
  115.     date = k[:date]
  116.     @metadata[:subject]   = @subject
  117.     @metadata[:title]     = "#{key}_#{date}"
  118.     @metadata[:title_jp]  = "#{@subject}_#{date}"
  119.     @metadata[:genre]     = "Speech"
  120.     @metadata[:create]    = "NHK"
  121.     @metadata[:year]      = @record_year.to_s
  122.     puts "日付:#{date}"
  123.     download_ondemand_file(v)
  124.   end
  125. end
  126.  
  127. def download_ondemand_file(subject_code)
  128.   master_m3u8 = "https://nhk-vh.akamaihd.net/i/gogaku-stream/mp4/#{subject_code}/master.m3u8"
  129.   title_path_jp = File.join(current_dir, @metadata[:title_jp])
  130.   if File.exists?("#{title_path_jp}.mp3") || File.exists?("#{title_path_jp}.mp3".tosjis)
  131.     puts "ダウンロード済み"
  132.     return
  133.   end
  134.   command_ffmpeg = %Q[ffmpeg -y -i #{master_m3u8} -ab 64k -metadata album="#{@metadata[:subject]}" -metadata title="#{@metadata[:title_jp]}" -metadata genre="#{@metadata[:genre]}" -metadata artist="#{@metadata[:create]}" -metadata date="#{@metadata[:year]}" -id3v2_version 3 "#{title_path_jp}.mp3" 2>&1]
  135.   command_ffmpeg = command_ffmpeg.tosjis if is_win?
  136.   print "ダウンロード中...\n"
  137.   IO.popen(command_ffmpeg) do |pipe|
  138.     duration = nil
  139.     progress = 0
  140.     pipe.each("r") do |each_line|
  141.       line =  is_win? ?
  142.               each_line.tosjis :
  143.               each_line
  144.       counter_duration_match = line.scan(/: (\d{2}):(\d{2}):(\d{2}).(\d{2}),/)
  145.       unless counter_duration_match == []
  146.         duration = time_counter_to_sec(counter_duration_match)
  147.       end
  148.       counter_progress_match = line.scan(/time=(\d{2}):(\d{2}):(\d{2}).(\d{2})/)
  149.       unless counter_progress_match == []
  150.         progress = time_counter_to_sec(counter_progress_match)
  151.         progress = duration if duration && progress > duration
  152.       end
  153.       if duration
  154.         progress_bar(progress, duration, "秒")
  155.       end
  156.     end
  157.     print "\n"
  158.   end
  159. end
  160.  
  161. def time_counter_to_sec(counter)
  162.   ((counter[0][0].to_i * 360000 + counter[0][1].to_i * 6000 + counter[0][2].to_i * 100 + counter[0][3].to_i) / 100.0).round
  163. end
  164.  
  165. def progress_bar(progress, max, unit)
  166.   max_digits = max.to_s.size
  167.   print "\r" + "[#{'%-50s' % ('*' * (progress.to_f / max * 50).to_i)}] #{'%*d' % [max_digits, progress]} / #{max} #{unit}"
  168. end
  169.  
  170. def current_dir
  171.   @pwd
  172. end
  173.  
  174. def push_dir(dir)
  175.   @pwds ||= []
  176.   @pwds.push(dir)
  177.   @pwd = @pwds.last
  178.   Dir::chdir(@pwd)
  179.   @pwd
  180. end
  181.  
  182. def pop_dir
  183.   @pwds.pop
  184.   @pwd = @pwds.last
  185.   Dir::chdir(@pwd)
  186.   @pwd
  187. end
  188.  
  189. def gogaku_on_demand
  190.   unless check_ffmpeg_status
  191.     print "gogakuondemand.rbを実行するには\nOpenSSLまたはGnuTLSに対応しているFFmpegが必要です。\nFFmpegの設定を見直してください。\n"
  192.     return
  193.   end
  194.   load_pref
  195.   print_download_subjects
  196.   data_hash = get_source_urls
  197.   data_hash.each do |key, value|
  198.     subject_dir = prepare_download_each_subject(key, value)
  199.     push_dir(subject_dir)
  200.     each_date_process(key, value)
  201.     pop_dir
  202.   end
  203.   puts "作業終了"
  204. end
  205.  
  206. gogaku_on_demand
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement