From 2aec84884b1a34ae8eb0bacad587d1a1f09dc9f9 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 19:10:19 +0300 Subject: [PATCH 1/5] Extract app shutdown fallback into `App.Shutdown` (#1539) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> --- DiscordChatExporter.Gui/App.axaml.cs | 12 +++++++++++- DiscordChatExporter.Gui/ViewModels/MainViewModel.cs | 5 +---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/DiscordChatExporter.Gui/App.axaml.cs b/DiscordChatExporter.Gui/App.axaml.cs index 92640636..37179c5c 100644 --- a/DiscordChatExporter.Gui/App.axaml.cs +++ b/DiscordChatExporter.Gui/App.axaml.cs @@ -7,6 +7,7 @@ using Avalonia.Platform; using DiscordChatExporter.Gui.Framework; using DiscordChatExporter.Gui.Localization; using DiscordChatExporter.Gui.Services; +using DiscordChatExporter.Gui.Utils.Extensions; using DiscordChatExporter.Gui.ViewModels; using DiscordChatExporter.Gui.ViewModels.Components; using DiscordChatExporter.Gui.ViewModels.Dialogs; @@ -17,7 +18,7 @@ using PowerKit.Extensions; namespace DiscordChatExporter.Gui; -public class App : Application, IDisposable +public partial class App : Application, IDisposable { private readonly ServiceProvider _services; private readonly SettingsService _settingsService; @@ -135,3 +136,12 @@ public class App : Application, IDisposable _services.Dispose(); } } + +public partial class App +{ + public static void Shutdown(int exitCode = 0) + { + if (Current?.ApplicationLifetime?.TryShutdown(exitCode) != true) + Environment.Exit(exitCode); + } +} diff --git a/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs b/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs index 0c0cd32f..dcf3df99 100644 --- a/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs @@ -1,7 +1,5 @@ -using System; using System.Diagnostics; using System.Threading.Tasks; -using Avalonia; using DiscordChatExporter.Gui.Framework; using DiscordChatExporter.Gui.Localization; using DiscordChatExporter.Gui.Services; @@ -88,8 +86,7 @@ public partial class MainViewModel( { updateService.FinalizeUpdate(true); - if (Application.Current?.ApplicationLifetime?.TryShutdown(2) != true) - Environment.Exit(2); + App.Shutdown(2); } ); } From 45629c9d7f289275066c85ab9b4dfdec48417cff Mon Sep 17 00:00:00 2001 From: tyrrrz <1935960+Tyrrrz@users.noreply.github.com> Date: Tue, 26 May 2026 15:00:42 +0300 Subject: [PATCH 2/5] Refactor message boxes --- DiscordChatExporter.Gui/Framework/ViewModelManager.cs | 5 +++-- .../ViewModels/Dialogs/MessageBoxViewModel.cs | 8 ++++---- DiscordChatExporter.Gui/ViewModels/MainViewModel.cs | 1 - 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/DiscordChatExporter.Gui/Framework/ViewModelManager.cs b/DiscordChatExporter.Gui/Framework/ViewModelManager.cs index aaed957d..0e25c2e7 100644 --- a/DiscordChatExporter.Gui/Framework/ViewModelManager.cs +++ b/DiscordChatExporter.Gui/Framework/ViewModelManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using DiscordChatExporter.Core.Discord.Data; +using DiscordChatExporter.Gui.Localization; using DiscordChatExporter.Gui.ViewModels; using DiscordChatExporter.Gui.ViewModels.Components; using DiscordChatExporter.Gui.ViewModels.Dialogs; @@ -8,7 +9,7 @@ using Microsoft.Extensions.DependencyInjection; namespace DiscordChatExporter.Gui.Framework; -public class ViewModelManager(IServiceProvider services) +public class ViewModelManager(IServiceProvider services, LocalizationManager localizationManager) { public MainViewModel GetMainViewModel() => services.GetRequiredService(); @@ -46,7 +47,7 @@ public class ViewModelManager(IServiceProvider services) } public MessageBoxViewModel GetMessageBoxViewModel(string title, string message) => - GetMessageBoxViewModel(title, message, "CLOSE", null); + GetMessageBoxViewModel(title, message, localizationManager.CloseButton, null); public SettingsViewModel GetSettingsViewModel() => services.GetRequiredService(); diff --git a/DiscordChatExporter.Gui/ViewModels/Dialogs/MessageBoxViewModel.cs b/DiscordChatExporter.Gui/ViewModels/Dialogs/MessageBoxViewModel.cs index fd695003..75c78f2e 100644 --- a/DiscordChatExporter.Gui/ViewModels/Dialogs/MessageBoxViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/Dialogs/MessageBoxViewModel.cs @@ -6,20 +6,20 @@ namespace DiscordChatExporter.Gui.ViewModels.Dialogs; public partial class MessageBoxViewModel : DialogViewModelBase { [ObservableProperty] - public partial string? Title { get; set; } = "Title"; + public partial string? Title { get; set; } [ObservableProperty] - public partial string? Message { get; set; } = "Message"; + public partial string? Message { get; set; } [ObservableProperty] [NotifyPropertyChangedFor(nameof(IsDefaultButtonVisible))] [NotifyPropertyChangedFor(nameof(ButtonsCount))] - public partial string? DefaultButtonText { get; set; } = "OK"; + public partial string? DefaultButtonText { get; set; } [ObservableProperty] [NotifyPropertyChangedFor(nameof(IsCancelButtonVisible))] [NotifyPropertyChangedFor(nameof(ButtonsCount))] - public partial string? CancelButtonText { get; set; } = "Cancel"; + public partial string? CancelButtonText { get; set; } public bool IsDefaultButtonVisible => !string.IsNullOrWhiteSpace(DefaultButtonText); diff --git a/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs b/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs index dcf3df99..169d50ce 100644 --- a/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using DiscordChatExporter.Gui.Framework; using DiscordChatExporter.Gui.Localization; using DiscordChatExporter.Gui.Services; -using DiscordChatExporter.Gui.Utils.Extensions; using DiscordChatExporter.Gui.ViewModels.Components; using PowerKit.Extensions; From f0e99765f7902dd3d6dc7d3c2cbf0fae072221c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 19:40:41 +0300 Subject: [PATCH 3/5] Bump the nuget group with 13 updates (#1542) Signed-off-by: dependabot[bot] --- Directory.Packages.props | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index a2df34fd..0f031eee 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,33 +7,33 @@ - - + + - + - - - + + + - + - + - - - + + + - + From 64a4ba296ecd08709ee813f1e3e0aee0913d5c18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 19:41:24 +0300 Subject: [PATCH 4/5] Bump the actions group with 4 updates (#1541) Signed-off-by: dependabot[bot] --- .github/workflows/docker.yml | 4 ++-- .github/workflows/main.yml | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 33177c50..ec56bde2 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - name: Build image run: > @@ -58,7 +58,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - name: Login to DockerHub run: > diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f857a9af..7e63cf6a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,7 +29,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install .NET - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 # Build the project separately to discern between build and format errors - name: Build @@ -65,7 +65,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install .NET - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 - name: Run tests env: @@ -81,7 +81,7 @@ jobs: DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover - name: Upload coverage - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -120,7 +120,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install .NET - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0 - name: Publish app run: > @@ -236,7 +236,7 @@ jobs: steps: - name: Notify Discord - uses: tyrrrz/action-http-request@25f132e48dea89c0f6b7955398270b506e1d51cb # 1.1.4 + uses: tyrrrz/action-http-request@110f1a0f0f7e91c3b2de349539249f4573c243fa # 1.1.5 with: url: ${{ secrets.DISCORD_WEBHOOK }} method: POST From 799dd1ad8151046c464762802c36dffefb1bd383 Mon Sep 17 00:00:00 2001 From: Colton <54053306+265866@users.noreply.github.com> Date: Wed, 3 Jun 2026 05:47:43 -0700 Subject: [PATCH 5/5] Stream asset downloads to avoid OutOfMemoryException on large files (#1540) * Stream asset downloads to avoid OutOfMemoryException on large files ExportAssetDownloader used HttpClient.GetAsync(url, ct), which defaults to HttpCompletionOption.ResponseContentRead and buffers the entire response body into memory before returning. Downloading a large attachment therefore tried to grow a single in-memory buffer to the full file size and threw OutOfMemoryException (HttpContent.LoadIntoBufferAsync -> GrowAndWrite). Pass HttpCompletionOption.ResponseHeadersRead so the body is streamed straight to disk via CopyToAsync in bounded chunks, matching how DiscordClient already issues its requests. * Update ExportAssetDownloader.cs --------- Co-authored-by: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> --- .../Exporting/ExportAssetDownloader.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs b/DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs index eb44d4a9..071616ec 100644 --- a/DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs +++ b/DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Threading; @@ -64,7 +65,14 @@ internal partial class ExportAssetDownloader(string workingDirPath, bool reuse) async innerCancellationToken => { // Download the file - using var response = await Http.Client.GetAsync(url, innerCancellationToken); + using var response = await Http.Client.GetAsync( + url, + HttpCompletionOption.ResponseHeadersRead, + innerCancellationToken + ); + + response.EnsureSuccessStatusCode(); + await using var output = File.Create(filePath); await response.Content.CopyToAsync(output, innerCancellationToken); },