end0tknr's kipple - 新web写経開発

http://d.hatena.ne.jp/end0tknr/ から移転します

download streaming file by rtmpdump and , convert to mp4 by ffmpeg

#!/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;

                sleep(2);
                
                ## 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 -acodec copy $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};
}