protected override async Task ExecuteAsync(CancellationToken cancelToken)
        {
            try
            {
                while (!cancelToken.IsCancellationRequested)
                {
                    try
                    {
                        Func <CancellationToken, Task <KonluluStreamGrabStateObject> > workItem = await taskQueue.DequeueAsync(cancelToken);

                        KonluluStreamGrabStateObject stateObj = await workItem(cancelToken);

                        {
                            switch (stateObj.State)
                            {
                            case KonluluStreamGrabState.GetUpcomingStream:
                            {
                                YouTubeService ytService    = ytInterface.GetYoutubeService();
                                string         livestreamId = await ytInterface.GetLiveStream(ytService, "Upcoming");

                                bool foundLivestream = livestreamId != null;
                                if (livestreamId == null)
                                {
                                    logger.LogInformation("found no upcoming stream");
                                    if (stateObj.IsStartup)
                                    {
                                        livestreamId = await ytInterface.GetLiveStream(ytService, "Live");

                                        foundLivestream = livestreamId != null;
                                        if (livestreamId == null)
                                        {
                                            logger.LogInformation("found no live stream");
                                        }
                                    }
                                }

                                if (!foundLivestream)
                                {
                                    taskQueue.QueueBackgroundWorkItem((c) =>
                                                                      StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                     KonluluStreamGrabState.GetUpcomingStream,
                                                                                     DateTime.UtcNow,
                                                                                     DateTime.UtcNow.AddHours(1))
                                                                                 )
                                                                      );
                                }
                                else
                                {
                                    logger.LogInformation($"found upcoming stream {livestreamId}");
                                    VideoDto video = await ytInterface.GetVideoInfo(ytService, livestreamId, getScheduledTime : true);

                                    if (video == null)
                                    {
                                        taskQueue.QueueBackgroundWorkItem((c) =>
                                                                          StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                         KonluluStreamGrabState.GetUpcomingStream,
                                                                                         DateTime.UtcNow,
                                                                                         DateTime.UtcNow.AddMinutes(20))
                                            {
                                                VideoId = stateObj.VideoId
                                            }
                                                                                     )
                                                                          );
                                    }
                                    else
                                    {
                                        taskQueue.QueueBackgroundWorkItem((c) =>
                                                                          StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                         KonluluStreamGrabState.WaitForTheUpcomingStream,
                                                                                         DateTime.UtcNow,
                                                                                         video.StartTime)
                                            {
                                                VideoId = livestreamId
                                            }
                                                                                     )
                                                                          );
                                    }
                                }
                                break;
                            }

                            case KonluluStreamGrabState.WaitForTheUpcomingStream:
                            {
                                taskQueue.QueueBackgroundWorkItem((c) =>
                                                                  StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                 KonluluStreamGrabState.WaitForActualStartOfStream,
                                                                                 DateTime.UtcNow,
                                                                                 DateTime.UtcNow.AddSeconds(1))
                                    {
                                        VideoId = stateObj.VideoId
                                    }
                                                                             )
                                                                  );
                                break;
                            }

                            case KonluluStreamGrabState.WaitForActualStartOfStream:
                            {
                                YouTubeService ytService = ytInterface.GetYoutubeService();
                                VideoDto       video     = null;
                                try
                                {
                                    video = await ytInterface.GetVideoInfo(ytService, stateObj.VideoId);

                                    if (video == null)
                                    {
                                        taskQueue.QueueBackgroundWorkItem((c) =>
                                                                          StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                         KonluluStreamGrabState.GetUpcomingStream,
                                                                                         DateTime.UtcNow,
                                                                                         DateTime.UtcNow.AddMinutes(20))
                                            {
                                                VideoId = stateObj.VideoId
                                            }
                                                                                     )
                                                                          );
                                    }
                                }
                                catch (StartCapturingTooSoonException)
                                {
                                    taskQueue.QueueBackgroundWorkItem((c) =>
                                                                      StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                     KonluluStreamGrabState.WaitForActualStartOfStream,
                                                                                     DateTime.UtcNow,
                                                                                     DateTime.UtcNow.AddMinutes(2))
                                        {
                                            VideoId = stateObj.VideoId
                                        }
                                                                                 )
                                                                      );
                                    break;
                                }
                                catch (Exception ex)
                                {
                                    logger.LogError(ex, nameof(KonluluStreamGrabState.WaitForActualStartOfStream));
                                    break;
                                }

                                using (IServiceScope scope = serviceScopeFactory.CreateScope())
                                {
                                    IVideoRepository videoDb    = scope.ServiceProvider.GetRequiredService <IVideoRepository>();
                                    ITagService      tagService = scope.ServiceProvider.GetRequiredService <ITagService>();

                                    videoDb.Save(new Video(video));
                                    logger.LogInformation("captured {0}", video.VideoId);

                                    await tagService.StartTag(video.VideoId);
                                }

                                taskQueue.QueueBackgroundWorkItem((c) =>
                                                                  StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                 KonluluStreamGrabState.WaitForEndOfStream,
                                                                                 DateTime.UtcNow,
                                                                                 DateTime.UtcNow.AddSeconds(1))
                                    {
                                        VideoId = stateObj.VideoId
                                    }
                                                                             )
                                                                  );

                                break;
                            }

                            case KonluluStreamGrabState.WaitForEndOfStream:
                            {
                                YouTubeService ytService = ytInterface.GetYoutubeService();
                                VideoDto       video     = null;
                                try
                                {
                                    video = await ytInterface.GetVideoInfo(ytService, stateObj.VideoId, getActualEndTime : true);

                                    if (video == null)
                                    {
                                        taskQueue.QueueBackgroundWorkItem((c) =>
                                                                          StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                         KonluluStreamGrabState.GetUpcomingStream,
                                                                                         DateTime.UtcNow,
                                                                                         DateTime.UtcNow.AddMinutes(20))
                                            {
                                                VideoId = stateObj.VideoId
                                            }
                                                                                     )
                                                                          );
                                    }
                                }
                                catch (NoActualEndtimeException)
                                {
                                    taskQueue.QueueBackgroundWorkItem((c) =>
                                                                      StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                     KonluluStreamGrabState.WaitForEndOfStream,
                                                                                     DateTime.UtcNow,
                                                                                     DateTime.UtcNow.AddMinutes(15))
                                        {
                                            VideoId = stateObj.VideoId
                                        }
                                                                                 )
                                                                      );
                                    break;
                                }
                                catch (Exception ex)
                                {
                                    logger.LogError(ex, nameof(KonluluStreamGrabState.WaitForActualStartOfStream));
                                    break;
                                }

                                using (IServiceScope scope = serviceScopeFactory.CreateScope())
                                {
                                    IVideoRepository videoDb = scope.ServiceProvider.GetRequiredService <IVideoRepository>();

                                    videoDb.Save(new Video(video));
                                    logger.LogInformation("captured the end of {0}", video.VideoId);
                                }

                                taskQueue.QueueBackgroundWorkItem((c) =>
                                                                  StateTimer(c, new KonluluStreamGrabStateObject(
                                                                                 KonluluStreamGrabState.GetUpcomingStream,
                                                                                 DateTime.UtcNow,
                                                                                 DateTime.UtcNow.AddSeconds(1))
                                    {
                                        VideoId = stateObj.VideoId
                                    }
                                                                             )
                                                                  );

                                break;
                            }

                            default:
                                logger.LogError("you shouldnt be here");
                                break;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.AppendLine(ex.Message);
                        sb.AppendLine(ex.StackTrace);
                        logger.LogError(sb.ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("Exception when loading command modules");
                sb.AppendLine(ex.Message);
                sb.AppendLine(ex.StackTrace);
                logger.LogError(sb.ToString());
            }
        }
        private static Task <KonluluStreamGrabStateObject> StateTimer(CancellationToken cancellationToken, KonluluStreamGrabStateObject stateobj)
        {
            int time = (int)(stateobj.StateWaitUntil - DateTime.UtcNow).TotalMilliseconds;

            if (time < 0)
            {
                time = 0;
            }
            return(Task.Delay(time).ContinueWith((c) =>
            {
                return stateobj;
            }));
        }