internal OutputWriter(SearchCommand command, string originalCommand) { regularForeGround = Console.ForegroundColor; //using current hasOutputPath = !string.IsNullOrEmpty(command.FileOutputPath); writeOutputFile = command.OutputHtml || hasOutputPath; this.command = command; if (!writeOutputFile) { return; } terms = command.Terms; if (command.OutputHtml) { var context = BrowsingContext.New(Configuration.Default); document = context.OpenNewAsync().Result; var style = document.CreateElement("style"); style.TextContent = "pre > em { background-color: yellow }"; document.Head.Append(style); output = document.CreateElement("pre"); document.Body.Append(output); } else { textOut = new StringWriter(); } WriteLine(originalCommand); WriteLine(); }
private static async Task Search(SearchCommand command, string originalCommand, Func <Youtube, IAsyncEnumerable <VideoSearchResult> > getResultsAsync) { var terms = command.Terms; if (!terms.Any()) { Console.WriteLine("None of the terms contain anything but whitespace. I refuse to work like this!"); return; } //inspired by https://johnthiriet.com/cancel-asynchronous-operation-in-csharp/ using (var search = new CancellationTokenSource()) { var searching = true; var cancel = Task.Run(async() => //start in background, don't wait for completion { Console.WriteLine("Press any key to cancel"); Console.WriteLine(); /* wait for key or search to finish, non-blockingly; but only as long as to not cause perceivable lag * inspired by https://stackoverflow.com/a/5620647 and https://stackoverflow.com/a/23628232 */ while (searching && !Console.KeyAvailable) { await Task.Delay(200, search.Token); } if (Console.KeyAvailable) { Console.ReadKey(true); //consume cancel key without displaying it } if (searching) { search.Cancel(); } }); var youtube = new Youtube(new JsonFileDataStore(GetCachePath())); var output = new OutputWriter(command, originalCommand); try { /* passing token into search implementations for them to react to cancellation, * see https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8#a-tour-through-async-enumerables*/ await foreach (var result in getResultsAsync(youtube).WithCancellation(search.Token)) { output.DisplayVideoResult(result); } } catch (OperationCanceledException) { Console.WriteLine("The search was cancelled."); } output.WriteOutputFile(() => GetFileStoragePath("out")); searching = false; //to complete the cancel task await cancel; //just to rethrow possible exceptions } }