事象の水平線

横を無理やり伸ばしたので、デザインがおかしいけど、気にしない。完璧に時代に取り残されたHTMLをいまさらいじるのがめんどくさい。個人的ブックマーク代わりなメモ書きブログ。

recpt1をhttp版に改造し、クライアントPCのTVtest(with BonDriver_HTTP.dll)からリアルタイム視聴を使っている訳ですが、リアルタイムで見ているときに予約録画が始まりチューナーが足りないと予約録画が失敗するので、EPGrec側を改造してみたメモ。

ちなみに、recpt1のhttp版に関しては
recpt1 http版 怒られながら入れてみる
recpt1 http版 プロセスが落ちたときにphpで手動でブラウザからexecする
recpt1 カテゴリー
あたり参照

ついでに、TVtest(with BonDriver_HTTP.dll)についても
TVtest with BonDriver_HTTP.dll でリアルタイム視聴
の記事を書く予定参照




動作の概要としては、予約録画が始まるときにdo-record.shが走るので、そこでチューナー数が足りないようならhttp版のdaemonをkillする。と言うだけの話。
で、予約録画が終わってチューナーに余裕がありそうならhttp版daemonを復活。
さらに、リアルタイム視聴しているときにたまにhttp版がよく分からない待ち状態に入り視聴できなくなるので、手動でブラウザから再起動できるようにもする。

ちなみに、考慮している環境
・PT3が一枚のみの場合  (それ以上の場合は適度に定数をいじってください)
・配信のポートは8888  (新規導入ならfirewallでudp,tcp8888開放とか)



/var/www/epgrec/do-record.sh
とりあえず自分の環境のをまんま載せておきます。関係するのは赤部分のみ。
#!/bin/bash
echo "CHANNEL : $CHANNEL"
echo "DURATION: $DURATION"
echo "OUTPUT : $OUTPUT"
echo "TUNER : $TUNER"
echo "TYPE : $TYPE"
echo "MODE : $MODE"
echo "SID : $SID"

RECORDER=/usr/local/bin/recpt1

# fail safe
case $CHANNEL in
101|102|191|192|193|200|201|202)
if [ $SID = 'hd' ]; then
SID=$CHANNEL
fi ;;
esac
if [ -z $SID ]; then
SID='hd'
fi

# recpt1-httpを終了
recpt1LivePID=`ps axl | grep recpt1 | grep 'http 8888' | awk '{print$3}'`;
if [ `ps -el | grep 'do-record.sh' | wc -l` -gt 2 ]; then
sudo kill -9 $recpt1LivePID ;
fi


if [ ${MODE} = 0 ]; then
# MODE=0では必ず無加工のTSを吐き出すこと because of epg
$RECORDER --b25 --strip $CHANNEL $DURATION ${OUTPUT} >/dev/null
elif [ ${MODE} = 1 ]; then
if [ ${CHANNEL} = "17" ] || [ ${CHANNEL} = "18" ]; then
# テレビ朝日とテレビ東京はFullTS
$RECORDER --b25 --strip $CHANNEL $DURATION ${OUTPUT} >/dev/null
else
# 目的のSIDのみ残す
$RECORDER --b25 --strip --sid $SID $CHANNEL $DURATION ${OUTPUT} >/dev/null
fi
elif [ ${MODE} = 2 ]; then
if [ ${CHANNEL} = "17" ] || [ ${CHANNEL} = "18" ]; then
# テレビ朝日とテレビ東京はFullTS
$RECORDER --b25 --strip $CHANNEL $DURATION ${OUTPUT} >/dev/null
else
# 目的のSIDのみ残す
$RECORDER --b25 --strip --sid $SID $CHANNEL $DURATION ${OUTPUT} >/dev/null
fi
/usr/local/bin/PSconvert.sh ${OUTPUT} >/dev/null
echo "------ do-record.sh MODE2 complete "`date` >> /var/log/autosuspend.log
fi

# recpt1-httpを復活
sleep 1
recpt1LivePID=`ps axl | grep recpt1 | grep 'http 8888' | awk '{print$3}'`;
if [ `ps -el | grep recpt1 | wc -l` -lt 2 ]; then
if [ `echo $recpt1LivePID | wc -w` -eq 0 ]; then
/usr/local/bin/reload_recpt1.sh
fi
fi

