From ef4800e8f4ed1c01f64e8c3f6a21f683dc6fba2b Mon Sep 17 00:00:00 2001 From: satomichan Date: Sun, 28 Sep 2025 17:44:19 +0900 Subject: [PATCH] =?utf8?q?=E3=83=AA=E3=83=88=E3=83=A9=E3=82=A4=E6=A9=9F?= =?utf8?q?=E8=83=BD=E3=82=92=E8=BF=BD=E5=8A=A0.=20fm=20=E3=81=97=E3=81=8B?= =?utf8?q?=E9=8C=B2=E9=9F=B3=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=E3=82=88?= =?utf8?q?=E3=81=86=E3=81=AB=E3=81=AA=E3=81=A3=E3=81=A6=E3=81=84=E3=81=9F?= =?utf8?q?=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- radiru2-dl.pl | 155 +++++++++++++++++++++++++++++++++++++++++++++-- rec-nhk-radio.pl | 2 +- 2 files changed, 151 insertions(+), 6 deletions(-) diff --git a/radiru2-dl.pl b/radiru2-dl.pl index e445084..ed5480d 100755 --- a/radiru2-dl.pl +++ b/radiru2-dl.pl @@ -40,19 +40,66 @@ use HTTP::Tiny; #sudo apt install libhttp-tiny-perl use Encode; use XML::XPath; #sudo apt install libxml-xpath-perl use XML::XPath::XMLParser; +use Getopt::Long qw(:config posix_default no_ignore_case gnu_compat); +#use Time::Piece; +use IPC::Open3 qw(open3); +use Symbol qw(gensym); +sub dp; my $config_url = 'https://www.nhk.or.jp/radio/config/config_web.xml'; -my($station, $duration, $output) = @ARGV; + +# オプション解析 +my $is_check_mode = 0; +my $is_verbose_mode = 0; +my $retry = 5; +GetOptions('check|c' => \$is_check_mode, + 'verbose|v' => \$is_verbose_mode, + 'retry|r=i' => \$retry, + ); +my($station, $req_duration, $output) = @ARGV; + +#HLS URL 取得 $station = 'tokyo-r2' if $station eq 'r2'; -my($area, $wave) = $station =~ /^([a-z]+)-([a-z]+)$/ or die "Bad Station Error: $station"; +my($area, $wave) = $station =~ /^([a-z]+)-([a-z0-9]+)$/ or die "Bad Station Error: $station"; +dp "area: $area, wave: $wave"; my $hls_url = get_hls_url($config_url, $area, $wave); +dp "hls_url: $hls_url"; + +#録音が求められている秒数 +my $req_duration_sec = duration2sec($req_duration); + + #録音実行 -exit system('ffmpeg', '-fflags', '+discardcorrupt', #破損したフレームを破棄 - '-loglevel', 'fatal', #ログレベル 致命的なもののみ出力 - '-i', $hls_url, '-t', $duration, $output); +exit if $is_check_mode; +my $total_recorded_sec = 0; #録音済みの秒数 +my $ret; +for(my $try = 0; $try <= $retry; $try++){ + #出力ファイル名 + my $numbered_filename = gen_filename($output, $try); + + #今回録音時間 + my $this_duration = sec2duration($req_duration_sec - $total_recorded_sec); + + dp "try: $try numbered_filename: $numbered_filename this_duration: $this_duration"; + + $ret = system('ffmpeg', '-fflags', '+discardcorrupt', #破損したフレームを破棄 + '-loglevel', 'fatal', #ログレベル 致命的なもののみ出力 + '-y', #Overwrite -> Yes + '-i', $hls_url, '-t', $this_duration, $numbered_filename); + + #出力ファイルが存在する? + next unless -f $numbered_filename; + + #時間どおりに録音されている? + my $this_time_rec_sec = get_rec_duration_by_file($numbered_filename); dp "this_time_rec_sec : $this_time_rec_sec"; + $total_recorded_sec += $this_time_rec_sec; dp "total_recorded_sec: $total_recorded_sec"; + last if ($req_duration_sec <= $total_recorded_sec); +} + +exit $ret; @@ -78,3 +125,101 @@ sub get_hls_url { } + + +#ffmpeg で録音時間を取得 (秒数で返す) +sub get_rec_duration_by_file { + my($file) = @_; + my $err = gensym; + my $pid = open3(undef, undef, $err, "ffmpeg -i $file"); + my $info = do { local $/; <$err> }; + waitpid($pid, 0); + + if ($info =~ /Duration: (\d+:\d{2}:\d{2})\./) { + return duration2sec($1); + } + + return; +} + + + +sub duration2sec { + my($dur_str) = @_; + + my $total_sec = 0; + my $base = 1; + + my @units = split(/:/, $dur_str); + foreach my $an_unit (reverse @units) { + die "Bad Duration Format Error: $dur_str" unless $an_unit =~ /^\d+$/; + $total_sec += $base * $an_unit; + $base *= 60; + } + + return $total_sec; +} + + + +sub sec2duration { + my($sec) = @_; + + my $min += int($sec / 60); + $sec = $sec % 60; + + my $hr = int($min / 60); + $min = $min % 60; + + return sprintf('%d:%02d:%02d', $hr, $min, $sec); +} + + + +sub gen_filename { + my($orig_name, $num) = @_; + + return $orig_name if $num == 0; + + my $base = $orig_name; + my $ext = ''; + if( $orig_name =~ /^(.+?)(\.[a-z0-9]+)$/ ){ + $base = $1; + $ext = $2; + } + + return "${base}_${num}${ext}"; +} + + + +#DEBUG PRINT +sub dp { + my $msg = join('', @_); + print STDERR "$msg\n" if $is_verbose_mode; +} + + +__END__ +dp gen_filename("aaaaa.mp3.mp4", 1); +dp gen_filename("aaaaa.mp3.mp4", 2); +dp gen_filename("dddd/ccccc.eee/aaaaa.mp3", 1); +dp gen_filename("dddd/ccccc.eee/aaaaa.mp3", 2); +dp gen_filename("aa/aaa", 1); +dp gen_filename("aa/aaa", 2); + + +sub get_end_time { + my($dur) = @_; + + my $now = localtime; + dp "now: ". $now->datetime; + + my $dur_sec = duration2sec($dur); + dp "dur_sec: $dur_sec"; + + my $end_time = $now + $dur_sec; + dp "end_time: ". $end_time->datetime; + + return $end_time; +} diff --git a/rec-nhk-radio.pl b/rec-nhk-radio.pl index 57ae68a..84190f8 100755 --- a/rec-nhk-radio.pl +++ b/rec-nhk-radio.pl @@ -144,7 +144,7 @@ my $duration = get_duration_string($min, $end_margin_sec); # コマンド構築 -my $rec_cmd = "cd $ENV{RADIKO_SAVE_TO}; $SLEEP $offset_time_sec; $DL $station $duration $mp3; $CHMOD $FILE_PERMISSION $mp3; "; +my $rec_cmd = "cd $ENV{RADIKO_SAVE_TO}; $SLEEP $offset_time_sec; $DL $station $duration $mp3; $CHMOD $FILE_PERMISSION $file_name_base*.mp3; "; my $at_time = sprintf('%d:%02d %02d.%02d.%02d', $time_h, $time_m, $d, $m, ($y - int($y/100)*100 ) ); my $cmd = qq{$ECHO -e '$BASH << EOC\\n$rec_cmd\\nEOC' | $AT "$at_time"}; -- 2.43.0