8 #Date_Init("TZ=JST","ConvTZ=JST");
11 use CGI::Carp qw( fatalsToBrowser );
21 #require SVG Time::Simple Encode Text::Ngram File::Find Data::Dumper Perl6::Slurp List::Util
23 %DB::packages = ( 'main' => 1 );
24 my $tz = DateTime::TimeZone->new( name => 'local' );
25 my $hires = Time::HiRes::time();
27 my $cfg = new Config::Simple;
28 if ( -e '/etc/rec10.conf' ) {
29 $cfg->read( '/etc/rec10.conf' );
32 $cfg->read( 'config.ini' );
35 my $sql = $cfg->param( 'db.db' );
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, {
47 $dbh->do( 'SET NAMES utf8' );
52 #print "Content-Type: text/html\n\n";
54 $HTTP_HEADER = "Content-Type: text/html\n\n";
56 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
59 <title>Rec10%HTML_TITLE_OPT%</title>
60 <meta http-equiv="Content-Script-Type" content="text/javascript">
61 <meta http-equiv="Content-Style-Type" content="text/css">
62 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
63 <link rev="made" href="Rea10">
64 <link rel="alternate" type="application/atom+xml" title= "Rec10 Atom Feed" href="./rectool.pl?mode=atom">
74 $q = new CGI::Minimal;
75 $mode = $q->param( 'mode' );
76 $mode_sub = $q->param( 'mode_sub' );
78 tie %type, 'Tie::IxHash';
80 'search_everyday' => '隔日検索',
81 'search_today' => '当日検索',
82 'reserve_flexible' => '浮動予約',
83 'reserve_fixed' => '確定予約',
85 'reserve_running' => '録画途中',
87 'convert_b25_ts' => '解読予約',
88 'convert_b25_ts_running' => '解読途中',
89 'convert_b25_ts_miss' => '解読失敗',
91 'convert_ts_mp4' => '縁故予約',
92 'convert_ts_mp4_running' => '縁故於鯖',
93 'convert_ts_mp4_network' => '縁故於網',
94 'convert_ts_mp4_finished' => '縁故完了',
96 'convert_avi_mkv' => '変換旧露',
97 'convert_avi_mp4' => '変換旧四',
98 'convert_mkv_mp4' => '変換露四',
99 'convert_mkv_mp4_runnings' => '換途露四',
101 'auto_suggest_dec' => '予測解読',
102 'auto_suggest_enc' => '予測縁故',
103 'auto_suggest_avi2fp' => '予測旧四',
104 'auto_suggest_ap2fp' => '予測露四',
106 'move_end' => '移動完了',
110 'auto_suggest_dec' => 'convert_b25_ts',
111 'auto_suggest_enc' => 'convert_ts_mp4',
112 'auto_suggest_avi2fp' => 'convert_avi_mkv',
113 'auto_suggest_ap2fp' => 'convert_mp4_mkv',
116 $type_user_made = "( 'search_everyday', 'search_today', 'reserve_flexible', 'reserve_fixed', 'reserve_running' )";
121 'variety' => 'バラエティ',
123 'information' => '情報',
130 if ( $mode eq 'schedule' ) {
132 $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Viewer/;
133 # $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="300">|;
135 <style type="text/css">
141 $css =~ s/^\t{2}//gm;
142 $HTML =~ s/%CSS%/$css/;
144 my $order = $q->param( 'order' );
145 my $extra = $q->param( 'extra' );
146 if ( $order ne 'id' ) {
149 $reverse_extra = $extra ? '' : '&extra=1';
150 $forward_order = $order eq 'btime' ? '' : '&order=id';
152 my $ary_ref = $dbh->selectall_arrayref(
153 "SELECT id, type, epg_ch.chtxt, epg_ch.ontv, epg_ch.chname, title, btime, etime, opt, deltaday, deltatime
155 INNER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt
158 $HTML .= qq {<div style="font-size: 10pt; float: left">\n};
159 $HTML .= qq {<form method="get" action="rectool.pl">\n};
160 $HTML .= qq {<div>\n};
161 $HTML .= qq {<input type="hidden" name="mode" value="change">\n};
162 $HTML .= qq {<table summary="rectimetable" border=1 cellspacing=0>\n<tr>\n};
163 $HTML .= qq {<th><a href="rectool.pl?mode=schedule$forward_order$reverse_extra">■</a></th>\n};
164 $HTML .= qq {<th><a href="rectool.pl?mode=schedule&order=id">ID</a></th>\n};
165 $HTML .= qq {<th>タイプ</th>\n};
166 $HTML .= qq {<th>チャンネル</th>\n};
167 $HTML .= qq {<th>タイトル</th>\n};
168 $HTML .= qq {<th><a href="rectool.pl?mode=schedule">開始時刻</a></th>\n};
169 $HTML .= qq {<th>終了時刻</th>\n};
170 $HTML .= qq {<th>録画時間</th>\n};
171 $HTML .= qq {<th>オプション</th>\n};
172 $HTML .= qq {<th>dd</th>\n};
173 $HTML .= qq {<th>dt</th>\n};
174 $HTML .= qq {</tr>\n};
175 foreach my $line ( @{ $ary_ref } ) {
177 $type = $type{$line->[1]} || $line->[1];
178 if ( $line->[1] =~ /^search/ ) {
179 $type = qq {<span style="color: #8B008B">$type</span>};
180 $line->[9] = qq {<span style="color: #FF0000">空</span>} if ( !$line->[9] && $line->[1] eq 'search_everyday' );
181 $line->[10] = qq {<span style="color: #FF0000">空</span>} if ( !$line->[10] );
183 elsif ( $line->[1] eq 'reserve_running' ) {
184 $type = qq {<span style="color: #FF8C00">$type</span>};
186 elsif ( $line->[1] =~ /^reserve/ ) {
187 $type = qq {<span style="color: #4169E1">$type</span>};
189 elsif ( $line->[1] eq 'convert_b25_ts' ) {
190 $type = qq {<span style="color: #BC8F8F">$type</span>};
192 elsif ( $line->[1] eq 'convert_b25_ts_running' ) {
193 $type = qq {<span style="color: #DC143C">$type</span>};
195 elsif ( $line->[1] eq 'convert_ts_mp4' ) {
196 $type = qq {<span style="color: #32CD32">$type</span>};
198 elsif ( $line->[1] eq 'convert_ts_mp4_running' ) {
199 $type = qq {<span style="color: #2E8B57">$type</span>};
202 $type = qq {<span style="color: #A0A0A0">$type</span>};
204 $chname_encoded = $q->url_encode( $line->[4] );
205 $line->[5] = 'タイトルなし' if ( !$line->[5] );
206 my $unix_6 = str2datetime( $line->[6] );
207 my $unix_7 = str2datetime( $line->[7] );
209 my $btime = $unix_6->strftime( '%Y%m%d%H%M%S' );
210 my $etime = $unix_7->strftime( '%Y%m%d%H%M%S' );
211 if ( $extra and $line->[1] =~ /^search_|^reserve_/ ) {
212 my @ary = $dbh->selectrow_array(
213 "SELECT title, exp FROM epg_timeline
214 WHERE channel = '$line->[3]'
216 AND stop = '$etime' ");
221 if ( $ary[0] ne $line->[5] ) {
222 my $count = $ary[0] =~ s/\Q$line->[5]\E//;
224 $ary[0] = qq {<span style="color: #FF4000">$ary[0]</span>};
232 $line->[11] = qq {<div style="float: right; cursor: help" title="$ary[1]">$ary[0]</div>};
235 $line->[11] = qq {<span style="float: right">説明なし</span>};
239 my $href = qq {<a href="rectool.pl?mode=edit&id=$line->[0]&suggest=auto">自動検索</a>};
240 $line->[11] = qq {<span style="float: right; color: #FF0000">!$href!</span>};
244 my $begin = $unix_6->strftime( '%m/%d(%a) %H:%M' );
245 utf8::encode( $begin );
247 if ( $unix_6->month == $unix_7->month && $unix_6->day == $unix_7->day )
249 $end = $unix_7->strftime( '%H:%M' );
252 $end = $unix_7->strftime( '翌 %H:%M' );
255 my ( $sec, $min, $hour );
256 $sec = $unix_7->epoch - $unix_6->epoch;
257 $min = int( $sec / 60 );
258 $sec = $sec - $min * 60;
259 $hour = int( $min / 60 );
260 $min = $min - $hour * 60;
262 $diff .= $hour . '時間' if ( $hour );
263 $diff .= $min . '分' if ( $min );
264 $diff .= $sec . '秒' if ( $sec );
268 $line->[1] eq 'reserve_running'
270 $unix_6->epoch <= time && time <= $unix_7->epoch
273 $percent = int( ( 100 * ( time - $unix_6->epoch ) ) / ( $unix_7->epoch - $unix_6->epoch ) );
274 $hr .= qq {<hr style="margin: 0 auto 0 0; height: 4px; width: $percent%;};
275 $hr .= qq { background-color: blue; border: none" title="$percent%">};
278 $line->[5] = qq {<div style="float: left">$line->[5]</div>} if ( $line->[11] );
279 $line->[5] = qq {<a href="rectool.pl?mode=edit&id=$line->[0]">$line->[5]</a>};
280 $HTML .= qq {<tr align="center">\n};
281 $HTML .= qq {<td><input type="checkbox" name="id" value="$line->[0]"></td>\n};
282 $HTML .= qq {<td>$line->[0]</td>\n};
283 $HTML .= qq {<td>$type</td>\n};
284 $HTML .= qq {<td><a href="rectool.pl?mode=program&chname=$chname_encoded">$line->[2]</a></td>\n};
285 $HTML .= qq {<td align="left" style="white-space: normal">$line->[5]$line->[11]</td>\n};
286 $HTML .= qq {<td>$begin</td>\n<td>$end</td>\n};
287 $HTML .= qq {<td>$hr$diff</td>\n};
288 $HTML .= qq {<td>$line->[8]</td>\n<td>$line->[9]</td>\n<td>$line->[10]</td>\n};
289 $HTML .= qq {</tr>\n};
291 $HTML .= qq {</table>\n};
292 $HTML .= qq {<input type="submit" name="edit" value="編集(要JS)">\n};
293 $HTML .= qq {<input type="submit" name="delete" value="削除">\n</div>\n</form>\n};
297 if ( $mode eq 'graph' ) {
299 $graph = $q->param( 'graph' );
303 print "Content-Type: image/svg+xml\n\n";
306 $graph = Date::Simple->new( split /-/, $graph );
307 $graph_bgn = $graph->format('%Y-%m-%d');
308 $graph_end = $graph->next->format('%Y-%m-%d');
310 $today = $graph eq Date::Simple->today() ? 1 : 0;
312 $tuner{terrestrial} = 2; #$cfg->param( 'env.te_max' );
313 $tuner{satellite} = 4; #$cfg->param( 'env.bscs_max' );
314 $tuner{all} = $tuner{terrestrial} + $tuner{satellite};
316 $width = 30 * $hours;
318 $svg = new SVG( width => 820, height => $tuner{all} * 20 + 40 );
319 $svg->rectangle( 'x' => 40, 'y' => 20,
320 width => $width + 20, height => $tuner{all} * 20 + 10,
322 style => { stroke => 'blue', fill => 'white' } );
323 for ( 1..$tuner{terrestrial} ) {
324 $svg->text( 'x' => 10, 'y' => ( $_ + 1 ) * 20 )
327 for ( 1..$tuner{satellite} ) {
328 $svg->text( 'x' => 10, 'y' => ( $_ + $tuner{terrestrial} + 1 ) * 20 )
332 $svg->text( 'x' => $_ * 30 + 65, 'y' => 15,
333 style => { 'text-anchor' => 'middle' } )
334 ->cdata( sprintf( '%02d', $_ ) ) if ( $_ < $hours );
335 # $svg->line( ); # can't use when required
336 $svg->tag( 'line', x1 => $_ * 30 + 50, x2 => $_ * 30 + 50, y1 => 30, y2 => $tuner{all} * 20 + 20,
337 style => { stroke => 'gray' } );
339 for ( 1..$tuner{all} ) {
340 $svg->rectangle( 'x' => 50, 'y' => $_ * 20 + 10, width => $width, height => 10 );
343 require Time::Simple;
344 my $time = Time::Simple->new();
345 my $x = ( $time->hours * 60 + $time->minutes ) * 0.5 + 50;
346 $svg->tag( 'line', x1 => $x, x2 => $x, y1 => 30, y2 => $tuner{all} * 20 + 20,
347 style => { stroke => 'red', 'fill-opacity' => '1.0' } );
349 foreach my $bctype ( 'te%', '_s%' ) {
350 my $tuner = $bctype eq 'te%' ? $tuner{terrestrial} : $tuner{satellite};
351 my $ary_ref = $dbh->selectall_arrayref(
352 "SELECT id, type, timeline.chtxt, title, btime, etime, opt FROM timeline
353 INNER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt
354 WHERE epg_ch.bctype LIKE '$bctype'
355 AND type IN $type_user_made
358 '$graph_bgn 00:00' <= btime AND btime < '$graph_end 00:00'
360 '$graph_bgn 00:00' < etime AND etime <= '$graph_end 00:00'
364 foreach my $line ( @{ $ary_ref } ) {
365 @start = $line->[4] =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2})/;
366 @stop = $line->[5] =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2})/;
367 $start = ( ( $day == $start[2] ? 0 : 24 * 60 ) + $start[3] * 60 + $start[4] ) * 0.5;
368 $stop = ( ( $day == $stop [2] ? 0 : 24 * 60 ) + $stop [3] * 60 + $stop [4] ) * 0.5;
369 $start = 0 if ( $start < 0 || $day > $start[2] ); # 月の変わり目はスルー
370 $stop = $width if ( $stop > $width );
374 my $ary = $dbh->selectall_arrayref(
375 "SELECT id, type, timeline.chtxt, title, btime, etime, opt FROM timeline
376 INNER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt
377 WHERE epg_ch.bctype LIKE '$bctype'
378 AND type IN $type_user_made
381 ( etime <= '$begin' )
388 for ( 0..$tuner - 1 ) {
392 $f = 0 if ( $line->[$_] ne $ary[$i]->[$_] );
398 my ( $r, $g, $b ) = ( 0, 0, 0 );
399 $r += 255 if ( $line->[6] =~ /a/ );
400 $g += 255 if ( $line->[6] =~ /H/ );
401 $b += 255 if ( $line->[6] =~ /2/ );
402 if ( $r + $g + $b == 255 * 3 ){
407 if ( $r + $g + $b == 0 ){
410 my %escaped = ( '&' => 'amp', '<' => 'lt', '>' => 'gt', '"' => 'quot' );
412 my $str = shift or return;
414 $result .= $escaped{$_} ? '&' . $escaped{$_} . ';' : $_
415 for (split //, $str);
419 -href => "rectool.pl?mode=edit&id=$line->[0]",
421 -title => html_escape( $line->[3] ),
424 'y' => 30 + ( $bctype eq 'te%' ? 0 : $tuner{terrestrial} * 20 ) + $slot * 20,
425 width => $stop - $start,
427 style => { fill => "rgb($r,$g,$b)" } );
435 $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Viewer - Graphical/;
436 $HTML .= qq {<div style="float: left">\n};
437 # $base64 = encode_base64( $svg->xmlify );
438 # $HTML .= qq {<object data="data:image/svg+xml;base64,$base64">\n</object>\n};
439 $HTML .= qq {予約状況一覧です。T1,T2は地上波、S1,S2はBS/CS、赤はアニメ、緑はHD、青は2 passを示しています。<br>\n};
440 $HTML .= qq {SVGが利用可能なブラウザでご覧ください。<br>\n};
442 $ary_ref = $dbh->selectcol_arrayref(
443 "SELECT DISTINCT DATE( btime )
445 WHERE type in $type_user_made
448 foreach my $date ( @{ $ary_ref } ) {
449 my @date = $date =~ /(.{4})-(.{2})-(.{2})/;
450 my $dn = DateTime->new( year => $date[0], month => $date[1], day => $date[2], locale => 'ja_JP' )->day_name;
452 $HTML .= qq {$date[1]/$date[2]($dn)の予約状況<br>\n};
453 $HTML .= qq {<object type="image/svg+xml" data="rectool.pl?mode=graph&graph=$date" width="820">\n};
454 $HTML .= qq {SVG Image $date\n</object>\n<br>\n};
456 $date2 = Date::Simple->new( @date )->next->format('%Y-%m-%d');
457 my $ary_ref = $dbh->selectall_arrayref(
458 "SELECT chtxt, title, btime, etime FROM timeline
459 WHERE '$date 00:00' <= btime AND etime <= '$date2 01:00'
463 foreach my $line ( @{ $ary_ref } ) {
464 # $HTML .= qq {$line->[0] $line->[1] $line->[2] $line->[3]<br>\n};
473 if ( $mode eq 'atom' ) {
474 require XML::Atom::Feed;
475 require XML::Atom::Entry;
477 my $recording_status;
478 my $ary_ref = $dbh->selectall_arrayref(
479 "SELECT chtxt, title, btime, etime, opt
481 WHERE type = 'reserve_running' ");
482 foreach my $line ( @{$ary_ref} ) {
483 my ( $begin, $end, $diff ) = &str2readable( $line->[2], $line->[3] );
484 $recording_status .= qq {$line->[0] $line->[1] $begin - $end $diff $line->[4]};
487 my $feed = XML::Atom::Feed->new;
488 $feed->title('Rec10 フィード');
490 my $entry = XML::Atom::Entry->new;
491 $entry->title('Rec10 録画状況');
492 $entry->id('tag:recording_status');
493 $entry->content($recording_status);
494 $feed->add_entry($entry);
496 $entry = XML::Atom::Entry->new;
497 $entry->title('Test');
498 $entry->id('testid');
499 $entry->content('TestData');
500 $feed->add_entry($entry);
502 my $xml = $feed->as_xml;
503 print "Content-Type: application/atom+xml\n\n";
508 if ( $mode eq 'edit' ) {
509 my $id = $q->param( 'id' );
511 $HTML =~ s/%HTML_TITLE_OPT%/ - Schedule Editor/;
512 $HTML .= qq {<div style="float: left">\n};
515 <script type="text/javascript" src="http://www.enjoyxstudy.com/javascript/dateformat/dateformat.js">
517 <script type="text/javascript">
518 function setType(value){
519 var index = document.reserve.type.selectedIndex;
520 var value = document.reserve.type[index].value;
521 if ( value == 'search_everyday' ) {
522 document.reserve.deltaday.value = 7;
523 document.reserve.deltatime.value = 3;
525 if ( value == 'convert_b25_ts' || value == 'convert_ts_mp4' ){
526 var date = new Date();
527 var dateFormat = new DateFormat("yyyy-MM-dd HH:mm:ss");
528 var minutes = date.getMinutes();
529 minutes = minutes - minutes % 5 + 10;
530 date.setMinutes(minutes, 0, 0);
531 document.reserve.begin.value = dateFormat.format(date);
532 date.setSeconds( date.getSeconds() + 3600 );
533 document.reserve.end.value = dateFormat.format(date);
536 function setSuggest(start, stop){
537 document.reserve.begin.value = start;
538 document.reserve.end.value = stop;
540 function shiftEndTime(value){
541 var dateFormat = new DateFormat("yyyy-MM-dd HH:mm:ss");
542 var date = dateFormat.parse(document.reserve.end.value || document.reserve.begin.value);
543 date.setSeconds( date.getSeconds() + value );
544 document.reserve.end.value = dateFormat.format(date);
548 $script =~ s/^\t{2}//gm;
549 $HTML =~ s/%SCRIPT%/$script/;
551 $HTML .= "スケジュール編集画面です。<br>\n";
552 $HTML .= "実装がとても適当なので、利用には細心の注意を払ってください。<br>\n<br>\n";
555 $button_bgn = $button_end = '';
558 $type = 'reserve_flexible';
559 $datetime_now = DateTime->now( time_zone => $tz )->set_second( 0 )->add( minutes => 1)->strftime( '%Y-%m-%d %H:%M:%S' );
560 $button_bgn = qq{<button type="button" onClick="document.reserve.begin.value='$datetime_now'">現在</button>\n<br>\n};
562 qq{<button type="button" onClick="document.reserve.end.value=document.reserve.begin.value">一致</button>}
563 .qq{<button type="button" onClick="shiftEndTime(300);">+5m</button>}
564 .qq{<button type="button" onClick="shiftEndTime(1800);">+30m</button>};
567 if ( $q->param( 'suggest' ) eq 'auto' ) {
568 my @btime = $begin =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/;
569 my @etime = $end =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/;
570 my $btime = DateTime->new(
571 year => $btime[0], month => $btime[1], day => $btime[2],
572 hour => $btime[3], minute => $btime[4], second => $btime[5],
574 my $etime = DateTime->new(
575 year => $etime[0], month => $etime[1], day => $etime[2],
576 hour => $etime[3], minute => $etime[4], second => $etime[5],
578 my %hash = &sqlgetsuggested( $btime, $etime );
580 $HTML .= qq {可能性のある番組<br>\n};
581 $HTML .= qq {<table summary="suggesttable" border=1 cellspacing=0>\n<tr>\n};
582 $HTML .= qq {<th>優先度</th>\n};
583 $HTML .= qq {<th>タイトル</th>\n};
584 $HTML .= qq {<th>開始時刻</th>\n};
585 $HTML .= qq {<th>終了時刻</th>\n};
586 $HTML .= qq {<th>説明</th>\n};
587 $HTML .= qq {<th>適用</th>\n};
588 $HTML .= qq {</tr>\n};
590 foreach my $key (sort keys %hash){
591 my $val = $hash{$key};
592 foreach my $val ( @{$val} ) {
593 my $style = qq {style="white-space: nowrap"};
594 $val->[0] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
595 $val->[1] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
596 $HTML .= qq {<tr>\n<td>$key</td>\n<td>$val->[2]</td>\n};
597 $HTML .= qq {<td $style>$val->[0]</td>\n<td $style>$val->[1]</td>\n<td>$val->[3]</td>\n};
598 $HTML .= qq {<td><button onClick="setSuggest('$val->[0]','$val->[1]');">適用</button></td>\n</tr>\n};
601 $HTML .= qq {</table>\n<br>\n};
604 my $len = length $id;
605 $HTML .= qq {<form method="get" action="rectool.pl" name="reserve">\n};
606 $HTML .= qq {<input type="hidden" name="mode" value="change">\n};
607 $HTML .= qq {<input type="hidden" name="mode_sub" value="update">\n};
608 $HTML .= qq {<input type="hidden" name="id" value="$id">\n};
609 $HTML .= qq {ID\n<input type="text" name="id" value="$id" size=$len disabled>\n};
610 $HTML .= qq {タイプ\n<select name="type" onChange="setType();">\n};
611 foreach my $key ( keys %type ) {
612 next if ( $key !~ /^search|^reserve|^convert_b25_ts$|^convert_ts_mp4$|^$type$/ );
613 $value = $type{$key};
614 if ( $key eq $type ) {
615 $HTML .= qq {<option value="$key" selected>$value</option>\n};
618 $HTML .= qq {<option value="$key">$value</option>\n};
621 $HTML .= qq {</select>\n};
622 $HTML .= qq {チャンネル\n<select name="chtxt">\n};
623 $ary_ref = $dbh->selectall_arrayref(
624 "SELECT chname, chtxt FROM epg_ch"
626 foreach my $line ( @{$ary_ref} ) {
627 if ( $line->[1] eq $chtxt ) {
628 $HTML .= qq {<option value="$line->[1]" selected>$line->[0]</option>\n};
631 $HTML .= qq {<option value="$line->[1]">$line->[0]</option>\n};
634 $HTML .= qq {</select><br>\n};
635 $HTML .= qq {タイトル\n<input type="text" name="title" value="$title" size=64><br>\n};
636 $HTML .= qq {開始時刻\n<input type="text" name="begin" value="$begin" maxlength=19 size=24>\n};
637 $HTML .= $button_bgn;
638 $HTML .= qq {終了時刻\n<input type="text" name="end" value="$end" maxlength=19 size=24>\n};
639 $HTML .= $button_end . "<br>\n";
640 $HTML .= qq {隔日周期\n<input type="text" name="deltaday" value="$deltaday" maxlength=2 size=2 >\n};
641 $HTML .= qq {時刻誤差\n<input type="text" name="deltatime" value="$deltatime" maxlength=2 size=2 >\n};
642 $HTML .= qq {オプション\n<input type="text" name="opt" value="$opt">\n};
643 $HTML .= qq {<input type="submit" name="update" value="更新">\n</form>\n};
646 if ( $mode eq 'change' ) {
647 @id = $q->param( 'id' );
649 $HTML =~ s/%HTML_TITLE_OPT%/ - Change/;
650 $HTML .= qq {<div style="float: left">\n};
652 if ( $q->param( 'delete' ) )
655 foreach my $id ( @id ) {
656 $dbh->do( "DELETE FROM timeline WHERE id = '$id'" );
658 $HTML .= "削除しました。<br>\n5秒後に予約確認画面に移動します。<br>\n";
659 $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="5; url=rectool.pl?mode=schedule">|;
663 if ( $q->param( 'update' ) )
665 $type = $q->param( 'type' );
666 $chtxt = $q->param( 'chtxt' );
667 $title = $q->param( 'title' );
668 $begin = $q->param( 'begin' );
669 $end = $q->param( 'end' );
670 $deltaday = $q->param( 'deltaday' );
671 $deltatime = $q->param( 'deltatime' );
672 $opt = $q->param( 'opt' );
676 "UPDATE timeline SET type = '$type', chtxt = '$chtxt', title = '$title',
677 btime = '$begin', etime = '$end',
678 deltaday = '$deltaday', deltatime = '$deltatime', opt = '$opt'
684 "INSERT INTO timeline ( type, chtxt, title, btime, etime, deltaday, deltatime, opt )
685 VALUES ( '$type', '$chtxt', '$title', '$begin', '$end', '$deltaday', '$deltatime', '$opt' )"
688 $HTML .= "更新しました。<br>\n5秒後に予約確認画面に移動します。<br>\n";
689 $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="5; url=rectool.pl?mode=schedule">|;
692 if ( $mode_sub eq 'proc' ) {
693 my $type = $q->param( 'type' );
694 my $chtxt = $q->param( 'chtxt' ) || 'nhk-k';
695 my $title = $q->param( 'title' );
696 my @opt = $q->param( 'opt' );
697 my $opt = join '', @opt;
699 my $datetime_now = DateTime->now( time_zone => $tz )->set_second( 0 )->add( minutes => 10);
700 my $sql_type = $type_suggest{$type};
701 my $begin = $datetime_now->strftime( '%Y-%m-%d %H:%M:%S' );
702 $datetime_now = $datetime_now->add( minutes => 60 );
703 my $end = $datetime_now->strftime( '%Y-%m-%d %H:%M:%S' );
706 "INSERT INTO timeline ( type, chtxt, title, btime, etime, opt )
707 VALUES ( '$sql_type', '$chtxt', '$title', '$begin', '$end', '$opt' )"
712 if ( $mode_sub eq 'move' ) {
713 my $mode_sub2 = $q->param( 'mode_sub2' );
714 my $title = $q->param( 'title' );
718 $ENV{'LANG'} = 'ja_JP.UTF-8';
719 if ( $mode_sub2 eq 'predict' ) {
720 eval '$HTML .= `python26 ' . $cfg->param( 'path.rec10' ) . "classify.py -s '$title'`";
722 elsif ( $mode_sub2 eq 'exec' ) {
723 eval '$HTML .= `python26 ' . $cfg->param( 'path.rec10' ) . "classify.py -e '$title'`";
731 if ( $mode eq 'confirm' ) {
732 if ( $mode_sub eq 'reserve' ) {
733 $HTML =~ s/%HTML_TITLE_OPT%/ - Reserver/;
734 $HTML .= qq {<div style="float: left">\n};
737 my $duration = ( str2datetime( $end ) - str2datetime( $begin ) )->delta_minutes;
738 $HTML .= "番組名:$title<br>\nチャンネル:$chname<br>\n放送継続時間:$duration分<br>\n番組内容:$desc<br>\n";
740 $longdesc =~ s/\\n/<br>\n/gs;
741 $HTML .= "番組内容(長):$longdesc<br>\n";
743 my $error = &check_error();
748 $ary_ref = $dbh->selectall_arrayref(
749 "SELECT start, stop FROM epg_timeline WHERE channel = '$ontv' AND title = '$title' "
752 $HTML .= "同一の番組の他の放送予定です。<br>\n";
753 foreach my $line ( @{$ary_ref} ) {
756 $begin =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
757 $end =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
758 $overlap = &get_overlap() >= 2 ? '不可能' :
759 qq {<a href="rectool.pl?mode=confirm&mode_sub=reserve&chname=$chname&start=$line->[0]&stop=$line->[1]">可能</a>};
760 $HTML .= "開始:$begin\n終了:$end\n録画は$overlap<br>\n";
765 if ( $chtxt =~ /\Qbs-nhk-hi\E/ ) {
766 $selected_f = 'selected';
768 elsif ( $chtxt =~ /movieplus/ ) {
769 $selected_h = 'selected';
772 $selected_g = 'selected';
774 $checked_v = $chtxt =~ /animax|atx|disney|kids/ || $category =~ /アニメ/ ? 'checked' : '';
775 $checked_d = $title =~ /\Q[二]\E|[二]|\Q(二)\E|(二)/ ? 'checked' : '';
776 $checked_5 = $title =~ /5\.1|5.1/ ? 'checked' : '';
777 $checked_2 = 'checked';
779 $HTML .= "録画予約の詳細設定を行ってください。<br>\n";
780 $HTML .= qq {<form method="get" action="rectool.pl">\n};
781 $HTML .= qq {<input type="hidden" name="mode" value="reserve">\n};
782 $HTML .= qq {<input type="hidden" name="chname" value="$chname">\n};
783 $HTML .= qq {<input type="hidden" name="start" value="$start">\n};
784 $HTML .= qq {<input type="hidden" name="stop" value="$stop">\n};
785 $HTML .= qq {<select name="opt">\n};
786 $HTML .= qq {<option value="L" $selected_l>L ***x*** 1250kbps</option>\n};
787 $HTML .= qq {<option value="G" $selected_g>G 1280x720 2500kbps</option>\n};
788 $HTML .= qq {<option value="H" $selected_h>H 1280x720 3750kbps</option>\n};
789 $HTML .= qq {<option value="F" $selected_f>F 1920x1080 5000kbps</option>\n};
790 $HTML .= qq {<option value="S">S 720x480 1250kbps</option>\n};
791 $HTML .= qq {</select>\n};
792 $HTML .= qq {<input type="checkbox" name="opt" value="v" $checked_v>可変フレームレート\n};
793 $HTML .= qq {<input type="checkbox" name="opt" value="d" $checked_d>二ヶ国語放送\n};
794 $HTML .= qq {<input type="checkbox" name="opt" value="2" $checked_2>2passモード\n};
795 $HTML .= qq {<input type="checkbox" name="opt" value="5" $checked_5>5.1ch放送\n};
796 $HTML .= qq {<br>\n};
797 $HTML .= qq {<select name="opt">\n};
798 $HTML .= qq {<option value="">移動なし</option>\n};
799 $HTML .= qq {<option value="R">録画後移動</option>\n};
800 $HTML .= qq {<option value="D">解読後移動</option>\n};
801 $HTML .= qq {<option value="E">縁故後移動</option>\n};
802 $HTML .= qq {</select>\n};
803 $HTML .= qq {<input type="checkbox" name="opt" value="N">ファイル名日時追加\n};
804 $HTML .= qq {<input type="checkbox" name="every" value="1">隔週録画\n};
805 $HTML .= qq {<input type="submit" value="予約">\n</form>\n};
809 # End of $mode_sub eq 'reserve';
811 if ( $mode_sub eq 'proc' ) {
812 my $type = $q->param( 'type' );
813 my $chtxt = $q->param( 'chtxt' );
814 my $title = $q->param( 'title' );
816 $HTML .= "詳細設定を行ってください。<br>\n";
817 $HTML .= "タイトル:$title\n<br>\n";
819 $HTML .= qq {<form method="get" action="rectool.pl">\n};
820 $HTML .= qq {<input type="hidden" name="mode" value="change">\n};
821 $HTML .= qq {<input type="hidden" name="mode_sub" value="proc">\n};
822 $HTML .= qq {<input type="hidden" name="type" value="$type">\n};
823 $HTML .= qq {<input type="hidden" name="title" value="$title">\n};
824 $HTML .= qq {<select name="chtxt">\n};
825 $ary_ref = $dbh->selectall_arrayref(
826 "SELECT chname, chtxt FROM epg_ch"
828 foreach my $line ( @{$ary_ref} ) {
829 if ( $line->[1] eq $chtxt ) {
830 $HTML .= qq {<option value="$line->[1]" selected>$line->[0]</option>\n};
833 $HTML .= qq {<option value="$line->[1]">$line->[0]</option>\n};
836 $HTML .= qq {</select>\n};
838 $HTML .= qq {<select name="opt">\n};
839 $HTML .= qq {<option value="L" $selected_l>L ***x*** 1250kbps</option>\n};
840 $HTML .= qq {<option value="G" $selected_g>G 1280x720 2500kbps</option>\n};
841 $HTML .= qq {<option value="H" $selected_h>H 1280x720 3750kbps</option>\n};
842 $HTML .= qq {<option value="F" $selected_f>F 1920x1080 5000kbps</option>\n};
843 $HTML .= qq {<option value="S">S 720x480 1250kbps</option>\n};
844 $HTML .= qq {</select>\n};
845 $HTML .= qq {<input type="checkbox" name="opt" value="a" $checked_a>アニメ\n};
846 $HTML .= qq {<input type="checkbox" name="opt" value="d" $checked_d>二ヶ国語放送\n};
847 $HTML .= qq {<input type="checkbox" name="opt" value="2" $checked_2>2passモード\n};
848 $HTML .= qq {<input type="checkbox" name="opt" value="5" $checked_5>5.1ch放送\n};
849 $HTML .= qq {<input type="submit" value="予約">\n</form>\n};
854 if ( $mode eq 'reserve' ) {
855 $HTML .= qq {<div style="float: left">\n};
857 @opt = $q->param( 'opt' );
858 $opt = join '', @opt;
859 my ( $deltaday, $deltatime );
861 if ( $q->param('every') eq '1' ) {
862 $type = 'search_everyday';
863 ( $changed_t ) = $title =~ /(.*) #/;
864 $title = $changed_t if ( $changed_t );
865 ( $changed_t ) = $title =~ /(.*) 第/;
866 $title = $changed_t if ( $changed_t );
874 $type = 'reserve_flexible';
876 if ( !&check_error ) {
878 "INSERT INTO timeline ( type, chtxt, title, btime, etime, opt, deltaday, deltatime )
879 VALUES ( '$type', '$chtxt', '$title', '$begin', '$end', '$opt', '$deltaday', '$deltatime' )"
882 $HTML .= "録画予約を実行しました。<br>\n5秒後にトップへ移動します。<br>\n";
883 $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="5; url=rectool.pl">|;
887 if ( $mode eq 'program' ) {
890 $HTML =~ s/%HTML_TITLE_OPT%/ - Program Viewer/;
891 $unix = DateTime->now( time_zone => $tz )->strftime( '%Y%m%d%H%M%S' );
893 "SELECT channel, chname, start, stop, title, category
895 INNER JOIN epg_ch ON epg_timeline.channel = epg_ch.ontv
896 WHERE $unix <= stop %CH% %DATE% %CATEGORY% %KEY% ORDER BY start";
899 my $ch = "AND channel = '$ontv'";
903 $date_1 = $date_sel . '000000';
904 $date_2 = Date::Simple->new( $date_sel =~ /(.{4})(.{2})(.{2})/ )->next->format('%Y%m%d') . '000000';
905 my $date = "AND '$date_1' <= stop AND start <= '$date_2'";
906 $sql =~ s/%DATE%/$date/;
908 if ( $category_sel ) {
910 # $category_tmp = $category{$category_sel} . $category_sel;
911 my $category = "AND category = '$category{$category_sel}'";
912 $sql =~ s/%CATEGORY%/$category/;
915 my $key = "AND TITLE LIKE '%$key%'";
916 $sql =~ s/%KEY%/$key/;
921 $sql =~ s/%CATEGORY%//;
923 $ary_ref = $dbh->selectall_arrayref( $sql );
924 foreach my $prg ( @{ $ary_ref } ) {
925 my @date = $prg->[2] =~ /(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/;
928 if ( $date != $prev ) {
929 my $date = DateTime->new(
930 year => $date[0], month => $date[1], day => $date[2],
934 my $dn = $date->day_name;
936 $HTML .= qq {--------$date[1]/$date[2]($dn)--------<br>\n};
938 $prg->[5] = $q->url_encode( $prg->[1] );
939 $HTML .= qq {$date[1]/$date[2] $date[3]:$date[4] };
940 $HTML .= qq {$prg->[1] } if ( !$ontv );
941 $HTML .= qq {<a href="rectool.pl?mode=confirm&mode_sub=reserve&chname=$prg->[5]&start=$prg->[2]&stop=$prg->[3]">$prg->[4]</a><br>\n};
947 if ( $mode eq 'list' ) {
950 $HTML =~ s/%HTML_TITLE_OPT%/ - List/;
952 my $recording = $cfg->param( 'path.recpath' );
953 my $recorded = $cfg->param( 'path.recorded' );
956 $HTML .= qq {<a href="rectool.pl?mode=list&mode_sub=new">録画中のみ</a>\n};
957 $HTML .= qq {<a href="rectool.pl?mode=list&mode_sub=old">録画後のみ</a>\n<br>\n};
959 if ( !$mode_sub || $mode_sub eq 'new' ) {
960 $HTML .= "録画中のファイル一覧<br>\n";
966 if ( !$mode_sub || $mode_sub eq 'old' ) {
967 $HTML .= "録画後のファイル一覧<br>\n";
968 &simple_list( $recorded );
974 my @exp = ( 'log', 'ts.b25', 'ts.tsmix', 'ts', 'ts.log.mbtree', 'ts.log',
975 'sa.avi', 'sa.avi.log', '120.avi', 'aac', 'timecode.txt', 'm2v', 'wav', 'avi', 'mkv', 'mp4' );
979 my $exp_count = scalar keys %exp;
981 my %opt = ( follow => 1, wanted => \&wanted, );
982 File::Find::find( \%opt, $path );
984 foreach my $name ( sort { $exp{$a} <=> $exp{$b} } keys %exp ) {
985 $HTML .= $exp{$name} + 1 . " = $name / ";
987 $HTML .= $exp_count+1 . qq { = サムネイル<br>\n○ = 完了 / ● = 書き込み中 / ◆ = ファイルサイズ異常<br>\n};
988 $HTML .= qq {<table summary="listtable" border=1 cellspacing=0>\n<tr>\n};
989 $HTML .= qq {<th>タイトル</th>\n};
990 $HTML .= qq {<th>$_</th>\n} for ( 1..$exp_count + 1 );
991 $HTML .= qq {<th colspan="2">自動移動</th>\n};
992 $HTML .= qq {</tr>\n};
994 foreach ( sort keys %list ) {
995 my $value = $list{$_};
996 my @flag = ( 0 ) x $exp_count;
997 $HTML .= qq {<tr>\n<td width="600" style="width: 600px; white-space: normal">$_</td>\n};
998 foreach ( keys %{$value} ) {
1000 $flag[$exp{$tmp}] = $value->{$_};
1003 my $size = $_->{size};
1004 my $last = $_->{last} || ( $_->{size} eq '0 B' ? '◆' : '○' );
1005 my $check = $size ? qq {<span title="$size">$last</span>} : '<br>';
1006 $HTML .= qq {<td>$check</td>\n};
1008 if ( $flag[$exp{mp4}] ) {
1011 my $img = $value->{mp4}->{img};
1012 $HTML .= qq {<td><a href="rectool.pl?mode=thumb&title=$img">■</a></td>\n};
1013 my $pre = qq {<a href="rectool.pl?mode=change&mode_sub=move&mode_sub2=predict&title=$_">予測</a>};
1014 $HTML .= qq {<td>$pre</td>\n};
1015 my $exe = qq {<a href="rectool.pl?mode=change&mode_sub=move&mode_sub2=exec&title=$_">実行</a>};
1016 $HTML .= qq {<td>$exe</td>\n};
1019 $HTML .= qq {<td><br></td>\n<td colspan="2"><br></td>\n};
1021 $HTML .= qq {</tr>\n};
1023 $HTML .= qq {</table>\n};
1027 return if ( -d $File::Find::name );
1028 return if ( $_ eq 'Thumbs.db' );
1029 return if ( /\.idx/ );
1031 my $regexp = join '|', keys %exp;
1032 my ( $title, $exp ) = /(.*?)\.($regexp)$/;
1033 my ( $size, $last ) = &get_size( $File::Find::name );
1035 $File::Find::name =~ s/\.temp$//;
1037 $title = '_error_exp_'.$_;
1040 if ( $title !~ /[^0-9A-F]+/ ) {
1041 my $tmp = pack( 'H*', $title );
1043 $title = '_error_b16_'.$_;
1047 $title = 'Base16_'.$tmp;
1050 if ( $_ =~ /mp4/ ) {
1056 $list{$title}->{$exp} = { 'last' => $last, 'size' => $size, 'img' => $img };
1061 local $path = shift;
1064 File::Find::find( \&simple_wanted, $path );
1068 $HTML .= "$_<br>\n";
1073 return if ( -d $File::Find::name );
1074 return if ( $_ eq 'Thumbs.db' );
1075 my ( $size ) = &get_size( $File::Find::name );
1076 $File::Find::name =~ s/\Q$path\E//;
1077 push @list, $File::Find::name ."\t\t". $size;
1083 my ( $size, $last ) = (stat( $file ))[7,9];
1084 my @unim = ("B","KB","MB","GB","TB","PB");
1087 while($size >= 1024 ){
1089 $size = $size / 1024;
1092 $size = int( $size );
1094 if ( time - $last < 10 ) {
1100 return ( "$size $unim[$count]", $last );
1104 if ( $mode eq 'thumb' ) {
1105 my $title = $q->param( 'title' );
1106 my $pos = $q->param( 'pos' );
1107 my $recording = $cfg->param( 'path.recpath' );
1111 print "Content-Type: image/jpeg\n\n";
1112 exec "ffmpeg -ss 300 -i '$recording/$title.mp4' -f image2 -pix_fmt jpg -vframes 1 -s 320x240 -";
1116 if ( $mode eq 'check' ) {
1119 if ( $mode eq 'bravia' ) {
1120 $HTML =~ s/%HTML_TITLE_OPT%/ - Bravia/;
1121 $HTML .= qq {<div>\n};
1122 $HTML .= qq {<form method="get" action="rectool.pl">\n};
1123 $HTML .= qq {<div>\n};
1124 $HTML .= qq {<table summary="bayestable" border=1 cellspacing=0>\n<tr>\n};
1125 $HTML .= qq {<th>ID</th>\n};
1126 $HTML .= qq {<th>チャンネル</th>\n};
1127 $HTML .= qq {<th>タイトル</th>\n};
1128 $HTML .= qq {<th><a href="rectool.pl?mode=bravia">開始時刻</a></th>\n};
1129 $HTML .= qq {<th>終了時刻</th>\n};
1130 $HTML .= qq {<th>録画時間</th>\n};
1131 $HTML .= qq {<th><a href="rectool.pl?mode=bravia&order=point">ポイント</a></th>\n};
1132 $HTML .= qq {<th>予約</th>\n};
1133 $HTML .= qq {</tr>\n};
1135 my $order = $q->param( 'order' );
1136 if ( $order ne 'point' ) {
1140 $order = 'point DESC';
1142 my $ary_ref = $dbh->selectall_arrayref(
1143 "SELECT id, chtxt, title, btime, etime, point
1144 FROM auto_timeline_bayes
1147 foreach my $line ( @{ $ary_ref } ) {
1148 my ( $begin, $end, $diff ) = &str2readable( $line->[3], $line->[4] );
1150 $HTML .= qq {<tr align="center">\n};
1151 $HTML .= qq {<td>$line->[0]</td>\n};
1152 $HTML .= qq {<td>$line->[1]</td>\n};
1153 $HTML .= qq {<td>$line->[2]</td>\n};
1154 $HTML .= qq {<td>$begin</td>\n<td>$end</td>\n<td>$diff</td>\n};
1155 $HTML .= qq {<td>$line->[5]</td>\n};
1156 $HTML .= qq {<td><a href="rectool.pl?mode=confirm&mode_sub=reserve&bayesid=$line->[0]">予約</a></td>\n};
1157 $HTML .= qq {</tr>\n};
1159 $HTML .= qq {</table>\n};
1160 $HTML .= qq {</div>\n};
1161 $HTML .= qq {</form>\n};
1165 if ( $mode eq 'proc' ) {
1166 $HTML =~ s/%HTML_TITLE_OPT%/ - Proposal/;
1167 $HTML .= qq {<div>\n};
1168 $HTML .= qq {<table summary="proctable" border=1 cellspacing=0>\n<tr>\n};
1169 $HTML .= qq {<th>タイプ</th>\n};
1170 $HTML .= qq {<th>タイトル</th>\n};
1171 $HTML .= qq {<th>予約</th>\n};
1172 $HTML .= qq {</tr>\n};
1174 my $ary_ref = $dbh->selectall_arrayref(
1175 "SELECT type, chtxt, title
1178 foreach my $line ( @{ $ary_ref } ) {
1180 $line->[3] = $q->url_encode( $line->[2] );
1182 if ( $line->[0] =~ /^auto_suggest_(dec|enc)/ ) {
1183 $url = qq {rectool.pl?mode=confirm&mode_sub=proc&type=$line->[0]&chtxt=$line->[1]&title=$line->[3]};
1186 $url = qq {rectool.pl?mode=change&mode_sub=proc&type=$line->[0]&chtxt=$line->[1]&title=$line->[3]};
1188 $line->[0] = $type{$line->[0]} ? $type{$line->[0]} : $line->[0];
1189 $HTML .= qq {<tr align="center">\n};
1190 $HTML .= qq {<td>$line->[0]</td>\n};
1191 $HTML .= qq {<td>$line->[2]</td>\n};
1192 $HTML .= qq {<td><a href="$url">予約</a></td>\n};
1193 $HTML .= qq {</tr>\n};
1196 $HTML .= qq {</table>\n};
1199 if ( $mode eq 'jbk' ) {
1200 $HTML =~ s/%HTML_TITLE_OPT%/ - JBK/;
1201 $HTML .= qq {<div>\n};
1203 if ( $mode_sub eq 'add' ) {
1204 my $keyword = $q->param( 'keyword' );
1205 $HTML .= "キーワード「$keyword」を追加しました。<br>\n";
1207 "INSERT INTO in_auto_jbk_key ( keyword )
1208 VALUES ( '$keyword' )"
1211 elsif ( $mode_sub eq 'del' ) {
1212 my $id = $q->param( 'id' );
1213 my $keyword = $dbh->selectrow_array(
1214 "SELECT keyword FROM in_auto_jbk_key
1215 WHERE id = '$id' " );
1216 $HTML .= "キーワード「$keyword」を削除しました。<br>\n";
1218 "DELETE FROM in_auto_jbk_key WHERE id = '$id'"
1222 $HTML .= qq {<table summary="jbktable" border=1 cellspacing=0>\n<tr>\n};
1223 $HTML .= qq {<th>ID</th>\n};
1224 $HTML .= qq {<th>キーワード</th>\n};
1225 $HTML .= qq {<th>削除</th>\n};
1226 $HTML .= qq {</tr>\n};
1228 my $ary_ref = $dbh->selectall_arrayref(
1230 FROM in_auto_jbk_key
1233 foreach my $line ( @{ $ary_ref } ) {
1234 my $url = "rectool.pl?mode=jbk&mode_sub=del&id=$line->[0]";
1236 $HTML .= qq {<tr align="center">\n};
1237 $HTML .= qq {<td>$line->[0]</td>\n};
1238 $HTML .= qq {<td>$line->[1]</td>\n};
1239 $HTML .= qq {<td><a href="$url">削除</a></td>\n};
1240 $HTML .= qq {</tr>\n};
1243 $HTML .= qq {</table>\n};
1245 $HTML .= qq {<form method="get" action="rectool.pl">\n};
1246 $HTML .= qq {<div>\n};
1247 $HTML .= qq {<input type="hidden" name="mode" value="jbk">\n};
1248 $HTML .= qq {<input type="hidden" name="mode_sub" value="add">\n};
1249 $HTML .= qq {<input name="keyword" type="text">\n};
1250 $HTML .= qq {<input type="submit" value="追加">\n</div>\n</form>\n<br>\n};
1252 $HTML .= qq {<table summary="jbkrestable" border=1 cellspacing=0>\n<tr>\n};
1253 $HTML .= qq {<th>ID</th>\n};
1254 $HTML .= qq {<th>チャンネル</th>\n};
1255 $HTML .= qq {<th>タイトル</th>\n};
1256 $HTML .= qq {<th>開始時刻</th>\n};
1257 $HTML .= qq {<th>終了時刻</th>\n};
1258 $HTML .= qq {<th>録画時間</th>\n};
1259 $HTML .= qq {<th>予約</th>\n};
1260 $HTML .= qq {</tr>\n};
1262 my $ary_ref = $dbh->selectall_arrayref(
1263 "SELECT id, chtxt, title, btime, etime
1264 FROM auto_timeline_keyword " );
1266 foreach my $line ( @{ $ary_ref } ) {
1267 my ( $begin, $end, $diff ) = &str2readable( $line->[3], $line->[4] );
1268 $line->[3] =~ s/(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/$1$2$3$4$5$6/;
1269 $line->[4] =~ s/(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/$1$2$3$4$5$6/;
1270 my $url = qq "rectool.pl?mode=confirm&mode_sub=reserve&chtxt=$line->[1]&start=$line->[3]&stop=$line->[4]";
1272 $HTML .= qq {<tr align="center">\n};
1273 $HTML .= qq {<td>$line->[0]</td>\n};
1274 $HTML .= qq {<td>$line->[1]</td>\n};
1275 $HTML .= qq {<td>$line->[2]</td>\n};
1276 $HTML .= qq {<td>$begin</td>\n};
1277 $HTML .= qq {<td>$end</td>\n};
1278 $HTML .= qq {<td>$diff</td>\n};
1279 $HTML .= qq {<td><a href="$url">予約</a></td>\n};
1280 $HTML .= qq {</tr>\n};
1283 $HTML .= qq {</table>\n};
1287 if ( $mode eq 'expert' ) {
1290 $HTML =~ s/%HTML_TITLE_OPT%/ - Expert/;
1291 $HTML .= qq {<div>\n};
1293 if ( $mode_sub eq 'reget' ) {
1294 my $bctype = $q->param( 'bctype' );
1295 my ( $ontv, $chname ) = $dbh->selectrow_array(
1296 "SELECT ontv, chname FROM epg_ch
1297 WHERE bctype = '$bctype' " );
1298 $HTML .= "Update for $chname ( ontv: $ontv ) has been reserved.<br>\n";
1299 $dbh->do( "UPDATE epg_ch SET status = '2' WHERE ontv = '$ontv' " );
1304 $ary_ref = $dbh->selectcol_arrayref(
1305 "SELECT DISTINCT category FROM epg_timeline"
1308 # my @category = map { $category{$_} . $_ } sort keys %category;
1309 my @category = sort values %category;
1310 $HTML .= qq {<hr>\n番組表のカテゴリ一覧と内蔵の一覧の合致を確認中...\n};
1311 if ( List::Compare->new( $ary_ref, \@category )->get_symdiff ) {
1312 $HTML .= qq {一致しません<br>\n};
1313 $HTML .= qq {番組表:@{$ary_ref}<br>\n内蔵:@category<br>\n};
1316 $HTML .= qq {一致しました<br>\n};
1319 my @ary = $dbh->selectrow_array( "SELECT terec, bscsrec, b252ts, ts2avi FROM in_status" );
1320 $HTML .= qq {<hr>\n地上波録画数:$ary[0]\n衛星波録画数:$ary[1]\n解読数:$ary[2]\n縁故数:$ary[3]\n<br>\n};
1323 $ary_ref = $dbh->selectall_arrayref( "SELECT chname, chtxt FROM epg_ch" );
1325 $HTML .= "<hr>\n番組表の欠落<br>\n";
1326 foreach my $line ( @{$ary_ref} ) {
1327 my $ary_ref = $dbh->selectall_arrayref(
1328 "SELECT start, stop, title FROM epg_timeline WHERE channel = '$line->[1]' ORDER BY start"
1331 my @program_old = ( '', $ary_ref->[0]->[0] );
1332 my $program_old = \@program_old;
1334 foreach my $program_new ( @{$ary_ref} ) {
1335 if ( $program_old->[1] ne $program_new->[0] &&
1336 $program_old->[2] !~ /クロ?ジング|クロージング|エンディング|休止|ミッドナイトプレゼント/ &&
1337 $program_new->[2] !~ /オープニング|ウィークリー・インフォメーション|モーニングプレゼント/ &&
1338 ( str2datetime( $program_new->[0] ) - str2datetime( $program_old->[1] ) )->delta_minutes > 30 ) {
1339 $program_old->[1] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
1340 $program_new->[0] =~ s/(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/$1-$2-$3 $4:$5:$6/;
1341 $error .= qq{ $program_old->[2] $program_old->[1]\n ? $program_new->[2] $program_new->[0]\n};
1343 $program_old = $program_new;
1345 $HTML .= qq {<pre>\n$line->[0]\n$error</pre>\n} if ( $error );
1348 $ary_ref = $dbh->selectall_arrayref(
1349 "SELECT chname, chtxt, ontv, bctype, ch, csch, updatetime, status
1351 ORDER BY bctype " );
1352 $HTML .= qq {<hr>\n番組表の更新状況<br>\n};
1353 $HTML .= qq {<table summary="channeltable" border=1 cellspacing=0>\n<tr>\n};
1354 $HTML .= qq {<th>チャンネル名</th>\n};
1355 $HTML .= qq {<th>チャンネルコード</th>\n};
1356 $HTML .= qq {<th>ontvコード</th>\n};
1357 $HTML .= qq {<th>タイプ</th>\n};
1358 $HTML .= qq {<th>ch</th>\n};
1359 $HTML .= qq {<th>csch</th>\n};
1360 $HTML .= qq {<th>最終更新時刻</th>\n};
1361 $HTML .= qq {<th>状態</th>\n};
1362 $HTML .= qq {</tr>\n};
1363 foreach my $status ( @{$ary_ref} ) {
1364 $HTML .= qq {<tr>\n};
1365 $HTML .= qq {<td>$status->[0]</td>\n<td>$status->[1]</td>\n<td>$status->[2]</td>\n<td>$status->[3]</td>\n};
1366 $HTML .= qq {<td>$status->[4]</td>\n<td>$status->[5]</td>\n<td>$status->[6]</td>\n<td>$status->[7]</td>\n};
1367 $HTML .= qq {</tr>\n};
1369 $HTML .= qq {</table>\n};
1371 $HTML .= qq {<form method="get" action="rectool.pl">\n};
1372 $HTML .= qq {<div>\n};
1373 $HTML .= qq {番組表を再取得する\n};
1374 $HTML .= qq {<input type="hidden" name="mode" value="expert">\n};
1375 $HTML .= qq {<input type="hidden" name="mode_sub" value="reget">\n};
1376 $HTML .= qq {<select name="bctype">\n};
1377 $ary_ref = $dbh->selectall_arrayref(
1378 "SELECT chname, bctype
1379 FROM epg_ch WHERE bctype NOT LIKE '_s%' "
1381 foreach my $line ( @{$ary_ref} ) {
1382 $HTML .= qq {<option value="$line->[1]">$line->[0]</option>\n};
1384 $HTML .= qq {<option value="bs">BS</option>\n};
1385 $HTML .= qq {<option value="cs1">CS1</option>\n};
1386 $HTML .= qq {<option value="cs2">CS2</option>\n};
1387 $HTML .= qq {</select>\n};
1388 $HTML .= qq {<input type="submit" value="実行">\n</div>\n</form>\n};
1392 $ary_ref = $dbh->selectall_arrayref(
1393 "SELECT id, type, chtxt, title, btime, etime, deltaday, deltatime
1396 $HTML .= qq {<hr>\n予約表<br>\n};
1397 $HTML .= qq {<table summary="rectimetable" border=1 cellspacing=0>\n<tr>\n};
1398 $HTML .= qq {<th>ID</th>\n};
1399 $HTML .= qq {<th>type</th>\n};
1400 $HTML .= qq {<th>chtxt</th>\n};
1401 $HTML .= qq {<th>title</th>\n};
1402 $HTML .= qq {<th>btime</th>\n};
1403 $HTML .= qq {<th>etime</th>\n};
1404 $HTML .= qq {<th>deltaday</th>\n};
1405 $HTML .= qq {<th>deltatime</th>\n};
1406 $HTML .= qq {</tr>\n};
1407 foreach my $status ( @{$ary_ref} ) {
1408 $HTML .= qq {<tr>\n};
1409 $HTML .= qq {<td>$status->[0]</td>\n<td>$status->[1]</td>\n<td>$status->[2]</td>\n<td>$status->[3]</td>\n};
1410 $HTML .= qq {<td>$status->[4]</td>\n<td>$status->[5]</td>\n<td>$status->[6]</td>\n<td>$status->[7]</td>\n};
1411 $HTML .= qq {</tr>\n};
1413 $HTML .= qq {</table>\n};
1416 if ( $mode eq 'help' ) {
1417 $HTML =~ s/%HTML_TITLE_OPT%/ - Help/;
1418 $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="300">|;
1419 $HTML .= qq {<div>\n};
1420 $HTML .= qq {ヘルプ\n};
1423 if ( $mode eq 'test' ) {
1424 $HTML =~ s/%HTML_TITLE_OPT%/ - Test/;
1425 $HTML =~ s|%REFRESH%|<meta http-equiv="refresh" content="300">|;
1426 $HTML .= qq {<div>\n};
1428 require Data::Dumper;
1429 require Perl6::Slurp;
1430 $tmp = Perl6::Slurp::slurp( 'config.ini' );
1431 $tmp =~ s/\n/<br>\n/gs;
1434 # $HTML .= Dumper( $ary_ref );
1439 $HTML =~ s/%HTML_TITLE_OPT%/ - Top/;
1440 $HTML .= qq {Welcome to Rec10!<br>\n};
1446 #<div style="float: right">
1453 #<div align="center">
1454 #$HTML_ADV = $HTML_ADV_IMG . $HTML_ADV_TEXT if ( !$HTML_ADV );
1455 $HTML_HEADER = qq {<div style="text-align: center">\n$HTML_ADV\n</div>\n};
1458 $HTML =~ s/%HTML_TITLE_OPT%//;
1459 $HTML =~ s/%REFRESH%//;
1460 $HTML =~ s/%SCRIPT%//;
1462 $HTML =~ s/%HTML_HEADER%/$HTML_HEADER/;
1468 $hires = Time::HiRes::time() - $hires;
1469 $last_modified = localtime((stat 'rectool.pl')[9]);
1471 $HTML_HEADER .= qq {<div>\n};
1472 $HTML_HEADER .= qq {<span style="float: right; font-size: 8px">Last-Modified: $last_modified<br>Time-Elasped: $hires秒</span>\n};
1473 $HTML_HEADER .= qq {<span style="float: left">\n};
1474 $HTML_HEADER .= qq {<a href="rectool.pl">トップ</a>\n};
1475 $HTML_HEADER .= qq {<a href="rectool.pl?mode=schedule">予約確認</a>\n};
1476 $HTML_HEADER .= qq {<a href="rectool.pl?mode=graph">予約状況(画像版)</a>\n};
1477 $HTML_HEADER .= qq {<a href="rectool.pl?mode=list">録画一覧</a>\n};
1478 $HTML_HEADER .= qq {<a href="rectool.pl?mode=bravia">おまかせ</a>\n};
1479 $HTML_HEADER .= qq {<a href="rectool.pl?mode=expert">玄人仕様</a>\n};
1480 $HTML_HEADER .= qq {<a href="rectool.pl?mode=proc">復旧支援</a>\n};
1481 $HTML_HEADER .= qq {<a href="rectool.pl?mode=jbk">地引</a>\n};
1482 $HTML_HEADER .= qq {<a href="../rec10web/rec10web.py">新規予約</a>\n};
1483 $HTML_HEADER .= qq {<a href="rectool.pl?mode=edit">新規予約2</a>\n};
1484 $HTML_HEADER .= qq {</span>\n};
1485 $HTML_HEADER .= qq {<hr style="clear: both; background-color: grey; height: 4px">\n};
1486 $HTML_HEADER .= qq {</div>\n};
1490 $chname = $q->param( 'chname' );
1491 $key = $q->param( 'key' );
1492 $ontv = $dbh->selectrow_array("SELECT ontv FROM epg_ch WHERE chname = '$chname' ");
1494 $HTML .= qq {<div style="float: left">\n};
1495 $HTML .= qq {<form method="get" action="rectool.pl">\n};
1496 $HTML .= qq {<div>\n};
1497 $HTML .= qq {<input type="hidden" name="mode" value="program">\n};
1500 $HTML .= qq {<select name="chname">\n<option value="" selected>無指定</option>\n};
1501 $ary_ref = $dbh->selectcol_arrayref(
1502 "SELECT chname FROM epg_ch"
1504 foreach my $line ( @{$ary_ref} ) {
1505 if ( $line eq $chname ) {
1506 $HTML .= qq {<option value="$line" selected>$line</option>\n};
1509 $HTML .= qq {<option value="$line">$line</option>\n};
1512 $HTML .= qq {</select>\n};
1515 $HTML .= qq {<select name="date">\n<option value="" selected>無指定</option>\n};
1516 $ary_ref = $dbh->selectcol_arrayref(
1517 "SELECT DISTINCT SUBSTRING(start, 1, 8) FROM epg_timeline ORDER BY start"
1519 $date_sel = $q->param( 'date' );
1520 foreach my $date ( @{ $ary_ref } ) {
1521 my @date = $date =~ /(.{4})(.{2})(.{2})/;
1522 $date_prt = "$date[1]/$date[2]";
1524 if ( $date eq $date_sel ) {
1525 $HTML .= qq {<option value="$date" selected>$date_prt</option>\n};
1528 $HTML .= qq {<option value="$date">$date_prt</option>\n};
1531 $HTML .= qq {</select>\n};
1534 $HTML .= qq {<select name="category">\n<option value="" selected>無指定</option>\n};
1535 $category_sel = $q->param( 'category' );
1536 foreach my $category ( keys %category ) {
1537 if ( $category eq $category_sel ) {
1538 $HTML .= qq {<option value="$category" selected>$category{$category}</option>\n};
1541 $HTML .= qq {<option value="$category">$category{$category}</option>\n};
1544 $HTML .= qq {</select>\n};
1547 $HTML .= qq {<input name="key" type="text" value="$key" style="width:200px">\n};
1550 $HTML .= qq {<input type="submit" value="更新">\n</div>\n</form>\n};
1554 $chname = $q->param( 'chname' );
1555 $chtxt = $q->param( 'chtxt' );
1556 $start = $q->param( 'start' );
1557 $stop = $q->param( 'stop' );
1558 $bayesid = $q->param( 'bayesid' );
1559 $id = $q->param( 'id' );
1562 $ontv = $dbh->selectrow_array("SELECT ontv FROM epg_ch WHERE chname = '$chname'");
1563 $chtxt = $dbh->selectrow_array("SELECT chtxt FROM epg_ch WHERE ontv = '$ontv'");
1566 $ontv = $dbh->selectrow_array("SELECT ontv FROM epg_ch WHERE chtxt = '$chtxt'");
1567 $chname = $dbh->selectrow_array("SELECT chname FROM epg_ch WHERE ontv = '$ontv'");
1569 $title = $dbh->selectrow_array("SELECT title FROM epg_timeline WHERE channel = '$ontv' AND start = '$start' AND stop = '$stop' ");
1570 $desc = $dbh->selectrow_array("SELECT exp FROM epg_timeline WHERE channel = '$ontv' AND start = '$start' AND stop = '$stop' ");
1571 $longdesc = $dbh->selectrow_array("SELECT longexp FROM epg_timeline WHERE channel = '$ontv' AND start = '$start' AND stop = '$stop' ");
1572 $category = $dbh->selectrow_array("SELECT category FROM epg_timeline WHERE channel = '$ontv' AND start = '$start' AND stop = '$stop' ");
1573 $bctype = $dbh->selectrow_array("SELECT bctype FROM epg_ch WHERE ontv = '$ontv'");
1576 ( $chtxt, $title, $begin, $end ) = $dbh->selectrow_array(
1577 "SELECT chtxt, title, btime, etime FROM auto_timeline_bayes WHERE id = '$bayesid' "
1579 ( $ontv, $chname, $bctype ) = $dbh->selectrow_array(
1580 "SELECT ontv, chname, bctype FROM epg_ch WHERE chtxt = '$chtxt' "
1582 $start = str2datetime( $begin )->strftime( '%Y%m%d%H%M%S' );
1583 $stop = str2datetime( $end )->strftime( '%Y%m%d%H%M%S' );
1584 ( $desc, $longdesc, $category ) = $dbh->selectrow_array(
1585 "SELECT exp, longexp, category FROM epg_timeline WHERE channel = '$ontv' AND start = '$start' AND stop = '$stop' "
1589 ( $type, $chtxt, $title, $begin, $end, $deltaday, $deltatime, $opt ) = $dbh->selectrow_array(
1590 "SELECT type, chtxt, title, btime, etime, deltaday, deltatime, opt
1591 FROM timeline WHERE id = '$id' "
1593 ( $ontv, $chname, $bctype ) = $dbh->selectrow_array(
1594 "SELECT ontv, chname, bctype FROM epg_ch WHERE chtxt = '$chtxt' "
1596 $start = str2datetime( $begin )->strftime( '%Y%m%d%H%M%S' );
1597 $stop = str2datetime( $end )->strftime( '%Y%m%d%H%M%S' );
1598 ( $desc, $longdesc, $category ) = $dbh->selectrow_array(
1599 "SELECT exp, longexp, category FROM epg_timeline WHERE channel = '$ontv' AND start = '$start' AND stop = '$stop' "
1602 if ( $bctype =~ /.s/ ) {
1603 $bctype_sql = '_s%';
1605 elsif ( $bctype =~ /te/ ) {
1606 $bctype_sql = 'te%';
1608 @start = $start =~ /(.{4})(.{2})(.{2})(.{2})(.{2})/;
1609 @stop = $stop =~ /(.{4})(.{2})(.{2})(.{2})(.{2})/;
1610 $begin = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', @start, '00' );
1611 $end = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', @stop , '00' );
1616 my $is_same = $dbh->selectrow_array(
1617 "SELECT COUNT(*) FROM timeline WHERE chtxt = '$chtxt' AND btime = '$begin' AND etime = '$end'"
1619 my @overlap = &get_overlap();
1622 $HTML .= "同一の番組が既に存在します。<br>\n";
1625 elsif ( $overlap[0] >= 2 ) {
1626 $HTML .= "時間が被る番組が既に2個存在します。<br>\n";
1627 $HTML .= $overlap[1];
1639 my $ary_ref = $dbh->selectall_arrayref(
1640 "SELECT btime, etime, title
1642 INNER JOIN epg_ch ON timeline.chtxt = epg_ch.chtxt
1643 WHERE bctype LIKE '$bctype_sql' AND type IN $type_user_made
1645 AND etime > '$begin'
1650 my $overlap = $max = 0;
1652 foreach my $prg ( @{ $ary_ref } ) {
1653 $str .= "$prg->[0] ? $prg->[1] : $prg->[2]<br>\n";
1654 $overlap{$prg->[0]} += 1;
1655 $overlap{$prg->[1]} -= 1;
1657 foreach my $key ( sort keys %overlap ) {
1658 $overlap += $overlap{$key};
1659 $max = List::Util::max( $max, $overlap );
1662 return ( $max, $str );
1672 return $str =~ /.{4}-.{2}-.{2} .{2}:.{2}:.{2}/ ? 0 : 1;
1679 if ( strisjoined( $str ) ) {
1680 @time = $str =~ /(.{4})(.{2})(.{2})(.{2})(.{2})(.{2})/;
1683 @time = $str =~ /(.{4})-(.{2})-(.{2}) (.{2}):(.{2}):(.{2})/;
1685 return DateTime->new(
1686 year => $time[0], month => $time[1], day => $time[2],
1687 hour => $time[3], minute => $time[4], second => $time[5],
1688 locale => 'ja_JP' , time_zone => $tz
1694 our %day_name_cache;
1696 if ( !$day_name_cache{$str} ) {
1697 $day_name_cache{$str} = str2datetime( $str )->day_name;
1699 return $day_name_cache{$str};
1706 my $dt_begin = &str2datetime( $begin );
1707 my $dt_end = &str2datetime( $end );
1709 my $str_begin = $dt_begin->strftime( '%m/%d(%a) %H:%M' );
1710 my $str_end = $dt_end ->strftime( $dt_begin->day == $dt_end->day ? '%H:%M' : '翌 %H:%M' );
1711 utf8::encode( $str_begin );
1713 my ( $sec, $min, $hour );
1714 $sec = $dt_end->epoch - $dt_begin->epoch;
1715 $min = int( $sec / 60 );
1716 $sec = $sec - $min * 60;
1717 $hour = int( $min / 60 );
1718 $min = $min - $hour * 60;
1720 $str_diff .= $hour . '時間' if ( $hour );
1721 $str_diff .= $min . '分' if ( $min );
1722 $str_diff .= $sec . '秒' if ( $sec );
1724 return ( $str_begin, $str_end, $str_diff );
1727 sub sqlgetsuggested {
1729 require Text::Ngram;
1731 my ( $btime, $etime ) = @_;
1733 $btime_bgn = $btime->clone->subtract( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' );
1734 $btime_end = $btime->clone->add( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' );
1735 $etime_bgn = $etime->clone->subtract( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' );
1736 $etime_end = $etime->clone->add( hours => $deltatime )->strftime( '%Y%m%d%H%M%S' );
1738 my $ontv = $dbh->selectrow_array( "SELECT ontv FROM epg_ch WHERE chtxt = '$chtxt' " );
1739 $ary_ref = $dbh->selectall_arrayref(
1740 "SELECT start, stop, title, exp
1742 WHERE channel = '$ontv'
1743 AND start BETWEEN '$btime_bgn' AND '$btime_end'
1744 AND stop BETWEEN '$etime_bgn' AND '$etime_end' "
1748 my $hash_r = Text::Ngram::ngram_counts( Encode::decode_utf8( $title ), 2 ); # bi-gram
1749 foreach my $program ( @{$ary_ref} ) {
1750 my $hash_k = Text::Ngram::ngram_counts( Encode::decode_utf8( $program->[2] ), 2 );
1752 map $point += $hash_k->{$_}, keys %{$hash_r};
1753 push @{$hash{$point}}, $program if ( $point );