まぁ、難しいことしてないんで動作の詳細説明は省略。(ぉぃ
最後の復活する際に、http版が走っていない時のみ復活の動作をさせているのは、リアルタイム視聴をしているときに不用意にrecpt1http版が再起動するのを避けるため。
sleep 1は気休めです。



/var/www/html/reload_recpt1.php
うまくリアルタイム視聴できなくなった時に手動でrecpt1http版を再起動するphp
phpを呼び出すフォームとかは『recpt1 http版 プロセスが落ちたときにphpで手動でブラウザからexecする』参照
<html>
<head>
<MEtA http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="refresh" content="20;URL=http:../">
<?php
//if submit has been pressed
if(isset($_POST['submit'])){
#reload_recpt1
exec("/usr/local/bin/reload_recpt1.sh");

#HTML
echo('<title>recpt1リロード終了</title>
</head>
<body><br><br><br>
recpt1をリロードしました。<br>
20秒後にHomeに戻ります。<br><br>
<font color="#0000FF"><b>チャンネルを切り替える</b>か、<b>TVTestを再起動</b></font>してください。<br><br>
それでも写らない場合、<b><font size="+2" color="#FF0000">2番組以上の録画をしている</font></b>可能性があります。<br>
その場合録画が優先されます。
');
}else{
echo('<title>不正に呼び出された</title></head><body>不正に呼び出されました。<br>20秒後にHomeに戻ります。');
}
php?>

</body>
</html>
phpの設定やパーミッションなどは良しなに・・・


/usr/local/bin/reload_recpt1.sh
do-record.shとreload_recpt1.phpが呼び出す、recpt1http版を再起動するスクリプト
分けたのは単に構築に至る紆余曲折によりこうなっただけで、それ以上の意味はないです。
#!/bin/bash

recpt1LivePID=`ps axl | grep recpt1 | grep 'http 8888' | awk '{print$3}'`;
if [ `echo $recpt1LivePID | wc -w` -gt 0 ]; then
sudo kill -9 $recpt1LivePID ;
fi

/usr/local/bin/recpt1 --b25 --strip --http 8888 > /dev/null 2>&1 &

recpt1http版は走っているが、よく分からない待ち状態になっていることがあるので、単に再度走らせるだけでなく確実にkillしてから起動している。



/var/www/epgrec/getepg.php
cronでgetepg.phpが走る(EPG取得)とこれもチューナーも使うしdo-record.shも使う。ので、1番組(以上)の録画中にリアルタイム視聴をしてるとEPG取得が行われるときにリアルタイム視聴が止まることになる。
デフォルトでEPGは2時間おきに取得になっているので、リアルタイムで見てるときにEPG更新されなくても、ま~いいやろ、と言うことで予約録画中はEPG取得をスルーするようにした。
他にも多少いじっているけれど、どうもEPGrecのバージョンでスクリプトが結構違うようでどれが最新か、自分の使っているのが最新かよく分からないので全文を載せておきます。やっていることは単純なので、環境に合わせて改造してください。
GPLだかGNUだかライセンスで問題があれば連絡ください。ライセンスとかよー分かりません
#!/usr/bin/php
<?php
$script_path = dirname( __FILE__ );
chdir( $script_path );
include_once( $script_path . '/config.php');
include_once( INSTALL_PATH . '/DBRecord.class.php' );
include_once( INSTALL_PATH . '/Reservation.class.php' );
include_once( INSTALL_PATH . '/Keyword.class.php' );
include_once( INSTALL_PATH . '/Settings.class.php' );
include_once( INSTALL_PATH . '/storeProgram.inc.php' );
include_once( INSTALL_PATH . '/recLog.inc.php' );


// SIGTERMシグナル
function handler( $signo = 0 ) {
// とりあえずシグナルは無視する
}

// デーモン化
function daemon() {
if( pcntl_fork() != 0 )
exit();
posix_setsid();
if( pcntl_fork() != 0 )
exit;
pcntl_signal(SIGTERM, "handler");

fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
}

function check_file( $file ) {
// ファイルがないなら無問題
if( ! file_exists( $file ) ) return true;

// 1時間以上前のファイルなら削除してやり直す
if( (time() - filemtime( $file )) > 3600 ) {
@unlink( $file );
return true;
}

return false;
}

// 子プロセス起動
function epgrec_exec( $cmd, $env = null ) {
$descspec = array(
0 => array( 'file','/dev/null','r' ),
1 => array( 'file','/dev/null','w' ),
2 => array( 'file','/dev/null','w' ),
);
$p = proc_open( $cmd, $descspec, $pipes, INSTALL_PATH, $env );
if( is_resource( $p ) ) return $p;

return false;
}

daemon();

$settings = Settings::factory();

// ユーザー/グループの切り替えを試みる
if(intval($settings->use_power_reduce) != 0 ) {
$userinfo = posix_getpwnam( $settings->www_user );
$groupinfp = posix_getgrnam( $settings->www_group );

posix_setgid( $groupinfo['gid'] );
posix_setuid( $userinfo['uid'] );
}


// 後方互換性
if( ! defined( "BS_EPG_CHANNEL" ) ) define( "BS_EPG_CHANNEL", "211" );
if( ! defined( "CS1_EPG_CHANNEL" ) ) define( "CS1_EPG_CHANNEL", "CS8" );
if( ! defined( "CS2_EPG_CHANNEL" ) ) define( "CS2_EPG_CHANNEL", "CS24" );

$bs_proc = false;
$gr_procs = array();
$cs1_proc = false;
$cs2_proc = false;


$temp_data_bs = $settings->temp_data.".bs";
$temp_data_cs1 = $settings->temp_data.".cs1";
$temp_data_cs2 = $settings->temp_data.".cs2";
$temp_data_gr = $settings->temp_data.".gr";

if( file_exists( $settings->temp_data ) ) @unlink( $settings->temp_data );


// forhttp////////////////////////////////////////////
$num = DBRecord::countRecords( RESERVE_TBL, "WHERE complete = '0' AND endtime > now() AND starttime < addtime( now(), '00:15:00')" );
if($num > 0) {
reclog("EPG更新をスルー");
exit();
}





// BSを処理する
if( $settings->bs_tuners != 0 ) {
// 録画重複チェック
$num = DBRecord::countRecords( RESERVE_TBL, "WHERE complete = '0' AND (type = 'BS' OR type = 'CS') AND endtime > now() AND starttime < addtime( now(), '00:03:05')" );
if($num < $settings->bs_tuners && check_file($temp_data_bs)) {
$cmdline = "CHANNEL=".BS_EPG_CHANNEL." DURATION=180 TYPE=BS TUNER=0 MODE=0 OUTPUT=".$temp_data_bs." ".DO_RECORD . " >/dev/null 2>&1";
// logに情報を追加
reclog("getepg:: BS".BS_EPG_CHANNEL." EPG取得用TSファイルの保存開始");
exec( $cmdline );
// logに情報を追加
reclog("getepg:: BS".BS_EPG_CHANNEL." EPG取得用TSファイルの保存完了");

//EPG番組表更新
$cmdline = INSTALL_PATH."/storeProgram.php BS ".$temp_data_bs;
$bs_proc = epgrec_exec( $cmdline );
// チューナーのチャンネル切り替えの為の待ち時間を追加
sleep((int)$settings->rec_switch_time);
}

// CS
if ($settings->cs_rec_flg != 0) {
$num = DBRecord::countRecords( RESERVE_TBL, "WHERE complete = '0' AND (type = 'BS' OR type = 'CS') AND endtime > now() AND starttime < addtime( now(), '00:03:05')" );
if($num < $settings->bs_tuners && check_file($temp_data_cs1)) {

$cmdline = "CHANNEL=".CS1_EPG_CHANNEL." DURATION=120 TYPE=CS TUNER=0 MODE=0 OUTPUT=".$temp_data_cs1." ".DO_RECORD . " >/dev/null 2>&1";
// logに情報を追加
reclog("getepg:: CS".CS1_EPG_CHANNEL." EPG取得用TSファイルの保存開始");
exec( $cmdline );
// logに情報を追加
reclog("getepg:: CS".CS1_EPG_CHANNEL." EPG取得用TSファイルの保存完了");

//EPG番組表更新
$cmdline = INSTALL_PATH."/storeProgram.php CS1 ".$temp_data_cs1;
$cs1_proc = epgrec_exec($cmdline);
// チューナーのチャンネル切り替えの為の待ち時間を追加
sleep((int)$settings->rec_switch_time);
}

$num = DBRecord::countRecords( RESERVE_TBL, "WHERE complete = '0' AND (type = 'BS' OR type = 'CS') AND endtime > now() AND starttime < addtime( now(), '00:03:05')" );
if( ($num < $settings->bs_tuners) && check_file($temp_data_cs2) ) {
$cmdline = "CHANNEL=".CS2_EPG_CHANNEL." DURATION=120 TYPE=CS TUNER=0 MODE=0 OUTPUT=".$temp_data_cs2." ".DO_RECORD . " >/dev/null 2>&1";
// logに情報を追加
reclog("getepg:: CS".CS2_EPG_CHANNEL." EPG取得用TSファイルの保存開始");
exec( $cmdline );
// logに情報を追加
reclog("getepg:: CS".CS2_EPG_CHANNEL." EPG取得用TSファイルの保存完了");

//EPG番組表更新
$cmdline = INSTALL_PATH."/storeProgram.php CS2 ".$temp_data_cs2;
$cs2_proc = epgrec_exec( $cmdline );
// チューナーのチャンネル切り替えの為の待ち時間を追加
sleep((int)$settings->rec_switch_time);
}
}
}

// 地上波を処理する
if( $settings->gr_tuners != 0 ) {
foreach( $GR_CHANNEL_MAP as $key=>$value ){
// 録画重複チェック
$num = DBRecord::countRecords( RESERVE_TBL, "WHERE complete = '0' AND type = 'GR' AND endtime > now() AND starttime < addtime( now(), '00:01:10')" );
if($num < $settings->gr_tuners && check_file($temp_data_gr.$value."")) {
$cmdline = "CHANNEL=".$value." DURATION=60 TYPE=GR TUNER=0 MODE=0 OUTPUT=".$temp_data_gr.$value." ".DO_RECORD . " >/dev/null 2>&1";
// logに情報を追加
reclog("getepg:: 地上波GR".$value." EPG取得用TSファイルの保存開始");
exec( $cmdline );
// logに情報を追加
reclog("getepg:: 地上波GR".$value." EPG取得用TSファイルの保存完了");

//EPG番組表更新
$cmdline = INSTALL_PATH."/storeProgram.php GR ".$temp_data_gr.$value." ".$key;
$gr_procs[] = epgrec_exec( $cmdline );
// チューナーのチャンネル切り替えの為の待ち時間を追加
sleep((int)$settings->rec_switch_time);
}
}
}

// 終了を待つ
// 一時的にdefunctするがまあいいや
$counter = 0;
do {
sleep(1);

$counter = 0;
if( count($gr_procs) != 0 ) {
foreach( $gr_procs as $proc ) {
$status = proc_get_status( $proc );
if( $status['running'] ) $counter++;
}
}

if( $bs_proc !== false ){
$status = proc_get_status($bs_proc);
if( $status['running'] ) $counter++;
}

if( $cs1_proc !== false ){
$status = proc_get_status($bs_proc);
if( $status['running'] ) $counter++;
}

if( $cs2_proc !== false ){
$status = proc_get_status($bs_proc);
if( $status['running'] ) $counter++;
}

} while( $counter != 0 );


garbageClean(); // 不要プログラム削除
doKeywordReservation(); // キーワード予約

reclog( "EPG更新終了" ); // 追加

if( intval($settings->use_power_reduce) != 0 ) {
if( file_exists(INSTALL_PATH. "/settings/wakeupvars.xml") ) {
$wakeupvars_text = file_get_contents( INSTALL_PATH. "/settings/wakeupvars.xml" );
$wakeupvars = new SimpleXMLElement($wakeupvars_text);

// getepg終了時を書込み
$wakeupvars->getepg_time = time();
// 起動理由を調べる
if( strcasecmp( "getepg", $wakeupvars->reason ) == 0 ) {
// 1時間以内に録画はないか?
$count = DBRecord::countRecords( RESERVE_TBL, " WHERE complete <> '1' AND starttime < addtime( now(), '01:00:00') AND endtime > now()" );
if( $count != 0 ) { // 録画があるなら録画起動にして終了
$wakeupvars->reason = "reserve";
}
else {
exec( $settings->shutdown . " -h +".$settings->wakeup_before );
}
}
$wakeupvars->asXML(INSTALL_PATH. "/settings/wakeupvars.xml");
}
}
exit();
?>
現在or今から15分以内に予約録画がある場合はEPG更新をスルー


それぞれを改造or作成し、それぞれの場所に置いてください。
PCの起動時やスリープ復帰時のrecpt1http版の起動やdaemon化は『recpt1 http版 怒られながら入れてみる』あたりを参照

また、killでsudo使うので、visudoでapacheに権限をあげてください。
apache ALL=(ALL) NOPASSWD: /usr/bin/kill とかかな。→visudo参照

do-record.shでkillしてすぐに録画用にrecpt1が走ってるけど今のところチューナーの切り替え等で問題は出てないです。
録画の開始が遅れることも特にないです。
EPGrecUNAに移ったほうがいいのかもしれないけれど、これで更に不具合も一個減ったしこのままでもいっかな~
自己責任でどうぞ。

PageTop
自動予約の連続予約をテストしている際に、なぜかうまく連続予約されないので調べたら秒単位のEPG情報があっていすから転げ落ちた。

mysql>  SELECT starttime,endtime,title FROM Recorder_programTbl WHERE starttime REGEXP '....-..-.. ..:..:0[1-9]' OR endtime REGEXP '....-..-.. ..:..:0[1-9]' ORDER BY starttime;
+---------------------+---------------------+-----------------------------------------------------+
| starttime | endtime | title |
+---------------------+---------------------+-----------------------------------------------------+
| 2013-01-18 18:53:00 | 2013-01-18 19:00:03 | 気象情報 |
| 2013-01-18 19:00:03 | 2013-01-18 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-19 06:30:00 | 2013-01-19 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-19 07:00:03 | 2013-01-19 07:30:00 | NHKニュース おはよう日本【字】 |
| 2013-01-19 11:54:00 | 2013-01-19 12:00:03 | 気象情報 |
| 2013-01-19 12:00:03 | 2013-01-19 12:17:00 | ニュース【字】 |
| 2013-01-19 18:53:00 | 2013-01-19 19:00:03 | 気象情報 |
| 2013-01-19 19:00:03 | 2013-01-19 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-20 06:53:00 | 2013-01-20 07:00:03 | 気象情報・ニュース |
| 2013-01-20 07:00:03 | 2013-01-20 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-20 11:54:00 | 2013-01-20 12:00:03 | 気象情報 |
| 2013-01-20 12:00:03 | 2013-01-20 12:17:00 | ニュース【字】 |
| 2013-01-20 18:53:00 | 2013-01-20 19:00:03 | 気象情報 |
| 2013-01-20 19:00:03 | 2013-01-20 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-21 06:30:00 | 2013-01-21 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-21 07:00:03 | 2013-01-21 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-21 11:54:00 | 2013-01-21 12:00:03 | 気象情報 |
| 2013-01-21 12:00:03 | 2013-01-21 12:20:00 | ニュース【字】 |
| 2013-01-21 18:52:00 | 2013-01-21 19:00:03 | 気象情報 |
| 2013-01-21 19:00:03 | 2013-01-21 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-22 06:30:00 | 2013-01-22 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-22 07:00:03 | 2013-01-22 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-22 11:54:00 | 2013-01-22 12:00:03 | 気象情報 |
| 2013-01-22 12:00:03 | 2013-01-22 12:20:00 | ニュース【字】 |
| 2013-01-22 18:52:00 | 2013-01-22 19:00:03 | 気象情報 |
| 2013-01-22 19:00:03 | 2013-01-22 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-23 06:30:00 | 2013-01-23 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-23 07:00:03 | 2013-01-23 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-23 11:54:00 | 2013-01-23 12:00:03 | 気象情報 |
| 2013-01-23 12:00:03 | 2013-01-23 12:20:00 | ニュース【字】 |
| 2013-01-23 18:52:00 | 2013-01-23 19:00:03 | 気象情報 |
| 2013-01-23 19:00:03 | 2013-01-23 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-24 06:30:00 | 2013-01-24 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-24 07:00:03 | 2013-01-24 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-24 11:54:00 | 2013-01-24 12:00:03 | 気象情報 |
| 2013-01-24 12:00:03 | 2013-01-24 12:20:00 | ニュース【字】 |
| 2013-01-24 18:52:00 | 2013-01-24 19:00:03 | 気象情報 |
| 2013-01-24 19:00:03 | 2013-01-24 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-25 06:30:00 | 2013-01-25 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-25 07:00:03 | 2013-01-25 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-25 11:54:00 | 2013-01-25 12:00:03 | 気象情報 |
| 2013-01-25 12:00:03 | 2013-01-25 12:20:00 | ニュース【字】 |
| 2013-01-25 18:52:00 | 2013-01-25 19:00:03 | 気象情報 |
| 2013-01-25 19:00:03 | 2013-01-25 19:32:00 | NHKニュース7【二】【字】 |
| 2013-01-26 06:30:00 | 2013-01-26 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-26 07:00:03 | 2013-01-26 07:30:00 | NHKニュース おはよう日本【字】 |
| 2013-01-26 11:54:00 | 2013-01-26 12:00:03 | 気象情報 |
| 2013-01-26 12:00:03 | 2013-01-26 12:15:00 | ニュース【字】 |
| 2013-01-26 18:53:00 | 2013-01-26 19:00:03 | 気象情報 |
| 2013-01-26 19:00:03 | 2013-01-26 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-27 06:53:00 | 2013-01-27 07:00:03 | 気象情報・ニュース |
| 2013-01-27 07:00:03 | 2013-01-27 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-27 11:54:00 | 2013-01-27 12:00:03 | 気象情報 |
| 2013-01-27 12:00:03 | 2013-01-27 12:15:00 | ニュース【字】 |
| 2013-01-27 18:53:00 | 2013-01-27 19:00:03 | 気象情報 |
| 2013-01-27 19:00:03 | 2013-01-27 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-28 06:30:00 | 2013-01-28 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-28 07:00:03 | 2013-01-28 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-28 11:54:00 | 2013-01-28 12:00:03 | 気象情報 |
| 2013-01-28 12:00:03 | 2013-01-28 12:20:00 | ニュース【字】 |
| 2013-01-28 18:52:00 | 2013-01-28 19:00:03 | 気象情報 |
| 2013-01-28 19:00:03 | 2013-01-28 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-29 06:30:00 | 2013-01-29 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-29 07:00:03 | 2013-01-29 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-29 11:54:00 | 2013-01-29 12:00:03 | 気象情報 |
| 2013-01-29 12:00:03 | 2013-01-29 12:20:00 | ニュース【字】 |
| 2013-01-29 18:52:00 | 2013-01-29 19:00:03 | 気象情報 |
| 2013-01-29 19:00:03 | 2013-01-29 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-30 06:30:00 | 2013-01-30 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-30 07:00:03 | 2013-01-30 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-30 11:54:00 | 2013-01-30 12:00:03 | 気象情報 |
| 2013-01-30 12:00:03 | 2013-01-30 12:20:00 | ニュース【字】 |
| 2013-01-30 18:52:00 | 2013-01-30 19:00:03 | 気象情報 |
| 2013-01-30 19:00:03 | 2013-01-30 19:30:00 | NHKニュース7【二】【字】 |
| 2013-01-31 06:30:00 | 2013-01-31 07:00:03 | NHKニュース おはよう日本 |
| 2013-01-31 07:00:03 | 2013-01-31 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-01-31 11:54:00 | 2013-01-31 12:00:03 | 気象情報 |
| 2013-01-31 12:00:03 | 2013-01-31 12:20:00 | ニュース【字】 |
| 2013-01-31 18:52:00 | 2013-01-31 19:00:03 | 気象情報 |
| 2013-01-31 19:00:03 | 2013-01-31 19:30:00 | NHKニュース7【二】【字】 |
| 2013-02-01 06:30:00 | 2013-02-01 07:00:03 | NHKニュース おはよう日本 |
| 2013-02-01 07:00:03 | 2013-02-01 07:45:00 | NHKニュース おはよう日本【字】 |
| 2013-02-01 11:53:00 | 2013-02-01 12:00:03 | 気象情報 |
| 2013-02-01 12:00:03 | 2013-02-01 12:20:00 | ニュース【字】 |
| 2013-02-01 18:52:00 | 2013-02-01 19:00:03 | 気象情報 |
| 2013-02-01 19:00:03 | 2013-02-01 19:30:00 | NHKニュース7【二】【字】 |
| 2013-02-02 06:00:00 | 2013-02-02 07:00:03 | NHKニュース おはよう日本 |
| 2013-02-02 07:00:03 | 2013-02-02 07:30:00 | NHKニュース おはよう日本【字】 |
| 2013-02-02 11:54:00 | 2013-02-02 12:00:03 | 気象情報 |
| 2013-02-02 12:00:03 | 2013-02-02 12:15:00 | ニュース【字】 |
| 2013-02-02 18:53:00 | 2013-02-02 19:00:03 | 気象情報 |
| 2013-02-02 19:00:03 | 2013-02-02 19:30:00 | NHKニュース7【二】【字】 |
+---------------------+---------------------+-----------------------------------------------------+
92 rows in set (0.33 sec)


思い込みはよくない!!ということですが、おかげでプログラムを疑って2時間も無駄に失った。

く○ばれんhk

PageTop
EPGrecの番組検索で放送局の絞込みプルダウンにスキップしてある放送局やら、録画しないに設定しているCSやらがダラダラ現れて邪魔なので、ちょこっといじってみた。
まぁ、頻繁には使わないから今までスルーしてたんだけど。

programTable.php公式epgrec_20111001.tar.gz)129行目から

$k_station_name = "";
// 放送局プルダウンの小改造
$option = " WHERE skip='0'";
if ($settings->cs_rec_flg == 0) { $option .= " AND channel NOT LIKE 'CS%'"; }
$option .= " ORDER BY type DESC";

$crecs = DBRecord::createRecords(CHANNEL_TBL , $option);
$stations = array();


ORDER BY 句とかはnameにするなりお好きにどうぞ。自分はこれが一番しっくりきたので。
ちなみに、データベースの構成はこうなってました。

mysql> show columns from Recorder_channelTbl;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| type | varchar(8) | NO | | GR | |
| channel | varchar(10) | NO | | 0 | |
| name | varchar(512) | NO | | none | |
| channel_disc | varchar(128) | NO | | none | |
| sid | varchar(64) | NO | | hd | |
| skip | tinyint(1) | NO | | 0 | |
+--------------+--------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

PageTop
意味の分からんタイトルですが。
EPGrecで放送中の番組を予約すると、約3分後から録画が始まる。というのは多分EPGrecを使い始めるとすぐにそういう仕様なんだと理解すると思う。が、それをキャンセルしたときのお話。

条件
When:放送開始時間後に
What:その放送の録画予約をし、そこから10秒以内にその録画をキャンセルすると

現象
1:予約は削除される
2:が、3分後に録画が開始されて、しかも予約一覧にも録画一覧にも表示されない
3:HDDには録画されたものが出来上がる

なぜこんなことになるか?
EPGrecは録画予約の実行にatを使っている。
Reservation.class.phpの279行あたりでatによる予約をしている。)
が、atは秒単位の指定は出来ない。
(ので、実際の録画開始はrecorder.phpの200行あたりでwhileとusleepを使って秒単位のpendingを掛けている。)

