From ad33600e7068404a18081997d5f8aa0b2f21c345 Mon Sep 17 00:00:00 2001 From: Kornelius Rohrschneider Date: Sun, 26 Oct 2025 01:28:24 +0200 Subject: [PATCH] Added UI options to set the file exists handling The setting the exporter uses to handle existing export files has been made configurable in both the CLI and the GUI (instead of being hardcoded): - A prev-export option has been added to all CLI export commands, which sets the file exists handling for the respective command. - A Previous Export option has been added to the GUI settings, which sets the file exists handling that's used for exports. --- .../Commands/Base/ExportCommandBase.cs | 7 +++++++ .../Exporting/ChannelExporter.cs | 8 +++----- DiscordChatExporter.Core/Exporting/ExportRequest.cs | 4 ++++ DiscordChatExporter.Gui/Services/SettingsService.cs | 3 +++ .../ViewModels/Components/DashboardViewModel.cs | 1 + .../ViewModels/Dialogs/SettingsViewModel.cs | 10 ++++++++++ .../Views/Dialogs/SettingsView.axaml | 13 +++++++++++++ 7 files changed, 41 insertions(+), 5 deletions(-) diff --git a/DiscordChatExporter.Cli/Commands/Base/ExportCommandBase.cs b/DiscordChatExporter.Cli/Commands/Base/ExportCommandBase.cs index 09ab2691..8573f4b6 100644 --- a/DiscordChatExporter.Cli/Commands/Base/ExportCommandBase.cs +++ b/DiscordChatExporter.Cli/Commands/Base/ExportCommandBase.cs @@ -114,6 +114,12 @@ public abstract class ExportCommandBase : DiscordCommandBase init => field = value is not null ? Path.GetFullPath(value) : null; } + [CommandOption( + "prev-export", + Description = "What the exporter should do if the channel had already been exported." + )] + public FileExistsHandling FileExistsHandling { get; init; } = FileExistsHandling.Abort; + [Obsolete("This option doesn't do anything. Kept for backwards compatibility.")] [CommandOption( "dateformat", @@ -265,6 +271,7 @@ public abstract class ExportCommandBase : DiscordCommandBase ExportFormat, After, Before, + FileExistsHandling, PartitionLimit, MessageFilter, ShouldFormatMarkdown, diff --git a/DiscordChatExporter.Core/Exporting/ChannelExporter.cs b/DiscordChatExporter.Core/Exporting/ChannelExporter.cs index b5ef7bc0..6a307970 100644 --- a/DiscordChatExporter.Core/Exporting/ChannelExporter.cs +++ b/DiscordChatExporter.Core/Exporting/ChannelExporter.cs @@ -32,10 +32,8 @@ public class ChannelExporter(DiscordClient discord) // TODO: Maybe add a way to search for old files after a username change if (File.Exists(request.OutputFilePath)) { - // TODO: Add a way for the user to choose the setting - var choice = FileExistsHandling.Abort; - - switch (choice) + // TODO: Maybe add an "Ask" option in the future + switch (request.FileExistsHandling) { case FileExistsHandling.Abort: Console.WriteLine("Channel aborted"); @@ -69,7 +67,7 @@ public class ChannelExporter(DiscordClient discord) break; default: throw new InvalidOperationException( - $"Unknown FileExistsHandling value '{choice}'." + $"Unknown FileExistsHandling value '{request.FileExistsHandling}'." ); } } diff --git a/DiscordChatExporter.Core/Exporting/ExportRequest.cs b/DiscordChatExporter.Core/Exporting/ExportRequest.cs index 7ba9b4e2..d3dcba70 100644 --- a/DiscordChatExporter.Core/Exporting/ExportRequest.cs +++ b/DiscordChatExporter.Core/Exporting/ExportRequest.cs @@ -30,6 +30,8 @@ public partial class ExportRequest public Snowflake? Before { get; } + public FileExistsHandling FileExistsHandling { get; } + public Snowflake? LastPriorMessage { get; set; } public PartitionLimit PartitionLimit { get; } @@ -56,6 +58,7 @@ public partial class ExportRequest ExportFormat format, Snowflake? after, Snowflake? before, + FileExistsHandling fileExistsHandling, PartitionLimit partitionLimit, MessageFilter messageFilter, bool shouldFormatMarkdown, @@ -70,6 +73,7 @@ public partial class ExportRequest Format = format; After = after; Before = before; + FileExistsHandling = fileExistsHandling; PartitionLimit = partitionLimit; MessageFilter = messageFilter; ShouldFormatMarkdown = shouldFormatMarkdown; diff --git a/DiscordChatExporter.Gui/Services/SettingsService.cs b/DiscordChatExporter.Gui/Services/SettingsService.cs index 87fb914b..c1a618d0 100644 --- a/DiscordChatExporter.Gui/Services/SettingsService.cs +++ b/DiscordChatExporter.Gui/Services/SettingsService.cs @@ -36,6 +36,9 @@ public partial class SettingsService() [ObservableProperty] public partial ThreadInclusionMode ThreadInclusionMode { get; set; } + [ObservableProperty] + public partial FileExistsHandling FileExistsHandling { get; set; } + [ObservableProperty] public partial string? Locale { get; set; } diff --git a/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs b/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs index a03d62d8..f5ead982 100644 --- a/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs @@ -270,6 +270,7 @@ public partial class DashboardViewModel : ViewModelBase dialog.SelectedFormat, dialog.After?.Pipe(timestamp => Snowflake.FromDate(timestamp, true)), dialog.Before?.Pipe(timestamp => Snowflake.FromDate(timestamp)), + _settingsService.FileExistsHandling, dialog.PartitionLimit, dialog.MessageFilter, dialog.ShouldFormatMarkdown, diff --git a/DiscordChatExporter.Gui/ViewModels/Dialogs/SettingsViewModel.cs b/DiscordChatExporter.Gui/ViewModels/Dialogs/SettingsViewModel.cs index d3eaad9f..c9dd1e61 100644 --- a/DiscordChatExporter.Gui/ViewModels/Dialogs/SettingsViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/Dialogs/SettingsViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using DiscordChatExporter.Core.Discord; +using DiscordChatExporter.Core.Exporting; using DiscordChatExporter.Core.Utils.Extensions; using DiscordChatExporter.Gui.Framework; using DiscordChatExporter.Gui.Models; @@ -61,6 +62,15 @@ public class SettingsViewModel : DialogViewModelBase set => _settingsService.ThreadInclusionMode = value; } + public IReadOnlyList AvailableFileExistHandlingOptions { get; } = + Enum.GetValues(); + + public FileExistsHandling FileExistsHandling + { + get => _settingsService.FileExistsHandling; + set => _settingsService.FileExistsHandling = value; + } + // These items have to be non-nullable because Avalonia ComboBox doesn't allow a null value to be selected public IReadOnlyList AvailableLocales { get; } = [ diff --git a/DiscordChatExporter.Gui/Views/Dialogs/SettingsView.axaml b/DiscordChatExporter.Gui/Views/Dialogs/SettingsView.axaml index a7a3c554..adce95e2 100644 --- a/DiscordChatExporter.Gui/Views/Dialogs/SettingsView.axaml +++ b/DiscordChatExporter.Gui/Views/Dialogs/SettingsView.axaml @@ -131,6 +131,19 @@ Value="{Binding ParallelLimit}" /> + + + + + +