最近 Amazon Echo Dot を入手して遊んでいる @riocampos です。
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 が得られました。めでたしめでたし。