mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2025-05-09 11:51:59 -04:00
parent
c405121c0b
commit
20a952aec5
12 changed files with 87 additions and 42 deletions
|
@ -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…
Add table
Add a link
Reference in a new issue