Пример #1
0
        //Does a dryrun using keywords.json - showing what it *would* do, but not actually doing it
        public void DryRun()
        {
            //Create channel history object
            ChannelHistory channelHistory = new ChannelHistory();

            //Grab schedule
            Schedule schedule = new Schedule();

            schedule.LoadSchedule(configuration["scheduleURL"], configuration["debug"]).Wait();
            scheduleShowList = schedule.GetScheduledShows();

            //Grabs schedule and builds a recording list based on keywords
            List <RecordInfo> recordInfoList = recordings.BuildRecordSchedule(scheduleShowList);

            //Send digest
            new Mailer().SendDailyDigest(configuration, recordings);

            //Go through record list and display
            foreach (RecordInfo recordInfo in recordInfoList)
            {
                //Create servers object
                Servers servers = new Servers(configuration["ServerList"]);

                //Create the server/channel selector object
                ServerChannelSelector scs = new ServerChannelSelector(new StreamWriter(Console.OpenStandardOutput()), channelHistory, servers, recordInfo);
            }
            Thread.Sleep(3000);
        }
Пример #2
0
        //Does a dryrun using keywords.json - showing what it *would* do, but not actually doing it
        public void DryRun()
        {
            //Create new recordings object to manage our recordings
            Recordings recordings = new Recordings(configuration);

            //Create channel history object
            ChannelHistory channelHistory = new ChannelHistory();

            //Grabs schedule and builds a recording list based on keywords
            List <RecordInfo> recordInfoList = recordings.BuildRecordSchedule();

            //Go through record list and display
            foreach (RecordInfo recordInfo in recordInfoList)
            {
                //Dump record info
                DumpRecordInfo(Console.Out, recordInfo);

                //Create servers object
                Servers servers = new Servers(configuration["ServerList"]);

                //Create the server/channel selector object
                ServerChannelSelector scs = new ServerChannelSelector(new StreamWriter(Console.OpenStandardOutput()), channelHistory, servers, recordInfo);
            }

            Thread.Sleep(3000);
        }
Пример #3
0
        public ServerChannelSelector(TextWriter _l, ChannelHistory _ch, Servers _s, RecordInfo _ri)
        {
            logWriter     = _l;
            channeHistory = _ch;
            servers       = _s;
            recordInfo    = _ri;

            //Let's build our sorted list now
            BuildSortedTupleList();
        }
Пример #4
0
        public static void Main(string[] args)
        {
            CommandLineApplication commandLineApplication = new CommandLineApplication(throwOnUnexpectedArg: false);
            CommandOption          channels = commandLineApplication.Option("-c | --channels", "Channels to record in the format nn+nn+nn (must be 2 digits)", CommandOptionType.SingleValue);
            CommandOption          duration = commandLineApplication.Option("-d | --duration", "Duration in minutes to record", CommandOptionType.SingleValue);
            CommandOption          filename = commandLineApplication.Option("-f | --filename", "File name (no extension)", CommandOptionType.SingleValue);
            CommandOption          datetime = commandLineApplication.Option("-d | --datetime", "Datetime MM/DD/YY HH:MM (optional)", CommandOptionType.SingleValue);
            CommandOption          test     = commandLineApplication.Option("-t | --test", "Does a dryrun based on keywords.json (optional)", CommandOptionType.SingleValue);

            commandLineApplication.HelpOption("-? | -h | --help");
            commandLineApplication.Execute(args);

            //Welcome message
            Console.WriteLine($"{DateTime.Now}: StreamCapture Version 0.99  2/12/2017");

            //Read and build config
            var builder       = new ConfigurationBuilder().AddJsonFile("appsettings.json");
            var configuration = builder.Build();

            VerifyAppsettings(configuration);

            //do we have optional args passed in?
            bool optionalArgsFlag = false;

            if (channels.HasValue() || duration.HasValue() || filename.HasValue())
            {
                VerifyCommandLineParams(channels, duration, filename, datetime);
                optionalArgsFlag = true;
            }
            else
            {
                Console.WriteLine($"{DateTime.Now}: Using keywords.json to search schedule. (Please run with --help if you're confused)");
                Console.WriteLine($"=======================");
            }

            //Use optional parameters to record are passed in
            if (optionalArgsFlag)
            {
                //Create new RecordInfo
                RecordInfo recordInfo = new RecordInfo();
                recordInfo.channels.LoadChannels(channels.Value());
                recordInfo.strDuration = duration.Value();
                recordInfo.strStartDT  = datetime.Value();
                recordInfo.fileName    = filename.Value();

                //Record a single show and then quit
                ChannelHistory channelHistory = new ChannelHistory();
                Recorder       recorder       = new Recorder(configuration);
                recorder.QueueRecording(channelHistory, recordInfo, configuration, false);
                Environment.Exit(0);
            }
            else if (test.HasValue())
            {
                //grab schedule and do a dryrun based on keywords.json to see what would happen, but don't actually do it
                Recorder recorder = new Recorder(configuration);
                recorder.DryRun();
                Environment.Exit(0);
            }
            else
            {
                //Monitor schedule and spawn capture sessions as needed
                Recorder recorder = new Recorder(configuration);
                recorder.MonitorMode();
            }
        }
