From: longinus Date: Sun, 19 Feb 2012 15:33:34 +0000 (+0000) Subject: try Ajax-powered popup window of mp4 files on mode=list X-Git-Url: http://git.osdn.net/view?p=rec10%2Frec10-git.git;a=commitdiff_plain;h=d4e8f5397a0f4731f8307dd35bed92c4ada59934 try Ajax-powered popup window of mp4 files on mode=list git-svn-id: svn+ssh://svn.sourceforge.jp/svnroot/rec10@927 4e526526-5e11-4fc0-8910-f8fd03428081 --- diff --git a/rectool/trunk/rectool.pl b/rectool/trunk/rectool.pl index e1b38b9..7a9491d 100755 --- a/rectool/trunk/rectool.pl +++ b/rectool/trunk/rectool.pl @@ -1,2356 +1,2407 @@ -#!/usr/bin/perl -# -d:SmallProf -#use Perl6::Slurp; -#use XML::Simple; -#use CGI; -#use CGI::Lite; -#use Date::Manip; -#Date_Init("TZ=JST","ConvTZ=JST"); -#use SVG; -#use KCatch; -use warnings; -use Algorithm::Diff qw(LCS); -use Archive::Zip; -use CGI; -use CGI::Carp qw( fatalsToBrowser warningsToBrowser ); -use Config::Simple; -use Data::Dumper; -use Date::Simple; -use DateTime; -use DBI; -use MIME::Base64; -use Perl6::Slurp; -use Sort::Naturally; -use Time::Piece; -use Time::Seconds; -use Time::HiRes; -use Tie::IxHash; -#require SVG Time::Simple XML::Atom Encode Text::Ngram List::Compare List::Util -use utf8; -#%DB::packages = ( 'main' => 1 ); - - -################ バージョン定義 ################ - - -my $rectool_version = 101; - - -################ 初期化ここから ################ - - -my $tz = DateTime::TimeZone->new( name => 'local' ); -my $hires = Time::HiRes::time(); - -my $cfg = new Config::Simple; -if ( -e 'rec10.conf' ) { - $cfg->read( 'rec10.conf' ); -} -elsif ( -e '/etc/rec10.conf' ) { - $cfg->read( '/etc/rec10.conf' ); -} -else { - die 'rec10.confが見つかりません。'; -} - -my $sql = $cfg->param( 'db.db' ); - -if ( $sql eq 'MySQL' ) { - my $name = $cfg->param( 'db.mysql_dbname' ); - my $host = $cfg->param( 'db.mysql_host' ); - my $port = $cfg->param( 'db.mysql_port' ); - my $user = $cfg->param( 'db.mysql_user' ); - my $pass = $cfg->param( 'db.mysql_passwd' ); - $dbh = DBI->connect("dbi:mysql:$name:$host:$port", $user, $pass, { - AutoCommit => 1, - RaiseError => 1, - mysql_enable_utf8 => 1, # only availavle for MySQL - }); - $dbh->do( 'SET NAMES utf8' ); -} - -my $rec10_version = eval { - $dbh->selectrow_array( "SELECT version FROM in_status " ); -}; - -my $HTML; - -$HTTP_HEADER = "Content-Type: text/html\n\n"; -$HTML .= < - - -Rec10%HTML_TITLE_OPT% - - - - - - -%REFRESH% -%SCRIPT% -%CSS% - - -%HTML_HEADER% -EOM - -my ( $user, $pass, $auth ); -( $user, $pass ) = eval { - $dbh->selectrow_array( "SELECT webuser, webpass FROM in_settings " ); -}; - -if ( $user and $pass ) { - if ( $ENV{'HTTP_AUTHORIZATION'} ) { - my ( $base64 ) = $ENV{'HTTP_AUTHORIZATION'} =~ /Basic\s(.*)/; - if ( $base64 eq encode_base64( "$user:$pass" ) ) { - $auth = 1; - } - else { - $auth = 0; - } - } - else { - $auth = 0; - } -} -else { - $auth = 1; -} - -if ( !$auth ) { - my ( $base64 ) = $ENV{'REMOTE_USER'} =~ /Basic (.*)/; - $HTTP_HEADER = qq {Status: 401 Authorization Required\nWWW-Authenticate: Basic realm="Protected Rec10 $ENV{'HTTP_AUTHORIZATION'}"\n} . $HTTP_HEADER; - goto end; -} - -if ( $rec10_version != $rectool_version ) { - $HTML .= qq {
\n}; - - if ( $rec10_version > $rectool_version ) { - $HTML .= qq {Rec10本体のバージョンが新しいため、実行できません。
\n}; - $HTML .= qq {rectoolのバージョンアップを行ってください。
\n}; - } - - if ( $rec10_version < $rectool_version ) { - $HTML .= qq {Rec10本体のバージョンが古いため、実行できません。
\n}; - $HTML .= qq {Rec10のバージョンアップを行ってください。
\n}; - } - - $HTML .= qq {Rec10のバージョンは$rec10_version 、rectoolのバージョンは$rectool_version です。
\n}; - $HTML .= qq {公式ページ\n}; - goto end; -} - -$q = new CGI; -%params = $q->Vars; -$mode = $params{ 'mode' }; -$mode_sub = $params{ 'mode_sub' }; - -################ %chtxt_chnameの準備 ################ - -my %chtxt_chname; -my %chtxt_0_chname; -tie %chtxt_0_chname, 'Tie::IxHash'; - -my $ary_ref = $dbh->selectall_arrayref( - "SELECT chtxt, chname, ch, bctype FROM epg_ch - WHERE visible = 1" -); - -%chtxt_chname = map { $_->[0], $_->[1] } @{$ary_ref}; - -# NHK BS 1/2/hiをBS/CSから除外(101-103) - by 2011/04 -# te: 地上波、BSのNHK以外 -# bc: BSのNHK、CS -my @te_ary = grep $_->[0]=~ /^\d|BS_(?!(10|19)[1-3])/, @{$ary_ref}; -my @bc_ary = grep $_->[0]!~ /^\d|BS_(?!(10|19)[1-3])/, @{$ary_ref}; - -# teの操作(まとめる) -foreach my $line ( @te_ary ) { - # te xx_yyyy(chtxt) -> xx(ch) - if ( $line->[3] =~ /te/ ) { - push @{ $chtxt_0_chname{ $line->[2] . '_0'} }, $line->[1]; - } - else { - push @{ $chtxt_0_chname{'BS_' . $line->[2] } }, $line->[1]; - } -} -foreach my $key ( keys %chtxt_0_chname ) { - my @chname = @{ $chtxt_0_chname{$key} }; - if ( @chname >= 2 ) { - # 2つ以上ある場合 - my @tmp = map { my @ary = split //, $_; \@ary } @chname; - # 1つ目と2つ目のみ比較 - # FIXME: すべてを比較するべき - $chtxt_0_chname{$key} = join '', LCS( $tmp[0], $tmp[1] ); - } - else { - # 1つしかない場合 - $chtxt_0_chname{$key} = $chname[0]; - } -} - -# bs/csの操作(そのまま) -foreach my $line ( @bc_ary ) { - $chtxt_0_chname{$line->[0]} = $line->[1]; -} -undef $ary_ref; - - -################ 定数宣言 ################ - - -tie %type, 'Tie::IxHash'; -%type = ( - 'search_everyday' => '隔日検索', - 'search_today' => '当日検索', - 'reserve_flexible' => '浮動予約', - 'reserve_fixed' => '確定予約', - - 'reserve_running' => '録画途中', - - 'convert_b25_ts' => '解読予約', - 'convert_b25_ts_running' => '解読途中', - 'convert_b25_ts_miss' => '解読失敗', - - 'convert_ts_mp4' => '縁故予約', - 'convert_ts_mp4_running' => '縁故於鯖', - 'convert_ts_mp4_network' => '縁故於網', - 'convert_ts_mp4_finished' => '縁故完了', - - 'convert_avi_mkv' => '変換旧露', - 'convert_avi_mp4' => '変換旧四', - 'convert_mkv_mp4' => '変換露四', - 'convert_mkv_mp4_runnings' => '換途露四', - - 'auto_suggest_dec' => '予測解読', - 'auto_suggest_enc' => '予測縁故', - 'auto_suggest_avi2fp' => '予測旧四', - 'auto_suggest_ap2fp' => '予測露四', - - 'move_end' => '移動完了', -); - -%type_suggest = ( - 'auto_suggest_dec' => 'convert_b25_ts', - 'auto_suggest_enc' => 'convert_ts_mp4', - 'auto_suggest_avi2fp' => 'convert_avi_mkv', - 'auto_suggest_ap2fp' => 'convert_mp4_mkv', -); - -%color = ( - 'search_everyday' => '#8B008B', - 'search_today' => '#8B008B', - 'reserve_flexible' => '#4169E1', - 'reserve_fixed' => '#4169E1', - 'reserve_running' => '#FF8C00', - 'convert_b25_ts' => '#CD5C5C', - 'convert_b25_ts_running' => '#DC143C', - 'convert_ts_mp4' => '#32CD32', - 'convert_ts_mp4_running' => '#2E8B57', - 'convert_ts_mp4_network' => '#808000', - - 'other' => '#A0A0A0', -); - -$type_user_made = "( 'search_everyday', 'search_today', 'reserve_flexible', 'reserve_fixed', 'reserve_running' )"; - -tie %category, 'Tie::IxHash'; -%category = ( - 'news' => { name => 'ニュース・報道' , color => '#ff0000' }, - 'sports' => { name => 'スポーツ' , color => '#ff8000' }, - 'information' => { name => '情報' , color => '#ffff00' }, - 'drama' => { name => 'ドラマ' , color => '#80ff00' }, - 'music' => { name => '音楽' , color => '#00ff00' }, - 'variety' => { name => 'バラエティ' , color => '#00ff80' }, - 'cinema' => { name => '映画' , color => '#00ffff' }, - 'anime' => { name => 'アニメ・特撮' , color => '#0080ff' }, - 'documentary' => { name => 'ドキュメンタリー・教養' , color => '#0000ff' }, - 'stage' => { name => '演劇' , color => '#8000ff' }, - 'hobby' => { name => '趣味・実用' , color => '#ff00ff' }, - 'etc' => { name => 'その他' , color => '#ff0080' }, -); - -################ 初期化ここまで ################ - - -################ mode=schedule ################ - -if ( $mode eq 'schedule' ) { - - $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Viewer/; - #$HTML =~ s|%REFRESH%||; - $css = < - td { - white-space: nowrap; - } - -EOM - $css =~ s/^\t{2}//gm; - $HTML =~ s/%CSS%/$css/; - - my $order = $params{ 'order' }; - my $extra = $params{ 'extra' }; - if ( $order ne 'id' ) { - $order = 'btime'; - } - $reverse_extra = $extra ? '' : '&extra=1'; - $forward_order = $order eq 'btime' ? '' : '&order=id'; - - my $ary_ref = $dbh->selectall_arrayref( - "SELECT id, type, timeline.chtxt, epg_ch.chname, title, btime, etime, opt, deltaday, deltatime, - epgtitle, epgbtime, epgetime, epgexp, epgduplicate, epgchange, counter - FROM timeline - LEFT OUTER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt - ORDER BY $order" - , {Slice=>{}}); - - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - foreach my $line ( @{ $ary_ref } ) { - - $type = $type{$line->{type}} || $line->{type}; - if ( $line->{type} =~ /^search/ ) { - $type = qq {$type}; - $line->{deltaday} = qq {空} if ( !$line->{deltaday} && $line->{type} eq 'search_everyday' ); - $line->{deltatime} = qq {空} if ( !$line->{deltatime} ); - } - else { - my $color = $color{$line->{type}} ? $color{$line->{type}} : $color{'other'}; - $type = qq {$type}; - } - # 地上波の場合、xx_yyyをxx_0に置換する - ( $line->{chtxt_0} = $line->{chtxt} ) =~ s/(\d+)_/$1_0/; - # chnameが無いとき(移動縁故など)、chtxtを代わりに使う - $line->{chname} = - $line->{chname} || - $chtxt_0_chname{$line->{chtxt}} || - $chtxt_0_chname{$line->{chtxt_0}}; - if ( !$line->{chname} ) { - # chnameが無いとき、リンクを作成しない - $line->{chname} = $line->{chtxt}; - $line->{chname_link} = qq {$line->{chname}}; - } - else { - $line->{chname_link} = qq {$line->{chname}}; - } - $line->{title} = 'タイトルなし' if ( !$line->{title} ); - $line->{tr_style} = ''; - $line->{title_2} = ''; - my $unix_b = str2datetime( $line->{btime} ); - my $unix_e = str2datetime( $line->{etime} ); - - my $btime = $unix_b->strftime( '%Y%m%d%H%M%S' ); - my $etime = $unix_e->strftime( '%Y%m%d%H%M%S' ); - if ( $extra and $line->{type} =~ /^search_|^reserve_(?!running)/ ) { - #my @ary = $dbh->selectrow_array( - # "SELECT title, exp FROM epg_timeline - # WHERE channel = '$line->{chname}' - # AND start = '$btime' - # AND stop = '$etime' "); - #my @ary = ( $line->{epgtitle}, $line->{epgexp} ); - my ( $epgtitle, $epgexp ) = ( $line->{epgtitle}, $line->{epgexp} ); - - if ( $epgtitle ) { - $epgtitle =~ s/無料≫//; - - if ( $epgtitle ne $line->{title} ) { - # epgtitleとtitleが一致しない - # []に囲まれた部分を除去して比較 - my @brackets = $line->{title} =~ /(\[.+\])+/; - my $epgtitle_nobrackets = $epgtitle; - my $title_nobrackets = $line->{title}; - if ( @brackets && $epgtitle =~ /(\[.+\])+/ >= @brackets ) { - foreach ( @brackets ) { - $epgtitle_nobrackets =~ s/\Q$_\E//; - } - } - $title_nobrackets =~ s/(\[.+\])+//; - if ( !scalar $epgtitle_nobrackets =~ s/\Q$title_nobrackets\E// ) { - # epgtitleにtitleが含まれていない - my $href = qq {自動検索}; - $epgtitle = qq {$epgtitle■$href■}; - } - else { - # epgtitleにtitleが含まれている - $epgtitle = $epgtitle_nobrackets; - } - } - else { - # epgtitleとtitleが一致している - $epgtitle = '説明'; - } - - $line->{title_2} = qq {
$epgtitle
}; - } - else { - # epgtitleがない - my $href = qq {自動検索}; - $line->{title_2} = qq {■$href■}; - $line->{tr_style} = qq {style="background-color: #A0A0A0"}; - } - } - - my ( $begin, $end, $diff ) = &str2readable( $unix_b, $unix_e ); - - my $hr = ''; - if ( - $line->{type} eq 'reserve_running' - && - $unix_b->epoch <= time && time <= $unix_e->epoch - ) - { - $percent = int( ( 100 * ( time - $unix_b->epoch ) ) / ( $unix_e->epoch - $unix_b->epoch ) ); - $hr .= qq {
}; - } - - $line->{title} = qq {$line->{title}}; - #$line->{title} = qq {
$line->{title}
} if ( $line->{title_2} ); - $HTML .= qq {{tr_style}>\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n\n\n\n}; - $HTML .= qq {\n}; - } - $HTML .= qq {
■IDタイプチャンネルタイトル開始時刻終了時刻録画時間オプションdddt残り
$line->{id}$type$line->{chname_link}$line->{title}$line->{title_2}$begin$end$hr$diff$line->{opt}$line->{deltaday}$line->{deltatime}$line->{counter}
\n}; - #$HTML .= qq {\n}; - $HTML .= qq {\n
\n
\n}; - goto end; -} - -################ mode=graph ################ - -if ( $mode eq 'graph' ) { - - my $date = $params{ 'date' }; - - if ( $date ) - { - print "Content-Type: image/svg+xml\n\n"; - - require SVG; - $date = Date::Simple->new( split /-/, $date ); - $graph_bgn = $date->format('%Y-%m-%d'); - $graph_end = $date->next->format('%Y-%m-%d'); - $day = $date->day; - $today = $date eq Date::Simple->today() ? 1 : 0; - - $tuner{terrestrial} = $cfg->param( 'env.te_max' );# 2; - $tuner{satellite} = $cfg->param( 'env.bscs_max' );# 2; - $tuner{all} = $tuner{terrestrial} + $tuner{satellite}; - $hours = 24; - $width = 30 * $hours; - my %category_color = map { $_->{name}, $_->{color} } values %category; - - $svg = new SVG( width => 820, height => $tuner{all} * 20 + 40 ); - $svg->rectangle( 'x' => 40, 'y' => 20, - width => $width + 20, height => $tuner{all} * 20 + 10, - rx => 15, ry => 15, - style => { stroke => 'blue', fill => 'white' } ); - for ( 1..$tuner{terrestrial} ) { - $svg->text( 'x' => 10, 'y' => ( $_ + 1 ) * 20 ) - ->cdata( "T$_" ); - } - for ( 1..$tuner{satellite} ) { - $svg->text( 'x' => 10, 'y' => ( $_ + $tuner{terrestrial} + 1 ) * 20 ) - ->cdata( "S$_" ); - } - for ( 0..$hours ) { - $svg->text( 'x' => $_ * 30 + 65, 'y' => 15, - style => { 'text-anchor' => 'middle' } ) - ->cdata( sprintf( '%02d', $_ ) ) if ( $_ < $hours ); - # $svg->line( ); # can't be used when required - $svg->tag( 'line', x1 => $_ * 30 + 50, x2 => $_ * 30 + 50, y1 => 30, y2 => $tuner{all} * 20 + 20, - style => { stroke => 'gray' } ); - } - for ( 1..$tuner{all} ) { -# $svg->tag( 'line', x1 =>50, x2 => 50 + $width, y1 => $_ * 20 + 10, y2 => $_ * 20 + 10, -# style => { stroke => 'gray' } ); -# $svg->rectangle( 'x' => 50, 'y' => $_ * 20 + 10, width => $width, height => 10 ); - $svg->rectangle( 'x' => 50, 'y' => $_ * 20 + 14, width => $width, height => 2 ); - } - if ( $today ) { - require Time::Simple; - my $time = Time::Simple->new(); - my $x = ( $time->hours * 60 + $time->minutes ) * 0.5 + 50; - $svg->tag( 'line', x1 => $x, x2 => $x, y1 => 30, y2 => $tuner{all} * 20 + 20, - style => { stroke => 'red', 'fill-opacity' => '1.0' } ); - } - my $ary_ref = $dbh->selectall_arrayref( - # epg_timeline.channel = timeline.chtxt && - "SELECT id, title, chtxt, btime, etime, epgcategory, opt FROM timeline - WHERE type IN $type_user_made - AND - ( - '$graph_bgn 00:00' <= btime AND btime < '$graph_end 00:00' - OR - '$graph_bgn 00:00' < etime AND etime <= '$graph_end 00:00' - ) - ORDER BY btime" - , {Slice=>{}} - ); - - foreach my $bctype ( '\d+_', 'S_' ) { - my $tuner = $bctype eq '\d+_' ? $tuner{terrestrial} : $tuner{satellite}; - my @ary_ref = grep { $_->{chtxt} =~ /$bctype/ } @{ $ary_ref }; - my @y_drawn = ('') x $tuner; - foreach my $line ( @ary_ref ) { - @start = $line->{btime} =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2})/; - @stop = $line->{etime} =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2})/; - $start = ( ( $day == $start[2] ? 0 : 24 * 60 ) + $start[3] * 60 + $start[4] ) * 0.5; - $stop = ( ( $day == $stop [2] ? 0 : 24 * 60 ) + $stop [3] * 60 + $stop [4] ) * 0.5; - $start = 0 if ( $start < 0 || $day > $start[2] ); # 月の変わり目はスルー - $stop = $width if ( $stop > $width ); - $begin = $line->{btime}; - $end = $line->{etime}; - - my @ary = grep { ( $_->{etime} cmp $line->{btime} ) > 0 and ( $_->{btime} cmp $line->{etime} ) < 0 and $_->{id} != $line->{id} } @ary_ref; - foreach my $i ( 0..$tuner - 1 ) { - next if ( ( $y_drawn[$i] cmp $line->{btime} ) > 0 ); - #for ( 'chtxt', 'btime', 'etime' ) { - # $f = 0 if ( $line->{$_} ne $ary[$i]->{$_} ); - #} - $line->{slot} = $i; - $y_drawn[$i] = $line->{etime}; - last; - } - my ( $r, $g, $b ) = ( 0, 0, 0 ); - $r += 255 if ( $line->{opt} =~ /a/ ); - $g += 255 if ( $line->{opt} =~ /H/ ); - $b += 255 if ( $line->{opt} =~ /I/ ); - if ( $r + $g + $b == 255 * 3 ){ - $r = 0; - $g = 255; - $b = 255; - } - if ( $r + $g + $b == 0 ){ - $r = $g = $b = 128; - } - my %escaped = ( '&' => 'amp', '<' => 'lt', '>' => 'gt', '"' => 'quot' ); - sub html_escape{ - my $str = shift or return; - my $result = ''; - $result .= $escaped{$_} ? '&' . $escaped{$_} . ';' : $_ - for (split //, $str); - $result; - } - $svg->anchor( - -href => "rectool.pl?mode=edit&id=$line->{id}", - target => '_blank', - -title => html_escape( $line->{title} ), - )->rectangle( - 'x' => 50 + $start, - 'y' => 30 + ( $bctype eq '\d+_' ? 0 : $tuner{terrestrial} * 20 ) + $line->{slot} * 20, - width => $stop - $start, - height => 10, - style => { fill => $category_color{$line->{epgcategory}} || $category_color{'その他'} } ); - #style => { fill => "rgb($r,$g,$b)" } ); - } - } - my $xml = $svg->xmlify; - utf8::encode( $xml ); - print $xml; - #warningsToBrowser(true); - exit; - } - else - { - $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Viewer - Graphical/; - $HTML .= qq {
\n}; - # $base64 = encode_base64( $svg->xmlify ); - # $HTML .= qq {\n\n}; - $HTML .= qq {予約状況一覧です。T1,T2は地上波、S1,S2はBS/CSを示しています。
\n}; - $HTML .= qq {SVGが利用可能なブラウザでご覧ください。
\n}; - $HTML .= qq {色とジャンルの対応\n}; - map { - $HTML .= qq {$_->{name}\n}; - } values %category; - $HTML .= qq {
\n}; - - $ary_ref = $dbh->selectcol_arrayref( - "SELECT DISTINCT DATE( btime ) - FROM timeline - WHERE type in $type_user_made - ORDER BY btime" - ); - foreach my $date ( @{ $ary_ref } ) { - my @date = $date =~ /(.{4})-(.{2})-(.{2})/; - my $dn = DateTime->new( year => $date[0], month => $date[1], day => $date[2], locale => 'ja_JP' )->day_name; - #utf8::encode( $dn ); - $HTML .= qq {$date[1]/$date[2]($dn)の予約状況
\n}; - # - $HTML .= qq {\n}; - $HTML .= qq {SVG Image $date\n\n
\n}; - - $date2 = Date::Simple->new( @date )->next->format('%Y-%m-%d'); - my $ary_ref = $dbh->selectall_arrayref( - "SELECT chtxt, title, btime, etime FROM timeline - WHERE '$date 00:00' <= btime AND etime <= '$date2 01:00' - ORDER BY btime" - ); - - foreach my $line ( @{ $ary_ref } ) { - #$HTML .= qq {$line->[0] $line->[1] $line->[2] $line->[3]
\n}; - } - - } - - goto end; - } -} - -################ mode=atom ################ - -if ( $mode eq 'atom' ) { - require XML::Atom::Feed; - require XML::Atom::Entry; - - my $recording_count = $encoding_count = $jbk_count = 0; - my $ary_ref = $dbh->selectall_arrayref( - "SELECT chtxt, title, btime, etime, opt - FROM timeline - WHERE type = 'reserve_running' "); - foreach my $line ( @{$ary_ref} ) { - my ( $begin, $end, $diff ) = &str2readable( $line->[2], $line->[3] ); - $recording_status .= qq {$line->[0] $line->[1] $begin - $end $diff $line->[4]
\n}; - $recording_count++; - } - $ary_ref = $dbh->selectall_arrayref( - "SELECT chtxt, title, btime, etime, opt - FROM timeline - WHERE type = 'convert_ts_mp4_running' "); - foreach my $line ( @{$ary_ref} ) { - my ( $begin, $end, $diff ) = &str2readable( $line->[2], $line->[3] ); - $encoding_status .= qq {$line->[0] $line->[1] $begin - $end $diff $line->[4]
\n}; - $encoding_count++; - } - $ary_ref = $dbh->selectall_arrayref( - "SELECT id, chtxt, title, btime, etime - FROM auto_timeline_keyword " ); - foreach my $line ( @{$ary_ref} ) { - my ( $begin, $end, $diff ) = &str2readable( $line->[3], $line->[4] ); - $jbk_status .= qq {$line->[0] $line->[1] $line->[2] $begin - $end $diff
\n}; - $jbk_count++; - } - - my $feed = XML::Atom::Feed->new( Version => 1.0 ); - $feed->title('Rec10 フィード'); - - my $entry = XML::Atom::Entry->new( Version => 1.0 ); - $entry->title("Rec10 録画状況 ($recording_count)"); - $entry->id('tag:recording_status'); - $entry->content($recording_status); - $entry->add_link(str_to_link( './rectool.pl?mode=schedule' ) ); - $feed->add_entry($entry); - - $entry = XML::Atom::Entry->new( Version => 1.0 ); - $entry->title("Rec10 縁故状況 ($encoding_count)"); - $entry->id('tag:encoding_status'); - $entry->content($encoding_status); - $entry->add_link(str_to_link( './rectool.pl?mode=schedule' ) ); - $feed->add_entry($entry); - - $entry = XML::Atom::Entry->new( Version => 1.0 ); - $entry->title("Rec10 地引状況 ($jbk_count)"); - $entry->id('tag:jbk_status'); - $entry->content($jbk_status); - $entry->add_link(str_to_link( './rectool.pl?mode=jbk' ) ); - $feed->add_entry($entry); - - my $xml = $feed->as_xml; - print "Content-Type: application/atom+xml\n\n"; - print $xml; - exit; - - sub str_to_link { - my $link = XML::Atom::Link->new( Version => 1.0 ); - $link->type('text/html'); - $link->rel('alternate'); - $link->href(shift); - return $link; - } -} - -################ mode=edit ################ - -if ( $mode eq 'edit' ) { - my $id = $params{ 'id' }; - - $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Editor/; - $HTML .= qq {
\n}; - - $script = < - - -EOM - $script =~ s/^\t{2}//gm; - $HTML =~ s/%SCRIPT%/$script/; - - $HTML .= "スケジュール編集画面です。
\n"; - $HTML .= "実装がとても適当なので、利用には細心の注意を払ってください。
\n
\n"; - if ( $id ) { - # 予約の編集 - &parse_program(); - $button_bgn = $button_end = ''; - } - else { - # 新規予約 - $type = 'reserve_flexible'; - $counter = -1; - $datetime_now = DateTime->now( time_zone => $tz )->set_second( 0 )->add( minutes => 1)->strftime( '%Y-%m-%d %H:%M:%S' ); - $button_bgn = qq{\n
\n}; - $button_end = - qq{} - .qq{} - .qq{}; - } - - if ( $params{ 'suggest' } eq 'auto' ) { - my @btime = $begin =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/; - my @etime = $end =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/; - my $btime = DateTime->new( - year => $btime[0], month => $btime[1], day => $btime[2], - hour => $btime[3], minute => $btime[4], second => $btime[5], - ); - my $etime = DateTime->new( - year => $etime[0], month => $etime[1], day => $etime[2], - hour => $etime[3], minute => $etime[4], second => $etime[5], - ); - my %hash = &sqlgetsuggested( $btime, $etime ); - - $HTML .= qq {可能性のある番組
\n}; - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - - foreach my $key (sort keys %hash){ - my $val = $hash{$key}; - foreach my $val ( @{$val} ) { - my $style = qq {style="white-space: nowrap"}; - $val->[0] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; - $val->[1] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; - $HTML .= qq {\n\n\n}; - $HTML .= qq {\n\n\n}; - $HTML .= qq {\n\n}; - } - } - $HTML .= qq {
優先度タイトル開始時刻終了時刻説明適用
$key$val->[2]$val->[0]$val->[1]$val->[3]
\n
\n}; - } - - my $len = length $id; - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {ID\n\n}; - $HTML .= qq {タイプ\n\n}; - - $HTML .= qq {チャンネル\n
\n}; - $HTML .= qq {タイトル\n
\n}; - $HTML .= qq {開始時刻\n\n}; - $HTML .= $button_bgn; - $HTML .= qq {終了時刻\n\n}; - $HTML .= $button_end . "
\n"; - $HTML .= qq {隔日周期\n\n}; - $HTML .= qq {時刻誤差\n\n}; - $HTML .= qq {オプション\n\n}; - $HTML .= qq {回数\n\n}; - $HTML .= qq {\n
\n}; -} - -################ mode=change ################ - -if ( $mode eq 'change' ) { - @id = $q->param( 'id' ); - - $HTML =~ s/%HTML_TITLE_OPT%/ - Change/; - $HTML .= qq {
\n}; - - if ( $params{ 'delete' } ) - { - if ( @id ) { - foreach my $id ( @id ) { - $dbh->do( "DELETE FROM timeline WHERE id = '$id'" ); - } - $HTML .= "削除しました。
\n5秒後に予約確認画面に移動します。
\n"; - $HTML =~ s|%REFRESH%||; - goto end; - } - } - if ( $params{ 'update' } ) - { - $type = $params{ 'type' }; - $chtxt = $params{ 'chtxt' }; - $title = $params{ 'title' }; - $begin = $params{ 'begin' }; - $end = $params{ 'end' }; - $deltaday = $params{ 'deltaday' }; - $deltatime = $params{ 'deltatime' }; - $opt = $params{ 'opt' }; - $counter = $params{ 'counter' }; - $id = $id[0]; - if ( $id ) { - $dbh->do( - "UPDATE timeline SET type = '$type', chtxt = '$chtxt', title = '$title', - btime = '$begin', etime = '$end', - deltaday = '$deltaday', deltatime = '$deltatime', opt = '$opt', counter = '$counter' - WHERE id = '$id'" - ); - } - else { - $dbh->do( - "INSERT INTO timeline ( type, chtxt, title, btime, etime, deltaday, deltatime, opt, counter ) - VALUES ( '$type', '$chtxt', '$title', '$begin', '$end', '$deltaday', '$deltatime', '$opt', '$counter' )" - ); - } - $HTML .= "更新しました。
\n5秒後に予約確認画面に移動します。
\n"; - $HTML =~ s|%REFRESH%||; - goto end; - } - if ( $mode_sub eq 'proc' ) { - my $type = $params{ 'type' }; - my $chtxt = $params{ 'chtxt' } || 'nhk-k'; - my $title = $params{ 'title' }; - my @opt = $q->param( 'opt' ); - my $opt = join '', @opt; - - my $datetime_now = DateTime->now( time_zone => $tz )->set_second( 0 )->add( minutes => 10); - my $sql_type = $type_suggest{$type}; - my $begin = $datetime_now->strftime( '%Y-%m-%d %H:%M:%S' ); - $datetime_now = $datetime_now->add( minutes => 60 ); - my $end = $datetime_now->strftime( '%Y-%m-%d %H:%M:%S' ); - - $dbh->do( - "INSERT INTO timeline ( type, chtxt, title, btime, etime, opt ) - VALUES ( '$sql_type', '$chtxt', '$title', '$begin', '$end', '$opt' )" - ); - - goto end; - } - if ( $mode_sub eq 'move' ) { - my $mode_sub2 = $params{ 'mode_sub2' }; - my $title = $params{ 'title' }; - my $response; - - $ENV{'LANG'} = 'ja_JP.UTF-8'; - if ( $mode_sub2 eq 'predict' ) { - $HTML .= "移動後のシミュレーション結果です。\n
"; - eval '$response = `python26 ' . $cfg->param( 'path.rec10' ) . "/classify.py -s '$title'`"; - } - elsif ( $mode_sub2 eq 'exec' ) { - eval '$response = `python26 ' . $cfg->param( 'path.rec10' ) . "/classify.py -e '$title'`"; - } - utf8::decode( $response ); - $HTML .= $response; - - goto end; - } - if ( $mode_sub eq 'setting' ) { - my $jbk = $params{ 'jbk' } || '0'; - my $bayes = $params{ 'bayes' } || '0'; - my $del_tmp = $params{ 'del_tmp' } || '0'; - my $opt = $params{ 'opt' } || ''; - my $user = $params{ 'user' } || ''; - my $pass = $params{ 'pass' } || ''; - - $dbh->do( - "UPDATE in_settings SET auto_jbk = '$jbk', auto_bayes = '$bayes', - auto_del_tmp = '$del_tmp', auto_opt = '$opt'" - ); - - goto end; - } - if ( $mode_sub eq 'fixstatus' ) { - my $key = $params{ 'terec' } ? 'terec' : $params{ 'bscsrec' } ? 'bscsrec' : - $params{ 'b252ts' } ? 'b252ts' : $params{ 'ts2avi' } ? 'ts2avi' : ''; - - $dbh->do( - "UPDATE in_status SET $key = 0" - ); - - goto end; - } - -} - -################ mode=confirm ################ - -if ( $mode eq 'confirm' ) { - if ( $mode_sub eq 'reserve' ) { - $HTML =~ s/%HTML_TITLE_OPT%/ - Reserver/; - $HTML .= qq {
\n}; - &parse_program(); - - my $duration = ( str2datetime( $end ) - str2datetime( $begin ) )->delta_minutes; - $HTML .= "番組名:$title
\nチャンネル:$chname
\n放送継続時間:$duration 分
\n番組内容:$desc
\nジャンル:$category
\n"; - if ( $longdesc ) { - $longdesc =~ s/\\n/
\n/gs; - $HTML .= "番組内容(長):$longdesc
\n"; - } - my $error = &check_error(); - if ( $error ) - { - # エラー - - $ary_ref = $dbh->selectall_arrayref( - "SELECT start, stop FROM epg_timeline WHERE channel = '$chtxt' AND title = '$title' " - ); - if ( $error != 1 ) { - $HTML .= "同一の番組の他の放送予定です。
\n"; - foreach my $line ( @{$ary_ref} ) { - $begin = $line->[0]; - $end = $line->[1]; - $begin =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; - $end =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; - $overlap = &get_overlap() >= 2 ? '不可能' : - qq {可能}; - $HTML .= "開始:$begin\n終了:$end\n録画は$overlap
\n"; - } - } - } - else { - $HTML .= "録画予約の詳細設定を行ってください。
\n"; - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n} if ( $params{ 'title' } ); - &draw_form_opt( 'reserve' ); - $HTML .= qq {\n
\n}; - } - goto end; - } - # End of $mode_sub eq 'reserve'; - - if ( $mode_sub eq 'proc' ) { - my $type = $params{ 'type' }; - local $chtxt = $params{ 'chtxt' }; - my $title = $params{ 'title' }; - local $opt = $params{ 'opt' }; - utf8::decode( $title ); - - $HTML .= "詳細設定を行ってください。
\n"; - $HTML .= "タイトル:$title\n
\n"; - - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - &draw_form_channel( 'nonone' ); - &draw_form_opt(); - $HTML .= qq {\n
\n}; - goto end; - } -} - -################ mode=reserve ################ - -if ( $mode eq 'reserve' ) { - $HTML .= qq {
\n}; - &parse_program(); - $title = $params{ 'title' } if ( !$title ); - @opt = $q->param( 'opt' ); - $opt = join '', @opt; - my ( $deltaday, $deltatime ); - - if ( $params{'every'} eq '1' ) { - $type = 'search_everyday'; - ( $changed_t ) = $title =~ /(.*)#/; - $title = $changed_t if ( $changed_t ); - ( $changed_t ) = $title =~ /(.*)第/; - $title = $changed_t if ( $changed_t ); - ( $changed_t ) = $title =~ /(.*)▽/; - $title = $changed_t if ( $changed_t ); - $title =~ s/「.*」//; - $title =~ s/<.*>//; - $title =~ s/(.*)//; - $title =~ s/\[新\]//; - $title =~ s/無料≫//; - $title =~ s/\s*$//; - $deltaday = 7; - $deltatime = 3; - } - else { - $type = 'reserve_flexible'; - } - $chtxt = $chtxt_0 if ( $chtxt_0 ); - if ( !&check_error ) { - $dbh->do( - "INSERT INTO timeline ( type, chtxt, title, btime, etime, opt, deltaday, deltatime ) - VALUES ( '$type', '$chtxt', '$title', '$begin', '$end', '$opt', '$deltaday', '$deltatime' )" - ); - } - $HTML .= "録画予約を実行しました。
\n5秒後にトップへ移動します。
\n"; - $HTML =~ s|%REFRESH%||; - goto end; -} - -################ mode=program ################ - -if ( $mode eq 'program' ) { - &draw_form(); - - $HTML =~ s/%HTML_TITLE_OPT%/ - Program Viewer/; - $unix = DateTime->now( time_zone => $tz )->strftime( '%Y%m%d%H%M%S' ); - $sql = - "SELECT channel, epg_ch.chname, start, stop, title, category - FROM epg_timeline - INNER JOIN epg_ch ON epg_timeline.channel = epg_ch.chtxt - WHERE $unix <= stop %CH% %DATE% %CATEGORY% %KEY% ORDER BY start"; - - if ( $chtxt ) { - my $ch; - if ( $chtxt =~ /^\d+(_0)?$/ ) { - # teはxx_yyy形式であるため - $chtxt =~ s/_0//; - $ch = "AND channel LIKE '$chtxt\_%'"; - } - else { - $ch = "AND channel = '$chtxt'"; - } - $sql =~ s/%CH%/$ch/; - } - if ( $date_sel ) { - $date_1 = $date_sel . '000000'; - $date_2 = Date::Simple->new( $date_sel =~ /(.{4})(.{2})(.{2})/ )->next->format('%Y%m%d') . '000000'; - my $date = "AND '$date_1' <= stop AND start <= '$date_2'"; - $sql =~ s/%DATE%/$date/; - } - if ( $category_sel ) { - # 一時的 - # $category_tmp = $category{$category_sel} . $category_sel; - my $category = "AND category = '$category{$category_sel}->{name}'"; - $sql =~ s/%CATEGORY%/$category/; - } - if ( $key ) { - my $key = "AND TITLE LIKE '%$key%'"; - $sql =~ s/%KEY%/$key/; - } - $sql =~ s/%CH%//; - $sql =~ s/%DATE%//; - $sql =~ s/%KEY%//; - $sql =~ s/%CATEGORY%//; - - $ary_ref = $dbh->selectall_arrayref( $sql ); - foreach my $prg ( @{ $ary_ref } ) { - my @date = $prg->[2] =~ /(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/; - - $date = $date[2]; - if ( $date != $prev ) { - my $date = DateTime->new( - year => $date[0], month => $date[1], day => $date[2], - locale => 'ja_JP' - ); - - my $dn = $date->day_name; - #utf8::encode( $dn ); - $HTML .= qq {--------$date[1]/$date[2]($dn)--------
\n}; - } - $HTML .= qq {$date[1]/$date[2] $date[3]:$date[4] }; - $HTML .= qq {$prg->[1] } if ( !$chtxt ); - $HTML .= qq {$prg->[4]
\n}; - $prev = $date; - } -} - -################ mode=list ################ - -if ( $mode eq 'list' ) { - $HTML =~ s/%HTML_TITLE_OPT%/ - List/; - $HTML .= qq {
\n}; - - my $recording = $cfg->param( 'path.recpath' ); - my $ts_movepath = $cfg->param( 'path.ts_movepath' ); - my $recorded = $cfg->param( 'path.recorded' ); - - if ( $mode_sub eq 'log' ) { - my $title = $params{ 'title' }; - my $log = slurp( "$recording/$title.log" ) if ( -e "$recording/$title.log" ); - utf8::decode( $log ); - $HTML .= '
'.$log."
\n"; - goto end; - } - if ( $mode_sub eq 'logzip' ) { - my $title = $params{ 'title' }; - my $zip = Archive::Zip->new(); - my $logzip; - die 'read error' unless $zip->read("$recording/$title.log.zip") == AZ_OK; - my @members = $zip->members(); - foreach (@members) { - $logzip .= $_->fileName() . "\n"; - my @lines = split /\n|\r/, $zip->contents( $_->fileName() ); - my %count; - @lines = grep {!$count{$_}++} @lines; - $logzip .= join "\n", @lines; - $logzip .= "\n\n"; - } - - utf8::decode( $logzip ); - $HTML .= '
'.$logzip."
\n"; - goto end; - } - if ( !$mode_sub ) { - $HTML .= qq {録画中のみ\n}; - $HTML .= qq {録画後のみ\n
\n}; - } - if ( !$mode_sub || $mode_sub eq 'new' ) { - $HTML .= "録画中のファイル一覧
\n"; - &list( $recording ); - } - if ( !$mode_sub ) { - $HTML .= "
\n"; - } - if ( !$mode_sub || $mode_sub eq 'old' ) { - $HTML .= "録画後のファイル一覧
\n"; - &simple_list( $ts_movepath ); - &simple_list( $recorded ); - } - - sub list { - local $path = shift; - local %list = (); - my @exp = ( 'log', 'log.zip', 'ts.b25', 'ts.tsmix', 'ts', 'ts.log', - 'aac', 'srt', 'm2v', 'wav', '264', 'mp4', 'mkv' ); - for ( 0..$#exp ) { - $exp{$exp[$_]} = $_; - } - my $exp_count = scalar keys %exp; - - &get_file_list_wrapper( $path, \&wanted ); - - my $help; - foreach my $name ( sort { $exp{$a} <=> $exp{$b} } keys %exp ) { - $help .= $exp{$name} + 1 . " = $name / "; - } - $HTML .= $help; - $help = qq {$help\n\n}; - $help .= qq {$_\n} for ( 1..$exp_count ); - - $HTML .= qq {
\n○ = 完了 / ● = 書き込み中 / ◆ = ファイルサイズ異常
\n}; - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n} for ( 1..$exp_count ); - $HTML .= qq {\n}; - - my $count = 0; - - foreach my $title ( sort keys %list ) { - my $value = $list{$title}; - my @flag = ( 0 ) x ( $exp_count ); - $HTML .= qq {\n\n}; - foreach my $exp ( keys %{$value} ) { - if ( $exp eq 'log' ) { - # ログへのリンクを追加 - my $title = $q->escape( $title ); - my $extra = qq {\n}; - - $value->{$exp}->{extra} = $extra; - } - elsif ( $exp eq 'log.zip' ) { - # ZIPログへのリンクを追加 - my $title = $q->escape( $title ); - my $extra = qq {\n}; - - $value->{$exp}->{extra} = $extra; - } - elsif ( $exp eq 'mp4' ) { - # ○などの代わりにサイズを表示 - $value->{$exp}->{style} = $value->{$exp}->{size}; - } - elsif ( $exp eq 'mkv' ) { - # サムネイルへのリンクを追加 - my $title = $q->escape( $title ); - - my $extra = qq {\n}; - $value->{$exp}->{extra} = $extra; - } - $flag[$exp{$exp}] = $value->{$exp}; - } - foreach ( @flag ) { - my $size = $_->{size}; - my $style = $_->{style}; - my $span = $size ? qq {$style} : '
'; - $HTML .= $_->{extra} || qq {\n}; - } - $HTML .= qq {\n}; - $HTML .= $help unless ( ++$count % 20 ); - } - $HTML .= qq {
タイトル$_
$title○○■$span
\n}; - - sub wanted { - my $rel = shift; - my $abs = shift; - - return if ( $rel =~ /Thumbs\.db/ ); - return if ( $rel =~ /\.idx/ ); - - $rel =~ s/\.temp$//; - my $regexp = join '|', keys %exp; - my ( $title, $exp ) = $rel =~ /(.*?)\.($regexp)$/; - my ( $size, $style ) = &get_size( $abs ); - $rel =~ s/\.temp$//; - if ( !$title ) { - $title = '_error_exp_'.$rel; - $exp = 'log'; - } - if ( $title !~ /[^0-9A-F]+/ ) { - my $tmp = pack( 'H*', $title ); - if ( !$tmp ) { - $title = '_error_b16_'.$rel; - $exp = 'log'; - } - else { - $title = 'Base16_'.$tmp; - } - } - $list{$title}->{$exp} = { 'style' => $style, 'size' => $size }; - } - } - - sub simple_list { - require Encode; - - local $path = shift; - local @list = (); - - &get_file_list_wrapper( $path, \&simple_wanted ); - -# @list = sort @list; - # natural sortを行う - #@list = map( Encode::decode_utf8( $_ ), @list ); - @list = nsort @list; - #@list = map( Encode::encode_utf8( $_ ), @list ); - - foreach ( @list ) { - $HTML .= "$_
\n"; - } - - sub simple_wanted { - my $rel = shift; - my $abs = shift; - - my ( $size ) = &get_size( $abs ); - push @list, $rel ."\t\t". $size; - } - } - - sub get_size { - my $file = shift; - my ( $size, $last ) = (stat( $file ))[7,9]; - my @unim = ("B","KiB","MiB","GiB","TiB","PiB"); - my $count = 0; - - while($size >= 1024 ){ - $count++; - $size = $size / 1024; - } - $size *= 100; - $size = int( $size ); - $size /= 100; - if ( time - $last < 10 ) { - $style = '●'; - } - elsif ( $size == 0 ) { - $style = '◆'; - } - else { - $style = '○'; - } - return ( "$size $unim[$count]", $style ); - } -} - -################ mode=thumb ################ - -if ( $mode eq 'thumb' ) { - my $title = $params{ 'title' }; - my $pos = $params{ 'pos' }; - my $recording = $cfg->param( 'path.recpath' ); - - print "Content-Type: image/jpeg\n\n"; - exec "ffmpeg -ss 300 -i '$recording/$title.mkv' -f image2 -pix_fmt jpg -vframes 1 -s 320x240 -"; - exit; -} - -################ mode=check ################ - -if ( $mode eq 'check' ) { -} - -################ mode=bravia ################ - -if ( $mode eq 'bravia' ) { - $HTML =~ s/%HTML_TITLE_OPT%/ - Bravia/; - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - my $order = $params{ 'order' }; - if ( $order ne 'point' ) { - $order = 'btime'; - } - else { - $order = 'point DESC'; - } - my $ary_ref = $dbh->selectall_arrayref( - "SELECT id, chtxt, title, btime, etime, point - FROM auto_timeline_bayes - ORDER BY $order" ); - - foreach my $line ( @{ $ary_ref } ) { - my ( $begin, $end, $diff ) = &str2readable( $line->[3], $line->[4] ); - - $line->[1] = $chtxt_chname{$line->[1]} || $line->[1]; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - } - $HTML .= qq {
IDチャンネルタイトル開始時刻終了時刻録画時間ポイント予約
$line->[0]$line->[1]$line->[2]$begin$end$diff$line->[5]予約
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - -} - -################ mode=proc ################ - -if ( $mode eq 'proc' ) { - $HTML =~ s/%HTML_TITLE_OPT%/ - Proposal/; - $HTML .= qq {
\n}; - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - - my $ary_ref = $dbh->selectall_arrayref( - "SELECT type, chtxt, title - FROM auto_proc - ORDER BY title " ); - - foreach my $line ( @{ $ary_ref } ) { - my $url; - $line->[3] = $q->escape( $line->[2] ); - my $opt = $dbh->selectrow_array( - "SELECT opt FROM in_timeline_log - WHERE title = '$line->[2]' " - ); - - if ( $line->[0] eq 'auto_suggest_dec' ) { - unless ( $dbh->selectrow_array( - "SELECT 1 FROM timeline - WHERE ( type = 'convert_b25_ts' OR type = 'convert_b25_ts_running' ) - AND title = '$line->[2]' " - ) ) { - $url = qq {rectool.pl?mode=confirm&mode_sub=proc&type=$line->[0]&chtxt=$line->[1]&title=$line->[3]&opt=$opt}; - } - } - elsif ( $line->[0] eq 'auto_suggest_enc' ) { - unless ( $dbh->selectrow_array( - "SELECT 1 FROM timeline - WHERE ( type = 'convert_ts_mp4' OR type = 'convert_ts_mp4_running' ) - AND title = '$line->[2]' " - ) ) { - $url = qq {rectool.pl?mode=confirm&mode_sub=proc&type=$line->[0]&chtxt=$line->[1]&title=$line->[3]&opt=$opt}; - } - } - else { - unless ( $dbh->selectrow_array( - "SELECT 1 FROM timeline - WHERE ( type LIKE 'convert_avi%' OR type = 'convert_mkv' ) - AND title = '$line->[2]' " - ) ) { - $url = qq {rectool.pl?mode=confirm&mode_sub=proc&type=$line->[0]&chtxt=$line->[1]&title=$line->[3]}; - } - } - if ( $url ) { - $href = qq {予約}; - } - else { - $href = q {予約済}; - } - - my $color = $color{$type_suggest{$line->[0]}} ? $color{$type_suggest{$line->[0]}} : ''; - $line->[0] = $type{$line->[0]} ? $type{$line->[0]} : $line->[0]; - $line->[0] = qq {$line->[0]} if ( $color ); - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - } - - $HTML .= qq {
タイプタイトル予約
$line->[0]$line->[2]$href
\n}; -} - -################ mode=jbk ################ - -if ( $mode eq 'jbk' ) { - $HTML =~ s/%HTML_TITLE_OPT%/ - JBK/; - $HTML .= qq {
\n}; - - if ( $mode_sub eq 'add' ) { - my $keyword = $params{ 'keyword' }; - utf8::decode( $keyword ); - $HTML .= "キーワード「$keyword」を追加しました。
\n"; - $dbh->do( - "INSERT INTO in_auto_jbk_key ( keyword ) - VALUES ( '$keyword' )" - ); - } - elsif ( $mode_sub eq 'del' ) { - my $id = $params{ 'id' }; - my $keyword = $dbh->selectrow_array( - "SELECT keyword FROM in_auto_jbk_key - WHERE id = '$id' " ); - $HTML .= "キーワード「$keyword」を削除しました。
\n"; - $dbh->do( - "DELETE FROM in_auto_jbk_key WHERE id = '$id'" - ); - } - elsif ( $mode_sub eq 'on' ) { - my $id = $params{ 'id' }; - $HTML .= "キーワード「$keyword」を自動録画対象にしました。
\n"; - $dbh->do( - "UPDATE in_auto_jbk_key SET auto = 1 WHERE id = '$id'" - ); - } - elsif ( $mode_sub eq 'off' ) { - my $id = $params{ 'id' }; - $HTML .= "キーワード「$keyword」を自動録画対象から外しました。
\n"; - $dbh->do( - "UPDATE in_auto_jbk_key SET auto = 0 WHERE id = '$id'" - ); - } - - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - - my $ary_ref = $dbh->selectall_arrayref( - "SELECT id, keyword, auto, opt - FROM in_auto_jbk_key - ORDER BY id " ); - - foreach my $line ( @{ $ary_ref } ) { - my $delurl = "rectool.pl?mode=jbk&mode_sub=del&id=$line->[0]"; - my $auto = $line->[2] ? 'on' : 'off'; - my $oppo = $line->[2] ? 'off' : 'on'; - my $oppourl = "rectool.pl?mode=jbk&mode_sub=$oppo&id=$line->[0]"; - $oppo .= "にする"; - - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - } - - $HTML .= qq {
IDキーワード自動録画切り替え録画オプション削除
$line->[0]$line->[1]$auto$oppo$line->[3]削除
\n}; - - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n
\n
\n
\n}; - - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - - $ary_ref = $dbh->selectall_arrayref( - "SELECT id, auto_timeline_keyword.chtxt, epg_ch.chname, title, btime, etime - FROM auto_timeline_keyword - INNER JOIN epg_ch ON auto_timeline_keyword.chtxt = epg_ch.chtxt - ORDER BY btime" - , {Slice=>{}} ); - - foreach my $line ( @{ $ary_ref } ) { - my ( $begin, $end, $diff ) = &str2readable( $line->{btime}, $line->{etime} ); - $line->{btime} =~ s/(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/$1$2$3$4$5$6/; - $line->{etime} =~ s/(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/$1$2$3$4$5$6/; - my $url = qq "rectool.pl?mode=confirm&mode_sub=reserve&chtxt=$line->{chtxt}&start=$line->{btime}&stop=$line->{etime}"; - - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - } - - $HTML .= qq {
IDチャンネルタイトル開始時刻終了時刻録画時間予約
$line->{id}$line->{chname}$line->{title}$begin$end$diff予約
\n}; - -} - -################ mode=recognize ################ - -if ( $mode eq 'recognize' ) { - $HTML =~ s/%HTML_TITLE_OPT%/ - Recognizer/; - - my $text = $params{ 'text' }; - utf8::decode( $text ); - $chtxt = $params{ 'chtxt' }; - my $title = $params{ 'title' }; - utf8::decode( $title ); - - $HTML .= qq {
\n}; - $HTML .= qq {与えられた文字列のうち、番組の放送時刻と思われる文字列を認識します。
\n}; - $HTML .= qq {番組表が取得できない一週間以上先の予約ができます。
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - &draw_form_channel( 'nonone' ); - $HTML .= qq {\n}; - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n
\n
\n}; - - my $ch_list = join '|', grep /.+/, values %chtxt_0_chname; - my %ch_reverse = reverse %chtxt_0_chname; - - if ( $text ) { - my ( $year, $month, $day ); - my ( $bhour, $bminute, $ehour, $eminute ); - my $next_day = 0; - foreach ( split /\n/, $text ) { - my @bdate = /(\d{4}).(\d{1,2}).(\d{1,2})/; - s/(\d{4}).(\d{2}).(\d{2})//; - my @btime = /(\d{1,2})[::](\d{1,2})/; - s/(\d{1,2})[::](\d{2})//; - my @etime = /(\d{1,2})[::](\d{1,2})/; - s/(\d{1,2})[::](\d{2})//; - s/\(.*\)//; - if ( !@bdate ) { - $bdate[0] = Time::Piece->localtime->year; - ( $bdate[1], $bdate[2] ) = /(\d{1,2})月(\d{1,2})日/; - s/(\d{1,2})月(\d{1,2})日//; - } - next if (!( @bdate || @btime )); - ( $year, $month, $day ) = @bdate if ( $bdate[0] && $bdate[1] && $bdate[2] ); - ( $bhour, $bminute ) = @btime if ( defined $btime[0] && defined $btime[1] ); - ( $ehour, $eminute ) = @etime if ( defined $etime[0] && defined $etime[1] ); - $next_day = 1 if ( /深夜/ ); - my ( $ch ) = /($ch_list)/; - my $chtxt = $ch_reverse{$ch} if ( $ch && $ch_reverse{$ch} ); - s/($ch_list)//; - - if ( $year && $month && $day && defined $bhour && defined $bminute ) { - my $tp = Time::Piece->strptime( "$year-$month-$day $bhour:$bminute", '%Y-%m-%d %H:%M' ); - my $etp = Time::Piece->strptime( "$year-$month-$day $ehour:$eminute", '%Y-%m-%d %H:%M' ) if ( defined $ehour && defined $eminute ); - $tp += ONE_DAY if ( $next_day ); - my $start = $tp->strftime( '%Y%m%d%H%M%S' ); - my $stop = defined $etp ? - $etp->strftime( '%Y%m%d%H%M%S' ) : - ( $tp + ONE_MINUTE * 30 )->strftime( '%Y%m%d%H%M%S' ); - $title = $_ if ( !$title ); - my $url = qq "rectool.pl?mode=confirm&mode_sub=reserve&chtxt=$chtxt&start=$start&stop=$stop&title=$title"; - $HTML .= qq {認識結果:$year-$month-$day $bhour:$bminute -> $ehour:$eminute 残り:$_リンク
\n}; - } - } - } -} - -################ mode=expert ################ - -if ( $mode eq 'expert' ) { - require List::Compare; - - my $ary_ref; - - $HTML =~ s/%HTML_TITLE_OPT%/ - Expert/; - $HTML .= qq {
\n}; - - if ( $mode_sub eq 'reget' ) { - my $bctype = $params{ 'bctype' }; - my ( $chtxt, $chname ) = $dbh->selectrow_array( - "SELECT chtxt, chname FROM epg_ch - WHERE bctype = '$bctype' " ); - $HTML .= "Update for $chname ( chtxt: $chtxt ) has been reserved.
\n"; - $dbh->do( "UPDATE epg_ch SET status = '2' WHERE chtxt = '$chtxt' " ); - goto end; - } - - - my @ary = $dbh->selectrow_array( - "SELECT auto_jbk, auto_bayes, auto_del_tmp, auto_opt - FROM in_settings " ); - my $opt = pop @ary; - @ary = map( $_ ? 'checked' : '', @ary ); - - $HTML .= qq {内部オプションの変更\n
}; - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {自動地引\n}; - $HTML .= qq {自動ベイズ\n}; - $HTML .= qq {自動一時ファイル削除\n}; - $HTML .= qq {自動オプション:\n}; - $HTML .= qq {\n
\n
\n}; - - - $HTML .= qq {
\n番組表のカテゴリ一覧と内蔵のカテゴリ一覧の合致を確認中...\n}; - $ary_ref = $dbh->selectcol_arrayref( - "SELECT DISTINCT category FROM epg_timeline" - ); - my @category = map {$_->{name}} sort values %category; - if ( List::Compare->new( $ary_ref, \@category )->get_symdiff ) { - $HTML .= qq {一致しません
\n}; - $HTML .= qq {番組表:@{$ary_ref}
\n内蔵:@category
\n}; - } - else { - $HTML .= qq {一致しました
\n}; - } - - - @ary = $dbh->selectrow_array( "SELECT terec, bscsrec, b252ts, ts2avi FROM in_status" ); - $HTML .= qq {
\n地上波録画数:$ary[0]\n衛星波録画数:$ary[1]\n解読数:$ary[2]\n縁故数:$ary[3]\n
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n
\n
\n}; - - - $HTML .= qq {
\nRec10 バージョン:$rec10_version\nrectool バージョン:$rectool_version\n
\n}; - - - $HTML .= qq {
\n番組表の欠落
\n}; - $ary_ref = $dbh->selectall_arrayref( "SELECT chname, chtxt FROM epg_ch" ); - foreach my $line ( @{$ary_ref} ) { - my $ary_ref = $dbh->selectall_arrayref( - "SELECT start, stop, title FROM epg_timeline WHERE channel = '$line->[1]' ORDER BY start" - ); - my $error; - my @program_old = ( '', $ary_ref->[0]->[0] ); - my $program_old = \@program_old; - - foreach my $program_new ( @{$ary_ref} ) { - if ( $program_old->[1] ne $program_new->[0] && - $program_old->[2] !~ /クロ?ジング|クロージング|エンディング|休止|ミッドナイト|ending/ && - $program_new->[2] !~ /オープニング|ウィークリー・インフォメーション|モーニング|opening/ && - ( str2datetime( $program_new->[0] ) - str2datetime( $program_old->[1] ) )->delta_minutes > 30 ) { - $program_old->[1] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; - $program_new->[0] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; - $error .= qq{ $program_old->[2] $program_old->[1]\n -> $program_new->[2] $program_new->[0]\n}; - } - $program_old = $program_new; - } - $HTML .= qq {
\n$line->[0]\n$error
\n} if ( $error ); - } - - - $ary_ref = $dbh->selectall_arrayref( - "SELECT chname, chtxt, bctype, ch, csch, updatetime, status, visible - FROM epg_ch - ORDER BY bctype " ); - $HTML .= qq {
\n番組表の更新状況
\n}; - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - foreach my $status ( @{$ary_ref} ) { - $HTML .= qq {\n}; - $HTML .= qq {\n\n\n\n}; - $HTML .= qq {\n\n\n\n}; - $HTML .= qq {\n}; - } - $HTML .= qq {
チャンネル名chtxtbctypechcsch最終更新時刻状態表示
$status->[0]$status->[1]$status->[2]$status->[3]$status->[4]$status->[5]$status->[6]$status->[7]
\n}; - - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {番組表を再取得する\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n
\n
\n}; - - - - $ary_ref = $dbh->selectall_arrayref( - "SELECT id, type, chtxt, title, btime, etime, opt, deltaday, deltatime - FROM timeline - ORDER BY id "); - $HTML .= qq {
\n予約表
\n}; - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - foreach my $status ( @{$ary_ref} ) { - $HTML .= qq {\n}; - $HTML .= qq {\n\n\n\n}; - $HTML .= qq {\n\n\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - } - $HTML .= qq {
IDtypechtxttitlebtimeetimeoptdeltadaydeltatime
$status->[0]$status->[1]$status->[2]$status->[3]$status->[4]$status->[5]$status->[6]$status->[7]$status->[8]
\n}; -} - -################ mode=log ################ - -if ( $mode eq 'log' ) { - $HTML =~ s/%HTML_TITLE_OPT%/ - Log/; - - $HTML .= qq {
\n}; - $HTML .= qq {\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - $ary_ref = $dbh->selectall_arrayref( - "SELECT id, chtxt, title, btime, etime, opt, exp, longexp, category - FROM in_timeline_log " - ); - foreach my $line ( @{$ary_ref} ) { - $HTML .= qq {\n}; - $HTML .= qq {\n\n\n\n}; - $HTML .= qq {\n\n\n\n}; - $HTML .= qq {\n}; - $HTML .= qq {\n}; - } - $HTML .= qq {
IDchtxttitlebtimeetimeoptexplongexpcategory
$line->[0]$line->[1]$line->[2]$line->[3]$line->[4]$line->[5]$line->[6]$line->[7]$line->[8]
\n}; -} - -################ mode=help ################ - -if ( $mode eq 'help' ) { - $HTML =~ s/%HTML_TITLE_OPT%/ - Help/; - $HTML =~ s|%REFRESH%||; - $HTML .= qq {
\n}; - $HTML .= qq {ヘルプ\n}; -} - -################ mode=test ################ - -if ( $mode eq 'test' ) { - $HTML =~ s/%HTML_TITLE_OPT%/ - Test/; - $HTML =~ s|%REFRESH%||; - $HTML .= qq {
\n}; - - require Data::Dumper; - $tmp = Perl6::Slurp::slurp( 'config.ini' ); - $tmp =~ s/\n/
\n/gs; - $HTML .= $tmp; - - # $HTML .= Dumper( $ary_ref ); -} - -################ mode nasi ################ - -if ( !$mode ) { - &draw_form(); - $HTML =~ s/%HTML_TITLE_OPT%/ - Top/; - $HTML .= qq {Welcome to Rec10!
\n}; - goto end; -} - - -end: -#
-$HTML .= < - - -EOM - -#
-#$HTML_ADV = $HTML_ADV_IMG . $HTML_ADV_TEXT if ( !$HTML_ADV ); -my $HTML_ADV = ''; -$HTML_HEADER = qq {
\n$HTML_ADV\n
\n}; - -&draw_menu(); -$HTML =~ s/%HTML_TITLE_OPT%//; -$HTML =~ s/%REFRESH%//; -$HTML =~ s/%SCRIPT%//; -$HTML =~ s/%CSS%//; -$HTML =~ s/%HTML_HEADER%/$HTML_HEADER/; - -utf8::encode( $HTML ); -print $HTTP_HEADER; -print $HTML; -exit; - -sub draw_menu { - $hires = Time::HiRes::time() - $hires; - $last_modified = localtime((stat 'rectool.pl')[9]); - - $HTML_HEADER .= qq {
\n}; - $HTML_HEADER .= qq {Last-Modified: $last_modified
Time-Elapsed: $hires 秒
\n}; - $HTML_HEADER .= qq {\n}; - $HTML_HEADER .= qq {トップ(検索)\n}; - $HTML_HEADER .= qq {予約確認\n}; - $HTML_HEADER .= qq {予約状況(画像版)\n}; - $HTML_HEADER .= qq {録画一覧\n}; - $HTML_HEADER .= qq {おまかせ\n}; - $HTML_HEADER .= qq {玄人仕様\n}; - $HTML_HEADER .= qq {復旧支援\n}; - $HTML_HEADER .= qq {地引\n}; - $HTML_HEADER .= qq {録画履歴\n}; - $HTML_HEADER .= qq {文字認識\n}; - $HTML_HEADER .= qq {新規予約\n}; -# $HTML_HEADER .= qq {新規予約\n}; - $HTML_HEADER .= qq {\n}; - $HTML_HEADER .= qq {
\n}; - $HTML_HEADER .= qq {
\n}; -} - -sub draw_form { - $chname = $params{ 'chname' }; - $chtxt = $params{ 'chtxt' }; - $key = $params{ 'key' }; - utf8::decode( $key ); - if ( $chname ) { - $chtxt = $dbh->selectrow_array("SELECT chtxt FROM epg_ch WHERE chname = '$chname' "); - } - - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - - # チャンネル指定 - &draw_form_channel(); - - # 日付指定 - $HTML .= qq {\n}; - - # カテゴリ指定 - $HTML .= qq {\n}; - - # キーワード指定 - $HTML .= qq {\n}; - - # フォーム描画 - $HTML .= qq {\n
\n
\n}; -} - -sub draw_form_channel { - $HTML .= qq {\n}; -} - -sub draw_form_opt { - my $shift = shift; - my ( %selected, %checked ); - - if ( $chtxt =~ /BS_103/ ) { - $selected{F} = 'selected'; - } - elsif ( $chtxt =~ /CS_239|CS_240|CS_335/ ) { - $selected{H} = 'selected'; - } - elsif ( $chtxt =~ /BS_101|BS_102/ || $bctype =~ /cs/ ) { - $selected{W} = 'selected'; - } - elsif ( $bctype =~ /bs|te/ ) { - $selected{H} = 'selected'; - } - $selected{g} = 'selected'; - $selected{s} = 'selected'; - $checked{a} = $chtxt =~ /CS_331|CS_332|CS_333|CS_334|CS_335/ || $category =~ /アニメ/ ? 'checked' : ''; - $checked{l} = ''; - $checked{d} = $title =~ /\Q[二]\E|[二]|\Q(二)\E|(二)/ ? 'checked' : ''; - $checked{5} = $title =~ /5\.1|5.1/ ? 'checked' : ''; - $checked{2} = 'checked'; - - if ( $opt ) { - undef %checked; - undef %selected; - my @opt = split //, $opt; - foreach my $opt ( @opt ) { - $selected{$opt} = 'selected' if ( $opt =~ /S|L|G|H|F/ ); - $checked {$opt} = 'checked' if ( $opt =~ /a|h|l|d|2|5/ ); - } - $checked{d} = $title =~ /\Q[二]\E|[二]|\Q(二)\E|(二)/ ? 'checked' : ''; - $checked{5} = $title =~ /5\.1|5.1/ ? 'checked' : ''; - } - # 画質/圧縮率ともに指定されていない場合、真ん中をselectedにする - $selected{g} = 'selected' unless ( $selected{u} || $selected{i} || $selected{o} || $selected{p} ); - $selected{s} = 'selected' unless ( $selected{q} || $selected{w} || $selected{e} || $selected{r} ); - - $HTML .= qq {\n}; - - $HTML .= qq {\n}; - - $HTML .= qq {\n}; - - $HTML .= qq {\n}; - - $HTML .= qq {\n}; - - $HTML .= qq {24fps(主にアニメ)\n}; - $HTML .= qq {二ヶ国語放送\n}; - #$HTML .= qq {2passモード\n}; - $HTML .= qq {5.1ch放送\n}; - $HTML .= qq {
\n}; - $HTML .= qq {\n}; - $HTML .= qq {ファイル名日時追加\n} if ( $shift eq 'reserve' ); - $HTML .= qq {隔週録画\n} if ( $shift eq 'reserve' ); -} - -sub parse_program { - $chname = $params{ 'chname' }; - $chtxt = $params{ 'chtxt' }; - $start = $params{ 'start' }; - $stop = $params{ 'stop' }; - $bayesid = $params{ 'bayesid' }; - $id = $params{ 'id' }; - - if ( $chname ) { - $chtxt = $dbh->selectrow_array("SELECT chtxt FROM epg_ch WHERE chname = '$chname'"); - } - elsif ( $chtxt && $chtxt_0_chname{$chtxt} ) { - $chname = $chtxt_0_chname{$chtxt}; - ( $chtxt_sql = $chtxt ) =~ s/_0/_%/; - $bctype = $dbh->selectrow_array("SELECT bctype FROM epg_ch WHERE chtxt LIKE '$chtxt_sql'"); - } - elsif ( $chtxt ) { - $chname = $dbh->selectrow_array("SELECT chname FROM epg_ch WHERE chtxt = '$chtxt'") - } - ( $title, $desc, $longdesc, $category ) = $dbh->selectrow_array( - "SELECT title, exp, longexp, category - FROM epg_timeline - WHERE channel = '$chtxt' AND start = '$start' AND stop = '$stop' "); - if ( !$bctype ) { - $bctype = $dbh->selectrow_array("SELECT bctype FROM epg_ch WHERE chtxt = '$chtxt'"); - } - - if ( $bayesid ) { - ( $chtxt, $title, $begin, $end ) = $dbh->selectrow_array( - "SELECT chtxt, title, btime, etime FROM auto_timeline_bayes WHERE id = '$bayesid' " - ); - ( $chname, $bctype ) = $dbh->selectrow_array( - "SELECT chname, bctype FROM epg_ch WHERE chtxt = '$chtxt' " - ); - $start = str2datetime( $begin )->strftime( '%Y%m%d%H%M%S' ); - $stop = str2datetime( $end )->strftime( '%Y%m%d%H%M%S' ); - ( $desc, $longdesc, $category ) = $dbh->selectrow_array( - "SELECT exp, longexp, category FROM epg_timeline WHERE channel = '$chtxt' AND start = '$start' AND stop = '$stop' " - ); - } - if ( $id ) { - ( $type, $chtxt, $title, $begin, $end, $deltaday, $deltatime, $opt, $counter ) = $dbh->selectrow_array( - "SELECT type, chtxt, title, btime, etime, deltaday, deltatime, opt, counter - FROM timeline WHERE id = '$id' " - ); - ( $chname, $bctype ) = $dbh->selectrow_array( - "SELECT chname, bctype FROM epg_ch WHERE chtxt = '$chtxt' " - ); - $start = str2datetime( $begin )->strftime( '%Y%m%d%H%M%S' ); - $stop = str2datetime( $end )->strftime( '%Y%m%d%H%M%S' ); - ( $desc, $longdesc, $category ) = $dbh->selectrow_array( - "SELECT exp, longexp, category FROM epg_timeline WHERE channel = '$chtxt' AND start = '$start' AND stop = '$stop' " - ); - } - if ( $bctype =~ /bs|cs/ ) { - $bctype_sql = '_s%'; - } - elsif ( $bctype =~ /te/ ) { - ( $chtxt_0 = $chtxt ) =~ s/(\d+)_.*/$1_0/; - ( $chtxt_sql = $chtxt ) =~ s/_0/_%/; - $bctype_sql = 'te%'; - } - #( $chtxt_no0 ) = $chtxt =~ /(\d+)_/; - @start = $start =~ /(.{4})(.{2})(.{2})(.{2})(.{2})/; - @stop = $stop =~ /(.{4})(.{2})(.{2})(.{2})(.{2})/; - $begin = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', @start, '00' ); - $end = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', @stop , '00' ); - - if ( $params{ 'title' } ) { - $title = $params{ 'title' }; - utf8::decode( $title ); - } - $HTML .= qq {\n}; -} - -sub check_error { - my $is_error; - my $is_same = $dbh->selectrow_array( - "SELECT COUNT(*) FROM timeline WHERE chtxt = '$chtxt' AND btime = '$begin' AND etime = '$end'" - ); - my @overlap = &get_overlap(); - - if ( $is_same ) { - $HTML .= "同一の番組が既に存在します。
\n"; - $is_error = 1; - } - elsif ( $overlap[0] >= 2 ) { - $HTML .= "時間が被る番組が既に2個存在します。
\n"; - $HTML .= $overlap[1]; - $is_error = 2; - } - else { - $is_error = 0; - } - return $is_error; -} - -sub get_overlap { - require List::Util; - - my $ary_ref = $dbh->selectall_arrayref( - "SELECT btime, etime, title - FROM timeline - INNER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt - WHERE bctype LIKE '$bctype_sql' AND type IN $type_user_made - AND btime < '$end' - AND etime > '$begin' - " - ); - - my %overlap; - my $overlap = $max = 0; - my $str; - foreach my $prg ( @{ $ary_ref } ) { - $str .= "$prg->[0] ? $prg->[1] : $prg->[2]
\n"; - $overlap{$prg->[0]} += 1; - $overlap{$prg->[1]} -= 1; - } - foreach my $key ( sort keys %overlap ) { - $overlap += $overlap{$key}; - $max = List::Util::max( $max, $overlap ); - } - if ( wantarray ) { - return ( $max, $str ); - } - else { - return $max; - } -} - -sub get_file_list_wrapper { - local $base_dir = shift; - local $ptr = shift; - - &get_file_list( $base_dir ); -} - -sub get_file_list{ - my $dir = shift; - - opendir ( DIR, $dir ); - my @list = sort readdir( DIR ); - closedir( DIR ); - - foreach my $file ( @list ) { - next if ( $file =~ /^\.{1,2}$/ ); - if ( -d "$dir/$file" ){ - &get_file_list("$dir/$file"); - } - else{ - $abs = "$dir/$file"; - utf8::decode( $abs ); - ( $rel ) = $abs =~ /^$base_dir\/(.*)$/; - $ptr->( $rel, $abs ); - } - } -} - -sub strisjoined { - my $str = shift; - - return $str =~ /.{4}-.{2}-.{2} .{2}:.{2}:.{2}/ ? 0 : 1; -} - -sub str2datetime { - my $str = shift; - my @time; - - if ( strisjoined( $str ) ) { - @time = $str =~ /(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/; - } - else { - @time = $str =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/; - } - return DateTime->new( - year => $time[0], month => $time[1], day => $time[2], - hour => $time[3], minute => $time[4], second => $time[5], - locale => 'ja_JP' , time_zone => $tz - ); -} - -sub str2dayname { - my $str = shift; - our %day_name_cache; - - if ( !$day_name_cache{$str} ) { - $day_name_cache{$str} = str2datetime( $str )->day_name; - } - return $day_name_cache{$str}; -} - -sub str2readable { - my $begin = shift; - my $end = shift; - - my $dt_begin = ref( $begin ) eq 'DateTime' ? $begin : &str2datetime( $begin ); - my $dt_end = ref( $end ) eq 'DateTime' ? $end : &str2datetime( $end ); - - my $str_begin = $dt_begin->strftime( '%m/%d(%a) %H:%M' ); - my $str_end = $dt_end ->strftime( $dt_begin->day == $dt_end->day ? '%H:%M' : '翌 %H:%M' ); - # utf8::encode( $str_begin ); - - my ( $sec, $min, $hour ); - $sec = $dt_end->epoch - $dt_begin->epoch; - $min = int( $sec / 60 ); - $sec = $sec - $min * 60; - $hour = int( $min / 60 ); - $min = $min - $hour * 60; - my $str_diff = ''; - $str_diff .= $hour . '時間' if ( $hour ); - $str_diff .= $min . '分' if ( $min ); - $str_diff .= $sec . '秒' if ( $sec ); - - return ( $str_begin, $str_end, $str_diff ); -} - -sub sqlgetsuggested { - require Encode; - require Text::Ngram; - - my ( $btime, $etime ) = @_; - $deltatime = 3 if ( !$deltatime ); - - $btime_bgn = $btime->clone->subtract( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' ); - $btime_end = $btime->clone->add( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' ); - $etime_bgn = $etime->clone->subtract( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' ); - $etime_end = $etime->clone->add( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' ); - - $ary_ref = $dbh->selectall_arrayref( - "SELECT start, stop, title, exp - FROM epg_timeline - WHERE channel LIKE '$chtxt_sql' - AND start BETWEEN '$btime_bgn' AND '$btime_end' - AND stop BETWEEN '$etime_bgn' AND '$etime_end' " - ); - #die Dumper $ary_ref; - - my %hash; - my $hash_r = Text::Ngram::ngram_counts( $title, 2 ); # bi-gram - foreach my $program ( @{$ary_ref} ) { - my $hash_k = Text::Ngram::ngram_counts( $program->[2], 2 ); - my $point; - map $point += $hash_k->{$_}, keys %{$hash_r}; - push @{$hash{$point}}, $program if ( $point ); - } - - return %hash; -} - +#!/usr/bin/perl +# -d:SmallProf +#use Perl6::Slurp; +#use XML::Simple; +#use CGI; +#use CGI::Lite; +#use Date::Manip; +#Date_Init("TZ=JST","ConvTZ=JST"); +#use SVG; +#use KCatch; +use warnings; +use Algorithm::Diff qw(LCS); +use Archive::Zip; +use CGI; +use CGI::Carp qw( fatalsToBrowser warningsToBrowser ); +use Config::Simple; +use Data::Dumper; +use Date::Simple; +use DateTime; +use DBI; +use MIME::Base64; +use Perl6::Slurp; +use Sort::Naturally; +use Time::Piece; +use Time::Seconds; +use Time::HiRes; +use Tie::IxHash; +#require SVG Time::Simple XML::Atom Encode Text::Ngram List::Compare List::Util +use utf8; +#%DB::packages = ( 'main' => 1 ); + + +################ バージョン定義 ################ + + +my $rectool_version = 101; + + +################ 初期化ここから ################ + + +my $tz = DateTime::TimeZone->new( name => 'local' ); +my $hires = Time::HiRes::time(); + +my $cfg = new Config::Simple; +if ( -e 'rec10.conf' ) { + $cfg->read( 'rec10.conf' ); +} +elsif ( -e '/etc/rec10.conf' ) { + $cfg->read( '/etc/rec10.conf' ); +} +else { + die 'rec10.confが見つかりません。'; +} + +my $sql = $cfg->param( 'db.db' ); + +if ( $sql eq 'MySQL' ) { + my $name = $cfg->param( 'db.mysql_dbname' ); + my $host = $cfg->param( 'db.mysql_host' ); + my $port = $cfg->param( 'db.mysql_port' ); + my $user = $cfg->param( 'db.mysql_user' ); + my $pass = $cfg->param( 'db.mysql_passwd' ); + $dbh = DBI->connect("dbi:mysql:$name:$host:$port", $user, $pass, { + AutoCommit => 1, + RaiseError => 1, + mysql_enable_utf8 => 1, # only availavle for MySQL + }); + $dbh->do( 'SET NAMES utf8' ); +} + +my $rec10_version = eval { + $dbh->selectrow_array( "SELECT version FROM in_status " ); +}; + +my $HTML; + +$HTTP_HEADER = "Content-Type: text/html\n\n"; +$HTML .= < + + +Rec10%HTML_TITLE_OPT% + + + + + + +%REFRESH% +%SCRIPT% +%CSS% + + +%HTML_HEADER% +EOM + +my ( $user, $pass, $auth ); +( $user, $pass ) = eval { + $dbh->selectrow_array( "SELECT webuser, webpass FROM in_settings " ); +}; + +if ( $user and $pass ) { + if ( $ENV{'HTTP_AUTHORIZATION'} ) { + my ( $base64 ) = $ENV{'HTTP_AUTHORIZATION'} =~ /Basic\s(.*)/; + if ( $base64 eq encode_base64( "$user:$pass" ) ) { + $auth = 1; + } + else { + $auth = 0; + } + } + else { + $auth = 0; + } +} +else { + $auth = 1; +} + +if ( !$auth ) { + my ( $base64 ) = $ENV{'REMOTE_USER'} =~ /Basic (.*)/; + $HTTP_HEADER = qq {Status: 401 Authorization Required\nWWW-Authenticate: Basic realm="Protected Rec10 $ENV{'HTTP_AUTHORIZATION'}"\n} . $HTTP_HEADER; + goto end; +} + +if ( $rec10_version != $rectool_version ) { + $HTML .= qq {
\n}; + + if ( $rec10_version > $rectool_version ) { + $HTML .= qq {Rec10本体のバージョンが新しいため、実行できません。
\n}; + $HTML .= qq {rectoolのバージョンアップを行ってください。
\n}; + } + + if ( $rec10_version < $rectool_version ) { + $HTML .= qq {Rec10本体のバージョンが古いため、実行できません。
\n}; + $HTML .= qq {Rec10のバージョンアップを行ってください。
\n}; + } + + $HTML .= qq {Rec10のバージョンは$rec10_version 、rectoolのバージョンは$rectool_version です。
\n}; + $HTML .= qq {公式ページ\n}; + goto end; +} + +$q = new CGI; +%params = $q->Vars; +$mode = $params{ 'mode' }; +$mode_sub = $params{ 'mode_sub' }; + +################ %chtxt_chnameの準備 ################ + +my %chtxt_chname; +my %chtxt_0_chname; +tie %chtxt_0_chname, 'Tie::IxHash'; + +my $ary_ref = $dbh->selectall_arrayref( + "SELECT chtxt, chname, ch, bctype FROM epg_ch + WHERE visible = 1" +); + +%chtxt_chname = map { $_->[0], $_->[1] } @{$ary_ref}; + +# NHK BS 1/2/hiをBS/CSから除外(101-103) - by 2011/04 +# te: 地上波、BSのNHK以外 +# bc: BSのNHK、CS +my @te_ary = grep $_->[0]=~ /^\d|BS_(?!(10|19)[1-3])/, @{$ary_ref}; +my @bc_ary = grep $_->[0]!~ /^\d|BS_(?!(10|19)[1-3])/, @{$ary_ref}; + +# teの操作(まとめる) +foreach my $line ( @te_ary ) { + # te xx_yyyy(chtxt) -> xx(ch) + if ( $line->[3] =~ /te/ ) { + push @{ $chtxt_0_chname{ $line->[2] . '_0'} }, $line->[1]; + } + else { + push @{ $chtxt_0_chname{'BS_' . $line->[2] } }, $line->[1]; + } +} +foreach my $key ( keys %chtxt_0_chname ) { + my @chname = @{ $chtxt_0_chname{$key} }; + if ( @chname >= 2 ) { + # 2つ以上ある場合 + my @tmp = map { my @ary = split //, $_; \@ary } @chname; + # 1つ目と2つ目のみ比較 + # FIXME: すべてを比較するべき + $chtxt_0_chname{$key} = join '', LCS( $tmp[0], $tmp[1] ); + } + else { + # 1つしかない場合 + $chtxt_0_chname{$key} = $chname[0]; + } +} + +# bs/csの操作(そのまま) +foreach my $line ( @bc_ary ) { + $chtxt_0_chname{$line->[0]} = $line->[1]; +} +undef $ary_ref; + + +################ 定数宣言 ################ + + +tie %type, 'Tie::IxHash'; +%type = ( + 'search_everyday' => '隔日検索', + 'search_today' => '当日検索', + 'reserve_flexible' => '浮動予約', + 'reserve_fixed' => '確定予約', + + 'reserve_running' => '録画途中', + + 'convert_b25_ts' => '解読予約', + 'convert_b25_ts_running' => '解読途中', + 'convert_b25_ts_miss' => '解読失敗', + + 'convert_ts_mp4' => '縁故予約', + 'convert_ts_mp4_running' => '縁故於鯖', + 'convert_ts_mp4_network' => '縁故於網', + 'convert_ts_mp4_finished' => '縁故完了', + + 'convert_avi_mkv' => '変換旧露', + 'convert_avi_mp4' => '変換旧四', + 'convert_mkv_mp4' => '変換露四', + 'convert_mkv_mp4_runnings' => '換途露四', + + 'auto_suggest_dec' => '予測解読', + 'auto_suggest_enc' => '予測縁故', + 'auto_suggest_avi2fp' => '予測旧四', + 'auto_suggest_ap2fp' => '予測露四', + + 'move_end' => '移動完了', +); + +%type_suggest = ( + 'auto_suggest_dec' => 'convert_b25_ts', + 'auto_suggest_enc' => 'convert_ts_mp4', + 'auto_suggest_avi2fp' => 'convert_avi_mkv', + 'auto_suggest_ap2fp' => 'convert_mp4_mkv', +); + +%color = ( + 'search_everyday' => '#8B008B', + 'search_today' => '#8B008B', + 'reserve_flexible' => '#4169E1', + 'reserve_fixed' => '#4169E1', + 'reserve_running' => '#FF8C00', + 'convert_b25_ts' => '#CD5C5C', + 'convert_b25_ts_running' => '#DC143C', + 'convert_ts_mp4' => '#32CD32', + 'convert_ts_mp4_running' => '#2E8B57', + 'convert_ts_mp4_network' => '#808000', + + 'other' => '#A0A0A0', +); + +$type_user_made = "( 'search_everyday', 'search_today', 'reserve_flexible', 'reserve_fixed', 'reserve_running' )"; + +tie %category, 'Tie::IxHash'; +%category = ( + 'news' => { name => 'ニュース・報道' , color => '#ff0000' }, + 'sports' => { name => 'スポーツ' , color => '#ff8000' }, + 'information' => { name => '情報' , color => '#ffff00' }, + 'drama' => { name => 'ドラマ' , color => '#80ff00' }, + 'music' => { name => '音楽' , color => '#00ff00' }, + 'variety' => { name => 'バラエティ' , color => '#00ff80' }, + 'cinema' => { name => '映画' , color => '#00ffff' }, + 'anime' => { name => 'アニメ・特撮' , color => '#0080ff' }, + 'documentary' => { name => 'ドキュメンタリー・教養' , color => '#0000ff' }, + 'stage' => { name => '演劇' , color => '#8000ff' }, + 'hobby' => { name => '趣味・実用' , color => '#ff00ff' }, + 'etc' => { name => 'その他' , color => '#ff0080' }, +); + +################ 初期化ここまで ################ + + +################ mode=schedule ################ + +if ( $mode eq 'schedule' ) { + + $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Viewer/; + #$HTML =~ s|%REFRESH%||; + $css = < + td { + white-space: nowrap; + } + +EOM + $css =~ s/^\t{2}//gm; + $HTML =~ s/%CSS%/$css/; + + my $order = $params{ 'order' }; + my $extra = $params{ 'extra' }; + if ( $order ne 'id' ) { + $order = 'btime'; + } + $reverse_extra = $extra ? '' : '&extra=1'; + $forward_order = $order eq 'btime' ? '' : '&order=id'; + + my $ary_ref = $dbh->selectall_arrayref( + "SELECT id, type, timeline.chtxt, epg_ch.chname, title, btime, etime, opt, deltaday, deltatime, + epgtitle, epgbtime, epgetime, epgexp, epgduplicate, epgchange, counter + FROM timeline + LEFT OUTER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt + ORDER BY $order" + , {Slice=>{}}); + + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + foreach my $line ( @{ $ary_ref } ) { + + $type = $type{$line->{type}} || $line->{type}; + if ( $line->{type} =~ /^search/ ) { + $type = qq {$type}; + $line->{deltaday} = qq {空} if ( !$line->{deltaday} && $line->{type} eq 'search_everyday' ); + $line->{deltatime} = qq {空} if ( !$line->{deltatime} ); + } + else { + my $color = $color{$line->{type}} ? $color{$line->{type}} : $color{'other'}; + $type = qq {$type}; + } + # 地上波の場合、xx_yyyをxx_0に置換する + ( $line->{chtxt_0} = $line->{chtxt} ) =~ s/(\d+)_/$1_0/; + # chnameが無いとき(移動縁故など)、chtxtを代わりに使う + $line->{chname} = + $line->{chname} || + $chtxt_0_chname{$line->{chtxt}} || + $chtxt_0_chname{$line->{chtxt_0}}; + if ( !$line->{chname} ) { + # chnameが無いとき、リンクを作成しない + $line->{chname} = $line->{chtxt}; + $line->{chname_link} = qq {$line->{chname}}; + } + else { + $line->{chname_link} = qq {$line->{chname}}; + } + $line->{title} = 'タイトルなし' if ( !$line->{title} ); + $line->{tr_style} = ''; + $line->{title_2} = ''; + my $unix_b = str2datetime( $line->{btime} ); + my $unix_e = str2datetime( $line->{etime} ); + + my $btime = $unix_b->strftime( '%Y%m%d%H%M%S' ); + my $etime = $unix_e->strftime( '%Y%m%d%H%M%S' ); + if ( $extra and $line->{type} =~ /^search_|^reserve_(?!running)/ ) { + #my @ary = $dbh->selectrow_array( + # "SELECT title, exp FROM epg_timeline + # WHERE channel = '$line->{chname}' + # AND start = '$btime' + # AND stop = '$etime' "); + #my @ary = ( $line->{epgtitle}, $line->{epgexp} ); + my ( $epgtitle, $epgexp ) = ( $line->{epgtitle}, $line->{epgexp} ); + + if ( $epgtitle ) { + $epgtitle =~ s/無料≫//; + + if ( $epgtitle ne $line->{title} ) { + # epgtitleとtitleが一致しない + # []に囲まれた部分を除去して比較 + my @brackets = $line->{title} =~ /(\[.+\])+/; + my $epgtitle_nobrackets = $epgtitle; + my $title_nobrackets = $line->{title}; + if ( @brackets && $epgtitle =~ /(\[.+\])+/ >= @brackets ) { + foreach ( @brackets ) { + $epgtitle_nobrackets =~ s/\Q$_\E//; + } + } + $title_nobrackets =~ s/(\[.+\])+//; + if ( !scalar $epgtitle_nobrackets =~ s/\Q$title_nobrackets\E// ) { + # epgtitleにtitleが含まれていない + my $href = qq {自動検索}; + $epgtitle = qq {$epgtitle■$href■}; + } + else { + # epgtitleにtitleが含まれている + $epgtitle = $epgtitle_nobrackets; + } + } + else { + # epgtitleとtitleが一致している + $epgtitle = '説明'; + } + + $line->{title_2} = qq {
$epgtitle
}; + } + else { + # epgtitleがない + my $href = qq {自動検索}; + $line->{title_2} = qq {■$href■}; + $line->{tr_style} = qq {style="background-color: #A0A0A0"}; + } + } + + my ( $begin, $end, $diff ) = &str2readable( $unix_b, $unix_e ); + + my $hr = ''; + if ( + $line->{type} eq 'reserve_running' + && + $unix_b->epoch <= time && time <= $unix_e->epoch + ) + { + $percent = int( ( 100 * ( time - $unix_b->epoch ) ) / ( $unix_e->epoch - $unix_b->epoch ) ); + $hr .= qq {
}; + } + + $line->{title} = qq {$line->{title}}; + #$line->{title} = qq {
$line->{title}
} if ( $line->{title_2} ); + $HTML .= qq {{tr_style}>\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n\n\n\n}; + $HTML .= qq {\n}; + } + $HTML .= qq {
■IDタイプチャンネルタイトル開始時刻終了時刻録画時間オプションdddt残り
$line->{id}$type$line->{chname_link}$line->{title}$line->{title_2}$begin$end$hr$diff$line->{opt}$line->{deltaday}$line->{deltatime}$line->{counter}
\n}; + #$HTML .= qq {\n}; + $HTML .= qq {\n
\n
\n}; + goto end; +} + +################ mode=graph ################ + +if ( $mode eq 'graph' ) { + + my $date = $params{ 'date' }; + + if ( $date ) + { + print "Content-Type: image/svg+xml\n\n"; + + require SVG; + $date = Date::Simple->new( split /-/, $date ); + $graph_bgn = $date->format('%Y-%m-%d'); + $graph_end = $date->next->format('%Y-%m-%d'); + $day = $date->day; + $today = $date eq Date::Simple->today() ? 1 : 0; + + $tuner{terrestrial} = $cfg->param( 'env.te_max' );# 2; + $tuner{satellite} = $cfg->param( 'env.bscs_max' );# 2; + $tuner{all} = $tuner{terrestrial} + $tuner{satellite}; + $hours = 24; + $width = 30 * $hours; + my %category_color = map { $_->{name}, $_->{color} } values %category; + + $svg = new SVG( width => 820, height => $tuner{all} * 20 + 40 ); + $svg->rectangle( 'x' => 40, 'y' => 20, + width => $width + 20, height => $tuner{all} * 20 + 10, + rx => 15, ry => 15, + style => { stroke => 'blue', fill => 'white' } ); + for ( 1..$tuner{terrestrial} ) { + $svg->text( 'x' => 10, 'y' => ( $_ + 1 ) * 20 ) + ->cdata( "T$_" ); + } + for ( 1..$tuner{satellite} ) { + $svg->text( 'x' => 10, 'y' => ( $_ + $tuner{terrestrial} + 1 ) * 20 ) + ->cdata( "S$_" ); + } + for ( 0..$hours ) { + $svg->text( 'x' => $_ * 30 + 65, 'y' => 15, + style => { 'text-anchor' => 'middle' } ) + ->cdata( sprintf( '%02d', $_ ) ) if ( $_ < $hours ); + # $svg->line( ); # can't be used when required + $svg->tag( 'line', x1 => $_ * 30 + 50, x2 => $_ * 30 + 50, y1 => 30, y2 => $tuner{all} * 20 + 20, + style => { stroke => 'gray' } ); + } + for ( 1..$tuner{all} ) { +# $svg->tag( 'line', x1 =>50, x2 => 50 + $width, y1 => $_ * 20 + 10, y2 => $_ * 20 + 10, +# style => { stroke => 'gray' } ); +# $svg->rectangle( 'x' => 50, 'y' => $_ * 20 + 10, width => $width, height => 10 ); + $svg->rectangle( 'x' => 50, 'y' => $_ * 20 + 14, width => $width, height => 2 ); + } + if ( $today ) { + require Time::Simple; + my $time = Time::Simple->new(); + my $x = ( $time->hours * 60 + $time->minutes ) * 0.5 + 50; + $svg->tag( 'line', x1 => $x, x2 => $x, y1 => 30, y2 => $tuner{all} * 20 + 20, + style => { stroke => 'red', 'fill-opacity' => '1.0' } ); + } + my $ary_ref = $dbh->selectall_arrayref( + # epg_timeline.channel = timeline.chtxt && + "SELECT id, title, chtxt, btime, etime, epgcategory, opt FROM timeline + WHERE type IN $type_user_made + AND + ( + '$graph_bgn 00:00' <= btime AND btime < '$graph_end 00:00' + OR + '$graph_bgn 00:00' < etime AND etime <= '$graph_end 00:00' + ) + ORDER BY btime" + , {Slice=>{}} + ); + + foreach my $bctype ( '\d+_', 'S_' ) { + my $tuner = $bctype eq '\d+_' ? $tuner{terrestrial} : $tuner{satellite}; + my @ary_ref = grep { $_->{chtxt} =~ /$bctype/ } @{ $ary_ref }; + my @y_drawn = ('') x $tuner; + foreach my $line ( @ary_ref ) { + @start = $line->{btime} =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2})/; + @stop = $line->{etime} =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2})/; + $start = ( ( $day == $start[2] ? 0 : 24 * 60 ) + $start[3] * 60 + $start[4] ) * 0.5; + $stop = ( ( $day == $stop [2] ? 0 : 24 * 60 ) + $stop [3] * 60 + $stop [4] ) * 0.5; + $start = 0 if ( $start < 0 || $day > $start[2] ); # 月の変わり目はスルー + $stop = $width if ( $stop > $width ); + $begin = $line->{btime}; + $end = $line->{etime}; + + my @ary = grep { ( $_->{etime} cmp $line->{btime} ) > 0 and ( $_->{btime} cmp $line->{etime} ) < 0 and $_->{id} != $line->{id} } @ary_ref; + foreach my $i ( 0..$tuner - 1 ) { + next if ( ( $y_drawn[$i] cmp $line->{btime} ) > 0 ); + #for ( 'chtxt', 'btime', 'etime' ) { + # $f = 0 if ( $line->{$_} ne $ary[$i]->{$_} ); + #} + $line->{slot} = $i; + $y_drawn[$i] = $line->{etime}; + last; + } + my ( $r, $g, $b ) = ( 0, 0, 0 ); + $r += 255 if ( $line->{opt} =~ /a/ ); + $g += 255 if ( $line->{opt} =~ /H/ ); + $b += 255 if ( $line->{opt} =~ /I/ ); + if ( $r + $g + $b == 255 * 3 ){ + $r = 0; + $g = 255; + $b = 255; + } + if ( $r + $g + $b == 0 ){ + $r = $g = $b = 128; + } + my %escaped = ( '&' => 'amp', '<' => 'lt', '>' => 'gt', '"' => 'quot' ); + sub html_escape{ + my $str = shift or return; + my $result = ''; + $result .= $escaped{$_} ? '&' . $escaped{$_} . ';' : $_ + for (split //, $str); + $result; + } + $svg->anchor( + -href => "rectool.pl?mode=edit&id=$line->{id}", + target => '_blank', + -title => html_escape( $line->{title} ), + )->rectangle( + 'x' => 50 + $start, + 'y' => 30 + ( $bctype eq '\d+_' ? 0 : $tuner{terrestrial} * 20 ) + $line->{slot} * 20, + width => $stop - $start, + height => 10, + style => { fill => $category_color{$line->{epgcategory}} || $category_color{'その他'} } ); + #style => { fill => "rgb($r,$g,$b)" } ); + } + } + my $xml = $svg->xmlify; + utf8::encode( $xml ); + print $xml; + #warningsToBrowser(true); + exit; + } + else + { + $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Viewer - Graphical/; + $HTML .= qq {
\n}; + # $base64 = encode_base64( $svg->xmlify ); + # $HTML .= qq {\n\n}; + $HTML .= qq {予約状況一覧です。T1,T2は地上波、S1,S2はBS/CSを示しています。
\n}; + $HTML .= qq {SVGが利用可能なブラウザでご覧ください。
\n}; + $HTML .= qq {色とジャンルの対応\n}; + map { + $HTML .= qq {$_->{name}\n}; + } values %category; + $HTML .= qq {
\n}; + + $ary_ref = $dbh->selectcol_arrayref( + "SELECT DISTINCT DATE( btime ) + FROM timeline + WHERE type in $type_user_made + ORDER BY btime" + ); + foreach my $date ( @{ $ary_ref } ) { + my @date = $date =~ /(.{4})-(.{2})-(.{2})/; + my $dn = DateTime->new( year => $date[0], month => $date[1], day => $date[2], locale => 'ja_JP' )->day_name; + #utf8::encode( $dn ); + $HTML .= qq {$date[1]/$date[2]($dn)の予約状況
\n}; + # + $HTML .= qq {\n}; + $HTML .= qq {SVG Image $date\n\n
\n}; + + $date2 = Date::Simple->new( @date )->next->format('%Y-%m-%d'); + my $ary_ref = $dbh->selectall_arrayref( + "SELECT chtxt, title, btime, etime FROM timeline + WHERE '$date 00:00' <= btime AND etime <= '$date2 01:00' + ORDER BY btime" + ); + + foreach my $line ( @{ $ary_ref } ) { + #$HTML .= qq {$line->[0] $line->[1] $line->[2] $line->[3]
\n}; + } + + } + + goto end; + } +} + +################ mode=atom ################ + +if ( $mode eq 'atom' ) { + require XML::Atom::Feed; + require XML::Atom::Entry; + + my $recording_count = $encoding_count = $jbk_count = 0; + my $ary_ref = $dbh->selectall_arrayref( + "SELECT chtxt, title, btime, etime, opt + FROM timeline + WHERE type = 'reserve_running' "); + foreach my $line ( @{$ary_ref} ) { + my ( $begin, $end, $diff ) = &str2readable( $line->[2], $line->[3] ); + $recording_status .= qq {$line->[0] $line->[1] $begin - $end $diff $line->[4]
\n}; + $recording_count++; + } + $ary_ref = $dbh->selectall_arrayref( + "SELECT chtxt, title, btime, etime, opt + FROM timeline + WHERE type = 'convert_ts_mp4_running' "); + foreach my $line ( @{$ary_ref} ) { + my ( $begin, $end, $diff ) = &str2readable( $line->[2], $line->[3] ); + $encoding_status .= qq {$line->[0] $line->[1] $begin - $end $diff $line->[4]
\n}; + $encoding_count++; + } + $ary_ref = $dbh->selectall_arrayref( + "SELECT id, chtxt, title, btime, etime + FROM auto_timeline_keyword " ); + foreach my $line ( @{$ary_ref} ) { + my ( $begin, $end, $diff ) = &str2readable( $line->[3], $line->[4] ); + $jbk_status .= qq {$line->[0] $line->[1] $line->[2] $begin - $end $diff
\n}; + $jbk_count++; + } + + my $feed = XML::Atom::Feed->new( Version => 1.0 ); + $feed->title('Rec10 フィード'); + + my $entry = XML::Atom::Entry->new( Version => 1.0 ); + $entry->title("Rec10 録画状況 ($recording_count)"); + $entry->id('tag:recording_status'); + $entry->content($recording_status); + $entry->add_link(str_to_link( './rectool.pl?mode=schedule' ) ); + $feed->add_entry($entry); + + $entry = XML::Atom::Entry->new( Version => 1.0 ); + $entry->title("Rec10 縁故状況 ($encoding_count)"); + $entry->id('tag:encoding_status'); + $entry->content($encoding_status); + $entry->add_link(str_to_link( './rectool.pl?mode=schedule' ) ); + $feed->add_entry($entry); + + $entry = XML::Atom::Entry->new( Version => 1.0 ); + $entry->title("Rec10 地引状況 ($jbk_count)"); + $entry->id('tag:jbk_status'); + $entry->content($jbk_status); + $entry->add_link(str_to_link( './rectool.pl?mode=jbk' ) ); + $feed->add_entry($entry); + + my $xml = $feed->as_xml; + print "Content-Type: application/atom+xml\n\n"; + print $xml; + exit; + + sub str_to_link { + my $link = XML::Atom::Link->new( Version => 1.0 ); + $link->type('text/html'); + $link->rel('alternate'); + $link->href(shift); + return $link; + } +} + +################ mode=edit ################ + +if ( $mode eq 'edit' ) { + my $id = $params{ 'id' }; + + $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Editor/; + $HTML .= qq {
\n}; + + $script = < + + +EOM + $script =~ s/^\t{2}//gm; + $HTML =~ s/%SCRIPT%/$script/; + + $HTML .= "スケジュール編集画面です。
\n"; + $HTML .= "実装がとても適当なので、利用には細心の注意を払ってください。
\n
\n"; + if ( $id ) { + # 予約の編集 + &parse_program(); + $button_bgn = $button_end = ''; + } + else { + # 新規予約 + $type = 'reserve_flexible'; + $counter = -1; + $datetime_now = DateTime->now( time_zone => $tz )->set_second( 0 )->add( minutes => 1)->strftime( '%Y-%m-%d %H:%M:%S' ); + $button_bgn = qq{\n
\n}; + $button_end = + qq{} + .qq{} + .qq{}; + } + + if ( $params{ 'suggest' } eq 'auto' ) { + my @btime = $begin =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/; + my @etime = $end =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/; + my $btime = DateTime->new( + year => $btime[0], month => $btime[1], day => $btime[2], + hour => $btime[3], minute => $btime[4], second => $btime[5], + ); + my $etime = DateTime->new( + year => $etime[0], month => $etime[1], day => $etime[2], + hour => $etime[3], minute => $etime[4], second => $etime[5], + ); + my %hash = &sqlgetsuggested( $btime, $etime ); + + $HTML .= qq {可能性のある番組
\n}; + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + + foreach my $key (sort keys %hash){ + my $val = $hash{$key}; + foreach my $val ( @{$val} ) { + my $style = qq {style="white-space: nowrap"}; + $val->[0] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; + $val->[1] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; + $HTML .= qq {\n\n\n}; + $HTML .= qq {\n\n\n}; + $HTML .= qq {\n\n}; + } + } + $HTML .= qq {
優先度タイトル開始時刻終了時刻説明適用
$key$val->[2]$val->[0]$val->[1]$val->[3]
\n
\n}; + } + + my $len = length $id; + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {ID\n\n}; + $HTML .= qq {タイプ\n\n}; + + $HTML .= qq {チャンネル\n
\n}; + $HTML .= qq {タイトル\n
\n}; + $HTML .= qq {開始時刻\n\n}; + $HTML .= $button_bgn; + $HTML .= qq {終了時刻\n\n}; + $HTML .= $button_end . "
\n"; + $HTML .= qq {隔日周期\n\n}; + $HTML .= qq {時刻誤差\n\n}; + $HTML .= qq {オプション\n\n}; + $HTML .= qq {回数\n\n}; + $HTML .= qq {\n
\n}; +} + +################ mode=change ################ + +if ( $mode eq 'change' ) { + @id = $q->param( 'id' ); + + $HTML =~ s/%HTML_TITLE_OPT%/ - Change/; + $HTML .= qq {
\n}; + + if ( $params{ 'delete' } ) + { + if ( @id ) { + foreach my $id ( @id ) { + $dbh->do( "DELETE FROM timeline WHERE id = '$id'" ); + } + $HTML .= "削除しました。
\n5秒後に予約確認画面に移動します。
\n"; + $HTML =~ s|%REFRESH%||; + goto end; + } + } + if ( $params{ 'update' } ) + { + $type = $params{ 'type' }; + $chtxt = $params{ 'chtxt' }; + $title = $params{ 'title' }; + $begin = $params{ 'begin' }; + $end = $params{ 'end' }; + $deltaday = $params{ 'deltaday' }; + $deltatime = $params{ 'deltatime' }; + $opt = $params{ 'opt' }; + $counter = $params{ 'counter' }; + $id = $id[0]; + if ( $id ) { + $dbh->do( + "UPDATE timeline SET type = '$type', chtxt = '$chtxt', title = '$title', + btime = '$begin', etime = '$end', + deltaday = '$deltaday', deltatime = '$deltatime', opt = '$opt', counter = '$counter' + WHERE id = '$id'" + ); + } + else { + $dbh->do( + "INSERT INTO timeline ( type, chtxt, title, btime, etime, deltaday, deltatime, opt, counter ) + VALUES ( '$type', '$chtxt', '$title', '$begin', '$end', '$deltaday', '$deltatime', '$opt', '$counter' )" + ); + } + $HTML .= "更新しました。
\n5秒後に予約確認画面に移動します。
\n"; + $HTML =~ s|%REFRESH%||; + goto end; + } + if ( $mode_sub eq 'proc' ) { + my $type = $params{ 'type' }; + my $chtxt = $params{ 'chtxt' } || 'nhk-k'; + my $title = $params{ 'title' }; + my @opt = $q->param( 'opt' ); + my $opt = join '', @opt; + + my $datetime_now = DateTime->now( time_zone => $tz )->set_second( 0 )->add( minutes => 10); + my $sql_type = $type_suggest{$type}; + my $begin = $datetime_now->strftime( '%Y-%m-%d %H:%M:%S' ); + $datetime_now = $datetime_now->add( minutes => 60 ); + my $end = $datetime_now->strftime( '%Y-%m-%d %H:%M:%S' ); + + $dbh->do( + "INSERT INTO timeline ( type, chtxt, title, btime, etime, opt ) + VALUES ( '$sql_type', '$chtxt', '$title', '$begin', '$end', '$opt' )" + ); + + goto end; + } + if ( $mode_sub eq 'move' ) { + my $mode_sub2 = $params{ 'mode_sub2' }; + my $title = $params{ 'title' }; + my $response; + + $ENV{'LANG'} = 'ja_JP.UTF-8'; + if ( $mode_sub2 eq 'predict' ) { + $HTML .= "移動後のシミュレーション結果です。\n
"; + eval '$response = `python26 ' . $cfg->param( 'path.rec10' ) . "/classify.py -s '$title'`"; + } + elsif ( $mode_sub2 eq 'exec' ) { + eval '$response = `python26 ' . $cfg->param( 'path.rec10' ) . "/classify.py -e '$title'`"; + } + utf8::decode( $response ); + $HTML .= $response; + + goto end; + } + if ( $mode_sub eq 'setting' ) { + my $jbk = $params{ 'jbk' } || '0'; + my $bayes = $params{ 'bayes' } || '0'; + my $del_tmp = $params{ 'del_tmp' } || '0'; + my $opt = $params{ 'opt' } || ''; + my $user = $params{ 'user' } || ''; + my $pass = $params{ 'pass' } || ''; + + $dbh->do( + "UPDATE in_settings SET auto_jbk = '$jbk', auto_bayes = '$bayes', + auto_del_tmp = '$del_tmp', auto_opt = '$opt'" + ); + + goto end; + } + if ( $mode_sub eq 'fixstatus' ) { + my $key = $params{ 'terec' } ? 'terec' : $params{ 'bscsrec' } ? 'bscsrec' : + $params{ 'b252ts' } ? 'b252ts' : $params{ 'ts2avi' } ? 'ts2avi' : ''; + + $dbh->do( + "UPDATE in_status SET $key = 0" + ); + + goto end; + } + +} + +################ mode=confirm ################ + +if ( $mode eq 'confirm' ) { + if ( $mode_sub eq 'reserve' ) { + $HTML =~ s/%HTML_TITLE_OPT%/ - Reserver/; + $HTML .= qq {
\n}; + &parse_program(); + + my $duration = ( str2datetime( $end ) - str2datetime( $begin ) )->delta_minutes; + $HTML .= "番組名:$title
\nチャンネル:$chname
\n放送継続時間:$duration 分
\n番組内容:$desc
\nジャンル:$category
\n"; + if ( $longdesc ) { + $longdesc =~ s/\\n/
\n/gs; + $HTML .= "番組内容(長):$longdesc
\n"; + } + my $error = &check_error(); + if ( $error ) + { + # エラー + + $ary_ref = $dbh->selectall_arrayref( + "SELECT start, stop FROM epg_timeline WHERE channel = '$chtxt' AND title = '$title' " + ); + if ( $error != 1 ) { + $HTML .= "同一の番組の他の放送予定です。
\n"; + foreach my $line ( @{$ary_ref} ) { + $begin = $line->[0]; + $end = $line->[1]; + $begin =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; + $end =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; + $overlap = &get_overlap() >= 2 ? '不可能' : + qq {可能}; + $HTML .= "開始:$begin\n終了:$end\n録画は$overlap
\n"; + } + } + } + else { + $HTML .= "録画予約の詳細設定を行ってください。
\n"; + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n} if ( $params{ 'title' } ); + &draw_form_opt( 'reserve' ); + $HTML .= qq {\n
\n}; + } + goto end; + } + # End of $mode_sub eq 'reserve'; + + if ( $mode_sub eq 'proc' ) { + my $type = $params{ 'type' }; + local $chtxt = $params{ 'chtxt' }; + my $title = $params{ 'title' }; + local $opt = $params{ 'opt' }; + utf8::decode( $title ); + + $HTML .= "詳細設定を行ってください。
\n"; + $HTML .= "タイトル:$title\n
\n"; + + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + &draw_form_channel( 'nonone' ); + &draw_form_opt(); + $HTML .= qq {\n
\n}; + goto end; + } +} + +################ mode=reserve ################ + +if ( $mode eq 'reserve' ) { + $HTML .= qq {
\n}; + &parse_program(); + $title = $params{ 'title' } if ( !$title ); + @opt = $q->param( 'opt' ); + $opt = join '', @opt; + my ( $deltaday, $deltatime ); + + if ( $params{'every'} eq '1' ) { + $type = 'search_everyday'; + ( $changed_t ) = $title =~ /(.*)#/; + $title = $changed_t if ( $changed_t ); + ( $changed_t ) = $title =~ /(.*)第/; + $title = $changed_t if ( $changed_t ); + ( $changed_t ) = $title =~ /(.*)▽/; + $title = $changed_t if ( $changed_t ); + $title =~ s/「.*」//; + $title =~ s/<.*>//; + $title =~ s/(.*)//; + $title =~ s/\[新\]//; + $title =~ s/無料≫//; + $title =~ s/\s*$//; + $deltaday = 7; + $deltatime = 3; + } + else { + $type = 'reserve_flexible'; + } + $chtxt = $chtxt_0 if ( $chtxt_0 ); + if ( !&check_error ) { + $dbh->do( + "INSERT INTO timeline ( type, chtxt, title, btime, etime, opt, deltaday, deltatime ) + VALUES ( '$type', '$chtxt', '$title', '$begin', '$end', '$opt', '$deltaday', '$deltatime' )" + ); + } + $HTML .= "録画予約を実行しました。
\n5秒後にトップへ移動します。
\n"; + $HTML =~ s|%REFRESH%||; + goto end; +} + +################ mode=program ################ + +if ( $mode eq 'program' ) { + &draw_form(); + + $HTML =~ s/%HTML_TITLE_OPT%/ - Program Viewer/; + $unix = DateTime->now( time_zone => $tz )->strftime( '%Y%m%d%H%M%S' ); + $sql = + "SELECT channel, epg_ch.chname, start, stop, title, category + FROM epg_timeline + INNER JOIN epg_ch ON epg_timeline.channel = epg_ch.chtxt + WHERE $unix <= stop %CH% %DATE% %CATEGORY% %KEY% ORDER BY start"; + + if ( $chtxt ) { + my $ch; + if ( $chtxt =~ /^\d+(_0)?$/ ) { + # teはxx_yyy形式であるため + $chtxt =~ s/_0//; + $ch = "AND channel LIKE '$chtxt\_%'"; + } + else { + $ch = "AND channel = '$chtxt'"; + } + $sql =~ s/%CH%/$ch/; + } + if ( $date_sel ) { + $date_1 = $date_sel . '000000'; + $date_2 = Date::Simple->new( $date_sel =~ /(.{4})(.{2})(.{2})/ )->next->format('%Y%m%d') . '000000'; + my $date = "AND '$date_1' <= stop AND start <= '$date_2'"; + $sql =~ s/%DATE%/$date/; + } + if ( $category_sel ) { + # 一時的 + # $category_tmp = $category{$category_sel} . $category_sel; + my $category = "AND category = '$category{$category_sel}->{name}'"; + $sql =~ s/%CATEGORY%/$category/; + } + if ( $key ) { + my $key = "AND TITLE LIKE '%$key%'"; + $sql =~ s/%KEY%/$key/; + } + $sql =~ s/%CH%//; + $sql =~ s/%DATE%//; + $sql =~ s/%KEY%//; + $sql =~ s/%CATEGORY%//; + + $ary_ref = $dbh->selectall_arrayref( $sql ); + foreach my $prg ( @{ $ary_ref } ) { + my @date = $prg->[2] =~ /(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/; + + $date = $date[2]; + if ( $date != $prev ) { + my $date = DateTime->new( + year => $date[0], month => $date[1], day => $date[2], + locale => 'ja_JP' + ); + + my $dn = $date->day_name; + #utf8::encode( $dn ); + $HTML .= qq {--------$date[1]/$date[2]($dn)--------
\n}; + } + $HTML .= qq {$date[1]/$date[2] $date[3]:$date[4] }; + $HTML .= qq {$prg->[1] } if ( !$chtxt ); + $HTML .= qq {$prg->[4]
\n}; + $prev = $date; + } +} + +################ mode=list ################ + +if ( $mode eq 'list' ) { + $HTML =~ s/%HTML_TITLE_OPT%/ - List/; + $HTML .= qq {
\n}; + + $script = < + + + + +EOM + $script =~ s/^\t{2}//gm; + $HTML =~ s/%SCRIPT%/$script/; + + my $recording = $cfg->param( 'path.recpath' ); + my $ts_movepath = $cfg->param( 'path.ts_movepath' ); + my $recorded = $cfg->param( 'path.recorded' ); + + if ( $mode_sub eq 'log' ) { + my $title = $params{ 'title' }; + my $log = slurp( "$recording/$title.log" ) if ( -e "$recording/$title.log" ); + utf8::decode( $log ); + $HTML .= '
'.$log."
\n"; + goto end; + } + if ( $mode_sub eq 'logzip' ) { + my $title = $params{ 'title' }; + my $zip = Archive::Zip->new(); + my $logzip; + die 'read error' unless $zip->read("$recording/$title.log.zip") == AZ_OK; + my @members = $zip->members(); + foreach (@members) { + $logzip .= $_->fileName() . "\n"; + my @lines = split /\n|\r/, $zip->contents( $_->fileName() ); + my %count; + @lines = grep {!$count{$_}++} @lines; + $logzip .= join "\n", @lines; + $logzip .= "\n
\n"; + } + + utf8::decode( $logzip ); + $HTML .= '
'.$logzip."
\n"; + goto end; + } + if ( $mode_sub eq 'ffmpeg' ) { + my $path = $params{ 'path' }; + # mediainfo (not working) + # ffprobe + my $ffmpeg = `ffmpeg -i "$path" 2>&1`; + utf8::decode($ffmpeg); + $ffmpeg = join "
\n", grep /Duration|Stream/, split /\n/, $ffmpeg; + $HTML = $ffmpeg; + goto end; + } + if ( !$mode_sub ) { + $HTML .= qq {録画中のみ\n}; + $HTML .= qq {録画後のみ\n
\n}; + } + if ( !$mode_sub || $mode_sub eq 'new' ) { + $HTML .= "録画中のファイル一覧
\n"; + &list( $recording ); + } + if ( !$mode_sub ) { + $HTML .= "
\n"; + } + if ( !$mode_sub || $mode_sub eq 'old' ) { + $HTML .= "録画後のファイル一覧
\n"; + &simple_list( $ts_movepath ); + &simple_list( $recorded ); + } + + sub list { + local $path = shift; + local %list = (); + my @exp = ( 'log', 'log.zip', 'ts.b25', 'ts.tsmix', 'ts', 'ts.log', + 'aac', 'srt', 'm2v', 'wav', '264', 'mp4', 'mkv' ); + for ( 0..$#exp ) { + $exp{$exp[$_]} = $_; + } + my $exp_count = scalar keys %exp; + + &get_file_list_wrapper( $path, \&wanted ); + + my $help; + foreach my $name ( sort { $exp{$a} <=> $exp{$b} } keys %exp ) { + $help .= $exp{$name} + 1 . " = $name / "; + } + $HTML .= $help; + $help = qq {$help\n\n}; + $help .= qq {$_\n} for ( 1..$exp_count ); + + $HTML .= qq {
\n○ = 完了 / ● = 書き込み中 / ◆ = ファイルサイズ異常
\n}; + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n} for ( 1..$exp_count ); + $HTML .= qq {\n}; + + my $count = 0; + + foreach my $title ( sort keys %list ) { + my $value = $list{$title}; + my @flag = ( 0 ) x ( $exp_count ); + $HTML .= qq {\n\n}; + foreach my $exp ( keys %{$value} ) { + if ( $exp eq 'log' ) { + # ログへのリンクを追加 + my $title = $q->escape( $title ); + my $extra = qq {\n}; + + $value->{$exp}->{extra} = $extra; + } + elsif ( $exp eq 'log.zip' ) { + # ZIPログへのリンクを追加 + my $title = $q->escape( $title ); + my $extra = qq {\n}; + + $value->{$exp}->{extra} = $extra; + } + elsif ( $exp eq 'mp4' ) { + # ○などの代わりにサイズを表示 + # $value->{$exp}->{style} = $value->{$exp}->{size}; + my $size = $value->{$exp}->{size}; + my $extra = qq {\n}; + $value->{$exp}->{extra} = $extra; + } + elsif ( $exp eq 'mkv' ) { + # サムネイルへのリンクを追加 + my $title = $q->escape( $title ); + + my $extra = qq {\n}; + $value->{$exp}->{extra} = $extra; + } + $flag[$exp{$exp}] = $value->{$exp}; + } + foreach ( @flag ) { + my $size = $_->{size}; + my $style = $_->{style}; + my $span = $size ? qq {$style} : '
'; + $HTML .= $_->{extra} || qq {\n}; + } + $HTML .= qq {\n}; + $HTML .= $help unless ( ++$count % 20 ); + } + $HTML .= qq {
タイトル$_
$title○○$size■$span
\n}; + + sub wanted { + my $rel = shift; + my $abs = shift; + + return if ( $rel =~ /Thumbs\.db/ ); + return if ( $rel =~ /\.idx/ ); + + $rel =~ s/\.temp$//; + my $regexp = join '|', keys %exp; + my ( $title, $exp ) = $rel =~ /(.*?)\.($regexp)$/; + my ( $size, $style ) = &get_size( $abs ); + $rel =~ s/\.temp$//; + if ( !$title ) { + $title = '_error_exp_'.$rel; + $exp = 'log'; + } + if ( $title !~ /[^0-9A-F]+/ ) { + my $tmp = pack( 'H*', $title ); + if ( !$tmp ) { + $title = '_error_b16_'.$rel; + $exp = 'log'; + } + else { + $title = 'Base16_'.$tmp; + } + } + $list{$title}->{$exp} = { 'style' => $style, 'size' => $size }; + } + } + + sub simple_list { + require Encode; + + local $path = shift; + local @list = (); + + &get_file_list_wrapper( $path, \&simple_wanted ); + +# @list = sort @list; + # natural sortを行う + #@list = map( Encode::decode_utf8( $_ ), @list ); + @list = nsort @list; + #@list = map( Encode::encode_utf8( $_ ), @list ); + + foreach ( @list ) { + $HTML .= "$_
\n"; + } + + sub simple_wanted { + my $rel = shift; + my $abs = shift; + + my ( $size ) = &get_size( $abs ); + $rel = qq {$rel}; + push @list, $rel ."\t".$result."\t". $size; + } + } + + sub get_size { + my $file = shift; + my ( $size, $last ) = (stat( $file ))[7,9]; + my @unim = ("B","KiB","MiB","GiB","TiB","PiB"); + my $count = 0; + + while($size >= 1024 ){ + $count++; + $size = $size / 1024; + } + $size *= 100; + $size = int( $size ); + $size /= 100; + if ( time - $last < 10 ) { + $style = '●'; + } + elsif ( $size == 0 ) { + $style = '◆'; + } + else { + $style = '○'; + } + return ( "$size $unim[$count]", $style ); + } +} + +################ mode=thumb ################ + +if ( $mode eq 'thumb' ) { + my $title = $params{ 'title' }; + my $pos = $params{ 'pos' }; + my $recording = $cfg->param( 'path.recpath' ); + + print "Content-Type: image/jpeg\n\n"; + exec "ffmpeg -ss 300 -i '$recording/$title.mkv' -f image2 -pix_fmt jpg -vframes 1 -s 320x240 -"; + exit; +} + +################ mode=check ################ + +if ( $mode eq 'check' ) { +} + +################ mode=bravia ################ + +if ( $mode eq 'bravia' ) { + $HTML =~ s/%HTML_TITLE_OPT%/ - Bravia/; + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + my $order = $params{ 'order' }; + if ( $order ne 'point' ) { + $order = 'btime'; + } + else { + $order = 'point DESC'; + } + my $ary_ref = $dbh->selectall_arrayref( + "SELECT id, chtxt, title, btime, etime, point + FROM auto_timeline_bayes + ORDER BY $order" ); + + foreach my $line ( @{ $ary_ref } ) { + my ( $begin, $end, $diff ) = &str2readable( $line->[3], $line->[4] ); + + $line->[1] = $chtxt_chname{$line->[1]} || $line->[1]; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + } + $HTML .= qq {
IDチャンネルタイトル開始時刻終了時刻録画時間ポイント予約
$line->[0]$line->[1]$line->[2]$begin$end$diff$line->[5]予約
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + +} + +################ mode=proc ################ + +if ( $mode eq 'proc' ) { + $HTML =~ s/%HTML_TITLE_OPT%/ - Proposal/; + $HTML .= qq {
\n}; + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + + my $ary_ref = $dbh->selectall_arrayref( + "SELECT type, chtxt, title + FROM auto_proc + ORDER BY title " ); + + foreach my $line ( @{ $ary_ref } ) { + my $url; + $line->[3] = $q->escape( $line->[2] ); + my $opt = $dbh->selectrow_array( + "SELECT opt FROM in_timeline_log + WHERE title = '$line->[2]' " + ); + + if ( $line->[0] eq 'auto_suggest_dec' ) { + unless ( $dbh->selectrow_array( + "SELECT 1 FROM timeline + WHERE ( type = 'convert_b25_ts' OR type = 'convert_b25_ts_running' ) + AND title = '$line->[2]' " + ) ) { + $url = qq {rectool.pl?mode=confirm&mode_sub=proc&type=$line->[0]&chtxt=$line->[1]&title=$line->[3]&opt=$opt}; + } + } + elsif ( $line->[0] eq 'auto_suggest_enc' ) { + unless ( $dbh->selectrow_array( + "SELECT 1 FROM timeline + WHERE ( type = 'convert_ts_mp4' OR type = 'convert_ts_mp4_running' ) + AND title = '$line->[2]' " + ) ) { + $url = qq {rectool.pl?mode=confirm&mode_sub=proc&type=$line->[0]&chtxt=$line->[1]&title=$line->[3]&opt=$opt}; + } + } + else { + unless ( $dbh->selectrow_array( + "SELECT 1 FROM timeline + WHERE ( type LIKE 'convert_avi%' OR type = 'convert_mkv' ) + AND title = '$line->[2]' " + ) ) { + $url = qq {rectool.pl?mode=confirm&mode_sub=proc&type=$line->[0]&chtxt=$line->[1]&title=$line->[3]}; + } + } + if ( $url ) { + $href = qq {予約}; + } + else { + $href = q {予約済}; + } + + my $color = $color{$type_suggest{$line->[0]}} ? $color{$type_suggest{$line->[0]}} : ''; + $line->[0] = $type{$line->[0]} ? $type{$line->[0]} : $line->[0]; + $line->[0] = qq {$line->[0]} if ( $color ); + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + } + + $HTML .= qq {
タイプタイトル予約
$line->[0]$line->[2]$href
\n}; +} + +################ mode=jbk ################ + +if ( $mode eq 'jbk' ) { + $HTML =~ s/%HTML_TITLE_OPT%/ - JBK/; + $HTML .= qq {
\n}; + + if ( $mode_sub eq 'add' ) { + my $keyword = $params{ 'keyword' }; + utf8::decode( $keyword ); + $HTML .= "キーワード「$keyword」を追加しました。
\n"; + $dbh->do( + "INSERT INTO in_auto_jbk_key ( keyword ) + VALUES ( '$keyword' )" + ); + } + elsif ( $mode_sub eq 'del' ) { + my $id = $params{ 'id' }; + my $keyword = $dbh->selectrow_array( + "SELECT keyword FROM in_auto_jbk_key + WHERE id = '$id' " ); + $HTML .= "キーワード「$keyword」を削除しました。
\n"; + $dbh->do( + "DELETE FROM in_auto_jbk_key WHERE id = '$id'" + ); + } + elsif ( $mode_sub eq 'on' ) { + my $id = $params{ 'id' }; + $HTML .= "キーワード「$keyword」を自動録画対象にしました。
\n"; + $dbh->do( + "UPDATE in_auto_jbk_key SET auto = 1 WHERE id = '$id'" + ); + } + elsif ( $mode_sub eq 'off' ) { + my $id = $params{ 'id' }; + $HTML .= "キーワード「$keyword」を自動録画対象から外しました。
\n"; + $dbh->do( + "UPDATE in_auto_jbk_key SET auto = 0 WHERE id = '$id'" + ); + } + + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + + my $ary_ref = $dbh->selectall_arrayref( + "SELECT id, keyword, auto, opt + FROM in_auto_jbk_key + ORDER BY id " ); + + foreach my $line ( @{ $ary_ref } ) { + my $delurl = "rectool.pl?mode=jbk&mode_sub=del&id=$line->[0]"; + my $auto = $line->[2] ? 'on' : 'off'; + my $oppo = $line->[2] ? 'off' : 'on'; + my $oppourl = "rectool.pl?mode=jbk&mode_sub=$oppo&id=$line->[0]"; + $oppo .= "にする"; + + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + } + + $HTML .= qq {
IDキーワード自動録画切り替え録画オプション削除
$line->[0]$line->[1]$auto$oppo$line->[3]削除
\n}; + + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n
\n
\n
\n}; + + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + + $ary_ref = $dbh->selectall_arrayref( + "SELECT id, auto_timeline_keyword.chtxt, epg_ch.chname, title, btime, etime + FROM auto_timeline_keyword + INNER JOIN epg_ch ON auto_timeline_keyword.chtxt = epg_ch.chtxt + ORDER BY btime" + , {Slice=>{}} ); + + foreach my $line ( @{ $ary_ref } ) { + my ( $begin, $end, $diff ) = &str2readable( $line->{btime}, $line->{etime} ); + $line->{btime} =~ s/(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/$1$2$3$4$5$6/; + $line->{etime} =~ s/(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/$1$2$3$4$5$6/; + my $url = qq "rectool.pl?mode=confirm&mode_sub=reserve&chtxt=$line->{chtxt}&start=$line->{btime}&stop=$line->{etime}"; + + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + } + + $HTML .= qq {
IDチャンネルタイトル開始時刻終了時刻録画時間予約
$line->{id}$line->{chname}$line->{title}$begin$end$diff予約
\n}; + +} + +################ mode=recognize ################ + +if ( $mode eq 'recognize' ) { + $HTML =~ s/%HTML_TITLE_OPT%/ - Recognizer/; + + my $text = $params{ 'text' }; + utf8::decode( $text ); + $chtxt = $params{ 'chtxt' }; + my $title = $params{ 'title' }; + utf8::decode( $title ); + + $HTML .= qq {
\n}; + $HTML .= qq {与えられた文字列のうち、番組の放送時刻と思われる文字列を認識します。
\n}; + $HTML .= qq {番組表が取得できない一週間以上先の予約ができます。
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + &draw_form_channel( 'nonone' ); + $HTML .= qq {\n}; + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n
\n
\n}; + + my $ch_list = join '|', grep /.+/, values %chtxt_0_chname; + my %ch_reverse = reverse %chtxt_0_chname; + + if ( $text ) { + my ( $year, $month, $day ); + my ( $bhour, $bminute, $ehour, $eminute ); + my $next_day = 0; + foreach ( split /\n/, $text ) { + my @bdate = /(\d{4}).(\d{1,2}).(\d{1,2})/; + s/(\d{4}).(\d{2}).(\d{2})//; + my @btime = /(\d{1,2})[::](\d{1,2})/; + s/(\d{1,2})[::](\d{2})//; + my @etime = /(\d{1,2})[::](\d{1,2})/; + s/(\d{1,2})[::](\d{2})//; + s/\(.*\)//; + if ( !@bdate ) { + $bdate[0] = Time::Piece->localtime->year; + ( $bdate[1], $bdate[2] ) = /(\d{1,2})月(\d{1,2})日/; + s/(\d{1,2})月(\d{1,2})日//; + } + next if (!( @bdate || @btime )); + ( $year, $month, $day ) = @bdate if ( $bdate[0] && $bdate[1] && $bdate[2] ); + ( $bhour, $bminute ) = @btime if ( defined $btime[0] && defined $btime[1] ); + ( $ehour, $eminute ) = @etime if ( defined $etime[0] && defined $etime[1] ); + $next_day = 1 if ( /深夜/ ); + my ( $ch ) = /($ch_list)/; + my $chtxt = $ch_reverse{$ch} if ( $ch && $ch_reverse{$ch} ); + s/($ch_list)//; + + if ( $year && $month && $day && defined $bhour && defined $bminute ) { + my $tp = Time::Piece->strptime( "$year-$month-$day $bhour:$bminute", '%Y-%m-%d %H:%M' ); + my $etp = Time::Piece->strptime( "$year-$month-$day $ehour:$eminute", '%Y-%m-%d %H:%M' ) if ( defined $ehour && defined $eminute ); + $tp += ONE_DAY if ( $next_day ); + my $start = $tp->strftime( '%Y%m%d%H%M%S' ); + my $stop = defined $etp ? + $etp->strftime( '%Y%m%d%H%M%S' ) : + ( $tp + ONE_MINUTE * 30 )->strftime( '%Y%m%d%H%M%S' ); + $title = $_ if ( !$title ); + my $url = qq "rectool.pl?mode=confirm&mode_sub=reserve&chtxt=$chtxt&start=$start&stop=$stop&title=$title"; + $HTML .= qq {認識結果:$year-$month-$day $bhour:$bminute -> $ehour:$eminute 残り:$_リンク
\n}; + } + } + } +} + +################ mode=expert ################ + +if ( $mode eq 'expert' ) { + require List::Compare; + + my $ary_ref; + + $HTML =~ s/%HTML_TITLE_OPT%/ - Expert/; + $HTML .= qq {
\n}; + + if ( $mode_sub eq 'reget' ) { + my $bctype = $params{ 'bctype' }; + my ( $chtxt, $chname ) = $dbh->selectrow_array( + "SELECT chtxt, chname FROM epg_ch + WHERE bctype = '$bctype' " ); + $HTML .= "Update for $chname ( chtxt: $chtxt ) has been reserved.
\n"; + $dbh->do( "UPDATE epg_ch SET status = '2' WHERE chtxt = '$chtxt' " ); + goto end; + } + + + my @ary = $dbh->selectrow_array( + "SELECT auto_jbk, auto_bayes, auto_del_tmp, auto_opt + FROM in_settings " ); + my $opt = pop @ary; + @ary = map( $_ ? 'checked' : '', @ary ); + + $HTML .= qq {内部オプションの変更\n
}; + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {自動地引\n}; + $HTML .= qq {自動ベイズ\n}; + $HTML .= qq {自動一時ファイル削除\n}; + $HTML .= qq {自動オプション:\n}; + $HTML .= qq {\n
\n
\n}; + + + $HTML .= qq {
\n番組表のカテゴリ一覧と内蔵のカテゴリ一覧の合致を確認中...\n}; + $ary_ref = $dbh->selectcol_arrayref( + "SELECT DISTINCT category FROM epg_timeline" + ); + my @category = map {$_->{name}} sort values %category; + if ( List::Compare->new( $ary_ref, \@category )->get_symdiff ) { + $HTML .= qq {一致しません
\n}; + $HTML .= qq {番組表:@{$ary_ref}
\n内蔵:@category
\n}; + } + else { + $HTML .= qq {一致しました
\n}; + } + + + @ary = $dbh->selectrow_array( "SELECT terec, bscsrec, b252ts, ts2avi FROM in_status" ); + $HTML .= qq {
\n地上波録画数:$ary[0]\n衛星波録画数:$ary[1]\n解読数:$ary[2]\n縁故数:$ary[3]\n
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n
\n
\n}; + + + $HTML .= qq {
\nRec10 バージョン:$rec10_version\nrectool バージョン:$rectool_version\n
\n}; + + + $HTML .= qq {
\n番組表の欠落
\n}; + $ary_ref = $dbh->selectall_arrayref( "SELECT chname, chtxt FROM epg_ch" ); + foreach my $line ( @{$ary_ref} ) { + my $ary_ref = $dbh->selectall_arrayref( + "SELECT start, stop, title FROM epg_timeline WHERE channel = '$line->[1]' ORDER BY start" + ); + my $error; + my @program_old = ( '', $ary_ref->[0]->[0] ); + my $program_old = \@program_old; + + foreach my $program_new ( @{$ary_ref} ) { + if ( $program_old->[1] ne $program_new->[0] && + $program_old->[2] !~ /クロ?ジング|クロージング|エンディング|休止|ミッドナイト|ending/ && + $program_new->[2] !~ /オープニング|ウィークリー・インフォメーション|モーニング|opening/ && + ( str2datetime( $program_new->[0] ) - str2datetime( $program_old->[1] ) )->delta_minutes > 30 ) { + $program_old->[1] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; + $program_new->[0] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/; + $error .= qq{ $program_old->[2] $program_old->[1]\n -> $program_new->[2] $program_new->[0]\n}; + } + $program_old = $program_new; + } + $HTML .= qq {
\n$line->[0]\n$error
\n} if ( $error ); + } + + + $ary_ref = $dbh->selectall_arrayref( + "SELECT chname, chtxt, bctype, ch, csch, updatetime, status, visible + FROM epg_ch + ORDER BY bctype " ); + $HTML .= qq {
\n番組表の更新状況
\n}; + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + foreach my $status ( @{$ary_ref} ) { + $HTML .= qq {\n}; + $HTML .= qq {\n\n\n\n}; + $HTML .= qq {\n\n\n\n}; + $HTML .= qq {\n}; + } + $HTML .= qq {
チャンネル名chtxtbctypechcsch最終更新時刻状態表示
$status->[0]$status->[1]$status->[2]$status->[3]$status->[4]$status->[5]$status->[6]$status->[7]
\n}; + + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {番組表を再取得する\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n
\n
\n}; + + + + $ary_ref = $dbh->selectall_arrayref( + "SELECT id, type, chtxt, title, btime, etime, opt, deltaday, deltatime + FROM timeline + ORDER BY id "); + $HTML .= qq {
\n予約表
\n}; + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + foreach my $status ( @{$ary_ref} ) { + $HTML .= qq {\n}; + $HTML .= qq {\n\n\n\n}; + $HTML .= qq {\n\n\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + } + $HTML .= qq {
IDtypechtxttitlebtimeetimeoptdeltadaydeltatime
$status->[0]$status->[1]$status->[2]$status->[3]$status->[4]$status->[5]$status->[6]$status->[7]$status->[8]
\n}; +} + +################ mode=log ################ + +if ( $mode eq 'log' ) { + $HTML =~ s/%HTML_TITLE_OPT%/ - Log/; + + $HTML .= qq {
\n}; + $HTML .= qq {\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + $ary_ref = $dbh->selectall_arrayref( + "SELECT id, chtxt, title, btime, etime, opt, exp, longexp, category + FROM in_timeline_log " + ); + foreach my $line ( @{$ary_ref} ) { + $HTML .= qq {\n}; + $HTML .= qq {\n\n\n\n}; + $HTML .= qq {\n\n\n\n}; + $HTML .= qq {\n}; + $HTML .= qq {\n}; + } + $HTML .= qq {
IDchtxttitlebtimeetimeoptexplongexpcategory
$line->[0]$line->[1]$line->[2]$line->[3]$line->[4]$line->[5]$line->[6]$line->[7]$line->[8]
\n}; +} + +################ mode=help ################ + +if ( $mode eq 'help' ) { + $HTML =~ s/%HTML_TITLE_OPT%/ - Help/; + $HTML =~ s|%REFRESH%||; + $HTML .= qq {
\n}; + $HTML .= qq {ヘルプ\n}; +} + +################ mode=test ################ + +if ( $mode eq 'test' ) { + $HTML =~ s/%HTML_TITLE_OPT%/ - Test/; + $HTML =~ s|%REFRESH%||; + $HTML .= qq {
\n}; + + require Data::Dumper; + $tmp = Perl6::Slurp::slurp( 'config.ini' ); + $tmp =~ s/\n/
\n/gs; + $HTML .= $tmp; + + # $HTML .= Dumper( $ary_ref ); +} + +################ mode nasi ################ + +if ( !$mode ) { + &draw_form(); + $HTML =~ s/%HTML_TITLE_OPT%/ - Top/; + $HTML .= qq {Welcome to Rec10!
\n}; + goto end; +} + + +end: +#
+$HTML .= < + + +EOM + +#
+#$HTML_ADV = $HTML_ADV_IMG . $HTML_ADV_TEXT if ( !$HTML_ADV ); +my $HTML_ADV = ''; +$HTML_HEADER = qq {
\n$HTML_ADV\n
\n}; + +&draw_menu(); +$HTML =~ s/%HTML_TITLE_OPT%//; +$HTML =~ s/%REFRESH%//; +$HTML =~ s/%SCRIPT%//; +$HTML =~ s/%CSS%//; +$HTML =~ s/%HTML_HEADER%/$HTML_HEADER/; + +utf8::encode( $HTML ); +print $HTTP_HEADER; +print $HTML; +exit; + +sub draw_menu { + $hires = Time::HiRes::time() - $hires; + $last_modified = localtime((stat 'rectool.pl')[9]); + + $HTML_HEADER .= qq {
\n}; + $HTML_HEADER .= qq {Last-Modified: $last_modified
Time-Elapsed: $hires 秒
\n}; + $HTML_HEADER .= qq {\n}; + $HTML_HEADER .= qq {トップ(検索)\n}; + $HTML_HEADER .= qq {予約確認\n}; + $HTML_HEADER .= qq {予約状況(画像版)\n}; + $HTML_HEADER .= qq {録画一覧\n}; + $HTML_HEADER .= qq {おまかせ\n}; + $HTML_HEADER .= qq {玄人仕様\n}; + $HTML_HEADER .= qq {復旧支援\n}; + $HTML_HEADER .= qq {地引\n}; + $HTML_HEADER .= qq {録画履歴\n}; + $HTML_HEADER .= qq {文字認識\n}; + $HTML_HEADER .= qq {新規予約\n}; +# $HTML_HEADER .= qq {新規予約\n}; + $HTML_HEADER .= qq {\n}; + $HTML_HEADER .= qq {
\n}; + $HTML_HEADER .= qq {
\n}; +} + +sub draw_form { + $chname = $params{ 'chname' }; + $chtxt = $params{ 'chtxt' }; + $key = $params{ 'key' }; + utf8::decode( $key ); + if ( $chname ) { + $chtxt = $dbh->selectrow_array("SELECT chtxt FROM epg_ch WHERE chname = '$chname' "); + } + + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + + # チャンネル指定 + &draw_form_channel(); + + # 日付指定 + $HTML .= qq {\n}; + + # カテゴリ指定 + $HTML .= qq {\n}; + + # キーワード指定 + $HTML .= qq {\n}; + + # フォーム描画 + $HTML .= qq {\n
\n
\n}; +} + +sub draw_form_channel { + $HTML .= qq {\n}; +} + +sub draw_form_opt { + my $shift = shift; + my ( %selected, %checked ); + + if ( $chtxt =~ /BS_103/ ) { + $selected{F} = 'selected'; + } + elsif ( $chtxt =~ /CS_239|CS_240|CS_335/ ) { + $selected{H} = 'selected'; + } + elsif ( $chtxt =~ /BS_101|BS_102/ || $bctype =~ /cs/ ) { + $selected{W} = 'selected'; + } + elsif ( $bctype =~ /bs|te/ ) { + $selected{H} = 'selected'; + } + $selected{g} = 'selected'; + $selected{s} = 'selected'; + $checked{a} = $chtxt =~ /CS_331|CS_332|CS_333|CS_334|CS_335/ || $category =~ /アニメ/ ? 'checked' : ''; + $checked{l} = ''; + $checked{d} = $title =~ /\Q[二]\E|[二]|\Q(二)\E|(二)/ ? 'checked' : ''; + $checked{5} = $title =~ /5\.1|5.1/ ? 'checked' : ''; + $checked{2} = 'checked'; + + if ( $opt ) { + undef %checked; + undef %selected; + my @opt = split //, $opt; + foreach my $opt ( @opt ) { + $selected{$opt} = 'selected' if ( $opt =~ /S|L|G|H|F/ ); + $checked {$opt} = 'checked' if ( $opt =~ /a|h|l|d|2|5/ ); + } + $checked{d} = $title =~ /\Q[二]\E|[二]|\Q(二)\E|(二)/ ? 'checked' : ''; + $checked{5} = $title =~ /5\.1|5.1/ ? 'checked' : ''; + } + # 画質/圧縮率ともに指定されていない場合、真ん中をselectedにする + $selected{g} = 'selected' unless ( $selected{u} || $selected{i} || $selected{o} || $selected{p} ); + $selected{s} = 'selected' unless ( $selected{q} || $selected{w} || $selected{e} || $selected{r} ); + + $HTML .= qq {\n}; + + $HTML .= qq {\n}; + + $HTML .= qq {\n}; + + $HTML .= qq {\n}; + + $HTML .= qq {\n}; + + $HTML .= qq {24fps(主にアニメ)\n}; + $HTML .= qq {二ヶ国語放送\n}; + #$HTML .= qq {2passモード\n}; + $HTML .= qq {5.1ch放送\n}; + $HTML .= qq {
\n}; + $HTML .= qq {\n}; + $HTML .= qq {ファイル名日時追加\n} if ( $shift eq 'reserve' ); + $HTML .= qq {隔週録画\n} if ( $shift eq 'reserve' ); +} + +sub parse_program { + $chname = $params{ 'chname' }; + $chtxt = $params{ 'chtxt' }; + $start = $params{ 'start' }; + $stop = $params{ 'stop' }; + $bayesid = $params{ 'bayesid' }; + $id = $params{ 'id' }; + + if ( $chname ) { + $chtxt = $dbh->selectrow_array("SELECT chtxt FROM epg_ch WHERE chname = '$chname'"); + } + elsif ( $chtxt && $chtxt_0_chname{$chtxt} ) { + $chname = $chtxt_0_chname{$chtxt}; + ( $chtxt_sql = $chtxt ) =~ s/_0/_%/; + $bctype = $dbh->selectrow_array("SELECT bctype FROM epg_ch WHERE chtxt LIKE '$chtxt_sql'"); + } + elsif ( $chtxt ) { + $chname = $dbh->selectrow_array("SELECT chname FROM epg_ch WHERE chtxt = '$chtxt'") + } + ( $title, $desc, $longdesc, $category ) = $dbh->selectrow_array( + "SELECT title, exp, longexp, category + FROM epg_timeline + WHERE channel = '$chtxt' AND start = '$start' AND stop = '$stop' "); + if ( !$bctype ) { + $bctype = $dbh->selectrow_array("SELECT bctype FROM epg_ch WHERE chtxt = '$chtxt'"); + } + + if ( $bayesid ) { + ( $chtxt, $title, $begin, $end ) = $dbh->selectrow_array( + "SELECT chtxt, title, btime, etime FROM auto_timeline_bayes WHERE id = '$bayesid' " + ); + ( $chname, $bctype ) = $dbh->selectrow_array( + "SELECT chname, bctype FROM epg_ch WHERE chtxt = '$chtxt' " + ); + $start = str2datetime( $begin )->strftime( '%Y%m%d%H%M%S' ); + $stop = str2datetime( $end )->strftime( '%Y%m%d%H%M%S' ); + ( $desc, $longdesc, $category ) = $dbh->selectrow_array( + "SELECT exp, longexp, category FROM epg_timeline WHERE channel = '$chtxt' AND start = '$start' AND stop = '$stop' " + ); + } + if ( $id ) { + ( $type, $chtxt, $title, $begin, $end, $deltaday, $deltatime, $opt, $counter ) = $dbh->selectrow_array( + "SELECT type, chtxt, title, btime, etime, deltaday, deltatime, opt, counter + FROM timeline WHERE id = '$id' " + ); + ( $chname, $bctype ) = $dbh->selectrow_array( + "SELECT chname, bctype FROM epg_ch WHERE chtxt = '$chtxt' " + ); + $start = str2datetime( $begin )->strftime( '%Y%m%d%H%M%S' ); + $stop = str2datetime( $end )->strftime( '%Y%m%d%H%M%S' ); + ( $desc, $longdesc, $category ) = $dbh->selectrow_array( + "SELECT exp, longexp, category FROM epg_timeline WHERE channel = '$chtxt' AND start = '$start' AND stop = '$stop' " + ); + } + if ( $bctype =~ /bs|cs/ ) { + $bctype_sql = '_s%'; + } + elsif ( $bctype =~ /te/ ) { + ( $chtxt_0 = $chtxt ) =~ s/(\d+)_.*/$1_0/; + ( $chtxt_sql = $chtxt ) =~ s/_0/_%/; + $bctype_sql = 'te%'; + } + #( $chtxt_no0 ) = $chtxt =~ /(\d+)_/; + @start = $start =~ /(.{4})(.{2})(.{2})(.{2})(.{2})/; + @stop = $stop =~ /(.{4})(.{2})(.{2})(.{2})(.{2})/; + $begin = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', @start, '00' ); + $end = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', @stop , '00' ); + + if ( $params{ 'title' } ) { + $title = $params{ 'title' }; + utf8::decode( $title ); + } + $HTML .= qq {\n}; +} + +sub check_error { + my $is_error; + my $is_same = $dbh->selectrow_array( + "SELECT COUNT(*) FROM timeline WHERE chtxt = '$chtxt' AND btime = '$begin' AND etime = '$end'" + ); + my @overlap = &get_overlap(); + + if ( $is_same ) { + $HTML .= "同一の番組が既に存在します。
\n"; + $is_error = 1; + } + elsif ( $overlap[0] >= 2 ) { + $HTML .= "時間が被る番組が既に2個存在します。
\n"; + $HTML .= $overlap[1]; + $is_error = 2; + } + else { + $is_error = 0; + } + return $is_error; +} + +sub get_overlap { + require List::Util; + + my $ary_ref = $dbh->selectall_arrayref( + "SELECT btime, etime, title + FROM timeline + INNER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt + WHERE bctype LIKE '$bctype_sql' AND type IN $type_user_made + AND btime < '$end' + AND etime > '$begin' + " + ); + + my %overlap; + my $overlap = $max = 0; + my $str; + foreach my $prg ( @{ $ary_ref } ) { + $str .= "$prg->[0] ? $prg->[1] : $prg->[2]
\n"; + $overlap{$prg->[0]} += 1; + $overlap{$prg->[1]} -= 1; + } + foreach my $key ( sort keys %overlap ) { + $overlap += $overlap{$key}; + $max = List::Util::max( $max, $overlap ); + } + if ( wantarray ) { + return ( $max, $str ); + } + else { + return $max; + } +} + +sub get_file_list_wrapper { + local $base_dir = shift; + local $ptr = shift; + + &get_file_list( $base_dir ); +} + +sub get_file_list{ + my $dir = shift; + + opendir ( DIR, $dir ); + my @list = sort readdir( DIR ); + closedir( DIR ); + + foreach my $file ( @list ) { + next if ( $file =~ /^\.{1,2}$/ ); + if ( -d "$dir/$file" ){ + &get_file_list("$dir/$file"); + } + else{ + $abs = "$dir/$file"; + utf8::decode( $abs ); + ( $rel ) = $abs =~ /^$base_dir\/(.*)$/; + $ptr->( $rel, $abs ); + } + } +} + +sub strisjoined { + my $str = shift; + + return $str =~ /.{4}-.{2}-.{2} .{2}:.{2}:.{2}/ ? 0 : 1; +} + +sub str2datetime { + my $str = shift; + my @time; + + if ( strisjoined( $str ) ) { + @time = $str =~ /(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/; + } + else { + @time = $str =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/; + } + return DateTime->new( + year => $time[0], month => $time[1], day => $time[2], + hour => $time[3], minute => $time[4], second => $time[5], + locale => 'ja_JP' , time_zone => $tz + ); +} + +sub str2dayname { + my $str = shift; + our %day_name_cache; + + if ( !$day_name_cache{$str} ) { + $day_name_cache{$str} = str2datetime( $str )->day_name; + } + return $day_name_cache{$str}; +} + +sub str2readable { + my $begin = shift; + my $end = shift; + + my $dt_begin = ref( $begin ) eq 'DateTime' ? $begin : &str2datetime( $begin ); + my $dt_end = ref( $end ) eq 'DateTime' ? $end : &str2datetime( $end ); + + my $str_begin = $dt_begin->strftime( '%m/%d(%a) %H:%M' ); + my $str_end = $dt_end ->strftime( $dt_begin->day == $dt_end->day ? '%H:%M' : '翌 %H:%M' ); + # utf8::encode( $str_begin ); + + my ( $sec, $min, $hour ); + $sec = $dt_end->epoch - $dt_begin->epoch; + $min = int( $sec / 60 ); + $sec = $sec - $min * 60; + $hour = int( $min / 60 ); + $min = $min - $hour * 60; + my $str_diff = ''; + $str_diff .= $hour . '時間' if ( $hour ); + $str_diff .= $min . '分' if ( $min ); + $str_diff .= $sec . '秒' if ( $sec ); + + return ( $str_begin, $str_end, $str_diff ); +} + +sub sqlgetsuggested { + require Encode; + require Text::Ngram; + + my ( $btime, $etime ) = @_; + $deltatime = 3 if ( !$deltatime ); + + $btime_bgn = $btime->clone->subtract( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' ); + $btime_end = $btime->clone->add( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' ); + $etime_bgn = $etime->clone->subtract( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' ); + $etime_end = $etime->clone->add( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' ); + + $ary_ref = $dbh->selectall_arrayref( + "SELECT start, stop, title, exp + FROM epg_timeline + WHERE channel LIKE '$chtxt_sql' + AND start BETWEEN '$btime_bgn' AND '$btime_end' + AND stop BETWEEN '$etime_bgn' AND '$etime_end' " + ); + #die Dumper $ary_ref; + + my %hash; + my $hash_r = Text::Ngram::ngram_counts( $title, 2 ); # bi-gram + foreach my $program ( @{$ary_ref} ) { + my $hash_k = Text::Ngram::ngram_counts( $program->[2], 2 ); + my $point; + map $point += $hash_k->{$_}, keys %{$hash_r}; + push @{$hash{$point}}, $program if ( $point ); + } + + return %hash; +} +