Reservation.class.phpの61行あたりで既に開始されている番組だと、
$start_time = time() + PADDING_TIME + 10;	// 録画開始時間を3分10秒先に設定する
今の時間から3分(PADDING_TIME)+10秒後に録画が始まるようにしてある。

そして、64行目で
$at_start = $start_time - PADDING_TIME;
atの開始時間を、録画開始の3分前(PADDING_TIME)になるようになっている。
atが秒を理解すれば、これでも予約をしてすぐにatは走らない(10秒間は)が、atは秒を理解しないので、大概の場合放送中の番組を予約すると即座にatが走る。
例えば、01:10:23に既に始まってる放送を録画予約する。
        ↓
録画開始時間を01:13:33とし、atの開始時間を01:13:23としてatに登録する。
        ↓
が、atは秒を理解しないのでatには01:13が自分の開始時間(既に始まっている)と解釈し即スタート

で、atが走るとatがrecorder.phpを動かして、$starttime(Reservation.class.phpの$start_timeとほぼ同じ)待ちになる(約3分後に録画開始)

さらに、ここでこの予約のキャンセルをすると、Reservation.class.php
361行目cancel関数で
if( toTimestamp($rec->starttime) < (time() + PADDING_TIME + $settings->former_time) )

録画開始時間が、現在時刻(time())+3分(PADDING_TIME)+録画開始の余裕時間(秒)($settings->former_time)※
よりも早い(=録画が既に始まっている)ことで場合分けをし、
録画開始後ならrecorder.phpの動作を止め予約をキャンセルしようとする。
録画開始以前ならrecorder.phpは動いていない“はず”なので、単にatを削除し、MySQLのRecorde_reserveTblの予約を削除して終わっている。
(ここには10秒が加算されていない)
(※$rec->starttimeはMySQLの予約テーブル上の開始時間で$settings->former_timeが考慮されている。
$start_timeは番組表テーブル上の開始時間で$settings->former_timeは含まれていない。
本題とは無関係)