Пример #5
0
        //A key member function (along with BuildRecordSchedule) which does the bulk of the work
        //
        //I'll be a bit more verbose then usual so I can remember later what I was thinking
        private void CaptureStream(TextWriter logWriter, string hashValue, ChannelHistory channelHistory, RecordInfo recordInfo, VideoFileManager videoFileManager)
        {
            //Process manager for ffmpeg
            //
            //This is there ffmpeg is called, and a watchdog timer created to make sure things are going ok
            ProcessManager processManager = new ProcessManager(configuration);

            //Test internet connection and get a baseline
            //Right now, the baseline is not used for anything other than a number in the logs.
            //This could be taken out...
            long internetSpeed = TestInternet(logWriter);

            //Create servers object
            //This is the list of live247 servers we'll use to cycle through, finding the best quality stream
            Servers servers = new Servers(configuration["ServerList"]);

            //Create the server/channel selector object
            //
            //This object is what uses the heurstics to determine the right server/channel combo to use.
            //Factors like language, quality, and rate factor in.
            ServerChannelSelector scs = new ServerChannelSelector(logWriter, channelHistory, servers, recordInfo);

            //Marking time we started and when we should be done
            DateTime captureStarted   = DateTime.Now;
            DateTime captureTargetEnd = recordInfo.GetStartDT().AddMinutes(recordInfo.GetDuration());

            if (!string.IsNullOrEmpty(configuration["debug"]))
            {
                captureTargetEnd = DateTime.Now.AddMinutes(1);
            }
            DateTime lastStartedTime = captureStarted;
            TimeSpan duration        = (captureTargetEnd.AddMinutes(1)) - captureStarted; //the 1 minute takes care of alignment slop

            //Update capture history
            //This saves to channelhistory.json file and is used to help determine the initial order of server/channel combos
            channelHistory.GetChannelHistoryInfo(scs.GetChannelNumber()).recordingsAttempted += 1;
            channelHistory.GetChannelHistoryInfo(scs.GetChannelNumber()).lastAttempt          = DateTime.Now;

            //Build output file - the resulting capture file.
            //See VideoFileManager for specifics around file management (e.g. there can be multiple if errors are encountered etc)
            VideoFileInfo videoFileInfo = videoFileManager.AddCaptureFile(configuration["outputPath"]);

            //Email that show started
            if (recordInfo.emailFlag)
            {
                new Mailer().SendShowStartedMail(configuration, recordInfo);
            }

            //Build ffmpeg capture command line with first channel and get things rolling
            string cmdLineArgs = BuildCaptureCmdLineArgs(scs.GetServerName(), scs.GetChannelNumber(), hashValue, videoFileInfo.GetFullFile());

            logWriter.WriteLine($"=========================================");
            logWriter.WriteLine($"{DateTime.Now}: Starting {captureStarted} on server/channel {scs.GetServerName()}/{scs.GetChannelNumber()}.  Expect to be done by {captureTargetEnd}.");
            logWriter.WriteLine($"                      {configuration["ffmpegPath"]} {cmdLineArgs}");
            CaptureProcessInfo captureProcessInfo = processManager.ExecProcess(logWriter, configuration["ffmpegPath"], cmdLineArgs, (int)duration.TotalMinutes, videoFileInfo.GetFullFile(), recordInfo.cancellationToken, scs.IsBestSelected());

            logWriter.WriteLine($"{DateTime.Now}: Exited Capture.  Exit Code: {captureProcessInfo.process.ExitCode}");

            //Main loop to capture
            //
            //This loop is never entered if the first capture section completes without incident.  However, it is not uncommon
            //for errors to occur, and this loop takes care of determining the right next server/channel combo
            //as well as making sure that we don't just try forever.
            int numRetries = Convert.ToInt32(configuration["numberOfRetries"]);
            int retryNum   = 0;

            for (retryNum = 0; DateTime.Now <= captureTargetEnd && retryNum < numRetries && !recordInfo.cancelledFlag; retryNum++)
            {
                logWriter.WriteLine($"{DateTime.Now}: Capture Failed for server/channel {scs.GetServerName()}/{scs.GetChannelNumber()}. Retry {retryNum+1} of {configuration["numberOfRetries"]}");

                //Let's make sure the interwebs are still there.  If not, let's loop until they come back or the show ends.
                while (!IsInternetOk() && DateTime.Now <= captureTargetEnd)
                {
                    bool logFlag = false;
                    if (!logFlag)
                    {
                        logWriter.WriteLine($"{DateTime.Now}: Interwebs are down.  Checking every minute until back or show ends");
                    }
                    TimeSpan oneMinute = new TimeSpan(0, 1, 0);
                    Thread.Sleep(oneMinute);
                }

                //Check to see if we need to re-authenticate  (most tokens have a lifespan)
                int authMinutes = Convert.ToInt16(configuration["authMinutes"]);
                if (DateTime.Now > captureStarted.AddMinutes(authMinutes))
                {
                    logWriter.WriteLine($"{DateTime.Now}: It's been more than {authMinutes} authMinutes.  Time to re-authenticate");
                    Task <string> authTask = Authenticate();
                    hashValue = authTask.Result;
                    if (string.IsNullOrEmpty(hashValue))
                    {
                        Console.WriteLine($"{DateTime.Now}: ERROR: Unable to authenticate.  Check username and password?");
                        throw new Exception("Unable to authenticate during a retry");
                    }
                }

                //Log avg streaming rate for channel history
                logWriter.WriteLine($"{DateTime.Now}: Avg rate is {captureProcessInfo.avgKBytesSec}KB/s for {scs.GetServerName()}/{scs.GetChannelNumber()}");

                //Set new avg streaming rate for channel history
                channelHistory.SetServerAvgKBytesSec(scs.GetChannelNumber(), scs.GetServerName(), captureProcessInfo.avgKBytesSec);

                //Go to next channel if channel has been alive for less than 15 minutes
                //The idea is that if a server/channel has been stable for at least 15 minutes, no sense trying to find another.  (could make it worse)
                TimeSpan fifteenMin = new TimeSpan(0, 15, 0);
                if ((DateTime.Now - lastStartedTime) < fifteenMin)
                {
                    //Set rate for current server/channel pair
                    scs.SetAvgKBytesSec(captureProcessInfo.avgKBytesSec);

                    //Get correct server and channel (determined by heuristics)
                    if (!scs.IsBestSelected())
                    {
                        scs.GetNextServerChannel();
                        retryNum = -1; //reset retries since we haven't got through the server/channel list yet
                    }
                }
                else
                {
                    retryNum = -1; //reset retries since it's been more than 15 minutes
                }

                //Set new started time and calc new timer
                TimeSpan timeJustRecorded = DateTime.Now - lastStartedTime;
                lastStartedTime = DateTime.Now;
                TimeSpan timeLeft = captureTargetEnd - DateTime.Now;

                //Update channel history
                channelHistory.GetChannelHistoryInfo(scs.GetChannelNumber()).hoursRecorded       += timeJustRecorded.TotalHours;
                channelHistory.GetChannelHistoryInfo(scs.GetChannelNumber()).recordingsAttempted += 1;
                channelHistory.GetChannelHistoryInfo(scs.GetChannelNumber()).lastAttempt          = DateTime.Now;

                //Build output file
                videoFileInfo = videoFileManager.AddCaptureFile(configuration["outputPath"]);

                //Now get capture setup and going again
                cmdLineArgs = BuildCaptureCmdLineArgs(scs.GetServerName(), scs.GetChannelNumber(), hashValue, videoFileInfo.GetFullFile());
                logWriter.WriteLine($"{DateTime.Now}: Starting Capture (again) on server/channel {scs.GetServerName()}/{scs.GetChannelNumber()}");
                logWriter.WriteLine($"                      {configuration["ffmpegPath"]} {cmdLineArgs}");
                captureProcessInfo = processManager.ExecProcess(logWriter, configuration["ffmpegPath"], cmdLineArgs, (int)timeLeft.TotalMinutes + 1, videoFileInfo.GetFullFile(), recordInfo.cancellationToken, scs.IsBestSelected());
            }
            recordInfo.completedFlag = true;
            logWriter.WriteLine($"{DateTime.Now}: Done Capturing Stream.");

            //Update capture history and save
            TimeSpan finalTimeJustRecorded = DateTime.Now - lastStartedTime;

            channelHistory.GetChannelHistoryInfo(scs.GetChannelNumber()).hoursRecorded += finalTimeJustRecorded.TotalHours;
            channelHistory.GetChannelHistoryInfo(scs.GetChannelNumber()).lastSuccess    = DateTime.Now;
            channelHistory.SetServerAvgKBytesSec(scs.GetChannelNumber(), scs.GetServerName(), captureProcessInfo.avgKBytesSec);
            channelHistory.Save();

            //check if actually done and didn't error out early
            //We assume too many retries as that's really the only way out of the loop (outside of an exception which is caught elsewhere)
            if (DateTime.Now < captureTargetEnd)
            {
                if (recordInfo.cancelledFlag)
                {
                    logWriter.WriteLine($"{DateTime.Now}: Cancelled {recordInfo.description}");
                }
                else
                {
                    logWriter.WriteLine($"{DateTime.Now}: ERROR!  Too many retries - {recordInfo.description}");
                }

                //set partial flag
                recordInfo.partialFlag = true;

                //Send alert mail
                string body = recordInfo.description + " partially recorded due to too many retries or cancellation.  Time actually recorded is " + finalTimeJustRecorded.TotalHours;
                new Mailer().SendErrorMail(configuration, "Partial: " + recordInfo.description, body);
            }
        }
