From 959e105924858df1ae0afd53eed6fede5d9810eb Mon Sep 17 00:00:00 2001 From: niksedk Date: Thu, 18 Aug 2022 16:19:57 +0200 Subject: [PATCH] Working on removing obsolete WebClient --- build.bat | 43 +++++------ build_beta.bat | 43 +++++------ installer/Subtitle_Edit_installer.iss | 2 + src/libse/Common/HttpClientHelper.cs | 93 ++++++++++++++++++++++++ src/libse/Common/Settings.cs | 2 + src/libse/LibSE.csproj | 1 + src/ui/Forms/AudioToTextModelDownload.cs | 69 ++++++++++-------- src/ui/Forms/DownloadFfmpeg.cs | 65 ++++++++++------- src/ui/Forms/DownloadVosk.Designer.cs | 4 +- src/ui/Forms/DownloadVosk.cs | 62 +++++++++------- src/ui/Forms/DownloadYouTubeDl.cs | 56 +++++++++----- src/ui/Forms/Options/SettingsMpv.cs | 93 +++++++++++++----------- 12 files changed, 347 insertions(+), 186 deletions(-) create mode 100644 src/libse/Common/HttpClientHelper.cs diff --git a/build.bat b/build.bat index 057fb0209..d780964f8 100644 --- a/build.bat +++ b/build.bat @@ -176,27 +176,28 @@ IF NOT EXIST "temp_zip\Tesseract302" MD "temp_zip\Tesseract302" IF NOT EXIST "temp_zip\Icons" MD "temp_zip\Icons" ECHO. -COPY /Y /V "..\..\..\..\LICENSE.txt" "temp_zip\" -COPY /Y /V "..\..\..\..\Changelog.txt" "temp_zip\" -COPY /Y /V "..\..\..\..\preview.mkv" "temp_zip\" -COPY /Y /V "Hunspellx86.dll" "temp_zip\" -COPY /Y /V "Hunspellx64.dll" "temp_zip\" -COPY /Y /V "libse.dll" "temp_zip\" -COPY /Y /V "zlib.net.dll" "temp_zip\" -COPY /Y /V "NHunspell.dll" "temp_zip\" -COPY /Y /V "UtfUnknown.dll" "temp_zip\" -COPY /Y /V "Vosk.dll" "temp_zip\" -COPY /Y /V "NCalc.dll" "temp_zip\" -COPY /Y /V "..\..\DLLs\Interop.QuartzTypeLib.dll" "temp_zip\" -COPY /Y /V "System.Net.Http.Extensions.dll" "temp_zip\" -COPY /Y /V "Newtonsoft.Json.dll" "temp_zip\" -COPY /Y /V "System.Net.Http.Primitives.dll" "temp_zip\" -COPY /Y /V "SubtitleEdit.exe" "temp_zip\" -COPY /Y /V "Languages\*.xml" "temp_zip\Languages\" -COPY /Y /V "..\..\..\..\Dictionaries\*.*" "temp_zip\Dictionaries\" -COPY /Y /V "..\..\..\..\Ocr\*.*" "temp_zip\Ocr\" -XCOPY /Y /V "..\..\..\..\Tesseract302\*.*" "temp_zip\Tesseract302\" /S -COPY /Y /V "..\..\..\..\Icons\*.ico" "temp_zip\Icons\" +COPY /Y /V "..\..\..\..\LICENSE.txt" "temp_zip\" +COPY /Y /V "..\..\..\..\Changelog.txt" "temp_zip\" +COPY /Y /V "..\..\..\..\preview.mkv" "temp_zip\" +COPY /Y /V "Hunspellx86.dll" "temp_zip\" +COPY /Y /V "Hunspellx64.dll" "temp_zip\" +COPY /Y /V "libse.dll" "temp_zip\" +COPY /Y /V "zlib.net.dll" "temp_zip\" +COPY /Y /V "NHunspell.dll" "temp_zip\" +COPY /Y /V "UtfUnknown.dll" "temp_zip\" +COPY /Y /V "Vosk.dll" "temp_zip\" +COPY /Y /V "NCalc.dll" "temp_zip\" +COPY /Y /V "..\..\DLLs\Interop.QuartzTypeLib.dll" "temp_zip\" +COPY /Y /V "System.Net.Http.Extensions.dll" "temp_zip\" +COPY /Y /V "Newtonsoft.Json.dll" "temp_zip\" +COPY /Y /V "System.Net.Http.Primitives.dll" "temp_zip\" +COPY /Y /V "System.Net.Http.dll" "temp_zip\" +COPY /Y /V "SubtitleEdit.exe" "temp_zip\" +COPY /Y /V "Languages\*.xml" "temp_zip\Languages\" +COPY /Y /V "..\..\..\..\Dictionaries\*.*" "temp_zip\Dictionaries\" +COPY /Y /V "..\..\..\..\Ocr\*.*" "temp_zip\Ocr\" +XCOPY /Y /V "..\..\..\..\Tesseract302\*.*" "temp_zip\Tesseract302\" /S +COPY /Y /V "..\..\..\..\Icons\*.ico" "temp_zip\Icons\" PUSHD "temp_zip" START "" /B /WAIT "%SEVENZIP%" a -tzip -mx=9 "SubtitleEdit-%VERSION%.zip" * >NUL diff --git a/build_beta.bat b/build_beta.bat index ceed5eac1..e700a6878 100644 --- a/build_beta.bat +++ b/build_beta.bat @@ -164,27 +164,28 @@ IF NOT EXIST "temp_zip\Tesseract302" MD "temp_zip\Tesseract302" IF NOT EXIST "temp_zip\Icons" MD "temp_zip\Icons" ECHO. -COPY /Y /V "..\..\..\..\LICENSE.txt" "temp_zip\" -COPY /Y /V "..\..\..\..\Changelog.txt" "temp_zip\" -COPY /Y /V "..\..\..\..\preview.mkv" "temp_zip\" -COPY /Y /V "Hunspellx86.dll" "temp_zip\" -COPY /Y /V "Hunspellx64.dll" "temp_zip\" -COPY /Y /V "libse.dll" "temp_zip\" -COPY /Y /V "zlib.net.dll" "temp_zip\" -COPY /Y /V "NHunspell.dll" "temp_zip\" -COPY /Y /V "UtfUnknown.dll" "temp_zip\" -COPY /Y /V "Vosk.dll" "temp_zip\" -COPY /Y /V "NCalc.dll" "temp_zip\" -COPY /Y /V "..\..\DLLs\Interop.QuartzTypeLib.dll" "temp_zip\" -COPY /Y /V "System.Net.Http.Extensions.dll" "temp_zip\" -COPY /Y /V "Newtonsoft.Json.dll" "temp_zip\" -COPY /Y /V "System.Net.Http.Primitives.dll" "temp_zip\" -COPY /Y /V "SubtitleEdit.exe" "temp_zip\" -COPY /Y /V "Languages\*.xml" "temp_zip\Languages\" -COPY /Y /V "..\..\..\..\Dictionaries\*.*" "temp_zip\Dictionaries\" -COPY /Y /V "..\..\..\..\Ocr\*.*" "temp_zip\Ocr\" -XCOPY /Y /V "..\..\..\..\Tesseract302\*.*" "temp_zip\Tesseract302\" /S -COPY /Y /V "..\..\..\..\Icons\*.ico" "temp_zip\Icons\" +COPY /Y /V "..\..\..\..\LICENSE.txt" "temp_zip\" +COPY /Y /V "..\..\..\..\Changelog.txt" "temp_zip\" +COPY /Y /V "..\..\..\..\preview.mkv" "temp_zip\" +COPY /Y /V "Hunspellx86.dll" "temp_zip\" +COPY /Y /V "Hunspellx64.dll" "temp_zip\" +COPY /Y /V "libse.dll" "temp_zip\" +COPY /Y /V "zlib.net.dll" "temp_zip\" +COPY /Y /V "NHunspell.dll" "temp_zip\" +COPY /Y /V "UtfUnknown.dll" "temp_zip\" +COPY /Y /V "Vosk.dll" "temp_zip\" +COPY /Y /V "NCalc.dll" "temp_zip\" +COPY /Y /V "..\..\DLLs\Interop.QuartzTypeLib.dll" "temp_zip\" +COPY /Y /V "System.Net.Http.Extensions.dll" "temp_zip\" +COPY /Y /V "Newtonsoft.Json.dll" "temp_zip\" +COPY /Y /V "System.Net.Http.Primitives.dll" "temp_zip\" +COPY /Y /V "System.Net.Http.dll" "temp_zip\" +COPY /Y /V "SubtitleEdit.exe" "temp_zip\" +COPY /Y /V "Languages\*.xml" "temp_zip\Languages\" +COPY /Y /V "..\..\..\..\Dictionaries\*.*" "temp_zip\Dictionaries\" +COPY /Y /V "..\..\..\..\Ocr\*.*" "temp_zip\Ocr\" +XCOPY /Y /V "..\..\..\..\Tesseract302\*.*" "temp_zip\Tesseract302\" /S +COPY /Y /V "..\..\..\..\Icons\*.ico" "temp_zip\Icons\" PUSHD "temp_zip" START "" /B /WAIT "%SEVENZIP%" a -tzip -mx=9 "SubtitleEditBeta.zip" * >NUL diff --git a/installer/Subtitle_Edit_installer.iss b/installer/Subtitle_Edit_installer.iss index d567aa828..44867f891 100644 --- a/installer/Subtitle_Edit_installer.iss +++ b/installer/Subtitle_Edit_installer.iss @@ -312,6 +312,7 @@ Source: ..\src\ui\DLLs\Interop.QuartzTypeLib.dll; DestDir: {app}; Source: {#bindir}\Newtonsoft.Json.dll; DestDir: {app}; Flags: ignoreversion; Components: main Source: {#bindir}\System.Net.Http.Extensions.dll; DestDir: {app}; Flags: ignoreversion; Components: main Source: {#bindir}\System.Net.Http.Primitives.dll; DestDir: {app}; Flags: ignoreversion; Components: main +Source: {#bindir}\System.Net.Http.dll; DestDir: {app}; Flags: ignoreversion; Components: main Source: ..\Changelog.txt; DestDir: {app}; Flags: ignoreversion; Components: main Source: ..\LICENSE.txt; DestDir: {app}; Flags: ignoreversion; Components: main Source: Icons\uninstall.ico; DestDir: {app}\Icons; Flags: ignoreversion; Components: main @@ -351,6 +352,7 @@ Type: files; Name: {app}\Interop.QuartzTypeLib.dll; Check: IsU Type: files; Name: {app}\Newtonsoft.Json.dll; Check: IsUpgrade() Type: files; Name: {app}\System.Net.Http.Extensions.dll; Check: IsUpgrade() Type: files; Name: {app}\System.Net.Http.Primitives.dll; Check: IsUpgrade() +Type: files; Name: {app}\System.Net.Http.dll; Check: IsUpgrade() ; Remove old files from the {app} dir Type: files; Name: {app}\Dictionaries\da_names.xml; Check: IsUpgrade() diff --git a/src/libse/Common/HttpClientHelper.cs b/src/libse/Common/HttpClientHelper.cs new file mode 100644 index 000000000..0be0983bb --- /dev/null +++ b/src/libse/Common/HttpClientHelper.cs @@ -0,0 +1,93 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Nikse.SubtitleEdit.Core.Common +{ + public static class HttpClientHelper + { + public static HttpClient MakeHttpClient() + { + return new HttpClient(HttpClientHelper.GetHttpClientHandler(Configuration.Settings.Proxy)); + } + + public static HttpClientHandler GetHttpClientHandler(ProxySettings proxySettings) + { + var handler = new HttpClientHandler(); + + if (!string.IsNullOrEmpty(proxySettings.ProxyAddress)) + { + handler.Proxy = new WebProxy(proxySettings.ProxyAddress); + handler.UseProxy = true; + } + + if (proxySettings.UseDefaultCredentials) + { + handler.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials; + handler.Credentials = CredentialCache.DefaultNetworkCredentials; + } + else if (!string.IsNullOrEmpty(proxySettings.UserName) && !string.IsNullOrEmpty(proxySettings.ProxyAddress)) + { + var credentialCache = new CredentialCache { { new Uri(proxySettings.ProxyAddress), proxySettings.AuthType, new NetworkCredential(proxySettings.UserName, proxySettings.Password) } }; + handler.Credentials = credentialCache; + } + + return handler; + } + + + public static async Task DownloadAsync(this HttpClient client, string requestUri, Stream destination, IProgress progress = null, CancellationToken cancellationToken = default) + { + using (var response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken)) + { + var contentLength = response.Content.Headers.ContentLength; + + using (var downloadStream = await response.Content.ReadAsStreamAsync()) + { + if (progress == null || !contentLength.HasValue) + { + await downloadStream.CopyToAsync(destination); + return; + } + + // Convert absolute progress (bytes downloaded) into relative progress (0% - 100%) + var relativeProgress = new Progress(totalBytes => progress.Report((float)totalBytes / contentLength.Value)); + // Use extension method to report progress while downloading + await CopyToAsync(downloadStream, destination, 81920, relativeProgress, cancellationToken); + progress.Report(1); + } + } + } + + private static async Task CopyToAsync(Stream source, Stream destination, int bufferSize, IProgress progress = null, CancellationToken cancellationToken = default) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (destination == null) + { + throw new ArgumentNullException(nameof(destination)); + } + + if (bufferSize < 0) + { + throw new ArgumentOutOfRangeException(nameof(bufferSize)); + } + + var buffer = new byte[bufferSize]; + long totalBytesRead = 0; + int bytesRead; + while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) + { + await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); + totalBytesRead += bytesRead; + progress?.Report(totalBytesRead); + } + } + } +} diff --git a/src/libse/Common/Settings.cs b/src/libse/Common/Settings.cs index 4a08d4628..dbabbbf83 100644 --- a/src/libse/Common/Settings.cs +++ b/src/libse/Common/Settings.cs @@ -836,6 +836,8 @@ $HorzAlign = Center public class ProxySettings { public string ProxyAddress { get; set; } + public string AuthType { get; set; } + public bool UseDefaultCredentials { get; set; } public string UserName { get; set; } public string Password { get; set; } public string Domain { get; set; } diff --git a/src/libse/LibSE.csproj b/src/libse/LibSE.csproj index 9fe07f724..76d8fcf2c 100644 --- a/src/libse/LibSE.csproj +++ b/src/libse/LibSE.csproj @@ -56,6 +56,7 @@ SE 3.6.7 + diff --git a/src/ui/Forms/AudioToTextModelDownload.cs b/src/ui/Forms/AudioToTextModelDownload.cs index 3558db1dd..8305e2cda 100644 --- a/src/ui/Forms/AudioToTextModelDownload.cs +++ b/src/ui/Forms/AudioToTextModelDownload.cs @@ -4,7 +4,7 @@ using Nikse.SubtitleEdit.Logic; using System; using System.IO; using System.Linq; -using System.Net; +using System.Threading; using System.Windows.Forms; namespace Nikse.SubtitleEdit.Forms @@ -12,6 +12,7 @@ namespace Nikse.SubtitleEdit.Forms public sealed partial class AudioToTextModelDownload : Form { public bool AutoClose { get; internal set; } + private readonly CancellationTokenSource _cancellationTokenSource; public AudioToTextModelDownload() { @@ -24,7 +25,7 @@ namespace Nikse.SubtitleEdit.Forms UiUtil.FixLargeFonts(this, buttonDownload); var selectedIndex = 0; - foreach (var downloadModel in DownloadModel.VoskModels.OrderBy(p=>p.LanguageName)) + foreach (var downloadModel in DownloadModel.VoskModels.OrderBy(p => p.LanguageName)) { comboBoxModels.Items.Add(downloadModel); if (selectedIndex == 0 && downloadModel.TwoLetterLanguageCode == "en") @@ -35,8 +36,8 @@ namespace Nikse.SubtitleEdit.Forms comboBoxModels.SelectedIndex = selectedIndex; labelPleaseWait.Text = string.Empty; - textBoxError.Visible = false; + _cancellationTokenSource = new CancellationTokenSource(); } private void AudioToTextDownload_KeyDown(object sender, KeyEventArgs e) @@ -55,63 +56,69 @@ namespace Nikse.SubtitleEdit.Forms } var downloadModel = (DownloadModel)comboBoxModels.Items[comboBoxModels.SelectedIndex]; + var url = downloadModel.Url; try { labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait; buttonDownload.Enabled = false; Refresh(); Cursor = Cursors.WaitCursor; - var url = downloadModel.Url; - var wc = new WebClient { Proxy = Utilities.GetProxy() }; - - wc.DownloadDataCompleted += wc_DownloadDataCompleted; - wc.DownloadProgressChanged += (o, args) => + var httpClient = HttpClientHelper.MakeHttpClient(); + using (var downloadStream = new MemoryStream()) { - labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + args.ProgressPercentage + "%"; - }; - wc.DownloadDataAsync(new Uri(url)); + var downloadTask = httpClient.DownloadAsync(url, downloadStream, new Progress((progress) => + { + var pct = (int)Math.Round(progress * 100.0, MidpointRounding.AwayFromZero); + labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + pct + "%"; + }), _cancellationTokenSource.Token); + + while (!downloadTask.IsCompleted && !downloadTask.IsCanceled) + { + Application.DoEvents(); + } + + if (downloadTask.IsCanceled) + { + DialogResult = DialogResult.Cancel; + labelPleaseWait.Refresh(); + return; + } + + CompleteDownload(downloadStream); + } } catch (Exception exception) { labelPleaseWait.Text = string.Empty; buttonDownload.Enabled = true; Cursor = Cursors.Default; - MessageBox.Show(exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); + MessageBox.Show($"Unable to download {url}!" + Environment.NewLine + Environment.NewLine + + exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); + DialogResult = DialogResult.Cancel; } } private void buttonCancel_Click(object sender, EventArgs e) { + _cancellationTokenSource.Cancel(); DialogResult = DialogResult.Cancel; } - private void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) + private void CompleteDownload(MemoryStream downloadStream) { + if (downloadStream.Length == 0) + { + throw new Exception("No content downloaded - missing file or no internet connection!"); + } + var folder = Path.Combine(Configuration.DataDirectory, "Vosk"); - if (e.Error != null) - { - Width = 630; - Height = 350; - labelPleaseWait.Text = string.Empty; - var errorMsg = string.Format(LanguageSettings.Current.SettingsFfmpeg.XDownloadFailed, "Vosk model"); - textBoxError.Visible = true; - var downloadModel = (DownloadModel)comboBoxModels.Items[comboBoxModels.SelectedIndex]; - var dirName = Path.GetFileNameWithoutExtension(downloadModel.Url); - textBoxError.Text = $"{errorMsg}{Environment.NewLine}{Environment.NewLine}You could manually download and unpack{Environment.NewLine}{downloadModel.Url}{Environment.NewLine}to{Environment.NewLine}{folder}{Path.DirectorySeparatorChar}{dirName}" + Environment.NewLine + - Environment.NewLine + - e.Error; - Cursor = Cursors.Default; - return; - } - if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } - using (var ms = new MemoryStream(e.Result)) - using (var zip = ZipExtractor.Open(ms)) + using (var zip = ZipExtractor.Open(downloadStream)) { var dir = zip.ReadCentralDir(); foreach (var entry in dir) diff --git a/src/ui/Forms/DownloadFfmpeg.cs b/src/ui/Forms/DownloadFfmpeg.cs index 8fa8247b0..385dda105 100644 --- a/src/ui/Forms/DownloadFfmpeg.cs +++ b/src/ui/Forms/DownloadFfmpeg.cs @@ -1,9 +1,8 @@ using Nikse.SubtitleEdit.Core.Common; using Nikse.SubtitleEdit.Logic; using System; -using System.Collections.Generic; using System.IO; -using System.Net; +using System.Threading; using System.Windows.Forms; namespace Nikse.SubtitleEdit.Forms @@ -12,6 +11,7 @@ namespace Nikse.SubtitleEdit.Forms { public string FFmpegPath { get; internal set; } public bool AutoClose { get; internal set; } + private readonly CancellationTokenSource _cancellationTokenSource; public DownloadFfmpeg() { @@ -22,6 +22,7 @@ namespace Nikse.SubtitleEdit.Forms buttonOK.Text = LanguageSettings.Current.General.Ok; buttonCancel.Text = LanguageSettings.Current.General.Cancel; UiUtil.FixLargeFonts(this, buttonOK); + _cancellationTokenSource = new CancellationTokenSource(); } private void DownloadFfmpeg_KeyDown(object sender, KeyEventArgs e) @@ -39,62 +40,76 @@ namespace Nikse.SubtitleEdit.Forms private void buttonCancel_Click(object sender, EventArgs e) { + _cancellationTokenSource.Cancel(); DialogResult = DialogResult.Cancel; } private void DownloadFfmpeg_Shown(object sender, EventArgs e) { + var url = "https://github.com/SubtitleEdit/support-files/raw/master/ffpmeg/ffmpeg-" + IntPtr.Size * 8 + ".zip"; + try { labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait; buttonOK.Enabled = false; - Refresh(); Cursor = Cursors.WaitCursor; - string url = "https://github.com/SubtitleEdit/support-files/raw/master/ffpmeg/ffmpeg-" + IntPtr.Size * 8 + ".zip"; - var wc = new WebClient { Proxy = Utilities.GetProxy() }; - - wc.DownloadDataCompleted += wc_DownloadDataCompleted; - wc.DownloadProgressChanged += (o, args) => + var httpClient = HttpClientHelper.MakeHttpClient(); + using (var downloadStream = new MemoryStream()) { - labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + args.ProgressPercentage + "%"; - }; - wc.DownloadDataAsync(new Uri(url)); + var downloadTask = httpClient.DownloadAsync(url, downloadStream, new Progress((progress) => + { + var pct = (int)Math.Round(progress * 100.0, MidpointRounding.AwayFromZero); + labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + pct + "%"; + }), _cancellationTokenSource.Token); + + while (!downloadTask.IsCompleted && !downloadTask.IsCanceled) + { + Application.DoEvents(); + } + + if (downloadTask.IsCanceled) + { + DialogResult = DialogResult.Cancel; + labelPleaseWait.Refresh(); + return; + } + + CompleteDownload(downloadStream); + } } catch (Exception exception) { labelPleaseWait.Text = string.Empty; buttonOK.Enabled = true; Cursor = Cursors.Default; - MessageBox.Show(exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); + MessageBox.Show($"Unable to download {url}!" + Environment.NewLine + Environment.NewLine + + exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); + DialogResult = DialogResult.Cancel; } } - private void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) + private void CompleteDownload(Stream downloadStream) { - if (e.Error != null) + if (downloadStream.Length == 0) { - labelPleaseWait.Text = string.Format(LanguageSettings.Current.SettingsFfmpeg.XDownloadFailed, "ffmpeg"); - buttonOK.Enabled = true; - Cursor = Cursors.Default; - return; + throw new Exception("No content downloaded - missing file or no internet connection!"); } - string folder = Path.Combine(Configuration.DataDirectory, "ffmpeg"); + var folder = Path.Combine(Configuration.DataDirectory, "ffmpeg"); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } - using (var ms = new MemoryStream(e.Result)) - using (ZipExtractor zip = ZipExtractor.Open(ms)) + using (var zip = ZipExtractor.Open(downloadStream)) { - List dir = zip.ReadCentralDir(); - foreach (ZipExtractor.ZipFileEntry entry in dir) + var dir = zip.ReadCentralDir(); + foreach (var entry in dir) { - string fileName = Path.GetFileName(entry.FilenameInZip); + var fileName = Path.GetFileName(entry.FilenameInZip); if (fileName != null) { - string path = Path.Combine(folder, fileName); + var path = Path.Combine(folder, fileName); if (fileName.EndsWith("ffmpeg.exe", StringComparison.OrdinalIgnoreCase)) { FFmpegPath = path; diff --git a/src/ui/Forms/DownloadVosk.Designer.cs b/src/ui/Forms/DownloadVosk.Designer.cs index d1de66425..350322cb0 100644 --- a/src/ui/Forms/DownloadVosk.Designer.cs +++ b/src/ui/Forms/DownloadVosk.Designer.cs @@ -51,7 +51,7 @@ this.buttonOK.Name = "buttonOK"; this.buttonOK.Size = new System.Drawing.Size(75, 23); this.buttonOK.TabIndex = 15; - this.buttonOK.Text = "&OK"; + this.buttonOK.Text = "7"; this.buttonOK.UseVisualStyleBackColor = true; this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); // @@ -68,7 +68,7 @@ this.buttonCancel.UseVisualStyleBackColor = true; this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); // - // textBox1 + // textBoxError // this.textBoxError.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) diff --git a/src/ui/Forms/DownloadVosk.cs b/src/ui/Forms/DownloadVosk.cs index 07c58e74e..fc84b9f32 100644 --- a/src/ui/Forms/DownloadVosk.cs +++ b/src/ui/Forms/DownloadVosk.cs @@ -3,7 +3,7 @@ using Nikse.SubtitleEdit.Logic; using System; using System.IO; using System.Linq; -using System.Net; +using System.Threading; using System.Windows.Forms; namespace Nikse.SubtitleEdit.Forms @@ -11,6 +11,7 @@ namespace Nikse.SubtitleEdit.Forms public sealed partial class DownloadVosk : Form { public bool AutoClose { get; internal set; } + private readonly CancellationTokenSource _cancellationTokenSource; private static readonly string[] VoskNewSha512Hashes = { @@ -28,6 +29,7 @@ namespace Nikse.SubtitleEdit.Forms buttonCancel.Text = LanguageSettings.Current.General.Cancel; UiUtil.FixLargeFonts(this, buttonOK); textBoxError.Visible = false; + _cancellationTokenSource = new CancellationTokenSource(); } private void DownloadVosk_KeyDown(object sender, KeyEventArgs e) @@ -45,6 +47,7 @@ namespace Nikse.SubtitleEdit.Forms private void buttonCancel_Click(object sender, EventArgs e) { + _cancellationTokenSource.Cancel(); DialogResult = DialogResult.Cancel; } @@ -59,50 +62,59 @@ namespace Nikse.SubtitleEdit.Forms Refresh(); Cursor = Cursors.WaitCursor; - var wc = new WebClient { Proxy = Utilities.GetProxy() }; - wc.DownloadDataCompleted += wc_DownloadDataCompleted; - wc.DownloadProgressChanged += (o, args) => + var httpClient = HttpClientHelper.MakeHttpClient(); + using (var downloadStream = new MemoryStream()) { - labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + args.ProgressPercentage + "%"; - }; - wc.DownloadDataAsync(new Uri(VoskUrl)); + var downloadTask = httpClient.DownloadAsync(VoskUrl, downloadStream, new Progress((progress) => + { + var pct = (int)Math.Round(progress * 100.0, MidpointRounding.AwayFromZero); + labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + pct + "%"; + }), _cancellationTokenSource.Token); + + while (!downloadTask.IsCompleted && !downloadTask.IsCanceled) + { + Application.DoEvents(); + } + + if (downloadTask.IsCanceled) + { + DialogResult = DialogResult.Cancel; + labelPleaseWait.Refresh(); + return; + } + + CompleteDownload(downloadStream); + } } catch (Exception exception) { labelPleaseWait.Text = string.Empty; buttonOK.Enabled = true; Cursor = Cursors.Default; - MessageBox.Show(exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); + MessageBox.Show($"Unable to download {VoskUrl}!" + Environment.NewLine + Environment.NewLine + + exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); + DialogResult = DialogResult.Cancel; } } - private void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) + private void CompleteDownload(MemoryStream downloadStream) { - var folder = Path.Combine(Configuration.DataDirectory, "Vosk"); - - if (e.Error != null) + if (downloadStream.Length == 0) { - Width = 630; - Height = 350; - labelPleaseWait.Text = string.Format(LanguageSettings.Current.SettingsFfmpeg.XDownloadFailed, "Vosk"); - textBoxError.Visible = true; - textBoxError.Text = $"You could manually download and unpack{Environment.NewLine}{VoskUrl}{Environment.NewLine}to{Environment.NewLine}{folder}" + Environment.NewLine + - Environment.NewLine + - e.Error; - buttonOK.Enabled = true; - Cursor = Cursors.Default; - return; + throw new Exception("No content downloaded - missing file or no internet connection!"); } - var hash = Utilities.GetSha512Hash(e.Result); + var folder = Path.Combine(Configuration.DataDirectory, "Vosk"); + + var hash = Utilities.GetSha512Hash(downloadStream.ToArray()); if (!VoskNewSha512Hashes.Contains(hash)) { MessageBox.Show("Vosk SHA-512 hash does not match!"); return; } - using (var ms = new MemoryStream(e.Result)) - using (var zip = ZipExtractor.Open(ms)) + downloadStream.Position = 0; + using (var zip = ZipExtractor.Open(downloadStream)) { var dir = zip.ReadCentralDir(); foreach (var entry in dir) diff --git a/src/ui/Forms/DownloadYouTubeDl.cs b/src/ui/Forms/DownloadYouTubeDl.cs index 167b366a9..47ba645d2 100644 --- a/src/ui/Forms/DownloadYouTubeDl.cs +++ b/src/ui/Forms/DownloadYouTubeDl.cs @@ -2,7 +2,7 @@ using Nikse.SubtitleEdit.Logic; using System; using System.IO; -using System.Net; +using System.Threading; using System.Windows.Forms; namespace Nikse.SubtitleEdit.Forms @@ -12,6 +12,7 @@ namespace Nikse.SubtitleEdit.Forms public const string Url = "https://github.com/yt-dlp/yt-dlp/releases/download/2022.05.18/yt-dlp.exe"; public const string Sha512Hash = "f8f55be89b8b4b5c9703bb594367ad10c245dd1e1de9182a8a3d8ae06220aeabe200ed9b797d6f176a5d10f99ff3bbb48176c4e52cd9f4cc3c1fac451df42dde"; public bool AutoClose { get; internal set; } + private readonly CancellationTokenSource _cancellationTokenSource; public DownloadYouTubeDl() { @@ -22,6 +23,7 @@ namespace Nikse.SubtitleEdit.Forms buttonOK.Text = LanguageSettings.Current.General.Ok; buttonCancel.Text = LanguageSettings.Current.General.Cancel; UiUtil.FixLargeFonts(this, buttonOK); + _cancellationTokenSource = new CancellationTokenSource(); } private void DownloadFfmpeg_KeyDown(object sender, KeyEventArgs e) @@ -39,6 +41,7 @@ namespace Nikse.SubtitleEdit.Forms private void buttonCancel_Click(object sender, EventArgs e) { + _cancellationTokenSource.Cancel(); DialogResult = DialogResult.Cancel; } @@ -50,48 +53,63 @@ namespace Nikse.SubtitleEdit.Forms buttonOK.Enabled = false; Refresh(); Cursor = Cursors.WaitCursor; - var wc = new WebClient { Proxy = Utilities.GetProxy() }; - - wc.DownloadDataCompleted += wc_DownloadDataCompleted; - wc.DownloadProgressChanged += (o, args) => + var httpClient = HttpClientHelper.MakeHttpClient(); + using (var downloadStream = new MemoryStream()) { - labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + args.ProgressPercentage + "%"; - }; - wc.DownloadDataAsync(new Uri(Url)); + var downloadTask = httpClient.DownloadAsync(Url, downloadStream, new Progress((progress) => + { + var pct = (int)Math.Round(progress * 100.0, MidpointRounding.AwayFromZero); + labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + pct + "%"; + }), _cancellationTokenSource.Token); + + while (!downloadTask.IsCompleted && !downloadTask.IsCanceled) + { + Application.DoEvents(); + } + + if (downloadTask.IsCanceled) + { + DialogResult = DialogResult.Cancel; + labelPleaseWait.Refresh(); + return; + } + + CompleteDownload(downloadStream); + } } catch (Exception exception) { labelPleaseWait.Text = string.Empty; buttonOK.Enabled = true; Cursor = Cursors.Default; - MessageBox.Show(exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); + MessageBox.Show($"Unable to download {Url}!" + Environment.NewLine + Environment.NewLine + + exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); + DialogResult = DialogResult.Cancel; } } - private void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) + private void CompleteDownload(MemoryStream downloadStream) { - if (e.Error != null) + if (downloadStream.Length == 0) { - labelPleaseWait.Text = string.Format(LanguageSettings.Current.SettingsFfmpeg.XDownloadFailed, "youtube-dl"); - buttonOK.Enabled = true; - Cursor = Cursors.Default; - return; + throw new Exception("No content downloaded - missing file or no internet connection!"); } - string folder = Path.Combine(Configuration.DataDirectory); + var folder = Path.Combine(Configuration.DataDirectory); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } - var hash = Utilities.GetSha512Hash(e.Result); + var bytes = downloadStream.ToArray(); + var hash = Utilities.GetSha512Hash(bytes); if (hash != Sha512Hash) { MessageBox.Show("yt-dlp.exe SHA-512 hash does not match!"); return; } - File.WriteAllBytes(Path.Combine(folder, "yt-dlp.exe"), e.Result); + File.WriteAllBytes(Path.Combine(folder, "yt-dlp.exe"), bytes); Cursor = Cursors.Default; labelPleaseWait.Text = string.Empty; @@ -103,7 +121,7 @@ namespace Nikse.SubtitleEdit.Forms } buttonOK.Enabled = true; - labelPleaseWait.Text = string.Format(LanguageSettings.Current.SettingsFfmpeg.XDownloadOk, "youtube-dl"); + labelPleaseWait.Text = string.Format(LanguageSettings.Current.SettingsFfmpeg.XDownloadOk, "yt-dlp.exe"); } } } diff --git a/src/ui/Forms/Options/SettingsMpv.cs b/src/ui/Forms/Options/SettingsMpv.cs index ec6e4ff0a..55e237f7b 100644 --- a/src/ui/Forms/Options/SettingsMpv.cs +++ b/src/ui/Forms/Options/SettingsMpv.cs @@ -4,7 +4,7 @@ using Nikse.SubtitleEdit.Logic.VideoPlayers; using System; using System.Collections.Generic; using System.IO; -using System.Net; +using System.Threading; using System.Windows.Forms; namespace Nikse.SubtitleEdit.Forms.Options @@ -13,6 +13,7 @@ namespace Nikse.SubtitleEdit.Forms.Options { private readonly bool _justDownload; private string _downloadUrl; + private readonly CancellationTokenSource _cancellationTokenSource; public SettingsMpv(bool justDownload) { @@ -31,27 +32,63 @@ namespace Nikse.SubtitleEdit.Forms.Options } UiUtil.FixLargeFonts(this, buttonOK); + _cancellationTokenSource = new CancellationTokenSource(); } - private void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) + private void ButtonDownloadClick(object sender, EventArgs e) { - if (e.Error != null) + _downloadUrl = "https://github.com/SubtitleEdit/support-files/blob/master/mpv/libmpv2-" + IntPtr.Size * 8 + ".zip?raw=true"; + try + { + labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait; + buttonOK.Enabled = false; + buttonDownload.Enabled = false; + Refresh(); + Cursor = Cursors.WaitCursor; + var httpClient = HttpClientHelper.MakeHttpClient(); + using (var downloadStream = new MemoryStream()) + { + var downloadTask = httpClient.DownloadAsync(_downloadUrl, downloadStream, new Progress((progress) => + { + var pct = (int)Math.Round(progress * 100.0, MidpointRounding.AwayFromZero); + labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + pct + "%"; + }), _cancellationTokenSource.Token); + + while (!downloadTask.IsCompleted && !downloadTask.IsCanceled) + { + Application.DoEvents(); + } + + if (downloadTask.IsCanceled) + { + DialogResult = DialogResult.Cancel; + labelPleaseWait.Refresh(); + return; + } + + CompleteDownload(downloadStream); + } + } + catch (Exception exception) { - MessageBox.Show(LanguageSettings.Current.SettingsMpv.DownloadMpvFailed + Environment.NewLine + - Environment.NewLine + - $"Manual action: Download \"{_downloadUrl}\" and unpack to \"{Configuration.DataDirectory}\"." + Environment.NewLine + - Environment.NewLine + - e.Error.Message); labelPleaseWait.Text = string.Empty; buttonOK.Enabled = true; - buttonDownload.Enabled = !Configuration.IsRunningOnLinux; Cursor = Cursors.Default; - return; + MessageBox.Show($"Unable to download {_downloadUrl}!" + Environment.NewLine + Environment.NewLine + + exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); + DialogResult = DialogResult.Cancel; + } + } + + private void CompleteDownload(MemoryStream downloadStream) + { + if (downloadStream.Length == 0) + { + throw new Exception("No content downloaded - missing file or no internet connection!"); } - string dictionaryFolder = Configuration.DataDirectory; - using (var ms = new MemoryStream(e.Result)) - using (ZipExtractor zip = ZipExtractor.Open(ms)) + var dictionaryFolder = Configuration.DataDirectory; + using (ZipExtractor zip = ZipExtractor.Open(downloadStream)) { List dir = zip.ReadCentralDir(); foreach (ZipExtractor.ZipFileEntry entry in dir) @@ -83,35 +120,6 @@ namespace Nikse.SubtitleEdit.Forms.Options DialogResult = DialogResult.OK; } - private void ButtonDownloadClick(object sender, EventArgs e) - { - try - { - labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait; - buttonOK.Enabled = false; - buttonDownload.Enabled = false; - Refresh(); - Cursor = Cursors.WaitCursor; - _downloadUrl = "https://github.com/SubtitleEdit/support-files/blob/master/mpv/libmpv2-" + IntPtr.Size * 8 + ".zip?raw=true"; - var wc = new WebClient { Proxy = Utilities.GetProxy() }; - - wc.DownloadDataCompleted += wc_DownloadDataCompleted; - wc.DownloadProgressChanged += (o, args) => - { - labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + args.ProgressPercentage + "%"; - }; - wc.DownloadDataAsync(new Uri(_downloadUrl)); - } - catch (Exception exception) - { - labelPleaseWait.Text = string.Empty; - buttonOK.Enabled = true; - buttonDownload.Enabled = !Configuration.IsRunningOnLinux; - Cursor = Cursors.Default; - MessageBox.Show(exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); - } - } - private void buttonOK_Click(object sender, EventArgs e) { DialogResult = DialogResult.OK; @@ -119,6 +127,7 @@ namespace Nikse.SubtitleEdit.Forms.Options private void buttonCancel_Click(object sender, EventArgs e) { + _cancellationTokenSource.Cancel(); DialogResult = DialogResult.Cancel; }