Add option to disable markdown formatting

Closes #741
pull/1003/head
Tyrrrz 1 year ago
parent c405121c0b
commit 20a952aec5

@ -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

@ -18,10 +18,12 @@ internal partial class CsvMessageWriter : MessageWriter
_writer = new StreamWriter(stream);
}
private ValueTask<string> FormatMarkdownAsync(
private async ValueTask<string> 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");

@ -19,6 +19,7 @@ public partial record ExportRequest(
Snowflake? Before,
PartitionLimit PartitionLimit,
MessageFilter MessageFilter,
bool ShouldFormatMarkdown,
bool ShouldDownloadAssets,
bool ShouldReuseAssets,
string DateFormat)

@ -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)
)

@ -28,10 +28,12 @@ internal class JsonMessageWriter : MessageWriter
});
}
private ValueTask<string> FormatMarkdownAsync(
private async ValueTask<string> 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,

@ -10,40 +10,44 @@
@inherits RazorBlade.HtmlTemplate
@functions {
public required ExportContext ExportContext { get; init; }
public required ExportContext Context { get; init; }
public required IReadOnlyList<Message> Messages { get; init; }
}
@{
ValueTask<string> ResolveAssetUrlAsync(string url) =>
ExportContext.ResolveAssetUrlAsync(url, CancellationToken);
Context.ResolveAssetUrlAsync(url, CancellationToken);
string FormatDate(DateTimeOffset instant) =>
ExportContext.FormatDate(instant);
Context.FormatDate(instant);
ValueTask<string> FormatMarkdownAsync(string markdown) =>
HtmlMarkdownVisitor.FormatAsync(ExportContext, markdown, true, CancellationToken);
async ValueTask<string> FormatMarkdownAsync(string markdown) =>
Context.Request.ShouldFormatMarkdown
? await HtmlMarkdownVisitor.FormatAsync(Context, markdown, true, CancellationToken)
: markdown;
ValueTask<string> FormatEmbedMarkdownAsync(string markdown) =>
HtmlMarkdownVisitor.FormatAsync(ExportContext, markdown, false, CancellationToken);
async ValueTask<string> 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;

@ -18,10 +18,12 @@ internal class PlainTextMessageWriter : MessageWriter
_writer = new StreamWriter(stream);
}
private ValueTask<string> FormatMarkdownAsync(
private async ValueTask<string> 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)
{

@ -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<string> ResolveAssetUrlAsync(string url) =>
ExportContext.ResolveAssetUrlAsync(url, CancellationToken);
Context.ResolveAssetUrlAsync(url, CancellationToken);
string FormatDate(DateTimeOffset instant) =>
ExportContext.FormatDate(instant);
Context.FormatDate(instant);
ValueTask<string> FormatMarkdownAsync(string markdown) =>
HtmlMarkdownVisitor.FormatAsync(ExportContext, markdown, true, CancellationToken);
async ValueTask<string> FormatMarkdownAsync(string markdown) =>
Context.Request.ShouldFormatMarkdown
? await HtmlMarkdownVisitor.FormatAsync(Context, markdown, true, CancellationToken)
: markdown;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>@ExportContext.Request.Guild.Name - @ExportContext.Request.Channel.Name</title>
<title>@Context.Request.Guild.Name - @Context.Request.Channel.Name</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
@ -914,31 +916,31 @@
<div class="preamble">
<div class="preamble__guild-icon-container">
<img class="preamble__guild-icon" src="@await ResolveAssetUrlAsync(ExportContext.Request.Channel.IconUrl ?? ExportContext.Request.Guild.IconUrl)" alt="Guild icon" loading="lazy">
<img class="preamble__guild-icon" src="@await ResolveAssetUrlAsync(Context.Request.Channel.IconUrl ?? Context.Request.Guild.IconUrl)" alt="Guild icon" loading="lazy">
</div>
<div class="preamble__entries-container">
<div class="preamble__entry">@ExportContext.Request.Guild.Name</div>
<div class="preamble__entry">@ExportContext.Request.Channel.Category.Name / @ExportContext.Request.Channel.Name</div>
<div class="preamble__entry">@Context.Request.Guild.Name</div>
<div class="preamble__entry">@Context.Request.Channel.Category.Name / @Context.Request.Channel.Name</div>
@if (!string.IsNullOrWhiteSpace(ExportContext.Request.Channel.Topic))
@if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic))
{
<div class="preamble__entry preamble__entry--small">@Html.Raw(await FormatMarkdownAsync(ExportContext.Request.Channel.Topic))</div>
<div class="preamble__entry preamble__entry--small">@Html.Raw(await FormatMarkdownAsync(Context.Request.Channel.Topic))</div>
}
@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)
{
<div class="preamble__entry preamble__entry--small">
@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())}")
}
</div>
}

@ -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()

@ -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

@ -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);

@ -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')" />
<!-- Markdown formatting -->
<Grid Margin="16,8" ToolTip="Process markdown, mentions, and other special tokens">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
VerticalAlignment="Center"
Text="Format markdown" />
<ToggleButton
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsChecked="{Binding ShouldFormatMarkdown}" />
</Grid>
<!-- Download assets -->
<Grid Margin="16,16" ToolTip="Download assets referenced by the export (user avatars, attached files, embedded images, etc.)">
<Grid Margin="16,8" ToolTip="Download assets referenced by the export (user avatars, attached files, embedded images, etc.)">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />

Loading…
Cancel
Save