で、
atが秒を理解していれば、放送中の番組を予約録画し、10秒以内にキャンセルしてもこれでいいのだけれど、atは秒を理解しないので、これをやると、Reservation.class.phpのcancel関数ではまだ録画が始まっていないと判定されるのに、すでにatは走っていて、recorder.phpも走っている。ので、正常に予約録画はキャンセルされたように見えるのに、3分後には録画が始まってしまう。しかも、atが走ったあとにatが削除され(atが削除されてもrecorder.phpは止まらない)、MySQLのRecorde_reserveTblの予約情報も消えているので、予約一覧からも、録画済一覧からも見れない。


対策?
10秒はおそらく予約の処理のための余裕時間なのだろう。
これをなくせばいいという問題でもないし、他に10秒足せばいいという問題でもない。(通常の予約の時誤判定を起こす)
なので、これは根本対策をするのがベストで、
Reservation.class.phpで、放送開始後と判定されたら、以降は通常の予約と同じ手段をとらずに即座にdo-record.shをたたいて、MySQLには別個に録画予約を登録するのがいいと思う。
そうすれば、3分の待ち時間もなくなるし、この問題もなくなる。
当然後に控えてる予約とバッティングしないかをチェックしなきゃいけないのは現状と同じで、その処理はサブルーチン化されてないから書き起こす(コピペる)必要がある。次の予約までのDurationで撮るとかも当然可能だけど、どの道ちょっとしたtipsレベルではなくちょっとした改造になる。

