#!/usr/local/bin/perl use strict; use warnings; use utf8; use Encode; use FindBin; use LWP::UserAgent; use XML::Simple; use Data::Dumper; ## NHKゴガク https://www2.nhk.or.jp/gogaku/english/ my $MUSIC_OUT_DIR = $FindBin::Bin; my $MUSIC_LIST_ROOT = 'https://www2.nhk.or.jp/gogaku/st/xml'; my $MUSIC_LIST_CHANNELS = {english=>[ 'enjoy', #エンジョイ・シンプル・イングリッシュ 'basic1', #基礎英語1 'basic2', #基礎英語2 'basic3', #基礎英語3 'kaiwa', #ラジオ英会話 'timetrial', #英会話タイムトライアル 'kouryaku', #攻略!英語リスニング 'business1', #入門ビジネス英語 'business2', #実践ビジネス英語 ], }; # There are some paramaters # in https://www2.nhk.or.jp/gogaku/st/flash/sound/ggk_str_pc3.swf , below. # You can extract from swf file # by Flare ( http://www.nowrap.de/flare.html ). my $MUSIC_FILE_ROOT = 'rtmpe://flvs.nhk.or.jp:1935/ondemand'; my $MUSCI_FILE_SUB_PATH = 'mp4:flv/gogaku-stream/mp4'; my $RTMPDUMP_CMD = '/usr/local/bin/rtmpdump'; my $FFMPEG_CMD = '/usr/bin/ffmpeg'; main(@ARGV); sub main { my (@cmd_args) = @_; for my $lang (sort keys %$MUSIC_LIST_CHANNELS ){ for my $channel (@{$MUSIC_LIST_CHANNELS->{$lang}}){ ## DOWNLOAD CHANNEL INFOS my $channel_infos = get_music_list($lang,$channel); next if(ref($channel_infos) ne 'ARRAY' or scalar(@$channel_infos) ==0 ); my $out_dir = get_output_dir($lang,$channel); for my $channel_info ( @$channel_infos ){ ## DOWNLOAD MUSIC FILE by rtmpdump my $music_file = get_music_file($channel_info, $out_dir); next unless $music_file; ## CORRECT by ffmpeg my $mp4_file = conv_to_mp4($music_file); print Encode::encode('utf8',"DONE $mp4_file"),"\n"; unlink $music_file or die "$music_file$!"; } } } } sub conv_to_mp4 { my($org_file) = @_; my $new_file = "$org_file.mp4"; my $cmd = "$FFMPEG_CMD -loglevel error -y -i $org_file $new_file"; my $fh; unless( open $fh, '-|', $cmd ){ print STDERR Encode::encode('utf8',"fail open $cmd"),"\n"; return; } unless( close($fh) ){ print STDERR Encode::encode('utf8',"fail close $cmd"),"\n"; return; } return $new_file; } sub get_output_dir { my($lang,$channel) = @_; my $out_dir_0 = join('/',$MUSIC_OUT_DIR,$lang); if(not -d $out_dir_0){ mkdir $out_dir_0 or die "fail mkdir $out_dir_0 $!"; } return $out_dir_0; # my $out_dir = join('/',$MUSIC_OUT_DIR,$lang,$channel); # if(not -d $out_dir ){ # mkdir $out_dir or die "fail mkdir $out_dir $!"; # } # return $out_dir; } sub get_music_file { my ($channel_info, $out_dir) = @_; my $url = join('/', $MUSIC_FILE_ROOT, $MUSCI_FILE_SUB_PATH, $channel_info->{file}); my $out_file = join('/', $out_dir, "$channel_info->{title}_$channel_info->{hdate}"); my $cmd = "$RTMPDUMP_CMD --quiet -r $url -o $out_file"; my $fh; unless( open $fh, '-|', $cmd ){ print STDERR Encode::encode('utf8',"fail open $cmd"),"\n"; return; } unless( close($fh) ){ print STDERR Encode::encode('utf8',"fail close $cmd"),"\n"; return; } return $out_file; } sub get_music_list { my ($lang, $channel) = @_; my $url = join('/',$MUSIC_LIST_ROOT,$lang, $channel,'listdataflv.xml'); my $ua = LWP::UserAgent->new; my $res = $ua->get($url); if(not $res->is_success ) { print STDERR $res->status_line , " $url\n"; return []; } my $xml_content = $res->content; $xml_content = Encode::decode('utf8',$xml_content); my $ret = XML::Simple::XMLin($xml_content); return $ret->{music}; }