From cca2cbd70b0e5185b10a60396503ffbfb517a56f Mon Sep 17 00:00:00 2001 From: bezzad Date: Sat, 18 Nov 2023 13:00:53 +0330 Subject: [PATCH] refactor samples to scoped namespaces --- src/Samples/Downloader.Sample/DownloadItem.cs | 13 +- .../Downloader.Sample.csproj | 1 + src/Samples/Downloader.Sample/Helper.cs | 99 +++-- .../Downloader.Sample/Program.Config.cs | 49 +++ src/Samples/Downloader.Sample/Program.cs | 406 ++++++++---------- 5 files changed, 286 insertions(+), 282 deletions(-) create mode 100644 src/Samples/Downloader.Sample/Program.Config.cs diff --git a/src/Samples/Downloader.Sample/DownloadItem.cs b/src/Samples/Downloader.Sample/DownloadItem.cs index ea553cd3..6fee2771 100644 --- a/src/Samples/Downloader.Sample/DownloadItem.cs +++ b/src/Samples/Downloader.Sample/DownloadItem.cs @@ -1,9 +1,8 @@ -namespace Downloader.Sample +namespace Downloader.Sample; + +public class DownloadItem { - public class DownloadItem - { - public string FolderPath { get; set; } - public string FileName { get; set; } - public string Url { get; set; } - } + public string FolderPath { get; set; } + public string FileName { get; set; } + public string Url { get; set; } } \ No newline at end of file diff --git a/src/Samples/Downloader.Sample/Downloader.Sample.csproj b/src/Samples/Downloader.Sample/Downloader.Sample.csproj index b947d2e9..0237d222 100644 --- a/src/Samples/Downloader.Sample/Downloader.Sample.csproj +++ b/src/Samples/Downloader.Sample/Downloader.Sample.csproj @@ -1,6 +1,7 @@  + latestMajor Exe netcoreapp3.1;net6.0; diff --git a/src/Samples/Downloader.Sample/Helper.cs b/src/Samples/Downloader.Sample/Helper.cs index 26430e43..01795068 100644 --- a/src/Samples/Downloader.Sample/Helper.cs +++ b/src/Samples/Downloader.Sample/Helper.cs @@ -1,61 +1,60 @@ using System; -namespace Downloader.Sample +namespace Downloader.Sample; + +public static class Helper { - public static class Helper + public static string CalcMemoryMensurableUnit(this long bytes) { - public static string CalcMemoryMensurableUnit(this long bytes) - { - return CalcMemoryMensurableUnit((double)bytes); - } + return CalcMemoryMensurableUnit((double)bytes); + } - public static string CalcMemoryMensurableUnit(this double bytes) + public static string CalcMemoryMensurableUnit(this double bytes) + { + double kb = bytes / 1024; // · 1024 Bytes = 1 Kilobyte + double mb = kb / 1024; // · 1024 Kilobytes = 1 Megabyte + double gb = mb / 1024; // · 1024 Megabytes = 1 Gigabyte + double tb = gb / 1024; // · 1024 Gigabytes = 1 Terabyte + + string result = + tb > 1 ? $"{tb:0.##}TB" : + gb > 1 ? $"{gb:0.##}GB" : + mb > 1 ? $"{mb:0.##}MB" : + kb > 1 ? $"{kb:0.##}KB" : + $"{bytes:0.##}B"; + + result = result.Replace("/", "."); + return result; + } + + public static void UpdateTitleInfo(this DownloadProgressChangedEventArgs e, bool isPaused) + { + int estimateTime = (int)Math.Ceiling((e.TotalBytesToReceive - e.ReceivedBytesSize) / e.AverageBytesPerSecondSpeed); + string timeLeftUnit = "seconds"; + + if (estimateTime >= 60) // isMinutes { - double kb = bytes / 1024; // · 1024 Bytes = 1 Kilobyte - double mb = kb / 1024; // · 1024 Kilobytes = 1 Megabyte - double gb = mb / 1024; // · 1024 Megabytes = 1 Gigabyte - double tb = gb / 1024; // · 1024 Gigabytes = 1 Terabyte - - string result = - tb > 1 ? $"{tb:0.##}TB" : - gb > 1 ? $"{gb:0.##}GB" : - mb > 1 ? $"{mb:0.##}MB" : - kb > 1 ? $"{kb:0.##}KB" : - $"{bytes:0.##}B"; - - result = result.Replace("/", "."); - return result; + timeLeftUnit = "minutes"; + estimateTime /= 60; } - - public static void UpdateTitleInfo(this DownloadProgressChangedEventArgs e, bool isPaused) + else if (estimateTime < 0) { - int estimateTime = (int)Math.Ceiling((e.TotalBytesToReceive - e.ReceivedBytesSize) / e.AverageBytesPerSecondSpeed); - string timeLeftUnit = "seconds"; - - if (estimateTime >= 60) // isMinutes - { - timeLeftUnit = "minutes"; - estimateTime /= 60; - } - else if (estimateTime < 0) - { - estimateTime = 0; - } - - string avgSpeed = e.AverageBytesPerSecondSpeed.CalcMemoryMensurableUnit(); - string speed = e.BytesPerSecondSpeed.CalcMemoryMensurableUnit(); - string bytesReceived = e.ReceivedBytesSize.CalcMemoryMensurableUnit(); - string totalBytesToReceive = e.TotalBytesToReceive.CalcMemoryMensurableUnit(); - string progressPercentage = $"{e.ProgressPercentage:F3}".Replace("/", "."); - string usedMemory = GC.GetTotalMemory(false).CalcMemoryMensurableUnit(); - - Console.Title = $"{estimateTime} {timeLeftUnit} left - " + - $"{speed}/s (avg: {avgSpeed}/s) - " + - $"{progressPercentage}% - " + - $"[{bytesReceived} of {totalBytesToReceive}] " + - $"Active Chunks: {e.ActiveChunks} - " + - $"[{usedMemory} memory] " + - (isPaused ? " - Paused" : ""); + estimateTime = 0; } + + string avgSpeed = e.AverageBytesPerSecondSpeed.CalcMemoryMensurableUnit(); + string speed = e.BytesPerSecondSpeed.CalcMemoryMensurableUnit(); + string bytesReceived = e.ReceivedBytesSize.CalcMemoryMensurableUnit(); + string totalBytesToReceive = e.TotalBytesToReceive.CalcMemoryMensurableUnit(); + string progressPercentage = $"{e.ProgressPercentage:F3}".Replace("/", "."); + string usedMemory = GC.GetTotalMemory(false).CalcMemoryMensurableUnit(); + + Console.Title = $"{estimateTime} {timeLeftUnit} left - " + + $"{speed}/s (avg: {avgSpeed}/s) - " + + $"{progressPercentage}% - " + + $"[{bytesReceived} of {totalBytesToReceive}] " + + $"Active Chunks: {e.ActiveChunks} - " + + $"[{usedMemory} memory] " + + (isPaused ? " - Paused" : ""); } } diff --git a/src/Samples/Downloader.Sample/Program.Config.cs b/src/Samples/Downloader.Sample/Program.Config.cs new file mode 100644 index 00000000..179077e4 --- /dev/null +++ b/src/Samples/Downloader.Sample/Program.Config.cs @@ -0,0 +1,49 @@ +using System.Net; +using System.Reflection; + +namespace Downloader.Sample; + +public partial class Program +{ + private static DownloadConfiguration GetDownloadConfiguration() + { + var cookies = new CookieContainer(); + cookies.Add(new Cookie("download-type", "test") { Domain = "domain.com" }); + + return new DownloadConfiguration { + BufferBlockSize = 10240, // usually, hosts support max to 8000 bytes, default values is 8000 + ChunkCount = 8, // file parts to download, default value is 1 + MaximumBytesPerSecond = 0, // download speed limited to 10MB/s, default values is zero or unlimited + MaxTryAgainOnFailover = 5, // the maximum number of times to fail + MaximumMemoryBufferBytes = 1024 * 1024 * 1024, // release memory buffer after each 1GB + ParallelDownload = true, // download parts of file as parallel or not. Default value is false + ParallelCount = 16, // number of parallel downloads. The default value is the same as the chunk count + Timeout = 3000, // timeout (millisecond) per stream block reader, default value is 1000 + RangeDownload = false, // set true if you want to download just a specific range of bytes of a large file + RangeLow = 0, // floor offset of download range of a large file + RangeHigh = 0, // ceiling offset of download range of a large file + ClearPackageOnCompletionWithFailure = true, // Clear package and downloaded data when download completed with failure, default value is false + MinimumSizeOfChunking = 1024, // minimum size of chunking to download a file in multiple parts, default value is 512 + ReserveStorageSpaceBeforeStartingDownload = true, // Before starting the download, reserve the storage space of the file as file size, default value is false + RequestConfiguration = + { + // config and customize request headers + Accept = "*/*", + CookieContainer = cookies, + Headers = new WebHeaderCollection(), // { your custom headers } + KeepAlive = true, // default value is false + ProtocolVersion = HttpVersion.Version11, // default value is HTTP 1.1 + UseDefaultCredentials = false, + // your custom user agent or your_app_name/app_version. + UserAgent = $"DownloaderSample/{Assembly.GetExecutingAssembly().GetName().Version?.ToString(3)}" + // Proxy = new WebProxy(new Uri($"socks5://127.0.0.1:9050")) + // Proxy = new WebProxy() { + // Address = new Uri("http://YourProxyServer/proxy.pac"), + // UseDefaultCredentials = false, + // Credentials = System.Net.CredentialCache.DefaultNetworkCredentials, + // BypassProxyOnLocal = true + // } + } + }; + } +} \ No newline at end of file diff --git a/src/Samples/Downloader.Sample/Program.cs b/src/Samples/Downloader.Sample/Program.cs index f383627b..13b6a3ad 100644 --- a/src/Samples/Downloader.Sample/Program.cs +++ b/src/Samples/Downloader.Sample/Program.cs @@ -6,274 +6,230 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; -using System.Net; -using System.Reflection; using System.Threading; using System.Threading.Tasks; -namespace Downloader.Sample +namespace Downloader.Sample; + +public partial class Program { - internal static class Program + private const string DownloadListFile = "DownloadList.json"; + private static List DownloadList; + private static ProgressBar ConsoleProgress; + private static ConcurrentDictionary ChildConsoleProgresses; + private static ProgressBarOptions ChildOption; + private static ProgressBarOptions ProcessBarOption; + private static IDownloadService CurrentDownloadService; + private static DownloadConfiguration CurrentDownloadConfiguration; + private static CancellationTokenSource CancelAllTokenSource; + + private static async Task Main() { - private const string DownloadListFile = "DownloadList.json"; - private static List DownloadList; - private static ProgressBar ConsoleProgress; - private static ConcurrentDictionary ChildConsoleProgresses; - private static ProgressBarOptions ChildOption; - private static ProgressBarOptions ProcessBarOption; - private static IDownloadService CurrentDownloadService; - private static DownloadConfiguration CurrentDownloadConfiguration; - private static CancellationTokenSource CancelAllTokenSource; - - private static async Task Main() + try { - try - { -#if NETCOREAPP - DummyHttpServer.HttpServer.Run(3333); -#endif - await Task.Delay(1000); - Console.Clear(); - Initial(); - new Task(KeyboardHandler).Start(); - await DownloadAll(DownloadList, CancelAllTokenSource.Token).ConfigureAwait(false); - } - catch (Exception e) - { - Console.Clear(); - Console.Error.WriteLine(e); - Debugger.Break(); - } - finally - { #if NETCOREAPP - await DummyHttpServer.HttpServer.Stop(); + DummyHttpServer.HttpServer.Run(3333); #endif - } - - Console.WriteLine("END"); + await Task.Delay(1000); + Console.Clear(); + Initial(); + new Task(KeyboardHandler).Start(); + await DownloadAll(DownloadList, CancelAllTokenSource.Token).ConfigureAwait(false); } - private static void Initial() + catch (Exception e) { - CancelAllTokenSource = new CancellationTokenSource(); - ChildConsoleProgresses = new ConcurrentDictionary(); - DownloadList = GetDownloadItems(); - - ProcessBarOption = new ProgressBarOptions { - ForegroundColor = ConsoleColor.Green, - ForegroundColorDone = ConsoleColor.DarkGreen, - BackgroundColor = ConsoleColor.DarkGray, - BackgroundCharacter = '\u2593', - EnableTaskBarProgress = true, - ProgressBarOnBottom = false, - ProgressCharacter = '#' - }; - ChildOption = new ProgressBarOptions { - ForegroundColor = ConsoleColor.Yellow, - BackgroundColor = ConsoleColor.DarkGray, - ProgressCharacter = '-', - ProgressBarOnBottom = true - }; + Console.Clear(); + Console.Error.WriteLine(e); + Debugger.Break(); } - private static void KeyboardHandler() + finally { - ConsoleKeyInfo cki; - Console.CancelKeyPress += CancelAll; +#if NETCOREAPP + await DummyHttpServer.HttpServer.Stop(); +#endif + } + + Console.WriteLine("END"); + } + private static void Initial() + { + CancelAllTokenSource = new CancellationTokenSource(); + ChildConsoleProgresses = new ConcurrentDictionary(); + DownloadList = GetDownloadItems(); + + ProcessBarOption = new ProgressBarOptions { + ForegroundColor = ConsoleColor.Green, + ForegroundColorDone = ConsoleColor.DarkGreen, + BackgroundColor = ConsoleColor.DarkGray, + BackgroundCharacter = '\u2593', + EnableTaskBarProgress = true, + ProgressBarOnBottom = false, + ProgressCharacter = '#' + }; + ChildOption = new ProgressBarOptions { + ForegroundColor = ConsoleColor.Yellow, + BackgroundColor = ConsoleColor.DarkGray, + ProgressCharacter = '-', + ProgressBarOnBottom = true + }; + } + private static void KeyboardHandler() + { + ConsoleKeyInfo cki; + Console.CancelKeyPress += CancelAll; - while (true) + while (true) + { + cki = Console.ReadKey(true); + if (CurrentDownloadConfiguration != null) { - cki = Console.ReadKey(true); - if (CurrentDownloadConfiguration != null) + switch (cki.Key) { - switch (cki.Key) - { - case ConsoleKey.P: - CurrentDownloadService?.Pause(); - Console.Beep(); - break; - case ConsoleKey.R: - CurrentDownloadService?.Resume(); - break; - case ConsoleKey.Escape: - CurrentDownloadService?.CancelAsync(); - break; - case ConsoleKey.UpArrow: - CurrentDownloadConfiguration.MaximumBytesPerSecond *= 2; - break; - case ConsoleKey.DownArrow: - CurrentDownloadConfiguration.MaximumBytesPerSecond /= 2; - break; - } + case ConsoleKey.P: + CurrentDownloadService?.Pause(); + Console.Beep(); + break; + case ConsoleKey.R: + CurrentDownloadService?.Resume(); + break; + case ConsoleKey.Escape: + CurrentDownloadService?.CancelAsync(); + break; + case ConsoleKey.UpArrow: + CurrentDownloadConfiguration.MaximumBytesPerSecond *= 2; + break; + case ConsoleKey.DownArrow: + CurrentDownloadConfiguration.MaximumBytesPerSecond /= 2; + break; } } } - private static void CancelAll(object sender, ConsoleCancelEventArgs e) - { - CancelAllTokenSource.Cancel(); - CurrentDownloadService?.CancelAsync(); - } + } + private static void CancelAll(object sender, ConsoleCancelEventArgs e) + { + CancelAllTokenSource.Cancel(); + CurrentDownloadService?.CancelAsync(); + } - private static DownloadConfiguration GetDownloadConfiguration() - { - var cookies = new CookieContainer(); - cookies.Add(new Cookie("download-type", "test") { Domain = "domain.com" }); + private static List GetDownloadItems() + { + List downloadList = File.Exists(DownloadListFile) + ? JsonConvert.DeserializeObject>(File.ReadAllText(DownloadListFile)) + : null; - return new DownloadConfiguration { - BufferBlockSize = 10240, // usually, hosts support max to 8000 bytes, default values is 8000 - ChunkCount = 8, // file parts to download, default value is 1 - MaximumBytesPerSecond = 0, // download speed limited to 10MB/s, default values is zero or unlimited - MaxTryAgainOnFailover = 5, // the maximum number of times to fail - MaximumMemoryBufferBytes = 1024 * 1024 * 600, // release memory buffer after each 200 MB - ParallelDownload = true, // download parts of file as parallel or not. Default value is false - ParallelCount = 16, // number of parallel downloads. The default value is the same as the chunk count - Timeout = 3000, // timeout (millisecond) per stream block reader, default value is 1000 - RangeDownload = false, // set true if you want to download just a specific range of bytes of a large file - RangeLow = 0, // floor offset of download range of a large file - RangeHigh = 0, // ceiling offset of download range of a large file - ClearPackageOnCompletionWithFailure = true, // Clear package and downloaded data when download completed with failure, default value is false - MinimumSizeOfChunking = 1024, // minimum size of chunking to download a file in multiple parts, default value is 512 - ReserveStorageSpaceBeforeStartingDownload = true, // Before starting the download, reserve the storage space of the file as file size, default value is false - RequestConfiguration = - { - // config and customize request headers - Accept = "*/*", - CookieContainer = cookies, - Headers = new WebHeaderCollection(), // { your custom headers } - KeepAlive = true, // default value is false - ProtocolVersion = HttpVersion.Version11, // default value is HTTP 1.1 - UseDefaultCredentials = false, - // your custom user agent or your_app_name/app_version. - UserAgent = $"DownloaderSample/{Assembly.GetExecutingAssembly().GetName().Version?.ToString(3)}" - // Proxy = new WebProxy(new Uri($"socks5://127.0.0.1:9050")) - // Proxy = new WebProxy() { - // Address = new Uri("http://YourProxyServer/proxy.pac"), - // UseDefaultCredentials = false, - // Credentials = System.Net.CredentialCache.DefaultNetworkCredentials, - // BypassProxyOnLocal = true - // } + if (downloadList == null) + { + downloadList = new List { + new DownloadItem { + FolderPath = Path.GetTempPath(), Url = "http://ipv4.download.thinkbroadband.com/100MB.zip" } }; } - private static List GetDownloadItems() - { - List downloadList = File.Exists(DownloadListFile) - ? JsonConvert.DeserializeObject>(File.ReadAllText(DownloadListFile)) - : null; - if (downloadList == null) - { - downloadList = new List { - new DownloadItem { - FolderPath = Path.GetTempPath(), Url = "http://ipv4.download.thinkbroadband.com/100MB.zip" - } - }; - } - - return downloadList; - } - private static async Task DownloadAll(IEnumerable downloadList, CancellationToken cancelToken) + return downloadList; + } + private static async Task DownloadAll(IEnumerable downloadList, CancellationToken cancelToken) + { + foreach (DownloadItem downloadItem in downloadList) { - foreach (DownloadItem downloadItem in downloadList) - { - if (cancelToken.IsCancellationRequested) - return; + if (cancelToken.IsCancellationRequested) + return; - // begin download from url - await DownloadFile(downloadItem).ConfigureAwait(false); - } + // begin download from url + await DownloadFile(downloadItem).ConfigureAwait(false); } - private static async Task DownloadFile(DownloadItem downloadItem) - { - CurrentDownloadConfiguration = GetDownloadConfiguration(); - CurrentDownloadService = CreateDownloadService(CurrentDownloadConfiguration); - - if (string.IsNullOrWhiteSpace(downloadItem.FileName)) - { - await CurrentDownloadService.DownloadFileTaskAsync(downloadItem.Url, new DirectoryInfo(downloadItem.FolderPath)).ConfigureAwait(false); - } - else - { - await CurrentDownloadService.DownloadFileTaskAsync(downloadItem.Url, downloadItem.FileName).ConfigureAwait(false); - } + } + private static async Task DownloadFile(DownloadItem downloadItem) + { + CurrentDownloadConfiguration = GetDownloadConfiguration(); + CurrentDownloadService = CreateDownloadService(CurrentDownloadConfiguration); - return CurrentDownloadService; - } - private static void WriteKeyboardGuidLines() + if (string.IsNullOrWhiteSpace(downloadItem.FileName)) { - Console.Clear(); - Console.WriteLine("Press Esc to Stop current file download"); - Console.WriteLine("Press P to Pause and R to Resume downloading"); - Console.WriteLine("Press Up Arrow to Increase download speed 2X"); - Console.WriteLine("Press Down Arrow to Decrease download speed 2X"); - Console.WriteLine(); + await CurrentDownloadService.DownloadFileTaskAsync(downloadItem.Url, new DirectoryInfo(downloadItem.FolderPath)).ConfigureAwait(false); } - private static DownloadService CreateDownloadService(DownloadConfiguration config) + else { - var downloadService = new DownloadService(config); - - // Provide `FileName` and `TotalBytesToReceive` at the start of each downloads - downloadService.DownloadStarted += OnDownloadStarted; + await CurrentDownloadService.DownloadFileTaskAsync(downloadItem.Url, downloadItem.FileName).ConfigureAwait(false); + } - // Provide any information about chunker downloads, - // like progress percentage per chunk, speed, - // total received bytes and received bytes array to live streaming. - downloadService.ChunkDownloadProgressChanged += OnChunkDownloadProgressChanged; + return CurrentDownloadService; + } + private static void WriteKeyboardGuidLines() + { + Console.Clear(); + Console.WriteLine("Press Esc to Stop current file download"); + Console.WriteLine("Press P to Pause and R to Resume downloading"); + Console.WriteLine("Press Up Arrow to Increase download speed 2X"); + Console.WriteLine("Press Down Arrow to Decrease download speed 2X"); + Console.WriteLine(); + } + private static DownloadService CreateDownloadService(DownloadConfiguration config) + { + var downloadService = new DownloadService(config); - // Provide any information about download progress, - // like progress percentage of sum of chunks, total speed, - // average speed, total received bytes and received bytes array - // to live streaming. - downloadService.DownloadProgressChanged += OnDownloadProgressChanged; + // Provide `FileName` and `TotalBytesToReceive` at the start of each downloads + downloadService.DownloadStarted += OnDownloadStarted; - // Download completed event that can include occurred errors or - // cancelled or download completed successfully. - downloadService.DownloadFileCompleted += OnDownloadFileCompleted; + // Provide any information about chunker downloads, + // like progress percentage per chunk, speed, + // total received bytes and received bytes array to live streaming. + downloadService.ChunkDownloadProgressChanged += OnChunkDownloadProgressChanged; - return downloadService; - } + // Provide any information about download progress, + // like progress percentage of sum of chunks, total speed, + // average speed, total received bytes and received bytes array + // to live streaming. + downloadService.DownloadProgressChanged += OnDownloadProgressChanged; - private static void OnDownloadStarted(object sender, DownloadStartedEventArgs e) - { - WriteKeyboardGuidLines(); - ConsoleProgress = new ProgressBar(10000, $"Downloading {Path.GetFileName(e.FileName)} ", ProcessBarOption); - } - private static void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e) - { - ConsoleProgress?.Tick(10000); + // Download completed event that can include occurred errors or + // cancelled or download completed successfully. + downloadService.DownloadFileCompleted += OnDownloadFileCompleted; - if (e.Cancelled) - { - ConsoleProgress.Message += " CANCELED"; - } - else if (e.Error != null) - { - Console.Error.WriteLine(e.Error); - Debugger.Break(); - } - else - { - ConsoleProgress.Message += " DONE"; - Console.Title = "100%"; - } + return downloadService; + } - foreach (var child in ChildConsoleProgresses.Values) - child.Dispose(); + private static void OnDownloadStarted(object sender, DownloadStartedEventArgs e) + { + WriteKeyboardGuidLines(); + ConsoleProgress = new ProgressBar(10000, $"Downloading {Path.GetFileName(e.FileName)} ", ProcessBarOption); + } + private static void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e) + { + ConsoleProgress?.Tick(10000); - ChildConsoleProgresses.Clear(); - ConsoleProgress?.Dispose(); + if (e.Cancelled) + { + ConsoleProgress.Message += " CANCELED"; } - private static void OnChunkDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) + else if (e.Error != null) { - ChildProgressBar progress = ChildConsoleProgresses.GetOrAdd(e.ProgressId, - id => ConsoleProgress?.Spawn(10000, $"chunk {id}", ChildOption)); - progress.Tick((int)(e.ProgressPercentage * 100)); - var activeChunksCount = e.ActiveChunks; // Running chunks count + Console.Error.WriteLine(e.Error); + Debugger.Break(); } - private static void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) + else { - ConsoleProgress.Tick((int)(e.ProgressPercentage * 100)); - if (sender is DownloadService ds) - e.UpdateTitleInfo(ds.IsPaused); + ConsoleProgress.Message += " DONE"; + Console.Title = "100%"; } + + foreach (var child in ChildConsoleProgresses.Values) + child.Dispose(); + + ChildConsoleProgresses.Clear(); + ConsoleProgress?.Dispose(); + } + private static void OnChunkDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) + { + ChildProgressBar progress = ChildConsoleProgresses.GetOrAdd(e.ProgressId, + id => ConsoleProgress?.Spawn(10000, $"chunk {id}", ChildOption)); + progress.Tick((int)(e.ProgressPercentage * 100)); + var activeChunksCount = e.ActiveChunks; // Running chunks count + } + private static void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) + { + ConsoleProgress.Tick((int)(e.ProgressPercentage * 100)); + if (sender is DownloadService ds) + e.UpdateTitleInfo(ds.IsPaused); } } \ No newline at end of file