と、いう所でそれをやるかどうかは・・・・・・
とりあえず、謎動作の原因が分かったので、メモ

EPGrecはLinux + PTxで一番使用者が多いと思うし、公開から数年たってるのでそこそこ枯れてるかと思ったのに、結構穴ぼこが多いなぁ;;
自動録画予約でも録画開始時間と放送時間変更とEPG更新のタイミングしだいでは録画失敗が起こりうるコードになってる。と思われる。
storeProgram.inc.phpの160行目とgetepg.phpの134行目のdoKeywordReservation();のタイミング参照
この間に放送開始だと録画されない。よね?
放送開始時間が頻繁に変更されるんhkで35分あたりから開始する番組で起こりうるのではないだろうか・・・
まだこの事象にはあってないけど。

しかし、ソースを見だしたら色々といじってしまった。メンテナンスが苦労するなぁ。。

PageTop
昨日、epgdumpのsegfault対策をしたのですが、その影響なのかはわかりませんが、EPGrecで開始時間よりも終了時間が遅い番組ができてしまうというおかしなことがおきたのでメモ

epgdump_bug00.png


今日は駅伝だかなんだかよく分かりませんけど、時間変更が頻繁に起きてた様で、んhkが間違った情報を流したのか、epgdumpがバグってこんなことになったのか分かりませんが、とりあえず、EPGrecのstoreProgram.inc.phpの135行目あたりを以下のようにstarttime>endtimeの場合例外を投げるようにしました。赤が追加部分です。
		// プログラム登録

try {
// $starttime > $endtime の例外処理
if( $starttime > $endtime ) {
throw new Exception("xmlデータで、番組開始時間より終了時間の方が早い番組をスルー");
}

//
$num = DBRecord::countRecords(PROGRAM_TBL, "WHERE program_disc = '".$program_disc."'" );

phpって型変換いらないんだったよね・・・
これで大丈夫かな?エラー出てくれないと確かめようがないですけど・・・

PageTop