OSDN Git Service

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