private void tunerTimer_Tick(object sender, EventArgs arg) { if (!base.Visible) { return; } try { string[] str = new string[] { "(視聴)", "(録画)", "(録画一時停止)", "", "(応答なし)" }; IEnumerator enumerator = this.tunerView.Nodes.GetEnumerator(); try { while (enumerator.MoveNext()) { TreeNode node = (TreeNode)enumerator.Current; Tuner tuner = (Tuner)node.Tag; int state = 0; Task.Factory.StartNew(() => { state = (int)tuner.GetState(); }, TaskCreationOptions.AttachedToParent).ContinueWith((_) => { node.Text = "{0} {1}".Formatex(new object[] { tuner.Name, str[state] }); }, TaskScheduler.FromCurrentSynchronizationContext()); } } finally { IDisposable disposable = enumerator as IDisposable; if (disposable != null) { disposable.Dispose(); } } this.tunerView.Invalidate(); } catch (Exception ex) { Log.Write("エラーが発生しました。[詳細] " + ex.Message); Log.Write(1, ex.StackTrace); } }
//チューナ選択 private void tunerView_AfterSelect(object sender, TreeViewEventArgs arg) { try { curTuner = (Tuner)arg.Node.Tag; SetService(); serviceView.Refresh(); } catch (Exception e) { MessageBox.Show("エラーが発生しました。[詳細] " + e.Message); } }
private void tunerView_AfterSelect(object sender, TreeViewEventArgs arg) { try { this.curTuner = (Tuner)arg.Node.Tag; this.SetService(); this.serviceView.Refresh(); } catch (Exception ex) { Log.Write("エラーが発生しました。[詳細] " + ex.Message); Log.Write(1, ex.StackTrace); } }
//■ダミーTVTest起動&終了 void StartRec_pre(Sql sql, Record rec, Tuner tuner) { var result = new Result(); var tsStatus = new TsStatus(); try { Log.Write(tuner.Name + ": ダミーTVTestを起動します。" + rec.Title); SleepState.SetSleepStop(true); tuner.Open(); var service = new Service(sql, rec.Fsid); tuner.SetService(service); Thread.Sleep(1000 * 12); //12秒視聴 } catch (Exception e) { result.Code = 1; result.Message = e.Message; throw; } finally { try { if (tuner != null) { tuner.Close(); } } catch (Exception e) { Log.Write("ダミーTVTest終了中エラーが発生しました。[詳細] " + e.Message); TVTest_ForceStop(); //エラーが起こった場合は強制終了 } try { SleepState.SetSleepStop(false); } catch (Exception e) { Log.Write("ダミーTVTest終了中エラーが発生しました2。[詳細] " + e.Message); } Log.Write(tuner.Name + ": ダミーTVTestを終了しました。" + rec.Title); } }
private void InitTunerView() { this.sql.Text = "select * from tuner order by id"; using (DataTable table = this.sql.GetTable()) { while (table.Read()) { Tuner tuner = new Tuner(table); TreeNode treeNode = new TreeNode(tuner.Name); treeNode.Tag = tuner; this.tunerView.Nodes.Add(treeNode); } } this.tunerTimer.Enabled = true; }
//チューナ更新 public static void Update(Sql sql) { var def = new DefineFile(System.IO.Path.Combine(Util.GetUserPath(), "tuner.def")); def.Load(); sql.Text = "delete from tuner"; sql.Execute(); foreach (var name in def.Keys) { var tuner = new Tuner(name, def[name]); tuner.Add(sql); } }
//チューナーをセット private void InitTunerView() { sql.Text = "select * from tuner order by id"; using (DataTable table = sql.GetTable()) { while (table.Read()) { var tuner = new Tuner(table); var node = new TreeNode(tuner.Name); node.Tag = tuner; tunerView.Nodes.Add(node); } } tunerTimer.Enabled = true; }
//■ダミーTVTest 開始時間前に起動&終了するためのクエリ private Record GetEnableRecord_pre(Sql sql, Tuner tuner) { Record rec = null; int margin = Program.UserDef["record.margin.start"].ToInt() - 90; //90秒前 var now = DateTime.Now - new TimeSpan(0, 0, margin); sql.Text = @"select * from record where tuner = '{0}' and status & {2} and start <= {1} and end > {2} order by start limit 1" .Formatex(tuner.Name, now.Ticks, (int)Record.RecStatus.Enable); using (var t = sql.GetTable()) { if (t.Read()) { rec = new Record(t); } } return(rec); }
//開始時間が過ぎていて、終了前で、有効な予約を取得 private Record GetEnableRecord(Sql sql, Tuner tuner) { Record rec = null; //■削除 int margin = Program.UserDef["record.margin.start"].ToInt(); int margin = Program.UserDef["record.margin.start"].ToInt() - 15; //■追加 きっちり録画開始&1度のチャンネル変更失敗を吸収するため、録画開始15秒前に起動するようにした var now = DateTime.Now - new TimeSpan(0, 0, margin); sql.Text = @"select * from record where tuner = '{0}' and status & {2} and start <= {1} and end > {2} order by start limit 1" .Formatex(tuner.Name, now.Ticks, (int)Record.RecStatus.Enable); using (var t = sql.GetTable()) { if (t.Read()) { rec = new Record(t); } } return(rec); }
//チューナで使用可能なサービスを取り出す public Service Dequ(Tuner tuner) { lock (list) { if (list.Count == 0) { return(null); } //ドライバで検索 Service service = null; foreach (var s in list) { if (s.Driver == tuner.Driver) { service = s; break; } else if (s.Driver == tuner.DriverId) //番兵かどうか { //番兵を削除する list.RemoveAll(sv => sv.Driver == tuner.DriverId); break; } } //取り出したサービスをキューから削除 if (service != null) { //チューナが複数ある場合、同じサービスが複数含まれているためRemoveAll list.RemoveAll(s => s.Fsid == service.Fsid); } //削除の結果キューが0になったらスリープ抑止を解除 if (list.Count == 0) { SleepState.SetSleepStop(false); } return(service); } }
public static Record GetNextRecord(Tuner tuner, Sql sql) { int @int = MainDef.GetInstance().GetInt("record.margin.start"); DateTime dateTime = DateTime.Now + new TimeSpan(0, 0, @int); sql.Text = "select * from record where tuner = '{0}' and status & {2} and start <= {1} and end > {2} order by start limit 1".Formatex(new object[] { tuner.Name, dateTime.Ticks, 1 }); using (DataTable table = sql.GetTable()) { if (table.Read()) { return(new Record(table)); } } return(null); }
//キューにサービスリストを入れる public void Enqu() { lock (list) { if (list.Count > 0) { return; } SleepState.SetSleepStop(true); //スリープを抑止 using (var sql = new Sql(true)) { sql.Text = "select * from service id order by id"; using (var t = sql.GetTable()) { while (t.Read()) { list.Add(new Service(t)); } } //番兵をチューナ毎に入れる //番組表取得終了を確認するために使用(番兵が全て取り出されたら終了と判断) //Service.DriverにDriverIdを入れる sql.Text = "select * from tuner"; using (var t = sql.GetTable()) { while (t.Read()) { var tuner = new Tuner(t); var s = new Service(); s.Id = -1; s.Fsid = 0; s.Driver = tuner.DriverId; list.Add(s); } } } } }
private void RunTunerTask(Tuner tuner) { Sql sql = new Sql(true); while (!this.stop) { Record nextRecord = Record.GetNextRecord(tuner, sql); if (nextRecord != null) { new RecTask(tuner, nextRecord).Run(); } else if (this.epgQueue.Enable && this.epgQueue.Peek(tuner) != null) { new EpgTask(tuner, this.epgQueue).Run(); } else { Thread.Sleep(1000); } } }
public EpgTask(Tuner tuner, EpgQueue epgQueue) { this.tuner = tuner; this.epgQueue = epgQueue; }
public void Start() { using (var sql = new Sql(true)) { //チューナ毎のスレッドを起動 sql.Text = @"select * from tuner"; using (var t = sql.GetTable()) { while (t.Read()) { var tuner = new Tuner(t); TaskList.StartNew(StartThread, tuner); } } //番組表取得時間を初期化 nextEpgTime = DateTime.Now.Date; nextEpgTime = nextEpgTime.AddHours(Program.UserDef["epg.autoupdate.hour"].ToInt()); //メインループ //番組表取得、自動予約の監視 while (stop == false) { try { if (nextEpgTime <= DateTime.Now) { //古い予約と番組情報の削除 //先に予約を消すこと(予約に番組情報への参照があるため) ClearnRecord(sql); ClearnEvent(sql); //番組表取得1時間以内なら実行 if (nextEpgTime + TimeSpan.FromHours(1) >= DateTime.Now) { epg = true; } //次回を翌日にセット nextEpgTime = DateTime.Now.Date; nextEpgTime = nextEpgTime.AddDays(1); //翌日 nextEpgTime = nextEpgTime.AddHours(Program.UserDef["epg.autoupdate.hour"].ToInt()); } //番組表取得 if (epg) { epgQu.Enqu(); epg = false; } StartAutoRecord(sql); //自動予約 Thread.Sleep(mainSleep); } catch (Exception e) { Log.Write("エラーが発生しました。[詳細] " + e.Message); } } } }
//録画開始 void StartRec(Sql sql, Record rec, Tuner tuner, long retry_times) //修正 { var result = new Result(); var tsStatus = new TsStatus(); var recContinue = false; //録画継続フラグ(録画時間変更に使用) var path = ""; //■追加 try { //Log.Write(tuner.Name + ": 録画を開始します。" + rec.Title); //■削除 Log.Write(tuner.Name + ": 録画準備をしています。" + rec.Title); //■追加 SleepState.SetSleepStop(true); rec.SetRecoding(sql, true); //■メモ ここで今録画中だとフラグをセットしている tuner.Open(); var service = new Service(sql, rec.Fsid); tuner.SetService(service); //string file = ConvertFileMacro(rec, Program.UserDef["record.file"]); //■削除 string file = ConvertFileMacro(rec, Program.UserDef["record.file"], service.Name); //■追加 //var path = System.IO.Path.Combine(Program.UserDef["record.folder"], file); //■削除 path = System.IO.Path.Combine(Program.UserDef["record.folder"], file); //■追加 path = CheckFilePath(path); //■追加 きっちり時間が来るまで待機 int seconds_prev = Program.UserDef["record.margin.start"].ToInt(); while (DateTime.Now < rec.StartTime + new TimeSpan(0, 0, seconds_prev)) { Thread.Sleep(0); } Log.Write(tuner.Name + ": 録画を開始します。" + rec.Title); tuner.StartRec(path); result.Title = rec.Title; result.ServiceName = service.Name; result.File = Path.GetFileName(path); result.SchStart = rec.StartTime; result.SchEnd = rec.EndTime; result.Start = DateTime.Now; var eventTimeError = false; //番組時間取得エラーフラグ int margin = Program.UserDef["record.margin.end"].ToInt(); while (DateTime.Now < rec.EndTime + new TimeSpan(0, 0, margin)) { if (stop) { throw new AppException(tuner.Name + ": アプリケーション終了のため、録画を中断します。"); } //現在の予約が有効かどうか確認 sql.Text = "select status from record where id = " + rec.Id; object status = sql.GetData(); if (status == null) //予約が取り消された { throw new AppException(tuner.Name + ": 予約が取り消されたため、録画を中断します。"); } else if (((int)(long)status & (int)Record.RecStatus.Enable) == 0) //予約が無効にされた { throw new AppException(tuner.Name + ": 予約が無効にされたため、録画を中断します。"); } //追従モード if ((rec.Status & (int)Record.RecStatus.EventMode) > 0) { //番組の時間に変更がないか確認 Event ev = null; try { ev = tuner.GetEventTime(service, rec.Eid); eventTimeError = false; //エラーフラグをリセット } catch { if (eventTimeError == false) //何度もエラーが表示されないようにする { Log.Write(tuner.Name + ": 番組時間の取得に失敗しました。番組がなくなった可能性があります。録画は続行します。" + rec.Title); eventTimeError = true; } } if (ev != null) { if (ev.Start != rec.StartTime || ev.Duration != rec.Duration) { Log.Write(tuner.Name + ": 番組時間が変更されました。" + rec.Title); //予約を変更 rec.StartTime = ev.Start; rec.Duration = ev.Duration; tuner.GetEvents(sql, service); //番組表を更新する UpdateRecordTime(sql, service); //予約を更新 //番組開始が、現時刻より1分以上後に変更された場合、一旦録画を終了する if (rec.StartTime - DateTime.Now > TimeSpan.FromMinutes(1)) { recContinue = true; throw new AppException(tuner.Name + ": 番組の開始時間が遅れているため、録画を中断します。"); } } } } if (tuner.GetState() != Tuner.State.Recoding) { throw new AppException(tuner.Name + ": 録画が中断しました。"); } tsStatus = tuner.GetTsStatus(); Thread.Sleep(recSleep); } if (eventTimeError) { result.Code = 1; result.Message = "番組時間の取得に失敗しました。録画は続行しました。"; } } catch (Exception e) { result.Code = 1; result.Message = e.Message; throw; } finally { if (retry_times < 2 && result.Message.IndexOf("TVTestでエラーが発生しました。エラーコード: 6") >= 0) { //■チャンネル変更エラーで終了した場合(2回目まで) try { Log.Write(tuner.Name + ": チャンネル変更に失敗しました。リトライします。" + result.Message); //録画開始前の状態に戻す rec.SetRecoding(sql, false); //チューナーを閉じる try { if (tuner != null) { tuner.Close(); } } catch (Exception ex9) { Log.Write("チューナー終了中エラーが発生しました(6)。[詳細] " + ex9.Message); TVTest_ForceStop(); //強制終了 } SleepState.SetSleepStop(false); } catch (Exception e) { Log.Write("チャンネル変更失敗時のエラー処理中にエラーが発生しました。[詳細] " + e.Message); } } else { //■修正 録画を終了させる try { if (tuner != null) { tuner.StopRec(); //■削除 tuner.Close(); } } catch (Exception e) { Log.Write("録画終了中エラーが発生しました。[詳細] " + e.Message); } //■追加 チューナーを閉じる try { if (tuner != null) { tuner.Close(); } } catch (Exception ex9) { Log.Write("チューナー終了中エラーが発生しました。[詳細] " + ex9.Message); TVTest_ForceStop(); //強制終了 } try { if (recContinue) { rec.SetRecoding(sql, false); //■メモ 前番組の延長により放送時間が変更になった場合 } else { rec.SetComplete(sql); } SleepState.SetSleepStop(false); result.Error = tsStatus.Error; result.Drop = tsStatus.Drop; result.Scramble = tsStatus.Scramble; result.End = DateTime.Now; result.Add(sql); } catch (Exception e) { Log.Write("録画終了中エラーが発生しました。[詳細] " + e.Message); } Log.Write(tuner.Name + ": 録画が終了しました。" + rec.Title); } } //■録画後処理 録画が正常終了した場合のみ実行される try { if (Program.UserDef["exe1"].Length > 0) { Thread.Sleep(rec.Title.Length); //少々ばらつきを持たせるか・・ Thread t = new Thread(new ParameterizedThreadStart(Execute_exe)); string path2 = Path.GetDirectoryName(path); if (path2.Length > 0) { path2 = path2 + "\\"; } t.Start(path2 + result.File); } } catch { //実行するコマンドが無い。Program.UserDef["exe1"]が存在しなかった } }
public RecTask(Tuner tuner, Record record) { this.tuner = tuner; this.record = record; }
static void UpdateTuner() { try { using (var sql = new Sql(true)) { Log.Write("チューナを更新しています..."); Tuner.Update(sql); //チューナ更新(DB更新) //サービス更新 Log.Write("サービスを更新しています..."); sql.Text = "delete from service"; sql.Execute(); var tuners = new List <Tuner>(); sql.Text = "select * from tuner group by driver "; using (var table = sql.GetTable()) { while (table.Read()) { tuners.Add(new Tuner(table)); } } bool dup = false; foreach (Tuner tuner in tuners) { try { tuner.GetServices(sql); //サービスをTVTestから読み込み } catch (DupServiceException) { dup = true; } } //以前から残っている番組で、新しくなったサービスにないものは削除する sql.Text = "delete from event where fsid not in (select fsid from service group by fsid)"; sql.Execute(); //同ユーザ番組表 sql.Text = "delete from user_epg where fsid not in (select fsid from service group by fsid)"; sql.Execute(); //同予約 sql.Text = "delete from record where fsid not in (select fsid from service group by fsid)"; sql.Execute(); //予約でチューナがないものは削除 sql.Text = "delete from record where tuner not in (select name from tuner)"; sql.Execute(); if (dup) { MessageBox.Show("サービスが重複しています。\nこのままでも使用できますが、TVTestのチャンネルスキャンで同じ放送局を1つを残して他は無効(チェックを外す)にすることをおすすめします。", Program.Logo); } } Log.Write("チューナ更新が完了しました。"); } catch (Exception e) { MessageBox.Show("チューナの読み込みに失敗しました。[詳細]" + e.Message, Program.Logo); throw; } }
//予約追加 public void Add(Sql sql) { if (this.EndTime < DateTime.Now) { throw new AppException("過去の番組は予約できません。"); } bool newId = this.Id == -1; //チューナが指定されているか? if (TunerName != "") { var tuner = new Tuner(sql, TunerName); //チューナが不正でないか作成してみる sql.Text = "select id from service where driver = '{0}' and fsid = {1}".Formatex(Sql.SqlEncode(tuner.Driver), this.Fsid); using (var t = sql.GetTable()) { if (t.Read() == false) { throw new AppException("指定されたチューナに、サービスがありません。チューナを変更してください。"); } } AddDb(sql); } else { //空きを探して予約する var list = new List <Tuner>(); //チューナを列挙 sql.Text = "select * from tuner where driver in (select driver from service where fsid = {0}) order by id".Formatex(Fsid); using (var table = sql.GetTable()) { while (table.Read()) { list.Add(new Tuner(table)); } } if (list.Count == 0) { throw new AppException("チューナが見つかりません。"); } foreach (var tuner in list) { if (IsReserved(sql, tuner.Name, StartTime, EndTime)) { TunerName = tuner.Name; break; } } //空きが見つからなかった if (TunerName == "") { TunerName = list[0].Name; } AddDb(sql); } if (newId) { Log.Write("予約しました。" + this.Title); } else { Log.Write("予約を変更しました。" + this.Title); } }