Пример #6
0
        public void QueueRecording(ChannelHistory channelHistory, RecordInfo recordInfo, IConfiguration configuration, bool useLogFlag)
        {
            //Write to our very own log as there might be other captures going too
            StreamWriter logWriter = new StreamWriter(Console.OpenStandardOutput());

            if (useLogFlag)
            {
                string     logPath    = Path.Combine(configuration["logPath"], recordInfo.fileName + "Log.txt");
                FileStream fileHandle = new FileStream(logPath, FileMode.OpenOrCreate, FileAccess.Write);
                logWriter = new StreamWriter(fileHandle);
            }
            logWriter.AutoFlush = true;

            //try-catch so we don't crash the whole thing
            try
            {
                //Dump
                logWriter.WriteLine($"{DateTime.Now}: Queuing show: {recordInfo.description} Starting on {recordInfo.GetStartDT()} for {recordInfo.GetDuration()} minutes ({recordInfo.GetDuration() / 60}hrs ish)");

                //Wait here until we're ready to start recording
                if (recordInfo.strStartDT != null)
                {
                    TimeSpan oneHour    = new TimeSpan(1, 0, 0);
                    DateTime recStart   = recordInfo.GetStartDT();
                    TimeSpan timeToWait = recStart - DateTime.Now;
                    logWriter.WriteLine($"{DateTime.Now}: Starting recording at {recStart} - Waiting for {timeToWait.Days} Days, {timeToWait.Hours} Hours, and {timeToWait.Minutes} minutes.");

                    while (timeToWait.Seconds >= 0 && DateTime.Now < recStart && !recordInfo.cancelledFlag)
                    {
                        if (timeToWait > oneHour)
                        {
                            timeToWait = oneHour;
                        }

                        if (timeToWait.Seconds >= 0)
                        {
                            recordInfo.mre.WaitOne(timeToWait);
                            mre.Reset();
                            logWriter.WriteLine($"{DateTime.Now}: Waking up to check...");
                        }

                        timeToWait = recStart - DateTime.Now;
                    }

                    if (recordInfo.cancelledFlag)
                    {
                        logWriter.WriteLine($"{DateTime.Now}: Cancelling due to request");
                        recordInfo.queuedFlag         = false;
                        recordInfo.processSpawnedFlag = false;
                        return;
                    }
                }

                //Authenticate
                Task <string> authTask  = Authenticate();
                string        hashValue = authTask.Result;
                if (string.IsNullOrEmpty(hashValue))
                {
                    Console.WriteLine($"ERROR: Unable to authenticate.  Check username and password?");
                    Environment.Exit(1);
                }

                //Get latest channels (Channels may have changed since the show was queued.  Exception is thrown if time has changed, or no longer there)
                logWriter.WriteLine($"{DateTime.Now}: Grabbing latest channels");
                new Schedule().RefreshChannelList(configuration, recordInfo);

                //We need to manage our resulting files
                VideoFileManager videoFileManager = new VideoFileManager(configuration, logWriter, recordInfo.fileName);

                //Set capture started flag
                recordInfo.captureStartedFlag = true;

                //Capture stream
                CaptureStream(logWriter, hashValue, channelHistory, recordInfo, videoFileManager);

                //Let's take care of processing and publishing the video files
                videoFileManager.ConcatFiles();
                videoFileManager.MuxFile(recordInfo.description);
                videoFileManager.PublishAndCleanUpAfterCapture(recordInfo.category, recordInfo.preMinutes);

                //Cleanup
                logWriter.WriteLine($"{DateTime.Now}: Done Capturing");
                logWriter.Dispose();

                //Send alert mail
                if (recordInfo.emailFlag)
                {
                    new Mailer().SendShowReadyMail(configuration, recordInfo);
                }
            }
            catch (Exception e)
            {
                logWriter.WriteLine("======================");
                logWriter.WriteLine($"{DateTime.Now}: ERROR - Exception!");
                logWriter.WriteLine("======================");
                logWriter.WriteLine($"{e.Message}\n{e.StackTrace}");

                //Send alert mail
                string body = recordInfo.description + " failed with Exception " + e.Message;
                body = body + "\n" + e.StackTrace;
                new Mailer().SendErrorMail(configuration, "StreamCapture Exception! (" + e.Message + ")", body);
            }
        }
