Clean up after last PR

This commit is contained in:
Tyrrrz
2026-02-27 17:30:06 +02:00
parent 532470e3db
commit b660edfe78
7 changed files with 69 additions and 72 deletions

View File

@@ -27,10 +27,16 @@ public partial record Message(
IReadOnlyList<User> MentionedUsers,
MessageReference? Reference,
Message? ReferencedMessage,
Interaction? Interaction,
MessageSnapshot? ForwardedMessage
MessageSnapshot? ForwardedMessage,
Interaction? Interaction
) : IHasId
{
public bool IsEmpty { get; } =
string.IsNullOrWhiteSpace(Content)
&& !Attachments.Any()
&& !Embeds.Any()
&& !Stickers.Any();
public bool IsSystemNotification { get; } =
Kind is >= MessageKind.RecipientAdd and <= MessageKind.ThreadCreated;
@@ -39,15 +45,8 @@ public partial record Message(
// App interactions are rendered as replies in the Discord client, but they are not actually replies
public bool IsReplyLike => IsReply || Interaction is not null;
// A message is a forward if its reference type is Forward
public bool IsForwarded { get; } = Reference?.Kind == MessageReferenceKind.Forward;
public bool IsEmpty { get; } =
string.IsNullOrWhiteSpace(Content)
&& !Attachments.Any()
&& !Embeds.Any()
&& !Stickers.Any();
public IEnumerable<User> GetReferencedUsers()
{
yield return Author;
@@ -175,16 +174,19 @@ public partial record Message
var messageReference = json.GetPropertyOrNull("message_reference")
?.Pipe(MessageReference.Parse);
var referencedMessage = json.GetPropertyOrNull("referenced_message")?.Pipe(Parse);
var interaction = json.GetPropertyOrNull("interaction")?.Pipe(Interaction.Parse);
// Parse message snapshots for forwarded messages
var referencedMessage = json.GetPropertyOrNull("referenced_message")?.Pipe(Parse);
// Currently Discord only supports 1 snapshot per forward
var forwardedMessage = json.GetPropertyOrNull("message_snapshots")
?.EnumerateArrayOrNull()
?.Select(MessageSnapshot.Parse)
?.Select(j => j.GetPropertyOrNull("message"))
.WhereNotNull()
.Select(MessageSnapshot.Parse)
.FirstOrDefault();
var interaction = json.GetPropertyOrNull("interaction")?.Pipe(Interaction.Parse);
return new Message(
id,
kind,
@@ -202,8 +204,8 @@ public partial record Message
mentionedUsers,
messageReference,
referencedMessage,
interaction,
forwardedMessage
forwardedMessage,
interaction
);
}
}

View File

@@ -6,14 +6,17 @@ namespace DiscordChatExporter.Core.Discord.Data;
// https://discord.com/developers/docs/resources/channel#message-object-message-reference-structure
public record MessageReference(
MessageReferenceKind Kind,
Snowflake? MessageId,
Snowflake? ChannelId,
Snowflake? GuildId,
MessageReferenceKind Kind
)
Snowflake? GuildId)
{
public static MessageReference Parse(JsonElement json)
{
var kind =
json.GetPropertyOrNull("type")?.GetInt32OrNull()?.Pipe(t => (MessageReferenceKind)t)
?? MessageReferenceKind.Default;
var messageId = json.GetPropertyOrNull("message_id")
?.GetNonWhiteSpaceStringOrNull()
?.Pipe(Snowflake.Parse);
@@ -26,10 +29,6 @@ public record MessageReference(
?.GetNonWhiteSpaceStringOrNull()
?.Pipe(Snowflake.Parse);
var kind =
json.GetPropertyOrNull("type")?.GetInt32OrNull()?.Pipe(t => (MessageReferenceKind)t)
?? MessageReferenceKind.Default;
return new MessageReference(messageId, channelId, guildId, kind);
return new MessageReference(kind, messageId, channelId, guildId);
}
}

View File

@@ -3,31 +3,34 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using DiscordChatExporter.Core.Discord.Data.Embeds;
using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Reading;
namespace DiscordChatExporter.Core.Discord.Data;
// https://discord.com/developers/docs/resources/channel#message-snapshot-object
// https://docs.discord.com/developers/resources/message#message-snapshot-object
// Message snapshots contain a subset of message fields for forwarded messages
public record MessageSnapshot(
DateTimeOffset Timestamp,
DateTimeOffset? EditedTimestamp,
string Content,
IReadOnlyList<Attachment> Attachments,
IReadOnlyList<Embed> Embeds,
IReadOnlyList<Sticker> Stickers,
DateTimeOffset Timestamp,
DateTimeOffset? EditedTimestamp
)
IReadOnlyList<Sticker> Stickers)
{
public static MessageSnapshot Parse(JsonElement json)
{
// The message snapshot has a "message" property containing the actual message data
var messageJson = json.GetPropertyOrNull("message") ?? json;
var timestamp =
json.GetPropertyOrNull("timestamp")?.GetDateTimeOffsetOrNull()
?? DateTimeOffset.MinValue;
var content = messageJson.GetPropertyOrNull("content")?.GetStringOrNull() ?? "";
var editedTimestamp = json
.GetPropertyOrNull("edited_timestamp")
?.GetDateTimeOffsetOrNull();
var content = json.GetPropertyOrNull("content")?.GetStringOrNull() ?? "";
var attachments =
messageJson
json
.GetPropertyOrNull("attachments")
?.EnumerateArrayOrNull()
?.Select(Attachment.Parse)
@@ -35,7 +38,7 @@ public record MessageSnapshot(
?? [];
var embeds =
messageJson
json
.GetPropertyOrNull("embeds")
?.EnumerateArrayOrNull()
?.Select(Embed.Parse)
@@ -43,28 +46,14 @@ public record MessageSnapshot(
?? [];
var stickers =
messageJson
json
.GetPropertyOrNull("sticker_items")
?.EnumerateArrayOrNull()
?.Select(Sticker.Parse)
.ToArray()
?? [];
var timestamp =
messageJson.GetPropertyOrNull("timestamp")?.GetDateTimeOffsetOrNull()
?? DateTimeOffset.MinValue;
var editedTimestamp = messageJson
.GetPropertyOrNull("edited_timestamp")
?.GetDateTimeOffsetOrNull();
return new MessageSnapshot(
content,
attachments,
embeds,
stickers,
timestamp,
editedTimestamp
);
return new MessageSnapshot(timestamp,
editedTimestamp, content, attachments, embeds, stickers);
}
}

View File

@@ -539,22 +539,20 @@ internal class JsonMessageWriter(Stream stream, ExportContext context)
{
_writer.WriteStartObject("forwardedMessage");
_writer.WriteString(
"content",
await FormatMarkdownAsync(message.ForwardedMessage.Content, cancellationToken)
);
_writer.WriteString(
"timestamp",
message.ForwardedMessage.Timestamp != DateTimeOffset.MinValue
? Context.NormalizeDate(message.ForwardedMessage.Timestamp)
: null
Context.NormalizeDate(message.ForwardedMessage.Timestamp)
);
_writer.WriteString(
"timestampEdited",
message.ForwardedMessage.EditedTimestamp?.Pipe(Context.NormalizeDate)
);
_writer.WriteString(
"content",
await FormatMarkdownAsync(message.ForwardedMessage.Content, cancellationToken)
);
// Forwarded attachments
_writer.WriteStartArray("attachments");

View File

@@ -263,9 +263,8 @@
}
@* Forwarded message content *@
@if (message.IsForwarded && message.ForwardedMessage is not null)
@if (message is { IsForwarded: true, ForwardedMessage: not null })
{
var fwd = message.ForwardedMessage;
<div class="chatlog__forwarded">
<div class="chatlog__forwarded-header">
<svg class="chatlog__forwarded-icon">
@@ -275,18 +274,18 @@
</div>
@* Forwarded text content *@
@if (!string.IsNullOrWhiteSpace(fwd.Content))
@if (!string.IsNullOrWhiteSpace(message.ForwardedMessage.Content))
{
<div class="chatlog__forwarded-content chatlog__markdown">
<span class="chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatMarkdownAsync(fwd.Content))<!--/wmm:ignore--></span>
<span class="chatlog__markdown-preserve"><!--wmm:ignore-->@Html.Raw(await FormatMarkdownAsync(message.ForwardedMessage.Content))<!--/wmm:ignore--></span>
</div>
}
@* Forwarded attachments *@
@if (fwd.Attachments.Any())
@if (message.ForwardedMessage.Attachments.Any())
{
<div class="chatlog__forwarded-attachments">
@foreach (var attachment in fwd.Attachments)
@foreach (var attachment in message.ForwardedMessage.Attachments)
{
@if (attachment.IsImage)
{
@@ -327,7 +326,7 @@
}
@* Forwarded stickers *@
@foreach (var sticker in fwd.Stickers)
@foreach (var sticker in message.ForwardedMessage.Stickers)
{
<div class="chatlog__sticker" title="@sticker.Name">
@if (sticker.IsImage)
@@ -343,10 +342,10 @@
@* Forwarded timestamp *@
<div class="chatlog__forwarded-timestamp">
<span title="@FormatDate(fwd.Timestamp, "f")">Originally sent: @FormatDate(fwd.Timestamp)</span>
@if (fwd.EditedTimestamp is not null)
<span title="@FormatDate(message.ForwardedMessage.Timestamp, "f")">Originally sent: @FormatDate(message.ForwardedMessage.Timestamp)</span>
@if (message.ForwardedMessage.EditedTimestamp is not null)
{
<span title="@FormatDate(fwd.EditedTimestamp.Value, "f")"> (edited)</span>
<span title="@FormatDate(message.ForwardedMessage.EditedTimestamp.Value, "f")"> (edited)</span>
}
</div>
</div>

View File

@@ -239,12 +239,9 @@ internal class PlainTextMessageWriter(Stream stream, ExportContext context)
);
}
if (forwardedMessage.Timestamp != DateTimeOffset.MinValue)
{
await _writer.WriteLineAsync(
$"Originally sent: {Context.FormatDate(forwardedMessage.Timestamp)}"
);
}
await WriteAttachmentsAsync(forwardedMessage.Attachments, cancellationToken);
await WriteEmbedsAsync(forwardedMessage.Embeds, cancellationToken);

View File

@@ -24,4 +24,17 @@ public static class CollectionExtensions
}
}
}
extension<T>(IEnumerable<T?> source)
where T : struct
{
public IEnumerable<T> WhereNotNull()
{
foreach (var o in source)
{
if (o is not null)
yield return o.Value;
}
}
}
}