diff --git a/DiscordChatExporter.Cli/Commands/Base/ExportCommandBase.cs b/DiscordChatExporter.Cli/Commands/Base/ExportCommandBase.cs index 3cf7164..11992a6 100644 --- a/DiscordChatExporter.Cli/Commands/Base/ExportCommandBase.cs +++ b/DiscordChatExporter.Cli/Commands/Base/ExportCommandBase.cs @@ -80,6 +80,12 @@ public abstract class ExportCommandBase : TokenCommandBase )] public int ParallelLimit { get; init; } = 1; + [CommandOption( + "markdown", + Description = "Process markdown, mentions, and other special tokens." + )] + public bool ShouldFormatMarkdown { get; init; } = true; + [CommandOption( "media", Description = "Download assets referenced by the export (user avatars, attached files, embedded images, etc.)." @@ -171,6 +177,7 @@ public abstract class ExportCommandBase : TokenCommandBase Before, PartitionLimit, MessageFilter, + ShouldFormatMarkdown, ShouldDownloadAssets, ShouldReuseAssets, DateFormat diff --git a/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs b/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs index 43f264b..9f2846d 100644 --- a/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs @@ -18,10 +18,12 @@ internal partial class CsvMessageWriter : MessageWriter _writer = new StreamWriter(stream); } - private ValueTask FormatMarkdownAsync( + private async ValueTask FormatMarkdownAsync( string markdown, CancellationToken cancellationToken = default) => - PlainTextMarkdownVisitor.FormatAsync(Context, markdown, cancellationToken); + Context.Request.ShouldFormatMarkdown + ? await PlainTextMarkdownVisitor.FormatAsync(Context, markdown, cancellationToken) + : markdown; public override async ValueTask WritePreambleAsync(CancellationToken cancellationToken = default) => await _writer.WriteLineAsync("AuthorID,Author,Date,Content,Attachments,Reactions"); diff --git a/DiscordChatExporter.Core/Exporting/ExportRequest.cs b/DiscordChatExporter.Core/Exporting/ExportRequest.cs index 0ea7146..6d0a421 100644 --- a/DiscordChatExporter.Core/Exporting/ExportRequest.cs +++ b/DiscordChatExporter.Core/Exporting/ExportRequest.cs @@ -19,6 +19,7 @@ public partial record ExportRequest( Snowflake? Before, PartitionLimit PartitionLimit, MessageFilter MessageFilter, + bool ShouldFormatMarkdown, bool ShouldDownloadAssets, bool ShouldReuseAssets, string DateFormat) diff --git a/DiscordChatExporter.Core/Exporting/HtmlMessageWriter.cs b/DiscordChatExporter.Core/Exporting/HtmlMessageWriter.cs index 95354f8..f4c0edf 100644 --- a/DiscordChatExporter.Core/Exporting/HtmlMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/HtmlMessageWriter.cs @@ -75,7 +75,7 @@ internal class HtmlMessageWriter : MessageWriter Minify( await new PreambleTemplate { - ExportContext = Context, + Context = Context, ThemeName = _themeName }.RenderAsync(cancellationToken) ) @@ -90,7 +90,7 @@ internal class HtmlMessageWriter : MessageWriter Minify( await new MessageGroupTemplate { - ExportContext = Context, + Context = Context, Messages = messages }.RenderAsync(cancellationToken) ) diff --git a/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs b/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs index 5aabd51..4acd6e9 100644 --- a/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs @@ -28,10 +28,12 @@ internal class JsonMessageWriter : MessageWriter }); } - private ValueTask FormatMarkdownAsync( + private async ValueTask FormatMarkdownAsync( string markdown, CancellationToken cancellationToken = default) => - PlainTextMarkdownVisitor.FormatAsync(Context, markdown, cancellationToken); + Context.Request.ShouldFormatMarkdown + ? await PlainTextMarkdownVisitor.FormatAsync(Context, markdown, cancellationToken) + : markdown; private async ValueTask WriteAttachmentAsync( Attachment attachment, diff --git a/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml b/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml index 8b2f4a8..48ba684 100644 --- a/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml +++ b/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml @@ -10,40 +10,44 @@ @inherits RazorBlade.HtmlTemplate @functions { - public required ExportContext ExportContext { get; init; } + public required ExportContext Context { get; init; } public required IReadOnlyList Messages { get; init; } } @{ ValueTask ResolveAssetUrlAsync(string url) => - ExportContext.ResolveAssetUrlAsync(url, CancellationToken); + Context.ResolveAssetUrlAsync(url, CancellationToken); string FormatDate(DateTimeOffset instant) => - ExportContext.FormatDate(instant); + Context.FormatDate(instant); - ValueTask FormatMarkdownAsync(string markdown) => - HtmlMarkdownVisitor.FormatAsync(ExportContext, markdown, true, CancellationToken); + async ValueTask FormatMarkdownAsync(string markdown) => + Context.Request.ShouldFormatMarkdown + ? await HtmlMarkdownVisitor.FormatAsync(Context, markdown, true, CancellationToken) + : markdown; - ValueTask FormatEmbedMarkdownAsync(string markdown) => - HtmlMarkdownVisitor.FormatAsync(ExportContext, markdown, false, CancellationToken); + async ValueTask FormatEmbedMarkdownAsync(string markdown) => + Context.Request.ShouldFormatMarkdown + ? await HtmlMarkdownVisitor.FormatAsync(Context, markdown, false, CancellationToken) + : markdown; var firstMessage = Messages.First(); - var userMember = ExportContext.TryGetMember(firstMessage.Author.Id); + var userMember = Context.TryGetMember(firstMessage.Author.Id); - var userColor = ExportContext.TryGetUserColor(firstMessage.Author.Id); + var userColor = Context.TryGetUserColor(firstMessage.Author.Id); var userNick = firstMessage.Author.IsBot ? firstMessage.Author.Name : userMember?.Nick ?? firstMessage.Author.Name; var referencedUserMember = firstMessage.ReferencedMessage is not null - ? ExportContext.TryGetMember(firstMessage.ReferencedMessage.Author.Id) + ? Context.TryGetMember(firstMessage.ReferencedMessage.Author.Id) : null; var referencedUserColor = firstMessage.ReferencedMessage is not null - ? ExportContext.TryGetUserColor(firstMessage.ReferencedMessage.Author.Id) + ? Context.TryGetUserColor(firstMessage.ReferencedMessage.Author.Id) : null; var referencedUserNick = firstMessage.ReferencedMessage is not null @@ -65,8 +69,8 @@ { // System notifications are grouped even if the message author is different. // That's why we have to update the user values with the author of the current message. - userMember = ExportContext.TryGetMember(message.Author.Id); - userColor = ExportContext.TryGetUserColor(message.Author.Id); + userMember = Context.TryGetMember(message.Author.Id); + userColor = Context.TryGetUserColor(message.Author.Id); userNick = message.Author.IsBot ? message.Author.Name : userMember?.Nick ?? message.Author.Name; @@ -323,7 +327,7 @@ foreach (var inviteCode in inviteCodes) { - var invite = await ExportContext.Discord.TryGetGuildInviteAsync(inviteCode, CancellationToken); + var invite = await Context.Discord.TryGetGuildInviteAsync(inviteCode, CancellationToken); if (invite is null) { continue; diff --git a/DiscordChatExporter.Core/Exporting/PlainTextMessageWriter.cs b/DiscordChatExporter.Core/Exporting/PlainTextMessageWriter.cs index 90474df..0bfa89e 100644 --- a/DiscordChatExporter.Core/Exporting/PlainTextMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/PlainTextMessageWriter.cs @@ -18,10 +18,12 @@ internal class PlainTextMessageWriter : MessageWriter _writer = new StreamWriter(stream); } - private ValueTask FormatMarkdownAsync( + private async ValueTask FormatMarkdownAsync( string markdown, CancellationToken cancellationToken = default) => - PlainTextMarkdownVisitor.FormatAsync(Context, markdown, cancellationToken); + Context.Request.ShouldFormatMarkdown + ? await PlainTextMarkdownVisitor.FormatAsync(Context, markdown, cancellationToken) + : markdown; private async ValueTask WriteMessageHeaderAsync(Message message) { diff --git a/DiscordChatExporter.Core/Exporting/PreambleTemplate.cshtml b/DiscordChatExporter.Core/Exporting/PreambleTemplate.cshtml index 5fd5ed9..0dc5ebe 100644 --- a/DiscordChatExporter.Core/Exporting/PreambleTemplate.cshtml +++ b/DiscordChatExporter.Core/Exporting/PreambleTemplate.cshtml @@ -4,7 +4,7 @@ @inherits RazorBlade.HtmlTemplate @functions { - public required ExportContext ExportContext { get; init; } + public required ExportContext Context { get; init; } public required string ThemeName { get; init; } } @@ -19,20 +19,22 @@ $"https://cdn.jsdelivr.net/gh/Tyrrrz/DiscordFonts@master/whitney-{weight}.woff"; ValueTask ResolveAssetUrlAsync(string url) => - ExportContext.ResolveAssetUrlAsync(url, CancellationToken); + Context.ResolveAssetUrlAsync(url, CancellationToken); string FormatDate(DateTimeOffset instant) => - ExportContext.FormatDate(instant); + Context.FormatDate(instant); - ValueTask FormatMarkdownAsync(string markdown) => - HtmlMarkdownVisitor.FormatAsync(ExportContext, markdown, true, CancellationToken); + async ValueTask FormatMarkdownAsync(string markdown) => + Context.Request.ShouldFormatMarkdown + ? await HtmlMarkdownVisitor.FormatAsync(Context, markdown, true, CancellationToken) + : markdown; } - @ExportContext.Request.Guild.Name - @ExportContext.Request.Channel.Name + @Context.Request.Guild.Name - @Context.Request.Channel.Name @@ -914,31 +916,31 @@
- Guild icon + Guild icon
-
@ExportContext.Request.Guild.Name
-
@ExportContext.Request.Channel.Category.Name / @ExportContext.Request.Channel.Name
+
@Context.Request.Guild.Name
+
@Context.Request.Channel.Category.Name / @Context.Request.Channel.Name
- @if (!string.IsNullOrWhiteSpace(ExportContext.Request.Channel.Topic)) + @if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic)) { -
@Html.Raw(await FormatMarkdownAsync(ExportContext.Request.Channel.Topic))
+
@Html.Raw(await FormatMarkdownAsync(Context.Request.Channel.Topic))
} - @if (ExportContext.Request.After is not null || ExportContext.Request.Before is not null) + @if (Context.Request.After is not null || Context.Request.Before is not null) {
- @if (ExportContext.Request.After is not null && ExportContext.Request.Before is not null) + @if (Context.Request.After is not null && Context.Request.Before is not null) { - @($"Between {FormatDate(ExportContext.Request.After.Value.ToDate())} and {FormatDate(ExportContext.Request.Before.Value.ToDate())}") + @($"Between {FormatDate(Context.Request.After.Value.ToDate())} and {FormatDate(Context.Request.Before.Value.ToDate())}") } - else if (ExportContext.Request.After is not null) + else if (Context.Request.After is not null) { - @($"After {FormatDate(ExportContext.Request.After.Value.ToDate())}") + @($"After {FormatDate(Context.Request.After.Value.ToDate())}") } - else if (ExportContext.Request.Before is not null) + else if (Context.Request.Before is not null) { - @($"Before {FormatDate(ExportContext.Request.Before.Value.ToDate())}") + @($"Before {FormatDate(Context.Request.Before.Value.ToDate())}") }
} diff --git a/DiscordChatExporter.Gui/Services/SettingsService.cs b/DiscordChatExporter.Gui/Services/SettingsService.cs index 0a81203..19958a4 100644 --- a/DiscordChatExporter.Gui/Services/SettingsService.cs +++ b/DiscordChatExporter.Gui/Services/SettingsService.cs @@ -31,6 +31,8 @@ public partial class SettingsService : SettingsManager public string? LastMessageFilterValue { get; set; } + public bool LastShouldFormatMarkdown { get; set; } = true; + public bool LastShouldDownloadAssets { get; set; } public SettingsService() diff --git a/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs b/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs index 9f5b527..9c99404 100644 --- a/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs @@ -191,6 +191,7 @@ public class DashboardViewModel : PropertyChangedBase dialog.Before?.Pipe(Snowflake.FromDate), dialog.PartitionLimit, dialog.MessageFilter, + dialog.ShouldFormatMarkdown, dialog.ShouldDownloadAssets, _settingsService.ShouldReuseAssets, _settingsService.DateFormat diff --git a/DiscordChatExporter.Gui/ViewModels/Dialogs/ExportSetupViewModel.cs b/DiscordChatExporter.Gui/ViewModels/Dialogs/ExportSetupViewModel.cs index da2648a..a30d51e 100644 --- a/DiscordChatExporter.Gui/ViewModels/Dialogs/ExportSetupViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/Dialogs/ExportSetupViewModel.cs @@ -59,6 +59,8 @@ public class ExportSetupViewModel : DialogScreen ? MessageFilter.Parse(MessageFilterValue) : MessageFilter.Null; + public bool ShouldFormatMarkdown { get; set; } + public bool ShouldDownloadAssets { get; set; } public bool IsAdvancedSectionDisplayed { get; set; } @@ -72,6 +74,7 @@ public class ExportSetupViewModel : DialogScreen SelectedFormat = _settingsService.LastExportFormat; PartitionLimitValue = _settingsService.LastPartitionLimitValue; MessageFilterValue = _settingsService.LastMessageFilterValue; + ShouldFormatMarkdown = _settingsService.LastShouldFormatMarkdown; ShouldDownloadAssets = _settingsService.LastShouldDownloadAssets; // Show the "advanced options" section by default if any @@ -129,6 +132,7 @@ public class ExportSetupViewModel : DialogScreen _settingsService.LastExportFormat = SelectedFormat; _settingsService.LastPartitionLimitValue = PartitionLimitValue; _settingsService.LastMessageFilterValue = MessageFilterValue; + _settingsService.LastShouldFormatMarkdown = ShouldFormatMarkdown; _settingsService.LastShouldDownloadAssets = ShouldDownloadAssets; Close(true); diff --git a/DiscordChatExporter.Gui/Views/Dialogs/ExportSetupView.xaml b/DiscordChatExporter.Gui/Views/Dialogs/ExportSetupView.xaml index 8566229..98e9150 100644 --- a/DiscordChatExporter.Gui/Views/Dialogs/ExportSetupView.xaml +++ b/DiscordChatExporter.Gui/Views/Dialogs/ExportSetupView.xaml @@ -230,10 +230,28 @@ materialDesign:HintAssist.IsFloating="True" Style="{DynamicResource MaterialDesignOutlinedTextBox}" Text="{Binding MessageFilterValue}" - ToolTip="Only include messages that satisfy this filter (e.g. 'from:foo#1234' or 'has:image')." /> + ToolTip="Only include messages that satisfy this filter (e.g. 'from:foo#1234' or 'has:image')" /> + + + + + + + + + + + - +