Пример #7
0
        public void MonitorMode()
        {
            //Create new recordings object to manage our recordings
            //Recordings recordings = new Recordings(configuration,mre);

            //Start web server
            StartWebServer();

            //Create channel history object
            ChannelHistory channelHistory = new ChannelHistory();

            try
            {
                //Grab schedule from interwebs and loop forever, checking every n hours for new shows to record
                while (true)
                {
                    //Refresh schedule from website
                    //
                    // This goes and grabs the online .json file which is the current schedule from Live247
                    // This list is *all* the shows currently posted.  Usually, live247 only posts a day or two at a time.
                    Schedule schedule = new Schedule();
                    schedule.LoadSchedule(configuration["scheduleURL"], configuration["debug"]).Wait();
                    scheduleShowList = schedule.GetScheduledShows();

                    //Grabs schedule and builds a recording list based on keywords
                    List <RecordInfo> recordInfoList = recordings.BuildRecordSchedule(scheduleShowList);

                    //Time to mail the daily digest and clean up master list (but only if it's the first hour on the hour list)
                    string[] times = configuration["scheduleCheck"].Split(',');
                    if (DateTime.Now.Hour == Convert.ToInt16(times[0]))
                    {
                        new Mailer().SendDailyDigest(configuration, recordings);
                        recordings.CleanupOldShows();
                    }

                    //Go through record list, spawn a new process for each show found
                    foreach (RecordInfo recordInfo in recordInfoList)
                    {
                        //If show is not already spawend and cancelled, let's go!
                        if (!recordInfo.processSpawnedFlag && !recordInfo.cancelledFlag)
                        {
                            recordInfo.processSpawnedFlag = true;

                            recordInfo.mre = new ManualResetEvent(false);
                            recordInfo.cancellationTokenSource = new CancellationTokenSource();
                            recordInfo.cancellationToken       = recordInfo.cancellationTokenSource.Token;

                            // Queue show to be recorded now
                            Task.Factory.StartNew(() => QueueRecording(channelHistory, recordInfo, configuration, true), recordInfo.cancellationToken);
                        }
                    }

                    //Determine how long to sleep before next check
                    DateTime nextRecord = DateTime.Now;

                    //find out if schedule time is still today
                    if (DateTime.Now.Hour < Convert.ToInt16(times[times.Length - 1]))
                    {
                        for (int i = 0; i < times.Length; i++)
                        {
                            int recHour = Convert.ToInt16(times[i]);
                            if (DateTime.Now.Hour < recHour)
                            {
                                nextRecord = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, recHour, 0, 0, 0, DateTime.Now.Kind);
                                break;
                            }
                        }
                    }
                    else
                    {
                        //build date tomorrow
                        int recHour = Convert.ToInt16(times[0]);  //grab first time in the list
                        nextRecord = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, recHour, 0, 0, 0, DateTime.Now.Kind);
                        nextRecord = nextRecord.AddDays(1);
                    }

                    //Since we're awake, let's see if there are any files needing cleaning up
                    VideoFileManager.CleanOldFiles(configuration);

                    //Wait
                    TimeSpan timeToWait = new TimeSpan(0, 1, 0);
                    if (nextRecord > DateTime.Now)
                    {
                        timeToWait = nextRecord - DateTime.Now;
                    }
                    Console.WriteLine($"{DateTime.Now}: Now sleeping for {timeToWait.Hours+1} hours before checking again at {nextRecord.ToString()}");
                    mre.WaitOne(timeToWait);
                    mre.Reset();
                    Console.WriteLine($"{DateTime.Now}: Woke up, now checking again...");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("======================");
                Console.WriteLine($"{DateTime.Now}: ERROR - Exception!");
                Console.WriteLine("======================");
                Console.WriteLine($"{e.Message}\n{e.StackTrace}");

                //Send alert mail
                string body = "NO LONGER RECORDING!  Main loop failed with Exception " + e.Message;
                body = body + "\n" + e.StackTrace;
                new Mailer().SendErrorMail(configuration, "NO LONGER RECORDING!  StreamCapture Exception: (" + e.Message + ")", body);
            }
        }
