OSDN Git Service

a993c4da85cbd4eaa00fef6c1d32f1540bdc4ed3
[rec10/rec10-git.git] / rectool / trunk / rectool.pl
1 #!/usr/bin/perl
2 # -d:SmallProf
3 #use Perl6::Slurp;
4 #use XML::Simple;
5 #use CGI;
6 #use CGI::Lite;
7 #use Date::Manip;
8 #Date_Init("TZ=JST","ConvTZ=JST");
9 #use SVG;
10 #use KCatch;
11 use CGI::Carp qw( fatalsToBrowser );
12 use warnings;
13 use DBI;
14 use Time::Piece;
15 use Time::Seconds;
16 use Date::Simple;
17 use DateTime;
18 use CGI;
19 use MIME::Base64;
20 use Config::Simple;
21 use Time::HiRes;
22 use Data::Dumper::Concise;
23 use Tie::IxHash;
24 use File::Slurp;
25 use Sort::Naturally;
26 use Algorithm::Diff qw(LCS);
27 #require SVG Time::Simple XML::Atom Encode Text::Ngram List::Compare List::Util
28 use utf8;
29 #%DB::packages = ( 'main' => 1 );
30
31
32 ################ バージョン定義 ################
33
34
35 my $rectool_version = 100;
36
37
38 ################ 初期化ここから ################
39
40
41 my $tz = DateTime::TimeZone->new( name => 'local' );
42 my $hires = Time::HiRes::time();
43
44 my $cfg = new Config::Simple;
45 if ( -e 'rec10.conf' ) {
46         $cfg->read( 'rec10.conf' );
47 }
48 elsif ( -e '/etc/rec10.conf' ) {
49         $cfg->read( '/etc/rec10.conf' );
50 }
51 else { 
52         die 'rec10.confが見つかりません。';
53 }
54
55 my $sql = $cfg->param( 'db.db' );
56
57 if ( $sql eq 'MySQL' ) {
58         my $name = $cfg->param( 'db.mysql_dbname' );
59         my $host = $cfg->param( 'db.mysql_host' );
60         my $port = $cfg->param( 'db.mysql_port' );
61         my $user = $cfg->param( 'db.mysql_user' );
62         my $pass = $cfg->param( 'db.mysql_passwd' );
63         $dbh = DBI->connect("dbi:mysql:$name:$host:$port", $user, $pass, {
64                 AutoCommit => 1,
65                 RaiseError => 1,
66                 mysql_enable_utf8 => 1, # only availavle for MySQL
67         });
68         $dbh->do( 'SET NAMES utf8' );
69 }
70
71 my $rec10_version = eval {
72         $dbh->selectrow_array( "SELECT version FROM in_status " );
73 };
74
75 my $HTML;
76
77 $HTTP_HEADER = "Content-Type: text/html\n\n";
78 $HTML .= <<EOM;
79 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
80 <html lang="ja">
81 <head>
82 <title>Rec10%HTML_TITLE_OPT%</title>
83 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
84 <meta http-equiv="Content-Script-Type" content="text/javascript">
85 <meta http-equiv="Content-Style-Type" content="text/css">
86 <meta name="robots" content="noindex,nofollow,noarchive">
87 <link rev="made" href="Rea10">
88 <link rel="alternate" type="application/atom+xml" title= "Rec10 Atom Feed" href="./rectool.pl?mode=atom">
89 %REFRESH%
90 %SCRIPT%
91 %CSS%
92 </head>
93 <body>
94 %HTML_HEADER%
95 EOM
96
97 my ( $user, $pass, $auth );
98 ( $user, $pass ) = eval {
99         $dbh->selectrow_array( "SELECT webuser, webpass FROM in_settings " );
100 };
101
102 if ( $user and $pass ) {
103         if ( $ENV{'HTTP_AUTHORIZATION'} ) {
104                 my ( $base64 ) = $ENV{'HTTP_AUTHORIZATION'} =~ /Basic\s(.*)/;
105                 if ( $base64 eq encode_base64( "$user:$pass" ) ) {
106                         $auth = 1;
107                 }
108                 else {
109                         $auth = 0;
110                 }
111         }
112         else {
113                 $auth = 0;
114         }
115 }
116 else {
117         $auth = 1;
118 }
119
120 if ( !$auth ) {
121         my ( $base64 ) = $ENV{'REMOTE_USER'} =~ /Basic (.*)/;
122         $HTTP_HEADER = qq {Status: 401 Authorization Required\nWWW-Authenticate: Basic realm="Protected Rec10 $ENV{'HTTP_AUTHORIZATION'}"\n} . $HTTP_HEADER;
123         goto end;
124 }
125
126 if ( $rec10_version != $rectool_version ) {
127         $HTML .= qq {<div style="font-size: 200%; font-weight: bold; color: red">\n};
128
129         if ( $rec10_version > $rectool_version ) {
130                 $HTML .= qq {Rec10本体のバージョンが新しいため、実行できません。<br>\n};
131                 $HTML .= qq {rectoolのバージョンアップを行ってください。<br>\n};
132         }
133
134         if ( $rec10_version < $rectool_version ) {
135                 $HTML .= qq {Rec10本体のバージョンが古いため、実行できません。<br>\n};
136                 $HTML .= qq {Rec10のバージョンアップを行ってください。<br>\n};
137         }
138
139         $HTML .= qq {Rec10のバージョンは$rec10_version 、rectoolのバージョンは$rectool_version です。<br>\n};
140         $HTML .= qq {<a href="http://sourceforge.jp/projects/rec10/">公式ページ</a>\n};
141         goto end;
142 }
143
144 $q = new CGI;
145 %params = $q->Vars;
146 $mode = $params{ 'mode' };
147 $mode_sub = $params{ 'mode_sub' };
148
149 ################ %chtxt_chnameの準備 ################
150
151 my %chtxt_chname;
152 my %chtxt_0_chname;
153 tie %chtxt_0_chname, 'Tie::IxHash';
154
155 my $ary_ref = $dbh->selectall_arrayref(
156         "SELECT chtxt, chname, ch, bctype FROM epg_ch
157         WHERE visible = 1"
158 );
159
160 %chtxt_chname = map { $_->[0], $_->[1] } @{$ary_ref};
161
162 # NHK BS 1/2/hiをBS/CSから除外(101-103) - by 2011/04
163 # te: 地上波、BSのNHK以外
164 # bc: BSのNHK、CS
165 my @te_ary = grep $_->[0]=~ /^\d|BS_(?!10[1-3])/, @{$ary_ref};
166 my @bc_ary = grep $_->[0]!~ /^\d|BS_(?!10[1-3])/, @{$ary_ref};
167
168 # teの操作(まとめる)
169 foreach my $line ( @te_ary ) {
170         # te xx_yyyy(chtxt) -> xx(ch)
171         if ( $line->[3] =~ /te/ ) {
172                 push @{ $chtxt_0_chname{        $line->[2] . '_0'} }, $line->[1];
173         }
174         else {
175                 push @{ $chtxt_0_chname{'BS_' . $line->[2]       } }, $line->[1];
176         }
177 }
178 foreach my $key ( keys %chtxt_0_chname ) {
179         my @chname = @{ $chtxt_0_chname{$key} };
180         if ( @chname >= 2 ) {
181                 # 2つ以上ある場合
182                 my @tmp = map { my @ary = split //, $_; \@ary } @chname;
183                 # 1つ目と2つ目のみ比較
184                 # FIXME: すべてを比較するべき
185                 $chtxt_0_chname{$key} = join '', LCS( $tmp[0], $tmp[1] );
186         }
187         else {
188                 # 1つしかない場合
189                 $chtxt_0_chname{$key} = $chname[0];
190         }
191 }
192
193 # bs/csの操作(そのまま)
194 foreach my $line ( @bc_ary ) {
195         $chtxt_0_chname{$line->[0]} = $line->[1];
196 }
197 undef $ary_ref;
198
199
200 ################ 定数宣言 ################
201
202
203 tie %type, 'Tie::IxHash';
204 %type = (
205         'search_everyday'          => '隔日検索',
206         'search_today'             => '当日検索',
207         'reserve_flexible'         => '浮動予約',
208         'reserve_fixed'            => '確定予約',
209
210         'reserve_running'          => '録画途中',
211
212         'convert_b25_ts'           => '解読予約',
213         'convert_b25_ts_running'   => '解読途中',
214         'convert_b25_ts_miss'      => '解読失敗',
215
216         'convert_ts_mp4'           => '縁故予約',
217         'convert_ts_mp4_running'   => '縁故於鯖',
218         'convert_ts_mp4_network'   => '縁故於網',
219         'convert_ts_mp4_finished'  => '縁故完了',
220
221         'convert_avi_mkv'          => '変換旧露',
222         'convert_avi_mp4'          => '変換旧四',
223         'convert_mkv_mp4'          => '変換露四',
224         'convert_mkv_mp4_runnings' => '換途露四',
225
226         'auto_suggest_dec'         => '予測解読',
227         'auto_suggest_enc'         => '予測縁故',
228         'auto_suggest_avi2fp'      => '予測旧四',
229         'auto_suggest_ap2fp'       => '予測露四',
230
231         'move_end'                 => '移動完了',
232 );
233
234 %type_suggest = (
235         'auto_suggest_dec'    => 'convert_b25_ts',
236         'auto_suggest_enc'    => 'convert_ts_mp4',
237         'auto_suggest_avi2fp' => 'convert_avi_mkv',
238         'auto_suggest_ap2fp'  => 'convert_mp4_mkv',
239 );
240
241 %color = (
242         'search_everyday'        => '#8B008B',
243         'search_today'           => '#8B008B',
244         'reserve_flexible'       => '#4169E1',
245         'reserve_fixed'          => '#4169E1',
246         'reserve_running'        => '#FF8C00',
247         'convert_b25_ts'         => '#CD5C5C',
248         'convert_b25_ts_running' => '#DC143C',
249         'convert_ts_mp4'         => '#32CD32',
250         'convert_ts_mp4_running' => '#2E8B57',
251         'convert_ts_mp4_network' => '#808000',
252
253         'other'                  => '#A0A0A0',
254 );
255
256 $type_user_made = "( 'search_everyday', 'search_today', 'reserve_flexible', 'reserve_fixed', 'reserve_running' )";
257
258 %category = (
259         'etc'         => 'その他', 
260         'news'        => 'ニュース・報道', 
261         'variety'     => 'バラエティ', 
262         'anime'       => 'アニメ・特撮', 
263         'information' => '情報', 
264         'drama'       => 'ドラマ', 
265         'sports'      => 'スポーツ', 
266         'music'       => '音楽', 
267         'cinema'      => '映画', 
268 );
269
270
271 ################ 初期化ここまで ################
272
273
274 ################ mode=schedule ################
275
276 if ( $mode eq 'schedule' ) {
277
278         $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Viewer/;
279         #$HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="300">|;
280         $css = <<EOM;
281                 <style type="text/css">
282                 td {
283                         white-space: nowrap;
284                 }
285                 </style>
286 EOM
287         $css =~ s/^\t{2}//gm;
288         $HTML =~ s/%CSS%/$css/;
289
290         my $order = $params{ 'order' };
291         my $extra = $params{ 'extra' };
292         if ( $order ne 'id' ) {
293                 $order = 'btime';
294         }
295         $reverse_extra = $extra            ? '' : '&amp;extra=1';
296         $forward_order = $order eq 'btime' ? '' : '&amp;order=id';
297
298         my $ary_ref = $dbh->selectall_arrayref(
299                 "SELECT id, type, timeline.chtxt, epg_ch.chname, title, btime, etime, opt, deltaday, deltatime, 
300                 epgtitle, epgbtime, epgetime, epgexp, epgduplicate, epgchange, counter 
301                 FROM timeline 
302                 LEFT OUTER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt 
303                 ORDER BY $order"
304                 , {Slice=>{}});
305
306         $HTML .= qq {<div style="font-size: 80%; float: left">\n};
307         $HTML .= qq {<form method="get" action="rectool.pl">\n};
308         $HTML .= qq {<div>\n};
309         $HTML .= qq {<input type="hidden" name="mode" value="change">\n};
310         $HTML .= qq {<table summary="rectimetable" border=1 cellspacing=0>\n<tr>\n};
311         $HTML .= qq {<th><a href="rectool.pl?mode=schedule$forward_order$reverse_extra">■</a></th>\n};
312         $HTML .= qq {<th><a href="rectool.pl?mode=schedule&amp;order=id">ID</a></th>\n};
313         $HTML .= qq {<th>タイプ</th>\n};
314         $HTML .= qq {<th>チャンネル</th>\n};
315         $HTML .= qq {<th>タイトル</th>\n};
316         $HTML .= qq {<th><a href="rectool.pl?mode=schedule">開始時刻</a></th>\n};
317         $HTML .= qq {<th>終了時刻</th>\n};
318         $HTML .= qq {<th>録画時間</th>\n};
319         $HTML .= qq {<th>オプション</th>\n};
320         $HTML .= qq {<th>dd</th>\n};
321         $HTML .= qq {<th>dt</th>\n};
322         $HTML .= qq {<th>残り</th>\n};
323         $HTML .= qq {</tr>\n};
324         foreach my $line ( @{ $ary_ref } ) {
325
326                 $type = $type{$line->{type}} || $line->{type};
327                 if    ( $line->{type} =~ /^search/ ) {
328                         $type = qq {<span style="color: #8B008B">$type</span>};
329                         $line->{deltaday} = qq {<span style="color: #FF0000">空</span>} if ( !$line->{deltaday} && $line->{type} eq 'search_everyday' );
330                         $line->{deltatime} = qq {<span style="color: #FF0000">空</span>} if ( !$line->{deltatime} );
331                 }
332                 else {
333                         my $color = $color{$line->{type}} ? $color{$line->{type}} : $color{'other'};
334                         $type = qq {<span style="color: $color">$type</span>};
335                 }
336                 # 地上波の場合、xx_yyyをxx_0に置換する
337                 ( $line->{chtxt_0} = $line->{chtxt} ) =~ s/(\d+)_/$1_0/;
338                 # chnameが無いとき(移動縁故など)、chtxtを代わりに使う
339                 $line->{chname} = 
340                         $line->{chname} || 
341                         $chtxt_0_chname{$line->{chtxt}} || 
342                         $chtxt_0_chname{$line->{chtxt_0}};
343                 if ( !$line->{chname} ) {
344                         # chnameが無いとき、リンクを作成しない
345                         $line->{chname} = $line->{chtxt};
346                         $line->{chname_link} = qq {$line->{chname}</a>};
347                 }
348                 else {
349                         $line->{chname_link} = qq {<a href="rectool.pl?mode=program&amp;chtxt=$line->{chtxt}">$line->{chname}</a>};
350                 }
351                 $line->{title} = 'タイトルなし' if ( !$line->{title} );
352                 $line->{tr_style} = '';
353                 $line->{title_2} = '';
354                 my $unix_b = str2datetime( $line->{btime} );
355                 my $unix_e = str2datetime( $line->{etime} );
356
357                 my $btime = $unix_b->strftime( '%Y%m%d%H%M%S' );
358                 my $etime = $unix_e->strftime( '%Y%m%d%H%M%S' );
359                 if ( $extra and $line->{type} =~ /^search_|^reserve_(?!running)/ ) {
360                         #my @ary = $dbh->selectrow_array(
361                         #       "SELECT title, exp FROM epg_timeline 
362                         #       WHERE channel = '$line->{chname}' 
363                         #       AND start = '$btime' 
364                         #       AND stop  = '$etime' ");
365                         #my @ary = ( $line->{epgtitle}, $line->{epgexp} );
366                         my ( $epgtitle, $epgexp ) = ( $line->{epgtitle}, $line->{epgexp} );
367
368                         if ( $epgtitle ) {
369                                 $epgtitle =~ s/無料≫//;
370
371                                 if ( $epgtitle ne $line->{title} ) {
372                                         # epgtitleとtitleが一致しない
373                                         # []に囲まれた部分を除去して比較
374                                         my @brackets = $line->{title} =~ /(\[.+\])+/;
375                                         my $epgtitle_nobrackets = $epgtitle;
376                                         my $title_nobrackets = $line->{title};
377                                         if ( @brackets && $epgtitle =~ /(\[.+\])+/ >= @brackets ) {
378                                                 foreach ( @brackets ) {
379                                                         $epgtitle_nobrackets =~ s/\Q$_\E//;
380                                                 }
381                                         }
382                                         $title_nobrackets =~ s/(\[.+\])+//;
383                                         if ( !scalar $epgtitle_nobrackets =~ s/\Q$title_nobrackets\E// ) {
384                                                 # epgtitleにtitleが含まれていない
385                                                 my $href  = qq {<a href="rectool.pl?mode=edit&amp;id=$line->{id}&amp;suggest=auto">自動検索</a>};
386                                                 $epgtitle = qq {<span style="color: #FF4000">$epgtitle■$href■</span>};
387                                         }
388                                         else {
389                                                 # epgtitleにtitleが含まれている
390                                                 $epgtitle = $epgtitle_nobrackets;
391                                         }
392                                 }
393                                 else {
394                                         # epgtitleとtitleが一致している
395                                         $epgtitle = '説明';
396                                 }
397
398                                 $line->{title_2} = qq {<div style="float: right; cursor: help" title="$epgexp">$epgtitle</div>};
399                         }
400                         else {
401                                 # epgtitleがない
402                                 my $href    = qq {<a href="rectool.pl?mode=edit&amp;id=$line->{id}&amp;suggest=auto">自動検索</a>};
403                                 $line->{title_2}  = qq {<span style="float: right; color: #FF0000">■$href■</span>};
404                                 $line->{tr_style} = qq {style="background-color: #A0A0A0"};
405                         }
406                 }
407
408                 my ( $begin, $end, $diff ) = &str2readable( $unix_b, $unix_e );
409
410                 my $hr = '';
411                 if ( 
412                         $line->{type} eq 'reserve_running' 
413                                 &&
414                         $unix_b->epoch <= time && time <= $unix_e->epoch
415                 )
416                 {
417                         $percent = int( ( 100 * ( time - $unix_b->epoch ) ) / ( $unix_e->epoch - $unix_b->epoch ) );
418                         $hr .= qq {<hr style="margin: 0 auto 0 0; height: 4px; width: $percent%;};
419                         $hr .= qq { background-color: blue; border: none" title="$percent%">};
420                 }
421
422                 $line->{title} = qq {<a href="rectool.pl?mode=edit&amp;id=$line->{id}">$line->{title}</a>};
423                 #$line->{title} = qq {<div style="float: left">$line->{title}</div>} if ( $line->{title_2} );
424                 $HTML .= qq {<tr align="center" $line->{tr_style}>\n};
425                 $HTML .= qq {<td><input type="checkbox" name="id" value="$line->{id}"></td>\n};
426                 $HTML .= qq {<td>$line->{id}</td>\n};
427                 $HTML .= qq {<td>$type</td>\n};
428                 $HTML .= qq {<td>$line->{chname_link}</td>\n};
429                 $HTML .= qq {<td align="left" style="white-space: normal">$line->{title}$line->{title_2}</td>\n};
430                 $HTML .= qq {<td>$begin</td>\n<td>$end</td>\n};
431                 $HTML .= qq {<td>$hr$diff</td>\n};
432                 $HTML .= qq {<td>$line->{opt}</td>\n<td>$line->{deltaday}</td>\n<td>$line->{deltatime}</td>\n<td>$line->{counter}</td>\n};
433                 $HTML .= qq {</tr>\n};
434         }
435         $HTML .= qq {</table>\n};
436         #$HTML .= qq {<input type="submit" name="edit" value="編集(要JS)">\n};
437         $HTML .= qq {<input type="submit" name="delete" value="削除">\n</div>\n</form>\n};
438         goto end;
439 }
440
441 ################ mode=graph ################
442
443 if ( $mode eq 'graph' ) {
444
445         my $date = $params{ 'date' };
446
447         if ( $date )
448         {
449                 print "Content-Type: image/svg+xml\n\n";
450
451                 require SVG;
452                 $date = Date::Simple->new( split /-/, $date );
453                 $graph_bgn = $date->format('%Y-%m-%d');
454                 $graph_end = $date->next->format('%Y-%m-%d');
455                 $day = $date->day;
456                 $today = $date eq Date::Simple->today() ? 1 : 0;
457
458                 $tuner{terrestrial} = 2; #$cfg->param( 'env.te_max' );
459                 $tuner{satellite}   = 2; #$cfg->param( 'env.bscs_max' );
460                 $tuner{all} = $tuner{terrestrial} + $tuner{satellite};
461                 $hours = 24;
462                 $width = 30 * $hours;
463
464                 $svg = new SVG( width => 820, height => $tuner{all} * 20 + 40 );
465                 $svg->rectangle( 'x' => 40, 'y' => 20, 
466                         width => $width + 20, height => $tuner{all} * 20 + 10, 
467                         rx => 15, ry => 15, 
468                         style => { stroke => 'blue', fill => 'white' } );
469                 for ( 1..$tuner{terrestrial} ) {
470                         $svg->text( 'x' => 10, 'y' => ( $_ + 1 ) * 20 )
471                                 ->cdata( "T$_" );
472                 }
473                 for ( 1..$tuner{satellite} ) {
474                         $svg->text( 'x' => 10, 'y' => ( $_ + $tuner{terrestrial} + 1 ) * 20 )
475                                 ->cdata( "S$_" );
476                 }
477                 for ( 0..$hours ) {
478                         $svg->text( 'x' => $_ * 30 + 65, 'y' => 15, 
479                                 style => { 'text-anchor' => 'middle' } )
480                                 ->cdata( sprintf( '%02d', $_ ) ) if ( $_ < $hours );
481                         # $svg->line( ); # can't be used when required
482                         $svg->tag( 'line', x1 => $_ * 30 + 50, x2 => $_ * 30 + 50, y1 => 30, y2 => $tuner{all} * 20 + 20, 
483                                 style => { stroke => 'gray' } );
484                 }
485                 for ( 1..$tuner{all} ) {
486                         $svg->rectangle( 'x' => 50, 'y' => $_ * 20 + 10, width => $width, height => 10 );
487                 }
488                 if ( $today ) {
489                         my $time = Time::Piece->localtime();
490                         my $x = ( $time->hour * 60 + $time->minute ) * 0.5 + 50;
491                         $svg->tag( 'line', x1 => $x, x2 => $x, y1 => 30, y2 => $tuner{all} * 20 + 20, 
492                                 style => { stroke => 'red', 'fill-opacity' => '1.0' } );
493                 }
494                 foreach my $bctype ( 'te%', '_s%' ) {
495                         my $tuner = $bctype eq 'te%' ? $tuner{terrestrial} : $tuner{satellite};
496                         my $ary_ref = $dbh->selectall_arrayref(
497                                 "SELECT id, title, timeline.chtxt, btime, etime, opt FROM timeline 
498                                 INNER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt 
499                                 WHERE epg_ch.bctype LIKE '$bctype' 
500                                 AND type IN $type_user_made 
501                                 AND 
502                                 (
503                                         '$graph_bgn 00:00' <= btime AND btime <  '$graph_end 00:00'
504                                                 OR
505                                         '$graph_bgn 00:00' <  etime AND etime <= '$graph_end 00:00'
506                                 )
507                                 ORDER BY id"
508                                 , {Slice=>{}}
509                         );
510                         foreach my $line ( @{ $ary_ref } ) {
511                                 @start = $line->{btime} =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2})/;
512                                 @stop  = $line->{etime} =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2})/;
513                                 $start = ( ( $day == $start[2] ? 0 : 24 * 60 ) + $start[3] * 60 + $start[4] ) * 0.5;
514                                 $stop  = ( ( $day == $stop [2] ? 0 : 24 * 60 ) + $stop [3] * 60 + $stop [4] ) * 0.5;
515                                 $start = 0      if ( $start < 0 || $day > $start[2] ); # 月の変わり目はスルー
516                                 $stop  = $width if ( $stop  > $width );
517                                 $begin = $line->{btime};
518                                 $end   = $line->{etime};
519
520                                 my $ary = $dbh->selectall_arrayref( 
521                                         "SELECT id, type, timeline.chtxt, title, btime, etime, opt FROM timeline 
522                                         INNER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt 
523                                         WHERE epg_ch.bctype LIKE '$bctype' 
524                                         AND type IN $type_user_made 
525                                         AND NOT 
526                                         ( 
527                                                 ( etime <= '$begin' ) 
528                                                         OR 
529                                                 ( btime >= '$end'   ) 
530                                         ) 
531                                         ORDER BY id" 
532                                         , {Slice=>{}}
533                                 );
534                                 my @ary = @{$ary};
535                                 for ( 0..$tuner - 1 ) {
536                                         my $f = 1;
537                                         my $i = $_;
538                                         for ( 'chtxt', 'btime', 'etime' ) {
539                                                 $f = 0 if ( $line->{$_} ne $ary[$i]->{$_} );
540                                         }
541                                         if ( $f ) {
542                                                 $slot = $i;
543                                         }
544                                 }
545                                 my ( $r, $g, $b ) = ( 0, 0, 0 );
546                                 $r += 255 if ( $line->{opt} =~ /a/ );
547                                 $g += 255 if ( $line->{opt} =~ /H/ );
548                                 $b += 255 if ( $line->{opt} =~ /I/ );
549                                 if ( $r + $g + $b == 255 * 3 ){
550                                         $r = 0;
551                                         $g = 255;
552                                         $b = 255;
553                                 }
554                                 if ( $r + $g + $b == 0 ){
555                                         $r = $g = $b = 128;
556                                 }
557                                 my %escaped = ( '&' => 'amp', '<' => 'lt', '>' => 'gt', '"' => 'quot' );
558                                 sub html_escape{
559                                     my $str = shift or return;
560                                     my $result = '';
561                                     $result .= $escaped{$_} ? '&' . $escaped{$_} . ';' : $_
562                                         for (split //, $str);
563                                     $result;
564                                 }
565                                 $svg->anchor(
566                                         -href  => "rectool.pl?mode=edit&amp;id=$line->{id}",
567                                         target => '_blank',
568                                         -title => html_escape( $line->{title} ),
569                                 )->rectangle( 
570                                         'x' => 50 + $start, 
571                                         'y' => 30 + ( $bctype eq 'te%' ? 0 : $tuner{terrestrial} * 20 ) + $slot * 20, 
572                                         width  => $stop - $start, 
573                                         height => 10, 
574                                         style  => { fill => "rgb($r,$g,$b)" } );
575                         }
576                 }
577                 print $svg->xmlify;
578                 exit;
579         }
580         else
581         {
582                 $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Viewer - Graphical/;
583                 $HTML .= qq {<div style="float: left">\n};
584                 # $base64 = encode_base64( $svg->xmlify );
585                 # $HTML .= qq {<object data="data:image/svg+xml;base64,$base64">\n</object>\n};
586                 $HTML .= qq {予約状況一覧です。T1,T2は地上波、S1,S2はBS/CS、赤はアニメ、緑はHD、青はインターレースを示しています。<br>\n};
587                 $HTML .= qq {SVGが利用可能なブラウザでご覧ください。<br>\n};
588
589                 $ary_ref = $dbh->selectcol_arrayref(
590                         "SELECT DISTINCT DATE( btime ) 
591                         FROM timeline 
592                         WHERE type in $type_user_made 
593                         ORDER BY btime"
594                 );
595                 foreach my $date ( @{ $ary_ref } ) {
596                         my @date = $date =~ /(.{4})-(.{2})-(.{2})/;
597                         my $dn = DateTime->new( year => $date[0], month => $date[1], day => $date[2], locale => 'ja_JP' )->day_name;
598                         #utf8::encode( $dn );
599                         $HTML .= qq {$date[1]/$date[2]($dn)の予約状況<br>\n};
600                         # <img src="">
601                         $HTML .= qq {<object type="image/svg+xml" data="rectool.pl?mode=graph&amp;date=$date" width="820">\n};
602                         $HTML .= qq {SVG Image $date\n</object>\n<br>\n};
603
604                         $date2 = Date::Simple->new( @date )->next->format('%Y-%m-%d');
605                         my $ary_ref = $dbh->selectall_arrayref(
606                                 "SELECT chtxt, title, btime, etime FROM timeline 
607                                 WHERE '$date 00:00' <= btime AND etime <= '$date2 01:00'
608                                 ORDER BY btime"
609                         );
610
611                         foreach my $line ( @{ $ary_ref } ) {
612                                 #$HTML .= qq {$line->[0] $line->[1] $line->[2] $line->[3]<br>\n};
613                         }
614
615                 }
616
617                 goto end;
618         }
619 }
620
621 ################ mode=atom ################
622
623 if ( $mode eq 'atom' ) {
624         require XML::Atom::Feed;
625         require XML::Atom::Entry;
626
627         my $recording_count = $encoding_count = $jbk_count = 0;
628         my $ary_ref = $dbh->selectall_arrayref(
629                 "SELECT chtxt, title, btime, etime, opt 
630                 FROM timeline 
631                 WHERE type = 'reserve_running' ");
632         foreach my $line ( @{$ary_ref} ) {
633                 my ( $begin, $end, $diff ) = &str2readable( $line->[2], $line->[3] );
634                 $recording_status .= qq {$line->[0] $line->[1] $begin - $end $diff $line->[4]<br />\n};
635                 $recording_count++;
636         }
637         $ary_ref = $dbh->selectall_arrayref(
638                 "SELECT chtxt, title, btime, etime, opt 
639                 FROM timeline 
640                 WHERE type = 'convert_ts_mp4_running' ");
641         foreach my $line ( @{$ary_ref} ) {
642                 my ( $begin, $end, $diff ) = &str2readable( $line->[2], $line->[3] );
643                 $encoding_status .= qq {$line->[0] $line->[1] $begin - $end $diff $line->[4]<br />\n};
644                 $encoding_count++;
645         }
646         $ary_ref = $dbh->selectall_arrayref(
647                 "SELECT id, chtxt, title, btime, etime 
648                 FROM auto_timeline_keyword " );
649         foreach my $line ( @{$ary_ref} ) {
650                 my ( $begin, $end, $diff ) = &str2readable( $line->[3], $line->[4] );
651                 $jbk_status .= qq {$line->[0] $line->[1] $line->[2] $begin - $end $diff<br />\n};
652                 $jbk_count++;
653         }
654
655         my $feed = XML::Atom::Feed->new( Version => 1.0 );
656         $feed->title('Rec10 フィード');
657
658         my $entry = XML::Atom::Entry->new( Version => 1.0 );
659         $entry->title("Rec10 録画状況 ($recording_count)");
660         $entry->id('tag:recording_status');
661         $entry->content($recording_status);
662         $entry->add_link(str_to_link( './rectool.pl?mode=schedule' ) );
663         $feed->add_entry($entry);
664
665         $entry = XML::Atom::Entry->new( Version => 1.0 );
666         $entry->title("Rec10 縁故状況 ($encoding_count)");
667         $entry->id('tag:encoding_status');
668         $entry->content($encoding_status);
669         $entry->add_link(str_to_link( './rectool.pl?mode=schedule' ) );
670         $feed->add_entry($entry);
671
672         $entry = XML::Atom::Entry->new( Version => 1.0 );
673         $entry->title("Rec10 地引状況 ($jbk_count)");
674         $entry->id('tag:jbk_status');
675         $entry->content($jbk_status);
676         $entry->add_link(str_to_link( './rectool.pl?mode=jbk' ) );
677         $feed->add_entry($entry);
678
679         my $xml = $feed->as_xml;
680         print "Content-Type: application/atom+xml\n\n";
681         print $xml;
682         exit;
683
684         sub str_to_link {
685                 my $link = XML::Atom::Link->new( Version => 1.0 );
686                 $link->type('text/html');
687                 $link->rel('alternate');
688                 $link->href(shift);
689                 return $link;
690         }
691 }
692
693 ################ mode=edit ################
694
695 if ( $mode eq 'edit' ) {
696         my $id = $params{ 'id' };
697
698         $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Editor/;
699         $HTML .= qq {<div style="float: left">\n};
700
701         $script = <<EOM;
702                 <script type="text/javascript" src="http://www.enjoyxstudy.com/javascript/dateformat/dateformat.js">
703                 </script>
704                 <script type="text/javascript">
705                 function setType(value){
706                         var index = document.reserve.type.selectedIndex;
707                         var value = document.reserve.type[index].value;
708                         if ( value == 'search_everyday' ) {
709                                 document.reserve.deltaday.value  = 7;
710                                 document.reserve.deltatime.value = 3;
711                         }
712                         if ( value == 'convert_b25_ts' || value == 'convert_ts_mp4' ){
713                                 var date       = new Date();
714                                 var dateFormat = new DateFormat("yyyy-MM-dd HH:mm:ss");
715                                 var minutes    = date.getMinutes();
716                                 minutes = minutes - minutes % 5 + 10;
717                                 date.setMinutes(minutes, 0, 0);
718                                 document.reserve.begin.value = dateFormat.format(date);
719                                 date.setSeconds( date.getSeconds() + 3600 );
720                                 document.reserve.end.value   = dateFormat.format(date);
721                         }
722                 }
723                 function setSuggest(start, stop){
724                         document.reserve.begin.value = start;
725                         document.reserve.end.value   = stop;
726                 }
727                 function shiftEndTime(value){
728                         var dateFormat = new DateFormat("yyyy-MM-dd HH:mm:ss");
729                         var date = dateFormat.parse(document.reserve.end.value || document.reserve.begin.value);
730                         date.setSeconds( date.getSeconds() + value );
731                         document.reserve.end.value = dateFormat.format(date);
732                 }
733                 </script>
734 EOM
735         $script =~ s/^\t{2}//gm;
736         $HTML =~ s/%SCRIPT%/$script/;
737
738         $HTML .= "スケジュール編集画面です。<br>\n";
739         $HTML .= "実装がとても適当なので、利用には細心の注意を払ってください。<br>\n<br>\n";
740         if ( $id ) {
741                 # 予約の編集
742                 &parse_program();
743                 $button_bgn = $button_end = '';
744         }
745         else {
746                 # 新規予約
747                 $type = 'reserve_flexible';
748                 $counter = -1;
749                 $datetime_now = DateTime->now( time_zone => $tz )->set_second( 0 )->add( minutes => 1)->strftime( '%Y-%m-%d %H:%M:%S' );
750                 $button_bgn = qq{<button type="button" onClick="document.reserve.begin.value='$datetime_now'">現在</button>\n<br>\n};
751                 $button_end = 
752                          qq{<button type="button" onClick="document.reserve.end.value=document.reserve.begin.value">一致</button>}
753                         .qq{<button type="button" onClick="shiftEndTime(300);">+5m</button>}
754                         .qq{<button type="button" onClick="shiftEndTime(1800);">+30m</button>};
755         }
756
757         if ( $params{ 'suggest' } eq 'auto' ) {
758                 my @btime = $begin =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/;
759                 my @etime = $end   =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/;
760                 my $btime = DateTime->new(
761                         year => $btime[0], month  => $btime[1], day    => $btime[2],
762                         hour => $btime[3], minute => $btime[4], second => $btime[5], 
763                 );
764                 my $etime = DateTime->new(
765                         year => $etime[0], month  => $etime[1], day    => $etime[2],
766                         hour => $etime[3], minute => $etime[4], second => $etime[5], 
767                 );
768                 my %hash = &sqlgetsuggested( $btime, $etime );
769
770                 $HTML .= qq {可能性のある番組<br>\n};
771                 $HTML .= qq {<table summary="suggesttable" border=1 cellspacing=0>\n<tr>\n};
772                 $HTML .= qq {<th>優先度</th>\n};
773                 $HTML .= qq {<th>タイトル</th>\n};
774                 $HTML .= qq {<th>開始時刻</th>\n};
775                 $HTML .= qq {<th>終了時刻</th>\n};
776                 $HTML .= qq {<th>説明</th>\n};
777                 $HTML .= qq {<th>適用</th>\n};
778                 $HTML .= qq {</tr>\n};
779
780                 foreach my $key (sort keys %hash){
781                         my $val = $hash{$key};
782                         foreach my $val ( @{$val} ) {
783                                 my $style = qq {style="white-space: nowrap"};
784                                 $val->[0] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
785                                 $val->[1] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
786                                 $HTML .= qq {<tr>\n<td>$key</td>\n<td>$val->[2]</td>\n};
787                                 $HTML .= qq {<td $style>$val->[0]</td>\n<td $style>$val->[1]</td>\n<td>$val->[3]</td>\n};
788                                 $HTML .= qq {<td><button onClick="setSuggest('$val->[0]','$val->[1]');">適用</button></td>\n</tr>\n};
789                         }
790                 }
791                 $HTML .= qq {</table>\n<br>\n};
792         }
793
794         my $len = length $id;
795         $HTML .= qq {<form method="get" action="rectool.pl" name="reserve">\n};
796         $HTML .= qq {<input type="hidden" name="mode" value="change">\n};
797         $HTML .= qq {<input type="hidden" name="mode_sub" value="update">\n};
798         $HTML .= qq {<input type="hidden" name="id" value="$id">\n};
799         $HTML .= qq {ID\n<input type="text" name="id" value="$id" size=$len disabled>\n};
800         $HTML .= qq {タイプ\n<select name="type" onChange="setType();">\n};
801         foreach my $key ( keys %type ) {
802                 next if ( $key !~ /^search|^reserve_flexible$|^reserve_fixed$|^convert_b25_ts$|^convert_ts_mp4$|^$type$/ );
803                 $value = $type{$key};
804                 if ( $key eq $type ) {
805                         $HTML .= qq {<option value="$key" selected>$value</option>\n};
806                 }
807                 else {
808                         $HTML .= qq {<option value="$key">$value</option>\n};
809                 }
810         }
811         $HTML .= qq {</select>\n};
812
813         $HTML .= qq {チャンネル\n<select name="chtxt">\n};
814         # 移動縁故など、チャンネルリスト内にchtxtが存在しない場合に備えて
815         $chtxt_0_chname{$chtxt} = $chname || $chtxt if ( !$chtxt_0_chname{$chtxt} );
816         foreach my $key ( sort keys %chtxt_0_chname ) {
817                 if ( $key eq $chtxt || $key eq $chtxt_0 ) {
818                         $HTML .= qq {<option value="$key" selected>$chtxt_0_chname{$key}</option>\n};
819                 }
820                 else {
821                         $HTML .= qq {<option value="$key">$chtxt_0_chname{$key}</option>\n};
822                 }
823         }
824         $HTML .= qq {</select><br>\n};
825         $HTML .= qq {タイトル\n<input type="text" name="title" value="$title" size=64><br>\n};
826         $HTML .= qq {開始時刻\n<input type="text" name="begin" value="$begin" maxlength=19 size=24>\n};
827         $HTML .= $button_bgn;
828         $HTML .= qq {終了時刻\n<input type="text" name="end" value="$end" maxlength=19 size=24>\n};
829         $HTML .= $button_end . "<br>\n";
830         $HTML .= qq {隔日周期\n<input type="text" name="deltaday" value="$deltaday" maxlength=2  size=2 >\n};
831         $HTML .= qq {時刻誤差\n<input type="text" name="deltatime" value="$deltatime" maxlength=2  size=2 >\n};
832         $HTML .= qq {オプション\n<input type="text" name="opt" value="$opt">\n};
833         $HTML .= qq {回数\n<input type="text" name="counter" value="$counter" size=2 >\n};
834         $HTML .= qq {<input type="submit" name="update" value="更新">\n</form>\n};
835 }
836
837 ################ mode=change ################
838
839 if ( $mode eq 'change' ) {
840         @id     = $q->param( 'id' );
841
842         $HTML =~ s/%HTML_TITLE_OPT%/ - Change/;
843         $HTML .= qq {<div style="float: left">\n};
844
845         if ( $params{ 'delete' } )
846         {
847                 if ( @id ) {
848                         foreach my $id ( @id ) {
849                                 $dbh->do( "DELETE FROM timeline WHERE id = '$id'" );
850                         }
851                         $HTML .= "削除しました。<br>\n5秒後に予約確認画面に移動します。<br>\n";
852                         $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="5; url=rectool.pl?mode=schedule">|;
853                         goto end;
854                 }
855         }
856         if ( $params{ 'update' } )
857         {
858                 $type      = $params{ 'type' };
859                 $chtxt     = $params{ 'chtxt' };
860                 $title     = $params{ 'title' };
861                 $begin     = $params{ 'begin' };
862                 $end       = $params{ 'end' };
863                 $deltaday  = $params{ 'deltaday' };
864                 $deltatime = $params{ 'deltatime' };
865                 $opt       = $params{ 'opt' };
866                 $counter   = $params{ 'counter' };
867                 $id        = $id[0];
868                 if ( $id ) {
869                         $dbh->do( 
870                                 "UPDATE timeline SET type = '$type', chtxt = '$chtxt', title = '$title', 
871                                 btime = '$begin', etime = '$end', 
872                                 deltaday = '$deltaday', deltatime = '$deltatime', opt = '$opt', counter = '$counter' 
873                                 WHERE id = '$id'" 
874                         );
875                 }
876                 else {
877                         $dbh->do( 
878                                 "INSERT INTO timeline ( type, chtxt, title, btime, etime, deltaday, deltatime, opt, counter ) 
879                                 VALUES ( '$type', '$chtxt', '$title', '$begin', '$end', '$deltaday', '$deltatime', '$opt', '$counter' )" 
880                         );
881                 }
882                 $HTML .= "更新しました。<br>\n5秒後に予約確認画面に移動します。<br>\n";
883                 $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="5; url=rectool.pl?mode=schedule">|;
884                 goto end;
885         }
886         if ( $mode_sub eq 'proc' ) {
887                 my $type  = $params{ 'type' };
888                 my $chtxt = $params{ 'chtxt' } || 'nhk-k';
889                 my $title = $params{ 'title' };
890                 my @opt   = $q->param( 'opt' );
891                 my $opt   = join '', @opt;
892
893                 my $datetime_now = DateTime->now( time_zone => $tz )->set_second( 0 )->add( minutes => 10);
894                 my $sql_type = $type_suggest{$type};
895                 my $begin = $datetime_now->strftime( '%Y-%m-%d %H:%M:%S' );
896                 $datetime_now = $datetime_now->add( minutes => 60 );
897                 my $end = $datetime_now->strftime( '%Y-%m-%d %H:%M:%S' );
898
899                 $dbh->do( 
900                         "INSERT INTO timeline ( type, chtxt, title, btime, etime, opt ) 
901                         VALUES ( '$sql_type', '$chtxt', '$title', '$begin', '$end', '$opt' )"
902                 );
903
904                 goto end;
905         }
906         if ( $mode_sub eq 'move' ) {
907                 my $mode_sub2  = $params{ 'mode_sub2' };
908                 my $title      = $params{ 'title' };
909                 my $response;
910
911                 $ENV{'LANG'} = 'ja_JP.UTF-8';
912                 if ( $mode_sub2 eq 'predict' ) {
913                         $HTML .= "移動後のシミュレーション結果です。\n<br>";
914                         eval '$response = `python26 ' . $cfg->param( 'path.rec10' ) . "/classify.py -s '$title'`";
915                 }
916                 elsif ( $mode_sub2 eq 'exec' ) {
917                         eval '$response = `python26 ' . $cfg->param( 'path.rec10' ) . "/classify.py -e '$title'`";
918                 }
919                 utf8::decode( $response );
920                 $HTML .= $response;
921
922                 goto end;
923         }
924         if ( $mode_sub eq 'setting' ) {
925                 my $jbk     = $params{ 'jbk' }     || '0';
926                 my $bayes   = $params{ 'bayes' }   || '0';
927                 my $del_tmp = $params{ 'del_tmp' } || '0';
928                 my $opt     = $params{ 'opt' }     || '';
929                 my $user    = $params{ 'user' }    || '';
930                 my $pass    = $params{ 'pass' }    || '';
931
932                 $dbh->do( 
933                         "UPDATE in_settings SET auto_jbk = '$jbk', auto_bayes = '$bayes', 
934                         auto_del_tmp = '$del_tmp', auto_opt = '$opt'"
935                 );
936
937                 goto end;
938         }
939         if ( $mode_sub eq 'fixstatus' ) {
940                 my $key = $params{ 'terec'  } ? 'terec'  : $params{ 'bscsrec' } ? 'bscsrec' : 
941                           $params{ 'b252ts' } ? 'b252ts' : $params{ 'ts2avi'  } ? 'ts2avi'  : '';
942
943                 $dbh->do( 
944                         "UPDATE in_status SET $key = 0"
945                 );
946
947                 goto end;
948         }
949
950 }
951
952 ################ mode=confirm ################
953
954 if ( $mode eq 'confirm' ) {
955         if ( $mode_sub eq 'reserve' ) {
956                 $HTML =~ s/%HTML_TITLE_OPT%/ - Reserver/;
957                 $HTML .= qq {<div style="float: left">\n};
958                 &parse_program();
959
960                 my $duration = ( str2datetime( $end ) - str2datetime( $begin ) )->delta_minutes;
961                 $HTML .= "番組名:$title<br>\nチャンネル:$chname<br>\n放送継続時間:$duration 分<br>\n番組内容:$desc<br>\n";
962                 if ( $longdesc ) {
963                         $longdesc =~ s/\\n/<br>\n/gs;
964                         $HTML .= "番組内容(長):$longdesc<br>\n";
965                 }
966                 my $error = &check_error();
967                 if ( $error )
968                 {
969                         # エラー
970
971                         $ary_ref = $dbh->selectall_arrayref(
972                                 "SELECT start, stop FROM epg_timeline WHERE channel = '$chtxt' AND title = '$title' "
973                         );
974                         if ( $error != 1 ) {
975                                 $HTML .= "同一の番組の他の放送予定です。<br>\n";
976                                 foreach my $line ( @{$ary_ref} ) {
977                                         $begin = $line->[0];
978                                         $end   = $line->[1];
979                                         $begin =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
980                                         $end   =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
981                                         $overlap = &get_overlap() >= 2 ? '不可能' : 
982                                                 qq {<a href="rectool.pl?mode=confirm&amp;mode_sub=reserve&amp;chtxt=$chtxt&amp;start=$line->[0]&amp;stop=$line->[1]">可能</a>};
983                                         $HTML .= "開始:$begin\n終了:$end\n録画は$overlap<br>\n";
984                                 }
985                         }
986                 }
987                 else {
988                         $HTML .= "録画予約の詳細設定を行ってください。<br>\n";
989                         $HTML .= qq {<form method="get" action="rectool.pl">\n};
990                         $HTML .= qq {<input type="hidden" name="mode"  value="reserve">\n};
991                         $HTML .= qq {<input type="hidden" name="chtxt" value="$chtxt">\n};
992                         $HTML .= qq {<input type="hidden" name="start" value="$start">\n};
993                         $HTML .= qq {<input type="hidden" name="stop"  value="$stop">\n};
994                         $HTML .= qq {<input type="hidden" name="title" value="$title">\n} if ( $params{ 'title' } );
995                         &draw_form_opt( 'reserve' );
996                         $HTML .= qq {<input type="submit" value="予約">\n</form>\n};
997                 }
998                 goto end;
999         }
1000         # End of $mode_sub eq 'reserve';
1001
1002         if ( $mode_sub eq 'proc' ) {
1003                 my    $type  = $params{ 'type' };
1004                 local $chtxt = $params{ 'chtxt' };
1005                 my    $title = $params{ 'title' };
1006                 local $opt   = $params{ 'opt' };
1007                 utf8::decode( $title );
1008
1009                 $HTML .= "詳細設定を行ってください。<br>\n";
1010                 $HTML .= "タイトル:$title\n<br>\n";
1011
1012                 $HTML .= qq {<form method="get" action="rectool.pl">\n};
1013                 $HTML .= qq {<input type="hidden" name="mode"     value="change">\n};
1014                 $HTML .= qq {<input type="hidden" name="mode_sub" value="proc">\n};
1015                 $HTML .= qq {<input type="hidden" name="type"     value="$type">\n};
1016                 $HTML .= qq {<input type="hidden" name="title"    value="$title">\n};
1017                 &draw_form_channel( 'nonone' );
1018                 &draw_form_opt();
1019                 $HTML .= qq {<input type="submit" value="予約">\n</form>\n};
1020                 goto end;
1021         }
1022 }
1023
1024 ################ mode=reserve ################
1025
1026 if ( $mode eq 'reserve' ) {
1027         $HTML .= qq {<div style="float: left">\n};
1028         &parse_program();
1029         $title = $params{ 'title' } if ( !$title );
1030         @opt = $q->param( 'opt' );
1031         $opt = join '', @opt;
1032         my ( $deltaday, $deltatime );
1033
1034         if ( $params{'every'} eq '1' ) {
1035                 $type = 'search_everyday';
1036                 ( $changed_t ) = $title =~ /(.*)#/;
1037                 $title = $changed_t if ( $changed_t );
1038                 ( $changed_t ) = $title =~ /(.*)第/;
1039                 $title = $changed_t if ( $changed_t );
1040                 ( $changed_t ) = $title =~ /(.*)▽/;
1041                 $title = $changed_t if ( $changed_t );
1042                 $title =~ s/「.*」//;
1043                 $title =~ s/<.*>//;
1044                 $title =~ s/(.*)//;
1045                 $title =~ s/\[新\]//;
1046                 $title =~ s/無料≫//;
1047                 $title =~ s/\s*$//;
1048                 $deltaday  = 7;
1049                 $deltatime = 3;
1050         }
1051         else {
1052                 $type = 'reserve_flexible';
1053         }
1054         $chtxt = $chtxt_0 if ( $chtxt_0 );
1055         if ( !&check_error ) {
1056                 $dbh->do( 
1057                         "INSERT INTO timeline ( type, chtxt, title, btime, etime, opt, deltaday, deltatime ) 
1058                         VALUES ( '$type', '$chtxt', '$title', '$begin', '$end', '$opt', '$deltaday', '$deltatime' )" 
1059                 );
1060         }
1061         $HTML .= "録画予約を実行しました。<br>\n5秒後にトップへ移動します。<br>\n";
1062         $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="5; url=rectool.pl">|;
1063         goto end;
1064 }
1065
1066 ################ mode=program ################
1067
1068 if ( $mode eq 'program' ) {
1069         &draw_form();
1070
1071         $HTML =~ s/%HTML_TITLE_OPT%/ - Program Viewer/;
1072         $unix = DateTime->now( time_zone => $tz )->strftime( '%Y%m%d%H%M%S' );
1073         $sql = 
1074                 "SELECT channel, epg_ch.chname, start, stop, title, category 
1075                 FROM epg_timeline 
1076                 INNER JOIN epg_ch ON epg_timeline.channel = epg_ch.chtxt 
1077                 WHERE $unix <= stop %CH% %DATE% %CATEGORY% %KEY% ORDER BY start";
1078
1079         if ( $chtxt ) {
1080                 my $ch;
1081                 if ( $chtxt =~ /^\d+(_0)?$/ ) {
1082                         # teはxx_yyy形式であるため
1083                         $chtxt =~ s/_0//;
1084                         $ch = "AND channel LIKE '$chtxt\_%'";
1085                 }
1086                 else {
1087                         $ch = "AND channel = '$chtxt'";
1088                 }
1089                 $sql =~ s/%CH%/$ch/;
1090         }
1091         if ( $date_sel ) {
1092                 $date_1 = $date_sel . '000000';
1093                 $date_2 = Date::Simple->new( $date_sel =~ /(.{4})(.{2})(.{2})/ )->next->format('%Y%m%d') . '000000';
1094                 my $date = "AND '$date_1' <= stop AND start <= '$date_2'";
1095                 $sql =~ s/%DATE%/$date/;
1096         }
1097         if ( $category_sel ) {
1098                 # 一時的
1099                 #       $category_tmp = $category{$category_sel} . $category_sel;
1100                 my $category = "AND category = '$category{$category_sel}'";
1101                 $sql =~ s/%CATEGORY%/$category/;
1102         }
1103         if ( $key ) {
1104                 my $key = "AND TITLE LIKE '%$key%'";
1105                 $sql =~ s/%KEY%/$key/;
1106         }
1107         $sql =~ s/%CH%//;
1108         $sql =~ s/%DATE%//;
1109         $sql =~ s/%KEY%//;
1110         $sql =~ s/%CATEGORY%//;
1111
1112         $ary_ref = $dbh->selectall_arrayref( $sql );
1113         foreach my $prg ( @{ $ary_ref } ) {
1114                 my @date = $prg->[2] =~ /(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/;
1115
1116                 $date = $date[2];
1117                 if ( $date != $prev ) {
1118                         my $date = DateTime->new(
1119                                 year => $date[0], month  => $date[1], day    => $date[2], 
1120                                 locale => 'ja_JP'
1121                         );
1122
1123                         my $dn = $date->day_name;
1124                         #utf8::encode( $dn );
1125                         $HTML .= qq {--------$date[1]/$date[2]($dn)--------<br>\n};
1126                 }
1127                 $HTML .= qq {$date[1]/$date[2] $date[3]:$date[4] };
1128                 $HTML .= qq {$prg->[1] } if ( !$chtxt );
1129                 $HTML .= qq {<a href="rectool.pl?mode=confirm&amp;mode_sub=reserve&amp;chtxt=$prg->[0]&amp;start=$prg->[2]&amp;stop=$prg->[3]">$prg->[4]</a><br>\n};
1130                 $prev = $date;
1131         }
1132 }
1133
1134 ################ mode=list ################
1135
1136 if ( $mode eq 'list' ) {
1137         $HTML =~ s/%HTML_TITLE_OPT%/ - List/;
1138         $HTML .= qq {<div>\n};
1139
1140         my $recording   = $cfg->param( 'path.recpath' );
1141         my $ts_movepath = $cfg->param( 'path.ts_movepath' );
1142         my $recorded    = $cfg->param( 'path.recorded' );
1143
1144         if ( $mode_sub eq 'log' ) {
1145                 my $title = $params{ 'title' };
1146                 my $log = read_file( "$recording/$title.log" ) if ( -e "$recording/$title.log" );
1147                 utf8::decode( $log );
1148                 $HTML .= '<pre>'.$log."</pre>\n";
1149                 goto end;
1150         }
1151         if ( !$mode_sub ) {
1152                 $HTML .= qq {<a href="rectool.pl?mode=list&amp;mode_sub=new">録画中のみ</a>\n};
1153                 $HTML .= qq {<a href="rectool.pl?mode=list&amp;mode_sub=old">録画後のみ</a>\n<br>\n};
1154         }
1155         if ( !$mode_sub || $mode_sub eq 'new' ) {
1156                 $HTML .= "録画中のファイル一覧<br>\n";
1157                 &list( $recording );
1158         }
1159         if ( !$mode_sub ) {
1160                 $HTML .= "<br>\n";
1161         }
1162         if ( !$mode_sub || $mode_sub eq 'old' ) {
1163                 $HTML .= "録画後のファイル一覧<br>\n";
1164                 &simple_list( $ts_movepath );
1165                 &simple_list( $recorded );
1166         }
1167
1168         sub list {
1169                 local $path = shift;
1170                 local %list = ();
1171                 my @exp = ( 'log', 'log.zip', 'ts.b25', 'ts.tsmix', 'ts', 'ts.log', 
1172                         'aac', 'srt', 'm2v', 'wav', '264', 'mp4', 'mkv' );
1173                 for ( 0..$#exp ) {
1174                         $exp{$exp[$_]} = $_;
1175                 }
1176                 my $exp_count = scalar keys %exp;
1177
1178                 &get_file_list_wrapper( $path, \&wanted );
1179
1180                 my $help;
1181                 foreach my $name ( sort { $exp{$a} <=> $exp{$b} } keys %exp ) {
1182                         $help .= $exp{$name} + 1 . " = $name / ";
1183                 }
1184                 $HTML .= $help;
1185                 $help  = qq {<tr style="background-color: #87CEEB"><td>$help\n</td>\n};
1186                 $help .= qq {<td>$_</td>\n} for ( 1..$exp_count );
1187                 $help .= qq {<td colspan="2">自動移動</td>\n</tr>\n};
1188                 $help .= qq {<tr>\n</tr>\n};
1189
1190                 $HTML .= qq {<br>\n○ = 完了 / ● = 書き込み中 / ◆ = ファイルサイズ異常<br>\n};
1191                 $HTML .= qq {<table summary="listtable" border=1 cellspacing=0>\n<tr>\n};
1192                 $HTML .= qq {<th>タイトル</th>\n};
1193                 $HTML .= qq {<th>$_</th>\n} for ( 1..$exp_count );
1194                 $HTML .= qq {<th colspan="2">自動移動</th>\n};
1195                 $HTML .= qq {</tr>\n};
1196
1197                 my $count = 0;
1198
1199                 foreach my $title ( sort keys %list ) {
1200                         my $value = $list{$title};
1201                         my @flag = ( 0 ) x ( $exp_count );
1202                         $HTML .= qq {<tr>\n<td width="600" style="width: 600px; white-space: normal">$title</td>\n};
1203                         foreach my $exp ( keys %{$value} ) {
1204                                 if ( $exp eq 'log' ) {
1205                                         my $title = $q->escape( $title );
1206                                         my $check = qq {<td><a href="rectool.pl?mode=list&amp;mode_sub=log&amp;title=$title">○</a></td>\n};
1207
1208                                         $value->{$exp}->{check} = $check;
1209                                 }
1210                                 elsif ( $exp eq 'mkv' ) {
1211                                         my $title = $q->escape( $title );
1212
1213                                         my $check = qq {<td><a title="$value->{$exp}->{size}" href="rectool.pl?mode=thumb&amp;title=$title">■</a></td>\n};
1214                                         $value->{$exp}->{check} = $check;
1215                                 }
1216                                 $flag[$exp{$exp}] = $value->{$exp};
1217                         }
1218                         if ( !$flag[$exp{'mkv'}] ) {
1219                                 $flag[@flag]->{check} = qq {<td colspan="2"><br></td>\n};
1220                         }
1221                         else {
1222                                 my $title = $q->escape( $title );
1223
1224                                 $flag[@flag]->{check} = 
1225                                         qq {<td><a href="rectool.pl?mode=change&amp;mode_sub=move&amp;mode_sub2=predict&amp;title=$title">予測</a></td>\n}.
1226                                         qq {<td><a href="rectool.pl?mode=change&amp;mode_sub=move&amp;mode_sub2=exec&amp;title=$title">実行</a></td>\n};
1227                         }
1228                         foreach ( @flag ) {
1229                                 my $size = $_->{size};
1230                                 my $last = $_->{last} || ( $_->{size} eq '0 B' ? '◆' : '○' );
1231                                 my $check =  $size ? qq {<span title="$size">$last</span>} : '<br>';
1232                                 $HTML .= $_->{check} ? $_->{check} : qq {<td>$check</td>\n};
1233                         }
1234                         $HTML .= qq {</tr>\n};
1235                         $HTML .= $help unless ( ++$count % 20 );
1236                 }
1237                 $HTML .= qq {</table>\n};
1238
1239                 sub wanted {
1240                         my $rel = shift;
1241                         my $abs = shift;
1242
1243                         return if ( $rel =~ /Thumbs\.db/ );
1244                         return if ( $rel =~ /\.idx/ );
1245
1246                         $rel =~ s/\.temp$//;
1247                         my $regexp = join '|', keys %exp;
1248                         my ( $title, $exp ) = $rel =~ /(.*?)\.($regexp)$/;
1249                         my ( $size, $last ) = &get_size( $abs );
1250                         $rel =~ s/\.temp$//;
1251                         if ( !$title ) {
1252                                 $title = '_error_exp_'.$rel;
1253                                 $exp   = 'log';
1254                         }
1255                         if ( $title !~ /[^0-9A-F]+/ ) {
1256                                 my $tmp = pack( 'H*', $title );
1257                                 if ( !$tmp ) {
1258                                         $title = '_error_b16_'.$rel;
1259                                         $exp   = 'log';
1260                                 }
1261                                 else {
1262                                         $title = 'Base16_'.$tmp;
1263                                 }
1264                         }
1265                         $list{$title}->{$exp} = { 'last' => $last, 'size' => $size };
1266                 }
1267         }
1268
1269         sub simple_list {
1270                 local $path = shift;
1271                 local @list = ();
1272
1273                 &get_file_list_wrapper( $path, \&simple_wanted );
1274
1275 #               @list = sort @list;
1276                 # natural sortを行う
1277                         #@list = map( Encode::decode_utf8( $_ ), @list );
1278                         @list = nsort @list;
1279                         #@list = map( Encode::encode_utf8( $_ ), @list );
1280
1281                 foreach ( @list ) {
1282                         $HTML .= "$_<br>\n";
1283                 }
1284
1285                 sub simple_wanted {
1286                         my $rel = shift;
1287                         my $abs = shift;
1288
1289                         my ( $size ) = &get_size( $abs );
1290                         push @list, $rel ."\t\t". $size;
1291                 }
1292         }
1293
1294         sub get_size {
1295                 my $file = shift;
1296                 my ( $size, $last ) = (stat( $file ))[7,9];
1297                 my @unim = ("B","KiB","MiB","GiB","TiB","PiB");
1298                 my $count = 0;
1299
1300                 while($size >= 1024 ){
1301                         $count++;
1302                         $size = $size / 1024;
1303                 }
1304                 $size *= 100;
1305                 $size  = int( $size );
1306                 $size /= 100;
1307                 if ( time - $last < 10 ) {
1308                         $last = '●';
1309                 }
1310                 else {
1311                         $last = '';
1312                 }
1313                 return ( "$size $unim[$count]", $last );
1314         }
1315 }
1316
1317 ################ mode=thumb ################
1318
1319 if ( $mode eq 'thumb' ) {
1320         my $title = $params{ 'title' };
1321         my $pos  = $params{ 'pos' };
1322         my $recording = $cfg->param( 'path.recpath' );
1323
1324         print "Content-Type: image/jpeg\n\n";
1325         exec "ffmpeg -ss 300 -i '$recording/$title.mkv' -f image2 -pix_fmt jpg -vframes 1 -s 320x240 -";
1326         exit;
1327 }
1328
1329 ################ mode=check ################
1330
1331 if ( $mode eq 'check' ) {
1332 }
1333
1334 ################ mode=bravia ################
1335
1336 if ( $mode eq 'bravia' ) {
1337         $HTML =~ s/%HTML_TITLE_OPT%/ - Bravia/;
1338         $HTML .= qq {<div>\n};
1339         $HTML .= qq {<form method="get" action="rectool.pl">\n};
1340         $HTML .= qq {<div>\n};
1341         $HTML .= qq {<table summary="bayestable" border=1 cellspacing=0>\n<tr>\n};
1342         $HTML .= qq {<th>ID</th>\n};
1343         $HTML .= qq {<th>チャンネル</th>\n};
1344         $HTML .= qq {<th>タイトル</th>\n};
1345         $HTML .= qq {<th><a href="rectool.pl?mode=bravia">開始時刻</a></th>\n};
1346         $HTML .= qq {<th>終了時刻</th>\n};
1347         $HTML .= qq {<th>録画時間</th>\n};
1348         $HTML .= qq {<th><a href="rectool.pl?mode=bravia&amp;order=point">ポイント</a></th>\n};
1349         $HTML .= qq {<th>予約</th>\n};
1350         $HTML .= qq {</tr>\n};
1351         my $order = $params{ 'order' };
1352         if ( $order ne 'point' ) {
1353                 $order = 'btime';
1354         }
1355         else {
1356                 $order = 'point DESC';
1357         }
1358         my $ary_ref = $dbh->selectall_arrayref(
1359                 "SELECT id, chtxt, title, btime, etime, point 
1360                 FROM auto_timeline_bayes 
1361                 ORDER BY $order" );
1362
1363         foreach my $line ( @{ $ary_ref } ) {
1364                 my ( $begin, $end, $diff ) = &str2readable( $line->[3], $line->[4] );
1365
1366                 $line->[1] = $chtxt_chname{$line->[1]} || $line->[1];
1367                 $HTML .= qq {<tr align="center">\n};
1368                 $HTML .= qq {<td>$line->[0]</td>\n};
1369                 $HTML .= qq {<td>$line->[1]</td>\n};
1370                 $HTML .= qq {<td>$line->[2]</td>\n};
1371                 $HTML .= qq {<td>$begin</td>\n<td>$end</td>\n<td>$diff</td>\n};
1372                 $HTML .= qq {<td>$line->[5]</td>\n};
1373                 $HTML .= qq {<td><a href="rectool.pl?mode=confirm&amp;mode_sub=reserve&amp;bayesid=$line->[0]">予約</a></td>\n};
1374                 $HTML .= qq {</tr>\n};
1375         }
1376         $HTML .= qq {</table>\n};
1377         $HTML .= qq {</div>\n};
1378         $HTML .= qq {</form>\n};
1379
1380 }
1381
1382 ################ mode=proc ################
1383
1384 if ( $mode eq 'proc' ) {
1385         $HTML =~ s/%HTML_TITLE_OPT%/ - Proposal/;
1386         $HTML .= qq {<div>\n};
1387         $HTML .= qq {<table summary="proctable" border=1 cellspacing=0>\n<tr>\n};
1388         $HTML .= qq {<th>タイプ</th>\n};
1389         $HTML .= qq {<th>タイトル</th>\n};
1390         $HTML .= qq {<th>予約</th>\n};
1391         $HTML .= qq {</tr>\n};
1392
1393         my $ary_ref = $dbh->selectall_arrayref(
1394                 "SELECT type, chtxt, title 
1395                 FROM auto_proc 
1396                 ORDER BY title " );
1397
1398         foreach my $line ( @{ $ary_ref } ) {
1399                 my $url;
1400                 $line->[3] = $q->escape( $line->[2] );
1401                 my $opt = $dbh->selectrow_array( 
1402                         "SELECT opt FROM in_timeline_log 
1403                         WHERE title = '$line->[2]' "
1404                 );
1405
1406                 if ( $line->[0] eq 'auto_suggest_dec' ) {
1407                         unless ( $dbh->selectrow_array( 
1408                                 "SELECT 1 FROM timeline 
1409                                 WHERE ( type = 'convert_b25_ts' OR type = 'convert_b25_ts_running' )
1410                                 AND title = '$line->[2]' "
1411                         ) ) {
1412                                 $url = qq {rectool.pl?mode=confirm&amp;mode_sub=proc&amp;type=$line->[0]&amp;chtxt=$line->[1]&amp;title=$line->[3]&amp;opt=$opt};
1413                         }
1414                 }
1415                 elsif ( $line->[0] eq 'auto_suggest_enc' ) {
1416                         unless ( $dbh->selectrow_array( 
1417                                 "SELECT 1 FROM timeline 
1418                                 WHERE ( type = 'convert_ts_mp4' OR type = 'convert_ts_mp4_running' ) 
1419                                 AND title = '$line->[2]' "
1420                         ) ) {
1421                                 $url = qq {rectool.pl?mode=confirm&amp;mode_sub=proc&amp;type=$line->[0]&amp;chtxt=$line->[1]&amp;title=$line->[3]&amp;opt=$opt};
1422                         }
1423                 }
1424                 else {
1425                         unless ( $dbh->selectrow_array( 
1426                                 "SELECT 1 FROM timeline 
1427                                 WHERE ( type LIKE 'convert_avi%' OR type = 'convert_mkv' ) 
1428                                 AND title = '$line->[2]' "
1429                         ) ) {
1430                                 $url = qq {rectool.pl?mode=confirm&amp;mode_sub=proc&amp;type=$line->[0]&amp;chtxt=$line->[1]&amp;title=$line->[3]};
1431                         }
1432                 }
1433                 if ( $url ) { 
1434                         $href = qq {<a href="$url">予約</a>};
1435                 }
1436                 else {
1437                         $href = q {予約済};
1438                 }
1439
1440                 my $color = $color{$type_suggest{$line->[0]}} ? $color{$type_suggest{$line->[0]}} : '';
1441                 $line->[0] = $type{$line->[0]} ? $type{$line->[0]} : $line->[0];
1442                 $line->[0] = qq {<span style="color: $color">$line->[0]</span>} if ( $color );
1443                 $HTML .= qq {<tr align="center">\n};
1444                 $HTML .= qq {<td>$line->[0]</td>\n};
1445                 $HTML .= qq {<td align="left">$line->[2]</td>\n};
1446                 $HTML .= qq {<td>$href</td>\n};
1447                 $HTML .= qq {</tr>\n};
1448         }
1449
1450         $HTML .= qq {</table>\n};
1451 }
1452
1453 ################ mode=jbk ################
1454
1455 if ( $mode eq 'jbk' ) {
1456         $HTML =~ s/%HTML_TITLE_OPT%/ - JBK/;
1457         $HTML .= qq {<div>\n};
1458
1459         if ( $mode_sub eq 'add' ) {
1460                 my $keyword = $params{ 'keyword' };
1461                 utf8::decode( $keyword );
1462                 $HTML .= "キーワード「$keyword」を追加しました。<br>\n";
1463                 $dbh->do( 
1464                         "INSERT INTO in_auto_jbk_key ( keyword ) 
1465                         VALUES ( '$keyword' )" 
1466                 );
1467         }
1468         elsif ( $mode_sub eq 'del' ) {
1469                 my $id = $params{ 'id' };
1470                 my $keyword = $dbh->selectrow_array( 
1471                         "SELECT keyword FROM in_auto_jbk_key 
1472                         WHERE id = '$id' " );
1473                 $HTML .= "キーワード「$keyword」を削除しました。<br>\n";
1474                 $dbh->do( 
1475                         "DELETE FROM in_auto_jbk_key WHERE id = '$id'" 
1476                 );
1477         }
1478         elsif ( $mode_sub eq 'on' ) {
1479                 my $id = $params{ 'id' };
1480                 $HTML .= "キーワード「$keyword」を自動録画対象にしました。<br>\n";
1481                 $dbh->do( 
1482                         "UPDATE in_auto_jbk_key SET auto = 1 WHERE id = '$id'" 
1483                 );
1484         }
1485         elsif ( $mode_sub eq 'off' ) {
1486                 my $id = $params{ 'id' };
1487                 $HTML .= "キーワード「$keyword」を自動録画対象から外しました。<br>\n";
1488                 $dbh->do( 
1489                         "UPDATE in_auto_jbk_key SET auto = 0 WHERE id = '$id'" 
1490                 );
1491         }
1492
1493         $HTML .= qq {<table summary="jbktable" border=1 cellspacing=0>\n<tr>\n};
1494         $HTML .= qq {<th>ID</th>\n};
1495         $HTML .= qq {<th>キーワード</th>\n};
1496         $HTML .= qq {<th>自動録画</th>\n};
1497         $HTML .= qq {<th>切り替え</th>\n};
1498         $HTML .= qq {<th>削除</th>\n};
1499         $HTML .= qq {</tr>\n};
1500
1501         my $ary_ref = $dbh->selectall_arrayref(
1502                 "SELECT id, keyword, auto 
1503                 FROM in_auto_jbk_key
1504                 ORDER BY id " );
1505
1506         foreach my $line ( @{ $ary_ref } ) {
1507                 my $delurl = "rectool.pl?mode=jbk&amp;mode_sub=del&amp;id=$line->[0]";
1508                 my $auto = $line->[2] ? 'on' : 'off';
1509                 my $oppo = $line->[2] ? 'off' : 'on';
1510                 my $oppourl = "rectool.pl?mode=jbk&amp;mode_sub=$oppo&amp;id=$line->[0]";
1511                 $oppo .= "にする";
1512
1513                 $HTML .= qq {<tr align="center">\n};
1514                 $HTML .= qq {<td>$line->[0]</td>\n};
1515                 $HTML .= qq {<td>$line->[1]</td>\n};
1516                 $HTML .= qq {<td>$auto</td>\n};
1517                 $HTML .= qq {<td><a href="$oppourl">$oppo</a></td>\n};
1518                 $HTML .= qq {<td><a href="$delurl">削除</a></td>\n};
1519                 $HTML .= qq {</tr>\n};
1520         }
1521
1522         $HTML .= qq {</table>\n};
1523
1524         $HTML .= qq {<form method="get" action="rectool.pl">\n};
1525         $HTML .= qq {<div>\n};
1526         $HTML .= qq {<input type="hidden" name="mode" value="jbk">\n};
1527         $HTML .= qq {<input type="hidden" name="mode_sub" value="add">\n};
1528         $HTML .= qq {<input name="keyword" type="text">\n};
1529         $HTML .= qq {<input type="submit" value="追加">\n</div>\n</form>\n<br>\n};
1530
1531         $HTML .= qq {<table summary="jbkrestable" border=1 cellspacing=0>\n<tr>\n};
1532         $HTML .= qq {<th>ID</th>\n};
1533         $HTML .= qq {<th>チャンネル</th>\n};
1534         $HTML .= qq {<th>タイトル</th>\n};
1535         $HTML .= qq {<th>開始時刻</th>\n};
1536         $HTML .= qq {<th>終了時刻</th>\n};
1537         $HTML .= qq {<th>録画時間</th>\n};
1538         $HTML .= qq {<th>予約</th>\n};
1539         $HTML .= qq {</tr>\n};
1540
1541         $ary_ref = $dbh->selectall_arrayref(
1542                 "SELECT id, auto_timeline_keyword.chtxt, epg_ch.chname, title, btime, etime 
1543                 FROM auto_timeline_keyword 
1544                 INNER JOIN epg_ch ON auto_timeline_keyword.chtxt = epg_ch.chtxt " 
1545                 , {Slice=>{}} );
1546
1547         foreach my $line ( @{ $ary_ref } ) {
1548                 my ( $begin, $end, $diff ) = &str2readable( $line->{btime}, $line->{etime} );
1549                 $line->{btime} =~ s/(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/$1$2$3$4$5$6/;
1550                 $line->{etime} =~ s/(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/$1$2$3$4$5$6/;
1551                 my $url = qq "rectool.pl?mode=confirm&amp;mode_sub=reserve&amp;chtxt=$line->{chtxt}&amp;start=$line->{btime}&amp;stop=$line->{etime}";
1552
1553                 $HTML .= qq {<tr align="center">\n};
1554                 $HTML .= qq {<td>$line->{id}</td>\n};
1555                 $HTML .= qq {<td>$line->{chname}</td>\n};
1556                 $HTML .= qq {<td>$line->{title}</td>\n};
1557                 $HTML .= qq {<td>$begin</td>\n};
1558                 $HTML .= qq {<td>$end</td>\n};
1559                 $HTML .= qq {<td>$diff</td>\n};
1560                 $HTML .= qq {<td><a href="$url">予約</a></td>\n};
1561                 $HTML .= qq {</tr>\n};
1562         }
1563
1564         $HTML .= qq {</table>\n};
1565
1566 }
1567
1568 ################ mode=recognize ################
1569
1570 if ( $mode eq 'recognize' ) {
1571         $HTML =~ s/%HTML_TITLE_OPT%/ - Recognizer/;
1572
1573         my $text  = $params{ 'text' };
1574         utf8::decode( $text );
1575         $chtxt = $params{ 'chtxt' };
1576         my $title = $params{ 'title' };
1577         utf8::decode( $title );
1578
1579         $HTML .= qq {<div>\n};
1580         $HTML .= qq {与えられた文字列のうち、番組の放送時刻と思われる文字列を認識します。<br>\n};
1581         $HTML .= qq {番組表が取得できない一週間以上先の予約ができます。<br>\n};
1582         $HTML .= qq {<form method="post" action="rectool.pl">\n};
1583         $HTML .= qq {<div>\n};
1584         &draw_form_channel( 'nonone' );
1585         $HTML .= qq {<input type="text" name="title" value="$title">\n};
1586         $HTML .= qq {<br>\n};
1587         $HTML .= qq {<input type="hidden" name="mode" value="recognize">\n};
1588         $HTML .= qq {<textarea name="text" cols=40 rows=4>\n$text</textarea>\n};
1589         $HTML .= qq {<input type="submit" value="実行">\n</div>\n</form>\n};
1590
1591         my $ch_list = join '|', grep /.+/, values %chtxt_0_chname;
1592         my %ch_reverse = reverse %chtxt_0_chname;
1593
1594         if ( $text ) {
1595                 my ( $year, $month, $day );
1596                 my ( $bhour, $bminute, $ehour, $eminute );
1597                 my $next_day = 0;
1598                 foreach ( split /\n/, $text ) {
1599                         my @bdate = /(\d{4}).(\d{1,2}).(\d{1,2})/;
1600                         s/(\d{4}).(\d{2}).(\d{2})//;
1601                         my @btime = /(\d{1,2})[::](\d{1,2})/;
1602                         s/(\d{1,2})[::](\d{2})//;
1603                         my @etime = /(\d{1,2})[::](\d{1,2})/;
1604                         s/(\d{1,2})[::](\d{2})//;
1605                         s/\(.*\)//;
1606                         if ( !@bdate ) {
1607                                 $bdate[0] = Time::Piece->localtime->year;
1608                                 ( $bdate[1], $bdate[2] ) = /(\d{1,2})月(\d{1,2})日/;
1609                                 s/(\d{1,2})月(\d{1,2})日//;
1610                         }
1611                         next if (!( @bdate || @btime ));
1612                         ( $year,  $month, $day ) = @bdate if ( $bdate[0] && $bdate[1] && $bdate[2] );
1613                         ( $bhour, $bminute )     = @btime if ( defined $btime[0] && defined $btime[1] );
1614                         ( $ehour, $eminute )     = @etime if ( defined $etime[0] && defined $etime[1] );
1615                         $next_day = 1 if ( /深夜/ );
1616                         my ( $ch ) = /($ch_list)/;
1617                         my $chtxt = $ch_reverse{$ch} if ( $ch && $ch_reverse{$ch} );
1618                         s/($ch_list)//;
1619
1620                         if ( $year && $month && $day && defined $bhour && defined $bminute ) {
1621                                 my $tp  = Time::Piece->strptime( "$year-$month-$day $bhour:$bminute", '%Y-%m-%d %H:%M' );
1622                                 my $etp = Time::Piece->strptime( "$year-$month-$day $ehour:$eminute", '%Y-%m-%d %H:%M' ) if ( defined $ehour && defined $eminute );
1623                                 $tp += ONE_DAY if ( $next_day );
1624                                 my $start = $tp->strftime( '%Y%m%d%H%M%S' );
1625                                 my $stop  = defined $etp ? 
1626                                         $etp->strftime( '%Y%m%d%H%M%S' ) :
1627                                         ( $tp + ONE_MINUTE * 30 )->strftime( '%Y%m%d%H%M%S' );
1628                                 $title = $_ if ( !$title );
1629                                 my $url = qq "rectool.pl?mode=confirm&amp;mode_sub=reserve&amp;chtxt=$chtxt&amp;start=$start&amp;stop=$stop&amp;title=$title";
1630                                 $HTML .= qq {認識結果:$year-$month-$day $bhour:$bminute -> $ehour:$eminute 残り:$_<a href="$url">リンク</a> <br>\n};
1631                         }
1632                 }
1633         }
1634 }
1635
1636 ################ mode=expert ################
1637
1638 if ( $mode eq 'expert' ) {
1639         require List::Compare;
1640
1641         my $ary_ref;
1642
1643         $HTML =~ s/%HTML_TITLE_OPT%/ - Expert/;
1644         $HTML .= qq {<div>\n};
1645
1646         if ( $mode_sub eq 'reget' ) {
1647                 my $bctype = $params{ 'bctype' };
1648                 my ( $chtxt, $chname ) = $dbh->selectrow_array( 
1649                         "SELECT chtxt, chname FROM epg_ch 
1650                         WHERE bctype = '$bctype' " );
1651                 $HTML .= "Update for $chname ( chtxt: $chtxt ) has been reserved.<br>\n";
1652                 $dbh->do( "UPDATE epg_ch SET status = '2' WHERE chtxt = '$chtxt' " );
1653                 goto end;
1654         }
1655
1656
1657         my @ary = $dbh->selectrow_array(
1658                 "SELECT auto_jbk, auto_bayes, auto_del_tmp, auto_opt 
1659                 FROM in_settings " );
1660         my $opt = pop @ary;
1661         @ary = map( $_ ? 'checked' : '', @ary );
1662
1663         $HTML .= qq {内部オプションの変更\n<br>};
1664         $HTML .= qq {<form method="get" action="rectool.pl">\n};
1665         $HTML .= qq {<div>\n};
1666         $HTML .= qq {<input type="hidden" name="mode"     value="change">\n};
1667         $HTML .= qq {<input type="hidden" name="mode_sub" value="setting">\n};
1668         $HTML .= qq {<input type="checkbox" name="jbk"     value="1" $ary[0]>自動地引\n};
1669         $HTML .= qq {<input type="checkbox" name="bayes"   value="1" $ary[1]>自動ベイズ\n};
1670         $HTML .= qq {<input type="checkbox" name="del_tmp" value="1" $ary[2]>自動一時ファイル削除\n};
1671         $HTML .= qq {自動オプション:<input type="text" name="opt" value="$opt">\n};
1672         $HTML .= qq {<input type="submit" value="保存">\n</div>\n</form>\n};
1673
1674
1675         $HTML .= qq {<hr>\n番組表のカテゴリ一覧と内蔵のカテゴリ一覧の合致を確認中...\n};
1676         $ary_ref = $dbh->selectcol_arrayref(
1677                 "SELECT DISTINCT category FROM epg_timeline"
1678         );
1679         my @category = sort values %category;
1680         if ( List::Compare->new( $ary_ref, \@category )->get_symdiff ) {
1681                 $HTML .= qq {一致しません<br>\n};
1682                 $HTML .= qq {番組表:@{$ary_ref}<br>\n内蔵:@category<br>\n};
1683         }
1684         else {
1685                 $HTML .= qq {一致しました<br>\n};
1686         }
1687
1688
1689         @ary = $dbh->selectrow_array( "SELECT terec, bscsrec, b252ts, ts2avi FROM in_status" );
1690         $HTML .= qq {<hr>\n地上波録画数:$ary[0]\n衛星波録画数:$ary[1]\n解読数:$ary[2]\n縁故数:$ary[3]\n<br>\n};
1691         $HTML .= qq {<form method="get" action="rectool.pl">\n};
1692         $HTML .= qq {<div>\n};
1693         $HTML .= qq {<input type="hidden" name="mode"     value="change">\n};
1694         $HTML .= qq {<input type="hidden" name="mode_sub" value="fixstatus">\n};
1695         $HTML .= qq {<input type="submit" name="terec"   value="地上波録画数をリセット">\n};
1696         $HTML .= qq {<input type="submit" name="bscsrec" value="衛星波録画数をリセット">\n};
1697         $HTML .= qq {<input type="submit" name="b252ts"  value="解読数をリセット">\n};
1698         $HTML .= qq {<input type="submit" name="ts2avi"  value="縁故数をリセット">\n</div>\n</form>\n};
1699
1700
1701         $HTML .= qq {<hr>\nRec10 バージョン:$rec10_version\nrectool バージョン:$rectool_version\n<br>\n};
1702
1703
1704         $HTML .= qq {<hr>\n番組表の欠落<br>\n};
1705         $ary_ref = $dbh->selectall_arrayref( "SELECT chname, chtxt FROM epg_ch" );
1706         foreach my $line ( @{$ary_ref} ) {
1707                 my $ary_ref = $dbh->selectall_arrayref( 
1708                         "SELECT start, stop, title FROM epg_timeline WHERE channel = '$line->[1]' ORDER BY start" 
1709                 );
1710                 my $error;
1711                 my @program_old = ( '', $ary_ref->[0]->[0] );
1712                 my $program_old = \@program_old;
1713
1714                 foreach my $program_new ( @{$ary_ref} ) {
1715                         if ( $program_old->[1] ne $program_new->[0] && 
1716                                 $program_old->[2] !~ /クロ?ジング|クロージング|エンディング|休止|ミッドナイト|ending/ && 
1717                                 $program_new->[2] !~ /オープニング|ウィークリー・インフォメーション|モーニング|opening/ && 
1718                                 ( str2datetime( $program_new->[0] ) - str2datetime( $program_old->[1] ) )->delta_minutes > 30 ) {
1719                                 $program_old->[1] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
1720                                 $program_new->[0] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
1721                                 $error .= qq{    $program_old->[2]    $program_old->[1]\n    ->  $program_new->[2]    $program_new->[0]\n};
1722                         }
1723                         $program_old = $program_new;
1724                 }
1725                 $HTML .= qq {<pre>\n$line->[0]\n$error</pre>\n} if ( $error );
1726                 }
1727
1728
1729         $ary_ref = $dbh->selectall_arrayref( 
1730                 "SELECT chname, chtxt, bctype, ch, csch, updatetime, status, visible 
1731                 FROM epg_ch 
1732                 ORDER BY bctype " );
1733         $HTML .= qq {<hr>\n番組表の更新状況<br>\n};
1734         $HTML .= qq {<table summary="channeltable" border=1 cellspacing=0>\n<tr>\n};
1735         $HTML .= qq {<th>チャンネル名</th>\n};
1736         $HTML .= qq {<th>chtxt</th>\n};
1737         $HTML .= qq {<th>bctype</th>\n};
1738         $HTML .= qq {<th>ch</th>\n};
1739         $HTML .= qq {<th>csch</th>\n};
1740         $HTML .= qq {<th>最終更新時刻</th>\n};
1741         $HTML .= qq {<th>状態</th>\n};
1742         $HTML .= qq {<th>表示</th>\n};
1743         $HTML .= qq {</tr>\n};
1744         foreach my $status ( @{$ary_ref} ) {
1745                 $HTML .= qq {<tr>\n};
1746                 $HTML .= qq {<td>$status->[0]</td>\n<td>$status->[1]</td>\n<td>$status->[2]</td>\n<td>$status->[3]</td>\n};
1747                 $HTML .= qq {<td>$status->[4]</td>\n<td>$status->[5]</td>\n<td>$status->[6]</td>\n<td>$status->[7]</td>\n};
1748                 $HTML .= qq {</tr>\n};
1749         }
1750         $HTML .= qq {</table>\n};
1751
1752         $HTML .= qq {<form method="get" action="rectool.pl">\n};
1753         $HTML .= qq {<div>\n};
1754         $HTML .= qq {番組表を再取得する\n};
1755         $HTML .= qq {<input type="hidden" name="mode" value="expert">\n};
1756         $HTML .= qq {<input type="hidden" name="mode_sub" value="reget">\n};
1757         $HTML .= qq {<select name="bctype">\n};
1758         $ary_ref = $dbh->selectall_arrayref(
1759                 "SELECT chname, bctype 
1760                 FROM epg_ch WHERE bctype NOT LIKE '_s%' "
1761         );
1762         foreach my $line ( @{$ary_ref} ) {
1763                 $HTML .= qq {<option value="$line->[1]">$line->[0]</option>\n};
1764         }
1765         $HTML .= qq {<option value="bs">BS</option>\n};
1766         $HTML .= qq {<option value="cs1">CS1</option>\n};
1767         $HTML .= qq {<option value="cs2">CS2</option>\n};
1768         $HTML .= qq {</select>\n};
1769         $HTML .= qq {<input type="submit" value="実行">\n</div>\n</form>\n};
1770
1771
1772
1773         $ary_ref = $dbh->selectall_arrayref(
1774                 "SELECT id, type, chtxt, title, btime, etime, opt, deltaday, deltatime 
1775                 FROM timeline 
1776                 ORDER BY id ");
1777         $HTML .= qq {<hr>\n予約表<br>\n};
1778         $HTML .= qq {<table summary="rectimetable" border=1 cellspacing=0>\n<tr>\n};
1779         $HTML .= qq {<th>ID</th>\n};
1780         $HTML .= qq {<th>type</th>\n};
1781         $HTML .= qq {<th>chtxt</th>\n};
1782         $HTML .= qq {<th>title</th>\n};
1783         $HTML .= qq {<th>btime</th>\n};
1784         $HTML .= qq {<th>etime</th>\n};
1785         $HTML .= qq {<th>opt</th>\n};
1786         $HTML .= qq {<th>deltaday</th>\n};
1787         $HTML .= qq {<th>deltatime</th>\n};
1788         $HTML .= qq {</tr>\n};
1789         foreach my $status ( @{$ary_ref} ) {
1790                 $HTML .= qq {<tr>\n};
1791                 $HTML .= qq {<td>$status->[0]</td>\n<td>$status->[1]</td>\n<td>$status->[2]</td>\n<td>$status->[3]</td>\n};
1792                 $HTML .= qq {<td>$status->[4]</td>\n<td>$status->[5]</td>\n<td>$status->[6]</td>\n<td>$status->[7]</td>\n};
1793                 $HTML .= qq {<td>$status->[8]</td>\n};
1794                 $HTML .= qq {</tr>\n};
1795         }
1796         $HTML .= qq {</table>\n};
1797 }
1798
1799 ################ mode=log ################
1800
1801 if ( $mode eq 'log' ) {
1802         $HTML =~ s/%HTML_TITLE_OPT%/ - Log/;
1803
1804         $HTML .= qq {<div>\n};
1805         $HTML .= qq {<table summary="reclogtable" border=1 cellspacing=0>\n<tr>\n};
1806         $HTML .= qq {<th>ID</th>\n};
1807         $HTML .= qq {<th>chtxt</th>\n};
1808         $HTML .= qq {<th>title</th>\n};
1809         $HTML .= qq {<th>btime</th>\n};
1810         $HTML .= qq {<th>etime</th>\n};
1811         $HTML .= qq {<th>opt</th>\n};
1812         $HTML .= qq {<th>exp</th>\n};
1813         $HTML .= qq {<th>longexp</th>\n};
1814         $HTML .= qq {<th>category</th>\n};
1815         $HTML .= qq {</tr>\n};
1816         $ary_ref = $dbh->selectall_arrayref(
1817                 "SELECT id, chtxt, title, btime, etime, opt, exp, longexp, category 
1818                 FROM in_timeline_log "
1819         );
1820         foreach my $line ( @{$ary_ref} ) {
1821                 $HTML .= qq {<tr>\n};
1822                 $HTML .= qq {<td>$line->[0]</td>\n<td>$line->[1]</td>\n<td>$line->[2]</td>\n<td>$line->[3]</td>\n};
1823                 $HTML .= qq {<td>$line->[4]</td>\n<td>$line->[5]</td>\n<td>$line->[6]</td>\n<td>$line->[7]</td>\n};
1824                 $HTML .= qq {<td>$line->[8]</td>\n};
1825                 $HTML .= qq {</tr>\n};
1826         }
1827         $HTML .= qq {</table>\n};
1828 }
1829
1830 ################ mode=help ################
1831
1832 if ( $mode eq 'help' ) {
1833         $HTML =~ s/%HTML_TITLE_OPT%/ - Help/;
1834         $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="300">|;
1835         $HTML .= qq {<div>\n};
1836         $HTML .= qq {ヘルプ\n};
1837 }
1838
1839 ################ mode=test ################
1840
1841 if ( $mode eq 'test' ) {
1842         $HTML =~ s/%HTML_TITLE_OPT%/ - Test/;
1843         $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="300">|;
1844         $HTML .= qq {<div>\n};
1845
1846         $tmp = read_file( 'config.ini' );
1847         $tmp =~ s/\n/<br>\n/gs;
1848         $HTML .= $tmp;
1849
1850         # $HTML .= Dumper( $ary_ref );
1851 }
1852
1853 ################ mode nasi ################
1854
1855 if ( !$mode ) {
1856         &draw_form();
1857         $HTML =~ s/%HTML_TITLE_OPT%/ - Top/;
1858         $HTML .= qq {Welcome to Rec10!<br>\n};
1859         goto end;
1860 }
1861
1862
1863 end:
1864 #<div style="float: right">
1865 $HTML .= <<EOM;
1866 </div>
1867 </body>
1868 </html>
1869 EOM
1870
1871 #<div align="center">
1872 #$HTML_ADV = $HTML_ADV_IMG . $HTML_ADV_TEXT if ( !$HTML_ADV );
1873 my $HTML_ADV = '';
1874 $HTML_HEADER = qq {<div style="text-align: center">\n$HTML_ADV\n</div>\n};
1875
1876 &draw_menu();
1877 $HTML =~ s/%HTML_TITLE_OPT%//;
1878 $HTML =~ s/%REFRESH%//;
1879 $HTML =~ s/%SCRIPT%//;
1880 $HTML =~ s/%CSS%//;
1881 $HTML =~ s/%HTML_HEADER%/$HTML_HEADER/;
1882
1883 utf8::encode( $HTML );
1884 print $HTTP_HEADER;
1885 print $HTML;
1886 exit;
1887
1888 sub draw_menu {
1889         $hires = Time::HiRes::time() - $hires;
1890         $last_modified = localtime((stat 'rectool.pl')[9]);
1891
1892         $HTML_HEADER .= qq {<div>\n};
1893         $HTML_HEADER .= qq {<span style="float: right; font-size: 8px">Last-Modified: $last_modified<br>Time-Elapsed: $hires 秒</span>\n};
1894         $HTML_HEADER .= qq {<span style="float: left">\n};
1895         $HTML_HEADER .= qq {<a href="rectool.pl">トップ(検索)</a>\n};
1896         $HTML_HEADER .= qq {<a href="rectool.pl?mode=schedule">予約確認</a>\n};
1897         $HTML_HEADER .= qq {<a href="rectool.pl?mode=graph">予約状況(画像版)</a>\n};
1898         $HTML_HEADER .= qq {<a href="rectool.pl?mode=list">録画一覧</a>\n};
1899         $HTML_HEADER .= qq {<a href="rectool.pl?mode=bravia">おまかせ</a>\n};
1900         $HTML_HEADER .= qq {<a href="rectool.pl?mode=expert">玄人仕様</a>\n};
1901         $HTML_HEADER .= qq {<a href="rectool.pl?mode=proc">復旧支援</a>\n};
1902         $HTML_HEADER .= qq {<a href="rectool.pl?mode=jbk">地引</a>\n};
1903         $HTML_HEADER .= qq {<a href="rectool.pl?mode=log">録画履歴</a>\n};
1904         $HTML_HEADER .= qq {<a href="rectool.pl?mode=recognize">文字認識</a>\n};
1905         $HTML_HEADER .= qq {<a href="rectool.pl?mode=edit">新規予約</a>\n};
1906 #       $HTML_HEADER .= qq {<a href="../rec10web/rec10web.py">新規予約</a>\n};
1907         $HTML_HEADER .= qq {</span>\n};
1908         $HTML_HEADER .= qq {<hr style="clear: both; background-color: grey; height: 4px">\n};
1909         $HTML_HEADER .= qq {</div>\n};
1910 }
1911
1912 sub draw_form {
1913         $chname = $params{ 'chname' };
1914         $chtxt  = $params{ 'chtxt' };
1915         $key    = $params{ 'key' };
1916         utf8::decode( $key );
1917         if ( $chname ) {
1918                 $chtxt = $dbh->selectrow_array("SELECT chtxt FROM epg_ch WHERE chname = '$chname' ");
1919         }
1920
1921         $HTML .= qq {<div style="float: left">\n};
1922         $HTML .= qq {<form method="get" action="rectool.pl">\n};
1923         $HTML .= qq {<div>\n};
1924         $HTML .= qq {<input type="hidden" name="mode" value="program">\n};
1925
1926         # チャンネル指定
1927         &draw_form_channel();
1928
1929         # 日付指定
1930         $HTML .= qq {<select name="date">\n<option value="" selected>無指定</option>\n};
1931         $ary_ref = $dbh->selectcol_arrayref(
1932                 "SELECT DISTINCT SUBSTRING(start, 1, 8) FROM epg_timeline ORDER BY start"
1933         );
1934         $date_sel = $params{ 'date' };
1935         foreach my $date ( @{ $ary_ref } ) {
1936                 my @date = $date =~ /(.{4})(.{2})(.{2})/;
1937                 $date_prt = "$date[1]/$date[2]";
1938
1939                 if ( $date eq $date_sel ) {
1940                         $HTML .= qq {<option value="$date" selected>$date_prt</option>\n};
1941                 }
1942                 else {
1943                         $HTML .= qq {<option value="$date">$date_prt</option>\n};
1944                 }
1945         }
1946         $HTML .= qq {</select>\n};
1947
1948         # カテゴリ指定
1949         $HTML .= qq {<select name="category">\n<option value="" selected>無指定</option>\n};
1950         $category_sel = $params{ 'category' };
1951         foreach my $category ( keys %category ) {
1952                 if ( $category eq $category_sel ) {
1953                         $HTML .= qq {<option value="$category" selected>$category{$category}</option>\n};
1954                 }
1955                 else {
1956                         $HTML .= qq {<option value="$category">$category{$category}</option>\n};
1957                 }
1958         }
1959         $HTML .= qq {</select>\n};
1960
1961         # キーワード指定
1962         $HTML .= qq {<input name="key" type="text" value="$key" style="width:200px" accesskey="s">\n};
1963
1964         # フォーム描画
1965         $HTML .= qq {<input type="submit" value="更新" accesskey="r">\n</div>\n</form>\n};
1966 }
1967
1968 sub draw_form_channel {
1969         $HTML .= qq {<select name="chtxt">\n};
1970         $HTML .= qq {<option value="" selected>無指定</option>\n} if ( shift ne 'nonone' );
1971
1972         foreach my $key ( keys %chtxt_0_chname ) {
1973                 my $value = $chtxt_0_chname{$key};
1974                 if ( ($chtxt && $key eq $chtxt ) || ( $chname && $value eq $chname ) ) {
1975                         $HTML .= qq {<option value="$key" selected>$value</option>\n};
1976                 }
1977                 else {
1978                         $HTML .= qq {<option value="$key">$value</option>\n};
1979                 }
1980         }
1981         $HTML .= qq {</select>\n};
1982 }
1983
1984 sub draw_form_opt {
1985         my $shift = shift;
1986         my ( %selected, %checked );
1987
1988         if ( $chtxt  =~ /BS_103/ ) {
1989                 $selected{F} = 'selected';
1990         }
1991         elsif ( $chtxt  =~ /CS_239|CS_240|CS_335/ ) {
1992                 $selected{H} = 'selected';
1993         }
1994         elsif ( $chtxt =~ /BS_101|BS_102/ || $bctype =~ /cs/ ) {
1995                 $selected{W} = 'selected';
1996         }
1997         elsif ( $bctype =~ /bs|te/ ) {
1998                 $selected{H} = 'selected';
1999         }
2000         $selected{g} = 'selected';
2001         $selected{s} = 'selected';
2002         $checked{a} = $chtxt =~ /CS_331|CS_332|CS_333|CS_334|CS_335/ || $category =~ /アニメ/ ? 'checked' : '';
2003         $checked{l} = '';
2004         $checked{d} = $title =~ /\Q[二]\E|[二]|\Q(二)\E|(二)/ ? 'checked' : '';
2005         $checked{5} = $title =~ /5\.1|5.1/ ? 'checked' : '';
2006         $checked{2} = 'checked';
2007
2008         if ( $opt ) {
2009                 undef %checked;
2010                 undef %selected;
2011                 my @opt = split //, $opt;
2012                 foreach my $opt ( @opt ) {
2013                         $selected{$opt} = 'selected' if ( $opt =~ /S|L|G|H|F/ );
2014                         $checked {$opt} = 'checked'  if ( $opt =~ /a|h|l|d|2|5/ );
2015                 }
2016                 $checked{d} = $title =~ /\Q[二]\E|[二]|\Q(二)\E|(二)/ ? 'checked' : '';
2017                 $checked{5} = $title =~ /5\.1|5.1/ ? 'checked' : '';
2018         }
2019         # 画質/圧縮率ともに指定されていない場合、真ん中をselectedにする
2020         $selected{g} = 'selected' unless ( $selected{u} || $selected{i} || $selected{o} || $selected{p} );
2021         $selected{s} = 'selected' unless ( $selected{q} || $selected{w} || $selected{e} || $selected{r} );
2022
2023         $HTML .= qq {<select name="opt">\n};
2024         #$HTML .= qq {<option value="S" $selected{S}>S 720x480</option>\n};
2025         $HTML .= qq {<option value="W" $selected{W}>W 854x480</option>\n};
2026         $HTML .= qq {<option value="H" $selected{H}>H 1280x720</option>\n};
2027         $HTML .= qq {<option value="F" $selected{F}>F 1920x1080</option>\n};
2028         $HTML .= qq {<option value="I" $selected{I}>I インタレ保持</option>\n};
2029         $HTML .= qq {</select>\n};
2030
2031         $HTML .= qq {<select name="opt">\n};
2032         $HTML .= qq {<option value="u" $selected{u}>最低</option>\n};
2033         $HTML .= qq {<option value="i" $selected{i}>低</option>\n};
2034         $HTML .= qq {<option value=""  $selected{g}>画質</option>\n};
2035         $HTML .= qq {<option value="o" $selected{o}>高</option>\n};
2036         $HTML .= qq {<option value="p" $selected{p}>最高</option>\n};
2037         $HTML .= qq {</select>\n};
2038
2039         $HTML .= qq {<select name="opt">\n};
2040         $HTML .= qq {<option value="q" $selected{q}>最低</option>\n};
2041         $HTML .= qq {<option value="w" $selected{w}>低</option>\n};
2042         $HTML .= qq {<option value=""  $selected{s}>圧縮率</option>\n};
2043         $HTML .= qq {<option value="e" $selected{e}>高</option>\n};
2044         $HTML .= qq {<option value="r" $selected{r}>最高</option>\n};
2045         $HTML .= qq {</select>\n};
2046
2047         $HTML .= qq {<select name="opt">\n};
2048         $HTML .= qq {<option value=""  $selected{s}>コンテナ</option>\n};
2049         $HTML .= qq {<option value="m" $selected{e}>MKV</option>\n};
2050         $HTML .= qq {<option value="4" $selected{r}>MP4</option>\n};
2051         $HTML .= qq {</select>\n};
2052
2053         $HTML .= qq {<select name="opt">\n};
2054         $HTML .= qq {<option value=""  $selected{s}>モバイル向け</option>\n};
2055         $HTML .= qq {<option value="1" $selected{e}>QVGA</option>\n};
2056         $HTML .= qq {<option value="2" $selected{r}>WVGA</option>\n};
2057         $HTML .= qq {</select>\n};
2058
2059         $HTML .= qq {<input type="checkbox" name="opt" value="a" $checked{a}>24fps(主にアニメ)\n};
2060         $HTML .= qq {<input type="checkbox" name="opt" value="d" $checked{d}>二ヶ国語放送\n};
2061         #$HTML .= qq {<input type="checkbox" name="opt" value="2" $checked{2}>2passモード\n};
2062         $HTML .= qq {<input type="checkbox" name="opt" value="5" $checked{5}>5.1ch放送\n};
2063         $HTML .= qq {<br>\n};
2064         $HTML .= qq {<select name="opt">\n};
2065         $HTML .= qq {<option value="">移動なし</option>\n};
2066         $HTML .= qq {<option value="R">録画後移動</option>\n};
2067         $HTML .= qq {<option value="D">解読後移動</option>\n};
2068         $HTML .= qq {<option value="E">縁故後移動</option>\n};
2069         $HTML .= qq {</select>\n};
2070         $HTML .= qq {<input type="checkbox" name="opt"   value="N">ファイル名日時追加\n} if ( $shift eq 'reserve' );
2071         $HTML .= qq {<input type="checkbox" name="every" value="1">隔週録画\n}           if ( $shift eq 'reserve' );
2072 }
2073
2074 sub parse_program {
2075         $chname  = $params{ 'chname' };
2076         $chtxt   = $params{ 'chtxt' };
2077         $start   = $params{ 'start' };
2078         $stop    = $params{ 'stop' };
2079         $bayesid = $params{ 'bayesid' };
2080         $id      = $params{ 'id' };
2081
2082         if ( $chname ) {
2083                 $chtxt = $dbh->selectrow_array("SELECT chtxt FROM epg_ch WHERE chname = '$chname'");
2084         }
2085         elsif ( $chtxt && $chtxt_0_chname{$chtxt} ) {
2086                 $chname = $chtxt_0_chname{$chtxt};
2087                 ( $chtxt_sql = $chtxt ) =~ s/_0/_%/;
2088                 $bctype = $dbh->selectrow_array("SELECT bctype FROM epg_ch WHERE chtxt LIKE '$chtxt_sql'");
2089         }
2090         elsif ( $chtxt ) {
2091                 $chname = $dbh->selectrow_array("SELECT chname FROM epg_ch WHERE chtxt = '$chtxt'")
2092         }
2093         ( $title, $desc, $longdesc, $category ) = $dbh->selectrow_array(
2094                 "SELECT title, exp, longexp, category
2095                 FROM epg_timeline 
2096                 WHERE channel = '$chtxt' AND start = '$start' AND stop = '$stop' ");
2097         if ( !$bctype ) {
2098                 $bctype = $dbh->selectrow_array("SELECT bctype FROM epg_ch WHERE chtxt = '$chtxt'");
2099         }
2100
2101         if ( $bayesid ) {
2102                 ( $chtxt, $title, $begin, $end ) = $dbh->selectrow_array( 
2103                         "SELECT chtxt, title, btime, etime FROM auto_timeline_bayes WHERE id = '$bayesid' " 
2104                 );
2105                 ( $chname, $bctype ) = $dbh->selectrow_array( 
2106                         "SELECT chname, bctype FROM epg_ch WHERE chtxt = '$chtxt' " 
2107                 );
2108                 $start = str2datetime( $begin )->strftime( '%Y%m%d%H%M%S' );
2109                 $stop  = str2datetime( $end   )->strftime( '%Y%m%d%H%M%S' );
2110                 ( $desc, $longdesc, $category ) = $dbh->selectrow_array( 
2111                         "SELECT exp, longexp, category FROM epg_timeline WHERE channel = '$chtxt' AND start = '$start' AND stop = '$stop' " 
2112                 );
2113         }
2114         if ( $id ) {
2115                 ( $type, $chtxt, $title, $begin, $end, $deltaday, $deltatime, $opt, $counter ) = $dbh->selectrow_array( 
2116                         "SELECT type, chtxt, title, btime, etime, deltaday, deltatime, opt, counter 
2117                         FROM timeline WHERE id = '$id' " 
2118                 );
2119                 ( $chname, $bctype ) = $dbh->selectrow_array( 
2120                         "SELECT chname, bctype FROM epg_ch WHERE chtxt = '$chtxt' " 
2121                 );
2122                 $start = str2datetime( $begin )->strftime( '%Y%m%d%H%M%S' );
2123                 $stop  = str2datetime( $end   )->strftime( '%Y%m%d%H%M%S' );
2124                 ( $desc, $longdesc, $category ) = $dbh->selectrow_array( 
2125                         "SELECT exp, longexp, category FROM epg_timeline WHERE channel = '$chtxt' AND start = '$start' AND stop = '$stop' " 
2126                 );
2127         }
2128         if ( $bctype =~ /bs|cs/ ) {
2129                 $bctype_sql = '_s%';
2130         }
2131         elsif ( $bctype =~ /te/ ) {
2132                 ( $chtxt_0   = $chtxt ) =~ s/(\d+)_.*/$1_0/;
2133                 ( $chtxt_sql = $chtxt ) =~ s/_0/_%/;
2134                 $bctype_sql = 'te%';
2135         }
2136         #( $chtxt_no0 ) = $chtxt   =~ /(\d+)_/;
2137         @start = $start =~ /(.{4})(.{2})(.{2})(.{2})(.{2})/;
2138         @stop  = $stop  =~ /(.{4})(.{2})(.{2})(.{2})(.{2})/;
2139         $begin = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', @start, '00' );
2140         $end   = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', @stop , '00' );
2141
2142         if ( $params{ 'title' } ) {
2143                 $title = $params{ 'title' };
2144                 utf8::decode( $title );
2145         }
2146         $HTML .= qq {<!-- chtxt=$chtxt chtxt_0=$chtxt_0 chtxt_sql=$chtxt_sql bctype=$bctype -->\n};
2147 }
2148
2149 sub check_error {
2150         my $is_error;
2151         my $is_same = $dbh->selectrow_array( 
2152                 "SELECT COUNT(*) FROM timeline WHERE chtxt = '$chtxt' AND btime = '$begin' AND etime = '$end'" 
2153         );
2154         my @overlap = &get_overlap();
2155
2156         if ( $is_same ) {
2157                 $HTML .= "同一の番組が既に存在します。<br>\n";
2158                 $is_error = 1;
2159         }
2160         elsif ( $overlap[0] >= 2 ) {
2161                 $HTML .= "時間が被る番組が既に2個存在します。<br>\n";
2162                 $HTML .= $overlap[1];
2163                 $is_error = 2;
2164         }
2165         else {
2166                 $is_error = 0;
2167         }
2168         return $is_error;
2169 }
2170
2171 sub get_overlap {
2172         require List::Util;
2173
2174         my $ary_ref = $dbh->selectall_arrayref(
2175                 "SELECT btime, etime, title
2176                 FROM timeline 
2177                 INNER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt 
2178                 WHERE bctype LIKE '$bctype_sql' AND type IN $type_user_made 
2179                 AND btime < '$end' 
2180                 AND etime > '$begin' 
2181                 "
2182         );
2183
2184         my %overlap;
2185         my $overlap = $max = 0;
2186         my $str;
2187         foreach my $prg ( @{ $ary_ref } ) {
2188                 $str .= "$prg->[0] ? $prg->[1] : $prg->[2]<br>\n";
2189                 $overlap{$prg->[0]} += 1;
2190                 $overlap{$prg->[1]} -= 1;
2191         }
2192         foreach my $key ( sort keys %overlap ) {
2193                 $overlap += $overlap{$key};
2194                 $max = List::Util::max( $max, $overlap );
2195         }
2196         if ( wantarray ) {
2197                 return ( $max, $str );
2198         }
2199         else {
2200                 return $max;
2201         }
2202 }
2203
2204 sub get_file_list_wrapper {
2205         local $base_dir = shift;
2206         local $ptr = shift;
2207
2208         &get_file_list( $base_dir );
2209 }
2210
2211 sub get_file_list{
2212         my $dir = shift;
2213
2214         opendir ( DIR, $dir );
2215         my @list = sort readdir( DIR );
2216         closedir( DIR );
2217
2218         foreach my $file ( @list ) {
2219                 next if ( $file =~ /^\.{1,2}$/ );
2220                 if ( -d "$dir/$file" ){
2221                         &get_file_list("$dir/$file");
2222                 }
2223                 else{
2224                         $abs = "$dir/$file";
2225                         utf8::decode( $abs );
2226                         ( $rel ) = $abs =~ /^$base_dir\/(.*)$/;
2227                         $ptr->( $rel, $abs );
2228                 }
2229         }
2230 }
2231
2232 sub strisjoined {
2233         my $str = shift;
2234
2235         return $str =~ /.{4}-.{2}-.{2} .{2}:.{2}:.{2}/ ? 0 : 1;
2236 }
2237
2238 sub str2datetime {
2239         my $str    = shift;
2240         my @time;
2241
2242         if ( strisjoined( $str ) ) {
2243                 @time = $str =~ /(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/;
2244         }
2245         else {
2246                 @time = $str =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/;
2247         }
2248         return DateTime->new(
2249                 year   => $time[0], month     => $time[1], day    => $time[2],
2250                 hour   => $time[3], minute    => $time[4], second => $time[5], 
2251                 locale => 'ja_JP' , time_zone => $tz
2252         );
2253 }
2254
2255 sub str2dayname {
2256         my  $str = shift;
2257         our %day_name_cache;
2258
2259         if ( !$day_name_cache{$str} ) {
2260                 $day_name_cache{$str} = str2datetime( $str )->day_name;
2261         }
2262         return $day_name_cache{$str};
2263 }
2264
2265 sub str2readable { 
2266         my $begin = shift;
2267         my $end   = shift;
2268
2269         my $dt_begin = ref( $begin ) eq 'DateTime' ? $begin : &str2datetime( $begin );
2270         my $dt_end   = ref( $end   ) eq 'DateTime' ? $end   : &str2datetime( $end );
2271
2272         my $str_begin = $dt_begin->strftime( '%m/%d(%a) %H:%M' );
2273         my $str_end   = $dt_end  ->strftime( $dt_begin->day == $dt_end->day ? '%H:%M' : '翌 %H:%M' );
2274         # utf8::encode( $str_begin );
2275
2276         my ( $sec, $min, $hour );
2277         $sec  = $dt_end->epoch - $dt_begin->epoch;
2278         $min  = int( $sec / 60 );
2279         $sec  = $sec - $min * 60;
2280         $hour = int( $min / 60 );
2281         $min  = $min - $hour * 60;
2282         my $str_diff = '';
2283         $str_diff .= $hour . '時間' if ( $hour );
2284         $str_diff .= $min  . '分'   if ( $min );
2285         $str_diff .= $sec  . '秒'   if ( $sec );
2286
2287         return ( $str_begin, $str_end, $str_diff );
2288 }
2289
2290 sub sqlgetsuggested {
2291         require Text::Ngram;
2292
2293         my ( $btime, $etime ) = @_;
2294         $deltatime = 3 if ( !$deltatime );
2295
2296         $btime_bgn = $btime->clone->subtract( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' );
2297         $btime_end = $btime->clone->add(      hours => $deltatime )->strftime( '%Y%m%d%H%M%S' );
2298         $etime_bgn = $etime->clone->subtract( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' );
2299         $etime_end = $etime->clone->add(      hours => $deltatime )->strftime( '%Y%m%d%H%M%S' );
2300
2301         $ary_ref = $dbh->selectall_arrayref(
2302                 "SELECT start, stop, title, exp 
2303                 FROM epg_timeline 
2304                 WHERE channel LIKE '$chtxt_sql' 
2305                 AND start BETWEEN '$btime_bgn' AND '$btime_end' 
2306                 AND stop  BETWEEN '$etime_bgn' AND '$etime_end' "
2307         );
2308         #die Dumper $ary_ref;
2309
2310         my %hash;
2311         my $hash_r = Text::Ngram::ngram_counts( $title, 2 ); # bi-gram
2312         foreach my $program ( @{$ary_ref} ) {
2313                 my $hash_k = Text::Ngram::ngram_counts( $program->[2], 2 );
2314                 my $point;
2315                 map $point += $hash_k->{$_}, keys %{$hash_r};
2316                 push @{$hash{$point}}, $program if ( $point );
2317         }
2318
2319         return %hash;
2320 }