public static async Task <string> Update() { string returnMsg = string.Empty; Regex versionRegex = new Regex(@"(\d{4}\.\d{2}\.\d{2})"); OperationLogger logger = OperationLogger.Create(OperationLogger.YTDLogFile); await Task.Run(delegate { Helper.StartProcess(YouTubeDlPath, Commands.Update, delegate(Process process, string line) { Match m; if ((m = versionRegex.Match(line)).Success) { returnMsg = m.Groups[1].Value; } }, delegate(Process process, string line) { returnMsg = "Failed"; }, null, logger) .WaitForExit(); }); return(returnMsg); }
protected override void WorkerDoWork(DoWorkEventArgs e) { try { using (var logger = OperationLogger.Create(OperationLogger.FFmpegDLogFile)) { if (_end == TimeSpan.MinValue) { FFmpeg.Crop(this.Input, this.Output, _start, this.ReportProgress, _cts.Token, logger); } else { FFmpeg.Crop(this.Input, this.Output, _start, _end, this.ReportProgress, _cts.Token, logger); } } _start = _end = TimeSpan.MinValue; e.Result = this.CancellationPending ? OperationStatus.Canceled : OperationStatus.Success; } catch (Exception ex) { Common.SaveException(ex); Helper.DeleteFiles(this.Output); e.Result = OperationStatus.Failed; } }
protected override void WorkerDoWork(DoWorkEventArgs e) { try { using (var logger = OperationLogger.Create(OperationLogger.FFmpegDLogFile)) { string tempFilename = this.Output.Substring(0, this.Output.LastIndexOf('.') + 1) + "ts"; if (this.Download(tempFilename)) { this.Optimize(logger, tempFilename); } else { // Download was canceled Helper.DeleteFiles(tempFilename); } } // Make sure progress reaches 100% if (this.Progress < ProgressMax) { this.ReportProgress(ProgressMax, null); } e.Result = OperationStatus.Success; } catch (Exception ex) { Common.SaveException(ex); e.Result = OperationStatus.Failed; } }
/// <summary> /// Fixes and optimizes final .ts file from .m3u8 playlist. /// </summary> public static FFmpegResult <bool> FixM3U8(string input, string output, OperationLogger logger = null) { var lines = new StringBuilder(); string arguments = string.Format(Commands.FixM3U8, input, output); LogHeader(arguments, logger); var p = Helper.StartProcess(FFmpegPath, arguments, null, delegate(Process process, string line) { lines.Append(line); }, EnvironmentVariables, logger); p.WaitForExit(); LogFooter(logger); if (p.ExitCode != 0) { string reportFile = FindReportFile(lines.ToString()); return(new FFmpegResult <bool>(false, p.ExitCode, CheckForErrors(reportFile))); } return(new FFmpegResult <bool>(true)); }
public TestLog( MethodInfo testMethod, bool writeToFile = false, string filename = null) { if (testMethod == null) { throw new ArgumentNullException(nameof(testMethod)); } var testName = $"{testMethod.DeclaringType.Name}.{testMethod.Name}"; disposables.Add(Disposable.Create(() => { Log.Dispose(); })); if (writeToFile) { filename = filename ?? $"{testName}-{DateTime.Now:yyyy-MM-dd-hh-mm-ss}.log"; LogFile = new FileInfo(filename); LogToFile(); } disposables.Add( LogEvents.Subscribe(e => Write(e.ToLogString()))); TestName = testName; Log = new OperationLogger(TestName, logOnStart: true); }
/// <summary> /// Writes log header to log. /// </summary> private static void LogHeader(string arguments, OperationLogger logger, [CallerMemberName] string caller = "") { logger?.LogLine($"[{DateTime.Now}]"); logger?.LogLine($"function: {caller}"); logger?.LogLine($"cmd: {arguments}"); logger?.LogLine(); logger?.LogLine("OUTPUT"); }
public async Task Does_Not_Log_Exceptions_With_Inner_Exception() { using (var stream = new MemoryStream()) using (var logger = new OperationLogger(stream)) { await logger.LogOperationAsync(DoWithInnerException); } }
public async Task Can_Log_A_Successful_Operations() { var stream = new MemoryStream(); var logger = new OperationLogger(stream); await logger.LogOperationAsync(DoWork); Assert.AreEqual("DoWork executed", await ReadStream(stream)); }
public async Task Can_Log_A_Failed_Operation() { var stream = new MemoryStream(); var logger = new OperationLogger(stream); await logger.LogOperationAsync(DoException); Assert.AreEqual("DoException failed", await ReadStream(stream)); }
/// <summary> /// Writes log header to log. /// </summary> /// <param name="arguments">The arguments to log in header.</param> /// <param name="url">The URL to log in header.</param> public static void LogHeader(OperationLogger logger, string arguments, [CallerMemberName] string caller = "") { logger?.LogLine("[" + DateTime.Now + "]"); logger?.LogLine("version: " + GetVersion()); logger?.LogLine("caller: " + caller); logger?.LogLine("cmd: " + arguments.Trim()); logger?.LogLine(); logger?.LogLine("OUTPUT"); }
/// <summary> /// Returns a <see cref="VideoInfo"/> of the given video. /// </summary> /// <param name="url">The url to the video.</param> public static VideoInfo GetVideoInfo(string url, YTDAuthentication authentication = null, OperationLogger logger = null) { string json_dir = Common.GetJsonDirectory(); string json_file = string.Empty; string arguments = string.Format(Commands.GetJsonInfo, json_dir, url, authentication == null ? string.Empty : authentication.ToCmdArgument()); VideoInfo video = new VideoInfo(); LogHeader(logger, arguments); Helper.StartProcess(YouTubeDlPath, arguments, delegate(Process process, string line) { line = line.Trim(); if (line.StartsWith("[info] Writing video description metadata as JSON to:")) { // Store file path json_file = line.Substring(line.IndexOf(":") + 1).Trim(); } else if (line.Contains("Refetching age-gated info webpage")) { video.RequiresAuthentication = true; } }, delegate(Process process, string error) { error = error.Trim(); if (error.Contains(ErrorSignIn)) { video.RequiresAuthentication = true; } else if (error.StartsWith("ERROR:")) { video.Failure = true; video.FailureReason = error.Substring("ERROR: ".Length); } }, null, logger) .WaitForExit(); if (!video.Failure && !video.RequiresAuthentication) { video.DeserializeJson(json_file); } return(video); }
private static void ExemplifyScoping(IWindsorContainer container, string scope) { using IDisposable _ = container.BeginScope(); OperationLogger logger = container.Resolve <OperationLogger>(); logger.LogOperations($"{scope}-Call 1 to GetRequiredService<OperationLogger>()"); Console.WriteLine("..."); logger = container.Resolve <OperationLogger>(); logger.LogOperations($"{scope}-Call 2 to GetRequiredService<OperationLogger>()"); }
static void ExemplifyScoping(IServiceProvider serviceProvider, string scope) { using var serviceScope = serviceProvider.CreateScope(); IServiceProvider provider = serviceScope.ServiceProvider; OperationLogger logger = provider.GetRequiredService <OperationLogger>(); logger.LogOperations($"{scope}-Call 1 to .GetRequiredService<OperationLogger>()"); Console.WriteLine("..."); logger = provider.GetRequiredService <OperationLogger>(); logger.LogOperations($"{scope}-Call 2 to .GetRequiredService<OperationLogger>()"); }
private void ProcessRequest(string operationId, HttpContext context) { this.logger?.Log(EventType.OperationLoading, "(OperationId: {0}) Find matching operation for request.", operationId); // create matching operation Operation operation = this.operationFactory.CreateMatchingOperation(context); if (operation == null) { this.logger?.Log(EventType.OperationLoadingError, "(OperationId: {0}) No matching operation was found for Url '{1}'.", operationId, context.Request.Url); context.Response.SetDefaultValues(); context.Response.StatusCode = 404; context.Response.WriteContent("No matching operation was found :("); return; } // initialize logger OperationLogger operationLogger = new OperationLogger( logWriter: this.logger?.LogWriter, clientIp: context.Request.RemoteEndpoint.Address.ToString(), localPort: context.Request.LocalEndpoint.Port.ToString(), operationId: operationId, operationName: operation.Name, url: context.Request.Url.PathAndQuery); // initialize operation operation.Initialize(operationLogger, operationId); operationLogger?.Log( EventType.OperationLoading, "Start executing operation for client '{0}: name: '{1}', id: '{2}', request: '{3}'", context.Request.RemoteEndpoint.Address, operation.Name, operation.ID, context.Request.RawUrl); DateTime startTime = DateTime.Now; // execute operation operation.Execute(context, this.authManager); operationLogger?.Log(EventType.OperationLoading, "Successfully finished operation '{0}' with id '{1}' after {2}s.", operation.Name, operation.ID, (DateTime.Now - startTime).TotalSeconds); }
public BatchOperation(string output, ICollection <string> inputs, PreferredQuality preferredQuality) { this.Title = $"Batch download (0/{inputs.Count} videos)"; this.ReportsProgress = true; this.Input = string.Join("|", inputs); this.Output = output; this.Inputs.AddRange(inputs); _preferredQuality = preferredQuality; _logger = OperationLogger.Create(OperationLogger.YTDLogFile); _downloader = new FileDownloader(); // Attach events _downloader.Canceled += downloader_Canceled; _downloader.Completed += downloader_Completed; _downloader.FileDownloadFailed += downloader_FileDownloadFailed; _downloader.CalculatedTotalFileSize += downloader_CalculatedTotalFileSize; _downloader.ProgressChanged += downloader_ProgressChanged; }
/// <summary> /// Returns true if given file can be converted to a MP3 file, false otherwise. /// </summary> /// <param name="file">The file to check.</param> public static FFmpegResult <bool> CanConvertToMP3(string file, OperationLogger logger = null) { bool hasAudioStream = false; string arguments = string.Format(Commands.GetFileInfo, file); var lines = new StringBuilder(); LogHeader(arguments, logger); var p = Helper.StartProcess(FFmpegPath, arguments, null, delegate(Process process, string line) { lines.AppendLine(line = line.Trim()); if (line.StartsWith("Stream #") && line.Contains("Audio")) { // File has audio stream hasAudioStream = true; } }, EnvironmentVariables, logger); p.WaitForExit(); LogFooter(logger); if (p.ExitCode != 0) { string reportFile = FindReportFile(lines.ToString()); var errors = (List <string>)CheckForErrors(reportFile); if (errors[0] != "At least one output file must be specified") { return(new FFmpegResult <bool>(p.ExitCode, CheckForErrors(reportFile))); } } return(new FFmpegResult <bool>(hasAudioStream)); }
/// <summary> /// Crops file from given start position to given end position. /// </summary> /// <param name="input">The input file.</param> /// <param name="output">The output destination.</param> /// <param name="start">The <see cref="System.TimeSpan"/> crop start position.</param> /// <param name="end">The <see cref="System.TimeSpan"/> crop end position.</param> /// <param name="reportProgress">The method to call when there is progress. Can be null.</param> public static FFmpegResult <bool> Crop(string input, string output, TimeSpan start, TimeSpan end, Action <int, object> reportProgress, CancellationToken ct, OperationLogger logger = null) { bool isTempFile = false; if (input == output) { input = FFmpeg.RenameTemp(input); isTempFile = true; } TimeSpan length = new TimeSpan((long)Math.Abs(start.Ticks - end.Ticks)); string[] args = new string[] { string.Format("{0:00}:{1:00}:{2:00}.{3:000}", start.Hours, start.Minutes, start.Seconds, start.Milliseconds), input, string.Format("{0:00}:{1:00}:{2:00}.{3:000}", length.Hours, length.Minutes, length.Seconds, length.Milliseconds), output }; bool canceled = false; bool started = false; double milliseconds = end.TotalMilliseconds; string arguments = string.Format(Commands.CropFromTo, args); var lines = new StringBuilder(); Process p = null; reportProgress?.Invoke(0, null); LogHeader(arguments, logger); p = Helper.StartProcess(FFmpegPath, arguments, null, delegate(Process process, string line) { // Queued lines might still fire even after canceling process, don't actually know if (canceled) { return; } lines.AppendLine(line = line.Trim()); if (ct != null && ct.IsCancellationRequested) { process.Kill(); canceled = true; return; } // If reportProgress is null it can't be invoked. So skip code below if (reportProgress == null) { return; } if (line == "Press [q] to stop, [?] for help") { started = true; reportProgress.Invoke(0, null); } else if (started && line.StartsWith("frame=")) { int lineStart = line.IndexOf("time=") + 5; int lineLength = "00:00:00.00".Length; string time = line.Substring(lineStart, lineLength); double currentMilli = TimeSpan.Parse(time).TotalMilliseconds; double percentage = (currentMilli / milliseconds) * 100; reportProgress.Invoke(System.Convert.ToInt32(percentage), null); } else if (started && line == string.Empty) { started = false; reportProgress.Invoke(100, null); } }, EnvironmentVariables, logger); p.WaitForExit(); if (isTempFile) { Helper.DeleteFiles(input); } LogFooter(logger); if (canceled) { return(new FFmpegResult <bool>(false)); } else if (p.ExitCode != 0) { string reportFile = FindReportFile(lines.ToString()); return(new FFmpegResult <bool>(false, p.ExitCode, CheckForErrors(reportFile))); } return(new FFmpegResult <bool>(true)); }
public static async Task GetVideoInfoBatchAsync(ICollection <string> urls, Action <VideoInfo> videoReady, YTDAuthentication authentication = null, OperationLogger logger = null) { string json_dir = Common.GetJsonDirectory(); string arguments = string.Format(Commands.GetJsonInfoBatch, json_dir, string.Join(" ", urls)); var videos = new OrderedDictionary(); var jsonFiles = new Dictionary <string, string>(); var findVideoID = new Regex(@"(?:\]|ERROR:)\s(.{11}):", RegexOptions.Compiled); var findVideoIDJson = new Regex(@":\s.*\\(.{11})_", RegexOptions.Compiled); LogHeader(logger, arguments); await Task.Run(() => { Helper.StartProcess(YouTubeDlPath, arguments, (Process process, string line) => { line = line.Trim(); Match m; string id; VideoInfo video = null; if ((m = findVideoID.Match(line)).Success) { id = findVideoID.Match(line).Groups[1].Value; video = videos.Get <VideoInfo>(id, new VideoInfo() { ID = id }); } if (line.StartsWith("[info] Writing video description metadata as JSON to:")) { id = findVideoIDJson.Match(line).Groups[1].Value; var jsonFile = line.Substring(line.IndexOf(":") + 1).Trim(); jsonFiles.Put(id, jsonFile); video = videos[id] as VideoInfo; video.DeserializeJson(jsonFile); videoReady(video); } else if (line.Contains("Refetching age-gated info webpage")) { video.RequiresAuthentication = true; } }, (Process process, string error) => { error = error.Trim(); var id = findVideoID.Match(error).Groups[1].Value; var video = videos.Get <VideoInfo>(id, new VideoInfo() { ID = id }); if (error.Contains(ErrorSignIn)) { video.RequiresAuthentication = true; } else if (error.StartsWith("ERROR:")) { video.Failure = true; video.FailureReason = error.Substring("ERROR: ".Length); } }, null, logger) .WaitForExit(); }); }
/// <summary> /// Combines separate audio & video to a single MP4 file. /// </summary> /// <param name="video">The input video file.</param> /// <param name="audio">The input audio file.</param> /// <param name="output">The output destination.</param> /// <param name="reportProgress">The method to call when there is progress. Can be null.</param> public static FFmpegResult <bool> Combine(string video, string audio, string output, Action <int> reportProgress, OperationLogger logger = null) { bool started = false; double milliseconds = 0; string arguments = string.Format(Commands.Combine, video, audio, output); var lines = new StringBuilder(); LogHeader(arguments, logger); var p = Helper.StartProcess(FFmpegPath, arguments, null, delegate(Process process, string line) { lines.AppendLine(line = line.Trim()); // If reportProgress is null it can't be invoked. So skip code below if (reportProgress == null) { return; } if (line.StartsWith("Duration: ")) { int lineStart = "Duration: ".Length; int length = "00:00:00.00".Length; string time = line.Substring(lineStart, length); milliseconds = TimeSpan.Parse(time).TotalMilliseconds; } else if (line == "Press [q] to stop, [?] for help") { started = true; reportProgress.Invoke(0); } else if (started && line.StartsWith("frame=")) { int lineStart = line.IndexOf("time=") + 5; int length = "00:00:00.00".Length; string time = line.Substring(lineStart, length); double currentMilli = TimeSpan.Parse(time).TotalMilliseconds; double percentage = (currentMilli / milliseconds) * 100; reportProgress.Invoke(System.Convert.ToInt32(percentage)); } else if (started && line == string.Empty) { started = false; reportProgress.Invoke(100); } }, EnvironmentVariables, logger); p.WaitForExit(); LogFooter(logger); if (p.ExitCode != 0) { string reportFile = FindReportFile(lines.ToString()); return(new FFmpegResult <bool>(false, p.ExitCode, CheckForErrors(reportFile))); } return(new FFmpegResult <bool>(true)); }
protected override void WorkerDoWork(DoWorkEventArgs e) { downloader.Start(); while (downloader?.IsBusy == true) { Thread.Sleep(200); } if (_combine && _downloadSuccessful) { string audio = downloader.Files[0].Path; string video = downloader.Files[1].Path; this.ReportProgress(-1, new Dictionary <string, object>() { { nameof(Progress), 0 } }); this.ReportProgress(ProgressMax, null); try { FFmpegResult <bool> result; this.ReportProgress(-1, new Dictionary <string, object>() { { nameof(ProgressText), "Combining..." } }); using (var logger = OperationLogger.Create(OperationLogger.FFmpegDLogFile)) { result = new FFmpegProcess(logger).Combine(video, audio, this.Output, delegate(int percentage) { // Combine progress this.ReportProgress(percentage, null); }); } if (result.Value) { e.Result = OperationStatus.Success; } else { e.Result = OperationStatus.Failed; this.ErrorsInternal.AddRange(result.Errors); } // Cleanup the separate audio and video files Helper.DeleteFiles(audio, video); } catch (Exception ex) { Common.SaveException(ex); e.Result = OperationStatus.Failed; } } else { e.Result = this.Status; } }
public static bool Combine(string audio, string video, string title, OperationLogger logger, out Exception exception, Action <int, object> reportProgress) { // Remove '_video' from video file to get a final filename. string error = string.Empty; string output = video.Replace("_video", string.Empty); FFmpegResult <bool> result = null; try { // Raise events on main thread reportProgress(-1, new Dictionary <string, object>() { { "ProgressText", "Combining..." } }); result = FFmpeg.Combine(video, audio, output, delegate(int percentage) { // Combine progress reportProgress(percentage, null); }, logger); // Save errors if combining failed if (!result.Value) { var sb = new StringBuilder(); sb.AppendLine(title); sb.AppendLine(string.Join( Environment.NewLine, result.Errors.Select(err => $" - {err}"))); error = sb.ToString(); } // Cleanup the separate audio and video files Helper.DeleteFiles(audio, video); } catch (Exception ex) { exception = ex; Common.SaveException(ex); return(false); } finally { // Raise events on main thread reportProgress(-1, new Dictionary <string, object>() { { "ProgressText", null } }); } exception = new Exception(error); return(result.Value); }
protected override void WorkerDoWork(DoWorkEventArgs e) { if (_mode == ConvertingMode.File) { try { using (var logger = OperationLogger.Create(OperationLogger.FFmpegDLogFile)) { FFmpeg.Convert(this.Input, this.Output, this.ReportProgress, _cts.Token, logger); // Crop if not operation wasn't canceled and _start has a valid value if (!this.CancellationPending && _start != TimeSpan.MinValue) { // Crop to end of file, unless _end has a valid value if (_end == TimeSpan.MinValue) { FFmpeg.Crop(this.Output, this.Output, _start, this.ReportProgress, _cts.Token, logger); } else { FFmpeg.Crop(this.Output, this.Output, _start, _end, this.ReportProgress, _cts.Token, logger); } } } // Reset variables _start = _end = TimeSpan.MinValue; } catch (Exception ex) { Common.SaveException(ex); Helper.DeleteFiles(this.Output); e.Result = OperationStatus.Failed; } } else { using (var logger = OperationLogger.Create(OperationLogger.FFmpegDLogFile)) { foreach (string input in Directory.GetFiles(this.Input, _searchPattern)) { if (this.CancellationPending) { break; } _count++; try { string output = string.Format("{0}\\{1}.mp3", this.Output, Path.GetFileNameWithoutExtension(input)); this.ReportProgress(UpdateProperties, new Dictionary <string, object>() { { nameof(Operation.Title), Path.GetFileName(input) }, { nameof(Operation.Duration), (int)FFmpeg.GetDuration(input).Value.TotalSeconds }, { nameof(Operation.FileSize), Helper.GetFileSize(input) } }); _currentOutput = output; FFmpeg.Convert(input, output, this.ReportProgress, _cts.Token, logger); _currentOutput = null; this.ProcessedFiles.Add(output); } catch (Exception ex) { _failures++; Common.SaveException(ex); Helper.DeleteFiles(_currentOutput); continue; } } } } // Set operation result e.Result = this.CancellationPending ? OperationStatus.Canceled : OperationStatus.Success; }
private bool Combine() { string audio = _downloader.Files[0].Path; string video = _downloader.Files[1].Path; // Remove '_video' from video file to get a final filename. string output = video.Replace("_video", string.Empty); FFmpegResult <bool> result = null; try { // Raise events on main thread this.ReportProgress(-1, new Dictionary <string, object>() { { nameof(ProgressText), "Combining..." } }); if (_ffmpegLogger == null) { _ffmpegLogger = OperationLogger.Create(OperationLogger.FFmpegDLogFile); } if (_ffmpeg == null) { _ffmpeg = new FFmpegProcess(_ffmpegLogger); } result = _ffmpeg.Combine(video, audio, output, delegate(int percentage) { // Combine progress this.ReportProgress(percentage, null); }); // Save errors if combining failed if (!result.Value) { var sb = new StringBuilder(); sb.AppendLine(this.Title); foreach (string error in result.Errors) { sb.AppendLine($" - {error}"); } this.ErrorsInternal.Add(sb.ToString()); } // Cleanup the separate audio and video files Helper.DeleteFiles(audio, video); } catch (Exception ex) { Common.SaveException(ex); return(false); } finally { // Raise events on main thread this.ReportProgress(-1, new Dictionary <string, object>() { { nameof(ProgressText), null } }); } return(result.Value); }
protected override void WorkerDoWork(DoWorkEventArgs e) { /* ToDo: * * [ ] Handle TimeoutException from PlaylistReader in 'GetPlaylistInfoAsync' somehow. * Can't catch it here, needs to catch it inside 'GetPlaylistInfoAsync'. */ this.GetPlaylistInfoAsync(); try { int count = 0; while (count < this.Videos.Count || _queryingVideos) { if (this.CancellationPending) { break; } // Wait for more videos? while (count == this.Videos.Count) { Thread.Sleep(200); continue; } // Reset variable(s) _downloaderSuccessful = null; _downloader.Files.Clear(); count++; var video = this.Videos[count - 1]; if (video.Failure) { // Something failed retrieving video info _failures++; continue; } VideoFormat format = Helper.GetPreferredFormat(video, _preferredQuality); // Update properties for new video this.ReportProgress(-1, new Dictionary <string, object>() { { nameof(Title), $"({count}/{_selectedVideosCount}) {video.Title}" }, { nameof(Duration), video.Duration }, { nameof(FileSize), format.FileSize } }); string prefix = _indexPrefix ? (_downloads + 1) + ". " : string.Empty; string finalFile = Path.Combine(this.Output, $"{prefix}{Helper.FormatTitle(format.VideoInfo.Title)}.{format.Extension}"); // Overwrite if finalFile already exists Helper.DeleteFiles(finalFile); this.DownloadedFiles.Add(finalFile); if (format.AudioOnly) { _downloader.Files.Add(new FileDownload(finalFile, format.DownloadUrl)); } else { VideoFormat audioFormat = Helper.GetAudioFormat(format); // Add '_audio' & '_video' to end of filename. Only get filename, not full path. string audioFile = Regex.Replace(finalFile, @"^(.*)(\..*)$", "$1_audio$2"); string videoFile = Regex.Replace(finalFile, @"^(.*)(\..*)$", "$1_video$2"); // Download audio and video _downloader.Files.Add(new FileDownload(audioFile, audioFormat.DownloadUrl)); _downloader.Files.Add(new FileDownload(videoFile, format.DownloadUrl)); // Delete _audio and _video files in case they exists from a previous attempt Helper.DeleteFiles(_downloader.Files[0].Path, _downloader.Files[1].Path); } _downloader.Start(); // Wait for downloader to finish while (_downloader.IsBusy || _downloader.IsPaused) { if (this.CancellationPending) { _downloader.Stop(); break; } Thread.Sleep(200); } if (_downloaderSuccessful == true) { // Combine video and audio if necessary if (!format.AudioOnly) { this.ReportProgress(-1, new Dictionary <string, object>() { { nameof(Progress), 0 } }); this.ReportProgress(ProgressMax, null); if (!this.Combine()) { _failures++; } this.ReportProgress(-1, new Dictionary <string, object>() { { nameof(Progress), 0 } }); } _downloads++; this.ReportProgress(EventFileDownloadComplete, finalFile); } else if (_downloaderSuccessful == false) { // Download failed, cleanup and continue _failures++; // Delete all related files. Helper method will check if it exists, throwing no errors Helper.DeleteFiles(_downloader.Files.Select(x => x.Path).ToArray()); } // Reset before starting new download. this.ReportProgress(ProgressMin, null); } // Throw stored exception if it exists. For example TimeoutException from 'GetPlaylistInfoAsync' if (_operationException != null) { throw _operationException; } e.Result = this.CancellationPending ? OperationStatus.Canceled : OperationStatus.Success; } catch (Exception ex) { Common.SaveException(ex); e.Result = OperationStatus.Failed; _operationException = ex; } finally { _ffmpegLogger?.Close(); _ffmpegLogger = null; _ffmpeg = null; } }
/// <summary> /// Writes log footer to log. /// </summary> private static void LogFooter(OperationLogger logger) { // Write log footer to stream. // Possibly write elapsed time and/or error in future. logger?.LogLine(Environment.NewLine); }
public FFmpegProcess(OperationLogger logger) { _logger = logger; }
private void Optimize(OperationLogger logger, string tsFile) { FFmpeg.FixM3U8(tsFile, this.Output, logger); Helper.DeleteFiles(tsFile); }
private void Optimize(OperationLogger logger, string tsFile) { new FFmpegProcess(logger).FixM3U8(tsFile, this.Output); Helper.DeleteFiles(tsFile); }
public YoutubeDlProcess(OperationLogger logger, YTDAuthentication authentication) { _logger = logger; _authentication = authentication; }