最近 Amazon Echo Dot を入手して遊んでいる @riocampos です。
Amazon Echoでニュースを聞く
Echo Dot へ向かって「Alexa、ニュース」と言うと NHK ラジオニュースの最新ニュースを流し、そのあとに天気予報を喋ってくれます。便利です。
さて、そのニュース元である NHK ラジオニュースの音声ファイルはどこにあるのかを確認してみました。
音声ファイルの場所を示すファイル
https://api.nhk.or.jp/r-news/v1/newslist.js
です。中身を見てみましょう。
radionews( {"lastBuildDate":"Fri, 02 Feb 2018 15:00:07 +09:00", "news":[ { "startdate":"Thu, 01 Feb 2018 19:00:03 +09:00", "enddate":"Thu, 01 Feb 2018 19:30:00 +09:00", "title":"夜7時NHKきょうのニュース", "soundlist":{ "sound_normal":{"size":"14376717","type":"mp3","duration":"1797","filename":"20180201190003_16134_1_1_1"}, "sound_fast":{"size":"8631693","type":"mp3","duration":"1078","filename":"20180201190003_16134_2_1_1"}, "sound_slow":{"size":"17263053","type":"mp3","duration":"2157","filename":"20180201190003_16134_3_1_2"} } }, { "startdate":"Thu, 01 Feb 2018 22:00:03 +09:00", "enddate":"Thu, 01 Feb 2018 23:10:00 +09:00", "title":"夜10時NHKジャーナル", "soundlist":{ "sound_normal":{"size":"16788717","type":"mp3","duration":"4197","filename":"20180201220003_16379_1_1_2"}, "sound_fast":{"size":"20152269","type":"mp3","duration":"2518","filename":"20180201220003_16379_2_1_1"}, "sound_slow":{"size":"20152125","type":"mp3","duration":"5037","filename":"20180201220003_16379_3_1_3"} } }, { "startdate":"Fri, 02 Feb 2018 07:00:03 +09:00", "enddate":"Fri, 02 Feb 2018 07:20:00 +09:00", "title":"朝7時NHKけさのニュース", "soundlist":{ "sound_normal":{"size":"9577485","type":"mp3","duration":"1197","filename":"20180202070003_15388_1_1_1"}, "sound_fast":{"size":"5752269","type":"mp3","duration":"718","filename":"20180202070003_15388_2_1_2"}, "sound_slow":{"size":"11504205","type":"mp3","duration":"1437","filename":"20180202070003_15388_3_1_3"} } }, { "startdate":"Fri, 02 Feb 2018 08:00:03 +09:00", "enddate":"Fri, 02 Feb 2018 08:05:00 +09:00", "title":"午前8時のNHKニュース", "soundlist":{ "sound_normal":{"size":"2376621","type":"mp3","duration":"297","filename":"20180202080003_13346_1_1_1"}, "sound_fast":{"size":"1431693","type":"mp3","duration":"178","filename":"20180202080003_13346_2_1_2"}, "sound_slow":{"size":"2863341","type":"mp3","duration":"357","filename":"20180202080003_13346_3_1_3"} } }, { "startdate":"Fri, 02 Feb 2018 12:00:03 +09:00", "enddate":"Fri, 02 Feb 2018 12:15:00 +09:00", "title":"正午のNHKニュース", "soundlist":{ "sound_normal":{"size":"7177293","type":"mp3","duration":"897","filename":"20180202120003_15633_1_1_1"}, "sound_fast":{"size":"4312269","type":"mp3","duration":"538","filename":"20180202120003_15633_2_1_1"}, "sound_slow":{"size":"8623917","type":"mp3","duration":"1077","filename":"20180202120003_15633_3_1_2"} } } ] } );
ニュースのスピードは「ふつう・ゆっくり・はやい」の三種類から選べるので、音声ファイルもそれぞれ3種類あります。
例えば「正午のNHKニュース」のふつうスピードの音声ファイルへのリンクは
http://www.nhk.or.jp/r-news/ondemand/mp3/20180202120003_15633_1_1_1.mp3?201802025155441
のような形式になっています。"正午のNHKニュース"のところの"filename"要素は"20180202120003_15633_1_1_1"になっているので、つまり
http://www.nhk.or.jp/r-news/ondemand/mp3/
に目的の"filename"要素+".mp3"としてしまえば、音声ファイルの URL が得られますね。
なお、この URL の"?"以降ですが、どうやらアクセスした日時 YYYY/MM/DD HH:MM:SS に対して
?YYYYMMDD5HHMMSS
となっているようです。他の日にセパレータ"5"が変わっていないかどうかをチェックしたいと思います*1。
Rubyで音声ファイルURLを取り出す
中身はほぼ JSON なのですが、JSON じゃなく JavaScript ファイルになっています。っていうか JSONP って言うんでしたっけ、よく分かりません。
このため、そのままでは JavaScript 以外だと取り扱いづらくなっています。JSON にしてしまいましょう。
いつものように Ruby で取り扱います。
JavaScript 的には radionews 関数として読めるようになっているので、その内側の部分を取得するようにしてしまえば JSONになりますね。
> require 'json' => true > require 'open-uri' => true > js = open('https://api.nhk.or.jp/r-news/v1/newslist.js').read; > json = js[/radionews\(([^)]+)\)/, 1]; > hash = JSON.parse(json) => {"lastBuildDate"=>"Fri, 02 Feb 2018 15:00:07 +09:00", "news"=> [{"startdate"=>"Thu, 01 Feb 2018 19:00:03 +09:00", "enddate"=>"Thu, 01 Feb 2018 19:30:00 +09:00", "title"=>"夜7時NHKきょうのニュース", "soundlist"=> {"sound_normal"=>{"size"=>"14376717", "type"=>"mp3", "duration"=>"1797", "filename"=>"20180201190003_16134_1_1_1"}, "sound_fast"=>{"size"=>"8631693", "type"=>"mp3", "duration"=>"1078", "filename"=>"20180201190003_16134_2_1_1"}, "sound_slow"=>{"size"=>"17263053", "type"=>"mp3", "duration"=>"2157", "filename"=>"20180201190003_16134_3_1_2"}}}, {"startdate"=>"Thu, 01 Feb 2018 22:00:03 +09:00", "enddate"=>"Thu, 01 Feb 2018 23:10:00 +09:00", "title"=>"夜10時NHKジャーナル", "soundlist"=> {"sound_normal"=>{"size"=>"16788717", "type"=>"mp3", "duration"=>"4197", "filename"=>"20180201220003_16379_1_1_2"}, "sound_fast"=>{"size"=>"20152269", "type"=>"mp3", "duration"=>"2518", "filename"=>"20180201220003_16379_2_1_1"}, "sound_slow"=>{"size"=>"20152125", "type"=>"mp3", "duration"=>"5037", "filename"=>"20180201220003_16379_3_1_3"}}}, {"startdate"=>"Fri, 02 Feb 2018 07:00:03 +09:00", "enddate"=>"Fri, 02 Feb 2018 07:20:00 +09:00", "title"=>"朝7時NHKけさのニュース", "soundlist"=> {"sound_normal"=>{"size"=>"9577485", "type"=>"mp3", "duration"=>"1197", "filename"=>"20180202070003_15388_1_1_1"}, "sound_fast"=>{"size"=>"5752269", "type"=>"mp3", "duration"=>"718", "filename"=>"20180202070003_15388_2_1_2"}, "sound_slow"=>{"size"=>"11504205", "type"=>"mp3", "duration"=>"1437", "filename"=>"20180202070003_15388_3_1_3"}}}, {"startdate"=>"Fri, 02 Feb 2018 08:00:03 +09:00", "enddate"=>"Fri, 02 Feb 2018 08:05:00 +09:00", "title"=>"午前8時のNHKニュース", "soundlist"=> {"sound_normal"=>{"size"=>"2376621", "type"=>"mp3", "duration"=>"297", "filename"=>"20180202080003_13346_1_1_1"}, "sound_fast"=>{"size"=>"1431693", "type"=>"mp3", "duration"=>"178", "filename"=>"20180202080003_13346_2_1_2"}, "sound_slow"=>{"size"=>"2863341", "type"=>"mp3", "duration"=>"357", "filename"=>"20180202080003_13346_3_1_3"}}}, {"startdate"=>"Fri, 02 Feb 2018 12:00:03 +09:00", "enddate"=>"Fri, 02 Feb 2018 12:15:00 +09:00", "title"=>"正午のNHKニュース", "soundlist"=> {"sound_normal"=>{"size"=>"7177293", "type"=>"mp3", "duration"=>"897", "filename"=>"20180202120003_15633_1_1_1"}, "sound_fast"=>{"size"=>"4312269", "type"=>"mp3", "duration"=>"538", "filename"=>"20180202120003_15633_2_1_1"}, "sound_slow"=>{"size"=>"8623917", "type"=>"mp3", "duration"=>"1077", "filename"=>"20180202120003_15633_3_1_2"}}}]}
目的の hash が得られました。
正午のニュースの音声ファイルURLを取得
まずは正午のニュースのハッシュ要素 noon を得ましょう。
> noon = hash["news"].find { |item| item["title"]["正午"] } => {"startdate"=>"Fri, 02 Feb 2018 12:00:03 +09:00", "enddate"=>"Fri, 02 Feb 2018 12:15:00 +09:00", "title"=>"正午のNHKニュース", "soundlist"=> {"sound_normal"=>{"size"=>"7177293", "type"=>"mp3", "duration"=>"897", "filename"=>"20180202120003_15633_1_1_1"}, "sound_fast"=>{"size"=>"4312269", "type"=>"mp3", "duration"=>"538", "filename"=>"20180202120003_15633_2_1_1"}, "sound_slow"=>{"size"=>"8623917", "type"=>"mp3", "duration"=>"1077", "filename"=>"20180202120003_15633_3_1_2"}}}
定時ニュースは5分間ですが、けさのニュースは20分、正午のニュースは15分、(夜7時の)きょうのニュースは30分、NHK ジャーナルは10分間なので、これらのニュースを聞くことが多いかと思います。それぞれ"けさ"、"正午"、"きょう"、"ジャーナル"を Array#find
のピックアップ要素にしてやれば抜き出せますね。
続いて通常スピードの音声ファイルの"filename"要素を得ましょう。
> normal_speed_file = noon["soundlist"]["sound_normal"]["filename"] => "20180202120003_15633_1_1_1"
では音声ファイルのURLを出してみましょう。
> base_url = "http://www.nhk.or.jp/r-news/ondemand/mp3/"; > mp3 = ".mp3"; > url = base_url + normal_speed_file + mp3 => "http://www.nhk.or.jp/r-news/ondemand/mp3/20180202120003_15633_1_1_1.mp3"
これで目的の URL が得られました。めでたしめでたし。
*1:2/2は5、2/4は0