Пример #8
0
        public void MonitorMode()
        {
            //Create new recordings object to manage our recordings
            Recordings recordings = new Recordings(configuration);

            //Create channel history object
            ChannelHistory channelHistory = new ChannelHistory();

            try
            {
                //Grab schedule from interwebs and loop forever, checking every n hours for new shows to record
                while (true)
                {
                    //Grabs schedule and builds a recording list based on keywords
                    List <RecordInfo> recordInfoList = recordings.BuildRecordSchedule();

                    //Go through record list, spawn a new process for each show found
                    foreach (RecordInfo recordInfo in recordInfoList)
                    {
                        //If show is not already queued, let's go!
                        bool showQueued = recordInfo.processSpawnedFlag;
                        if (!showQueued)
                        {
                            recordInfo.processSpawnedFlag = true;
                            DumpRecordInfo(Console.Out, recordInfo);

                            // Queue show to be recorded now
                            Task.Factory.StartNew(() => QueueRecording(channelHistory, recordInfo, configuration, true));
                        }
                    }

                    //Determine how long to sleep before next check
                    string[] times      = configuration["scheduleCheck"].Split(',');
                    DateTime nextRecord = DateTime.Now;

                    //find out if schedule time is still today
                    if (DateTime.Now.Hour < Convert.ToInt32(times[times.Length - 1]))
                    {
                        for (int i = 0; i < times.Length; i++)
                        {
                            int recHour = Convert.ToInt32(times[i]);
                            if (DateTime.Now.AddMinutes(10).Hour < recHour)  //add fudge factor for bad timers
                            {
                                nextRecord = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, recHour, 0, 0, 0, DateTime.Now.Kind);
                                break;
                            }
                        }
                    }
                    else
                    {
                        //build date tomorrow
                        int recHour = Convert.ToInt32(times[0]);  //grab first time in the list
                        nextRecord = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, recHour, 0, 0, 0, DateTime.Now.Kind);
                        nextRecord = nextRecord.AddDays(1);
                    }

                    //Since we're awake, let's see if there are any files needing cleaning up
                    VideoFileManager.CleanOldFiles(configuration);

                    //Wait
                    TimeSpan timeToWait = nextRecord - DateTime.Now;
                    Console.WriteLine($"{DateTime.Now}: Now sleeping for {timeToWait.Hours+1} hours before checking again at {nextRecord.ToString()}");
                    Thread.Sleep(timeToWait);
                    Console.WriteLine($"{DateTime.Now}: Woke up, now checking again...");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("======================");
                Console.WriteLine($"{DateTime.Now}: ERROR - Exception!");
                Console.WriteLine("======================");
                Console.WriteLine($"{e.Message}\n{e.StackTrace}");

                //Send alert mail
                string body = "NO LONGER RECORDING!  Main loop failed with Exception " + e.Message;
                body = body + "\n" + e.StackTrace;
                new Mailer().SendErrorMail(configuration, "NO LONGER RECORDING!  StreamCapture Exception: (" + e.Message + ")", body);
            }
        }
