// Spludlow Software
// Copyright © Samuel P. Ludlow 2020 All Rights Reserved
// Distributed under the terms of the GNU General Public License version 3
// Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
// https://www.spludlow.co.uk/LICENCE.TXT
// The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission
// v1.14
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
namespace Spludlow.Video
{
///
/// Very simple PVR demo
///
/// Call SubmitRecording() method, it will drop a file
///
/// The "Run" method will pick up dropped files & start VLC recording for a specific duration when required.
///
/// Ensure "Run" thead is running (line in Spludlow-Service.txt)
/// Method VideoRecorder Spludlow Spludlow.Video.Recorder Run
///
/// Make sure config set: "VideoRecorder.Directory" and have permissions to directory
///
public class Recorder
{
private string RecordDirectory;
private string SubmitDirectory;
private string ScheduleFilename;
private int TickMilliSeconds = 10 * 1000;
public DataTable Schedule;
public Recorder()
{
this.Load(false);
}
public Recorder(bool dontLoad)
{
this.Load(dontLoad);
}
public DataTable NewScheduleTable()
{
return Spludlow.Data.TextTable.ReadText(new string[]
{
"Number StartTime EndTime Filename Frequency ServiceId",
"Int32* DateTime* DateTime String Int32 Int32",
});
}
public void Load(bool dontLoad)
{
this.RecordDirectory = Spludlow.Config.Get("VideoRecorder.Directory");
this.SubmitDirectory = this.RecordDirectory + @"\Submit";
this.ScheduleFilename = this.RecordDirectory + @"\Schedule.txt";
if (dontLoad == true)
return;
if (Directory.Exists(this.RecordDirectory) == false)
Directory.CreateDirectory(this.RecordDirectory);
if (Directory.Exists(this.SubmitDirectory) == false)
Directory.CreateDirectory(this.SubmitDirectory);
if (File.Exists(this.ScheduleFilename) == false)
{
this.Schedule = this.NewScheduleTable();
Spludlow.Data.TextTable.Write(this.ScheduleFilename, this.Schedule);
}
this.Schedule = Spludlow.Data.TextTable.ReadFile(this.ScheduleFilename);
}
public void SubmitRecording(DataRow channel, DataRow programme)
{
int channelNumber = (int)channel["Number"];
DateTime startTime = (DateTime)programme["StartDate"];
DateTime endTime = (DateTime)programme["EndDate"];
string channelName = (string)channel["Name"];
string programmeTitle = (string)programme["Title"];
int frequency = (int)channel["Frequency"];
int serviceId = (int)channel["ServiceId"];
this.SubmitRecording(channelNumber, startTime, endTime, channelName, programmeTitle, frequency, serviceId);
}
public void SubmitRecording(int channelNumber, DateTime startTime, DateTime endTime, string channelName, string programmeTitle, int frequency, int serviceId)
{
startTime = TruncateToMinutes(startTime);
channelName = FixName(channelName);
programmeTitle = FixName(programmeTitle);
StringBuilder text = new StringBuilder();
text.Append(startTime.ToString("yyyy-MM-dd_HH-mm"));
text.Append("_");
text.Append(channelNumber);
text.Append("_");
text.Append(Spludlow.Io.Paths.LegalFileName(channelName));
text.Append("_");
text.Append(Spludlow.Io.Paths.LegalFileName(programmeTitle));
string filename = text.ToString();
DataTable table = this.NewScheduleTable();
table.Rows.Add(new object[] { channelNumber, startTime, endTime, filename, frequency, serviceId });
Spludlow.Data.TextTable.Write(this.SubmitDirectory + @"\" + filename + ".txt", table);
}
private static string FixName(string name)
{
name = name.Replace('\'', '_');
name = name.Replace('"', '_');
return name;
}
private System.Threading.EventWaitHandle WaitFinished = null;
public void Run()
{
this.WaitFinished = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset);
Spludlow.Log.Report("VideoRecorder; Starting", new object[] { this.Schedule });
while (this.WaitFinished.WaitOne(this.TickMilliSeconds) == false)
{
int changes = 0;
changes += this.CheckSubmit();
changes += this.CheckSchedule();
if (changes > 0)
{
Spludlow.Data.TextTable.Write(this.ScheduleFilename, this.Schedule);
Spludlow.Log.Info("VideoRecorder; Changes:\t" + changes, new object[] { this.Schedule });
}
}
Spludlow.Log.Finish("VideoRecorder; Clean Exit", new object[] { this.Schedule });
}
public void Stop()
{
this.WaitFinished.Set();
}
private int CheckSubmit()
{
int changeCount = 0;
foreach (string filename in Directory.GetFiles(this.SubmitDirectory, "*.txt"))
{
if (Spludlow.Io.Files.IsOpen(filename) == true)
continue;
DataTable importTable = Spludlow.Data.TextTable.ReadFile(filename);
foreach (DataRow row in importTable.Rows)
{
this.Schedule.ImportRow(row);
Spludlow.Log.Info("VideoRecorder; Import Recording:\t" + (string)row["Filename"]);
++changeCount;
}
File.Delete(filename);
}
return changeCount;
}
private int CheckSchedule()
{
DateTime nowTime = TruncateToMinutes(DateTime.Now);
List removeList = new List();
foreach (DataRow row in this.Schedule.Rows)
{
DateTime startTime = (DateTime)row["StartTime"];
DateTime endTime = (DateTime)row["EndTime"];
if (nowTime >= startTime)
{
string filename = (string)row["Filename"];
int durationMinutes = (int)(endTime - nowTime).TotalMinutes;
if (nowTime < endTime && durationMinutes > 0)
{
int frequency = (int)row["Frequency"];
int serviceId = (int)row["ServiceId"];
filename = this.RecordDirectory + @"\" + filename + ".ts";
Spludlow.VLC.StartRecording(filename, durationMinutes * 60, frequency, serviceId);
Spludlow.Log.Report("VideoRecorder; Started Recording:\t" + filename);
}
else
{
Spludlow.Log.Warning("VideoRecorder; Missed Recording:\t" + filename);
}
removeList.Add(row);
}
}
foreach (DataRow row in removeList)
row.Delete();
this.Schedule.AcceptChanges();
return removeList.Count;
}
public static DateTime TruncateToMinutes(DateTime dateTime)
{
return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, 0);
}
}
}