/// <summary>
        /// Transcode's all videos of a site
        /// </summary>
        /// <param name="configuration">Json configuration of IDBrowserService as IDBrowserConfiguration class</param>
        /// <param name="cancellationToken">CancellationToken</param>
        /// <param name="siteName">Site name to transcode</param>
        /// <param name="videoSize">Video size to transcode. (e.g. Hd480, Hd720, Hd1080)</param>
        /// <param name="taskCount">FFmpeg task count (Default 2)</param>
        /// <param name="logLevel">Serilog log level</param>
        public static void TranscodeAllVideos(IDBrowserConfiguration configuration, CancellationToken cancellationToken,
                                              string siteName, string videoSize, Serilog.Events.LogEventLevel logLevel, int taskCount)
        {
            LoggingLevelSwitch loggingLevelSwitch = new LoggingLevelSwitch
            {
                MinimumLevel = logLevel
            };

            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.ControlledBy(loggingLevelSwitch)
                         .WriteTo.File(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log", "ConsoleFunctions.log"))
                         .CreateLogger();

            SiteSettings siteSettings = configuration.Sites[siteName];

            IDImagerDB db = new IDImagerDB(GetIDImagerDBOptionsBuilder <IDImagerDB>(siteSettings.ConnectionStrings.DBType,
                                                                                    siteSettings.ConnectionStrings.IDImager).Options);

            var query = db.idCatalogItem
                        .Include(x => x.idFilePath)
                        .Where(x => configuration.VideoFileExtensions.Contains(x.idFileType));

            ProgressTaskFactory progressTaskFactory = new ProgressTaskFactory(taskCount, 100, 60, Log.Logger);

            Task windowChangeListenerTask = new Task(() =>
            {
                int width  = Console.WindowWidth;
                int height = Console.WindowHeight;

                while (!cancellationToken.IsCancellationRequested)
                {
                    if (width != Console.WindowWidth || height != Console.WindowHeight)
                    {
                        width  = Console.WindowWidth;
                        height = Console.WindowHeight;

                        progressTaskFactory.RedrawConsoleWindows(100, 60);
                    }

                    cancellationToken.WaitHandle.WaitOne(100);
                }
            }, cancellationToken);

            windowChangeListenerTask.Start();

            if (!IsWindows)
            {
                // Log output scrolling not supported at the moment because Console.MoveBufferArea is currently not supported under Linux and MacOs.
                // But we can write a single infoline.
                progressTaskFactory.WriteLog("Log output in console not supported under Linux at the moment. Please take a look at the ConsoleFunctions.log in Logs directory.",
                                             true, LogEventLevel.Information);
            }

            List <TranscodeVideoBatchInfo> listTranscodeVideoBatch = new List <TranscodeVideoBatchInfo>();

            foreach (idCatalogItem catalogItem in query)
            {
                catalogItem.GetHeightAndWidth(out int originalVideoWidth, out int originalVideoHeight);

                string strTranscodeFilePath = StaticFunctions.GetTranscodeFilePath(catalogItem.GUID,
                                                                                   siteSettings.ServiceSettings.TranscodeDirectory, videoSize);
                FileInfo transcodeFileInfo = new FileInfo(strTranscodeFilePath);

                if (!transcodeFileInfo.Exists)
                {
                    string strOriginalFilePath = StaticFunctions.GetImageFilePath(catalogItem, siteSettings.ServiceSettings.FilePathReplace);

                    TranscodeVideoBatchInfo transcodeVideoBatchInfo = new TranscodeVideoBatchInfo(catalogItem.GUID, originalVideoWidth, originalVideoHeight,
                                                                                                  strOriginalFilePath, strTranscodeFilePath);

                    listTranscodeVideoBatch.Add(transcodeVideoBatchInfo);
                }
            }

            db.Dispose();

            int intTotalCount = listTranscodeVideoBatch.Count();
            int intCounter    = 1;
            TranscodeVideoBatchInfo lastTranscodeVideoBatch = listTranscodeVideoBatch.LastOrDefault();

            foreach (TranscodeVideoBatchInfo transcodeVideoBatchInfo in listTranscodeVideoBatch)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                string strTranscodeFilePath = StaticFunctions.GetTranscodeFilePath(transcodeVideoBatchInfo.GUID,
                                                                                   siteSettings.ServiceSettings.TranscodeDirectory, videoSize);

                StaticFunctions.GetTranscodeVideoSize(videoSize, transcodeVideoBatchInfo.VideoWidth, transcodeVideoBatchInfo.VideoHeight,
                                                      out VideoSize targetVideoSize, out int targetVideoWidth, out int targetVideoHeight);

                var conversionOptions = StaticFunctions.GetConversionOptions(targetVideoSize, transcodeVideoBatchInfo.VideoWidth,
                                                                             transcodeVideoBatchInfo.VideoHeight);

                progressTaskFactory.WriteLog(string.Format("Transcoding file {0} of {1} with guid {2} and path \"{3}\" from resolution {4}x{5} to {6}x{7} ",
                                                           intCounter, intTotalCount, transcodeVideoBatchInfo.GUID, transcodeVideoBatchInfo.VideoFileInfo.FullName, transcodeVideoBatchInfo.VideoWidth,
                                                           transcodeVideoBatchInfo.VideoHeight, targetVideoWidth, targetVideoHeight),
                                             IsWindows, LogEventLevel.Information);

                ProgressTask progressTask = progressTaskFactory.GetIdleProgressTask();

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                if (progressTask == null)
                {
                    progressTask = progressTaskFactory
                                   .WaitForAnyTask()
                                   .Result;
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                string progressBarText = string.Format("{0} ({1} of {2})", transcodeVideoBatchInfo.TranscodeFileInfo.Name, intCounter, intTotalCount);

                progressTask.Task = new Task(() => {
                    TranscodeVideoProgressTask(transcodeVideoBatchInfo, videoSize, cancellationToken, progressTask, progressBarText);
                });

                progressTask.Task.Start();

                // If we are on the last item we have to wait for all tasks to complete
                if (transcodeVideoBatchInfo == lastTranscodeVideoBatch)
                {
                    progressTaskFactory.WaitForAllTasks();
                }

                intCounter++;
            }

            Log.CloseAndFlush();
        }
        /// <summary>
        /// Transcodes single video with console progresbar updates.
        /// </summary>
        /// <param name="transcodeVideoBatchInfo">Transcode video batch info</param>
        /// <param name="videoSize">Video size</param>
        /// <param name="cancellationToken">CancellationToken</param>
        /// <param name="progressTask">Progress task</param>
        /// <param name="progressBarText">Progress bar text</param>
        public static void TranscodeVideoProgressTask(TranscodeVideoBatchInfo transcodeVideoBatchInfo, string videoSize,
                                                      CancellationToken cancellationToken, ProgressTask progressTask, string progressBarText)
        {
            try
            {
                Engine ffmpegEngine = StaticFunctions.GetFFmpegEngine();

                ffmpegEngine.Error += (sender, eventArgs) =>
                {
                    progressTask.ProgressTaskFactory.WriteLog(string.Format("FFmpeg error on file \"{0}\" => {1}",
                                                                            transcodeVideoBatchInfo.VideoFileInfo.FullName, eventArgs.Exception.ToString()),
                                                              IsWindows, LogEventLevel.Error);
                };

                ffmpegEngine.Progress += (sender, eventArgs) =>
                {
                    int intProgress = (int)Math.Round(eventArgs.ProcessedDuration * 100 / eventArgs.TotalDuration);
                    intProgress = Math.Max(0, Math.Min(100, intProgress));
                    progressTask.RefreshProgressBar(intProgress, progressBarText);
                };

                progressTask.RefreshProgressBar(0, progressBarText);

                Task task = StaticFunctions.TranscodeVideo(ffmpegEngine, cancellationToken, transcodeVideoBatchInfo.VideoFileInfo.FullName,
                                                           transcodeVideoBatchInfo.TranscodeFileInfo.FullName, videoSize, transcodeVideoBatchInfo.VideoWidth, transcodeVideoBatchInfo.VideoHeight);

                task.Wait();

                transcodeVideoBatchInfo.TranscodeFileInfo.Refresh();

                if (!transcodeVideoBatchInfo.TranscodeFileInfo.Exists)
                {
                    progressTask.ProgressTaskFactory.WriteLog(string.Format("Transcoding on file \"{0}\" failed, file does not exist.",
                                                                            transcodeVideoBatchInfo.VideoFileInfo.FullName),
                                                              IsWindows, LogEventLevel.Error);
                    progressTask.RefreshProgressBar(0, progressBarText + " (failed)");
                }
                else if (transcodeVideoBatchInfo.TranscodeFileInfo.Length == 0)
                {
                    transcodeVideoBatchInfo.TranscodeFileInfo.Delete();
                    progressTask.ProgressTaskFactory.WriteLog(string.Format("Transcoding failed on file \"{0}\", file size is zero. Unfinished transcoded file \"{1}\" deleted.",
                                                                            transcodeVideoBatchInfo.VideoFileInfo.FullName, transcodeVideoBatchInfo.TranscodeFileInfo.FullName),
                                                              IsWindows, LogEventLevel.Error);
                    progressTask.RefreshProgressBar(0, progressBarText + " (failed)");
                }
                else
                {
                    progressTask.RefreshProgressBar(100, progressBarText);
                }
            }
            catch (Exception ex)
            {
                // Wait for file to be unlocked
                Thread.Sleep(2000);
                transcodeVideoBatchInfo.TranscodeFileInfo.Refresh();

                if (transcodeVideoBatchInfo.TranscodeFileInfo != null && transcodeVideoBatchInfo.TranscodeFileInfo.Exists)
                {
                    transcodeVideoBatchInfo.TranscodeFileInfo.Delete();
                    progressTask.ProgressTaskFactory.WriteLog(string.Format("Unfinished transcoded file \"{0}\" deleted.",
                                                                            transcodeVideoBatchInfo.TranscodeFileInfo.FullName),
                                                              IsWindows, LogEventLevel.Error);
                }

                if (ex.GetType() == typeof(AggregateException) &&
                    ex.InnerException != null &&
                    ex.InnerException.GetType() == typeof(TaskCanceledException))
                {
                    progressTask.ProgressTaskFactory.WriteLog("Transcoding cancelled", IsWindows, Serilog.Events.LogEventLevel.Information);
                }
                else
                {
                    progressTask.ProgressTaskFactory.WriteLog(ex.ToString(), IsWindows, Serilog.Events.LogEventLevel.Information);
                }

                return;
            }
        }