Пример #9
0
        public void QueueRecording(ChannelHistory channelHistory, RecordInfo recordInfo, IConfiguration configuration, bool useLogFlag)
        {
            //Write to our very own log as there might be other captures going too
            StreamWriter logWriter = new StreamWriter(Console.OpenStandardOutput());

            if (useLogFlag)
            {
                string     logPath    = Path.Combine(configuration["logPath"], recordInfo.fileName + "Log.txt");
                FileStream fileHandle = new FileStream(logPath, FileMode.OpenOrCreate, FileAccess.Write);
                logWriter = new StreamWriter(fileHandle);
            }
            logWriter.AutoFlush = true;

            //try-catch so we don't crash the whole thing
            try
            {
                //Dump
                DumpRecordInfo(logWriter, recordInfo);

                //Wait here until we're ready to start recording
                if (recordInfo.strStartDT != null)
                {
                    DateTime recStart   = recordInfo.GetStartDT();
                    TimeSpan timeToWait = recStart - DateTime.Now;
                    logWriter.WriteLine($"{DateTime.Now}: Starting recording at {recStart} - Waiting for {timeToWait.Days} Days, {timeToWait.Hours} Hours, and {timeToWait.Minutes} minutes.");
                    if (timeToWait.Seconds >= 0)
                    {
                        Thread.Sleep(timeToWait);
                    }
                }

                //Authenticate
                Task <string> authTask  = Authenticate();
                string        hashValue = authTask.Result;
                if (string.IsNullOrEmpty(hashValue))
                {
                    Console.WriteLine($"ERROR: Unable to authenticate.  Check username and password?");
                    Environment.Exit(1);
                }

                //We need to manage our resulting files
                VideoFileManager videoFileManager = new VideoFileManager(configuration, logWriter, recordInfo.fileName);

                //Capture stream
                CaptureStream(logWriter, hashValue, channelHistory, recordInfo, videoFileManager);

                //Let's take care of processing and publishing the video files
                videoFileManager.ConcatFiles();
                videoFileManager.MuxFile(recordInfo.description);
                videoFileManager.PublishAndCleanUpAfterCapture(recordInfo.category);

                //Cleanup
                logWriter.WriteLine($"{DateTime.Now}: Done Capturing");
                logWriter.Dispose();

                //Send alert mail
                if (recordInfo.emailFlag)
                {
                    new Mailer().SendShowReadyMail(configuration, recordInfo);
                }
            }
            catch (Exception e)
            {
                logWriter.WriteLine("======================");
                logWriter.WriteLine($"{DateTime.Now}: ERROR - Exception!");
                logWriter.WriteLine("======================");
                logWriter.WriteLine($"{e.Message}\n{e.StackTrace}");

                //Send alert mail
                string body = recordInfo.description + " failed with Exception " + e.Message;
                body = body + "\n" + e.StackTrace;
                new Mailer().SendErrorMail(configuration, "StreamCapture Exception! (" + e.Message + ")", body);
            }
        }