diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs index 524b0b8..a2a03b2 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs @@ -11,7 +11,7 @@ namespace DiscordChatExporter.Core.Discord.Data.Embeds; // https://discord.com/developers/docs/resources/channel#embed-object public partial record Embed( string? Title, - string? Type, + EmbedKind Kind, string? Url, DateTimeOffset? Timestamp, Color? Color, @@ -23,17 +23,11 @@ public partial record Embed( EmbedVideo? Video, EmbedFooter? Footer) { - public PlainImageEmbedProjection? TryGetPlainImage() => - PlainImageEmbedProjection.TryResolve(this); - public SpotifyTrackEmbedProjection? TryGetSpotifyTrack() => SpotifyTrackEmbedProjection.TryResolve(this); public YouTubeVideoEmbedProjection? TryGetYouTubeVideo() => YouTubeVideoEmbedProjection.TryResolve(this); - - public GifvEmbedProjection? TryGetGifv() => - GifvEmbedProjection.TryResolve(this); } public partial record Embed @@ -41,10 +35,20 @@ public partial record Embed public static Embed Parse(JsonElement json) { var title = json.GetPropertyOrNull("title")?.GetStringOrNull(); - var type = json.GetPropertyOrNull("type")?.GetStringOrNull(); + + var kind = + json.GetPropertyOrNull("type")?.GetStringOrNull()?.Pipe(s => Enum.Parse(s, true)) ?? + EmbedKind.Rich; + var url = json.GetPropertyOrNull("url")?.GetNonWhiteSpaceStringOrNull(); var timestamp = json.GetPropertyOrNull("timestamp")?.GetDateTimeOffset(); - var color = json.GetPropertyOrNull("color")?.GetInt32OrNull()?.Pipe(System.Drawing.Color.FromArgb).ResetAlpha(); + + var color = json + .GetPropertyOrNull("color")? + .GetInt32OrNull()? + .Pipe(System.Drawing.Color.FromArgb) + .ResetAlpha(); + var author = json.GetPropertyOrNull("author")?.Pipe(EmbedAuthor.Parse); var description = json.GetPropertyOrNull("description")?.GetStringOrNull(); @@ -71,7 +75,7 @@ public partial record Embed return new Embed( title, - type, + kind, url, timestamp, color, diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedKind.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedKind.cs new file mode 100644 index 0000000..19ebd55 --- /dev/null +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedKind.cs @@ -0,0 +1,12 @@ +namespace DiscordChatExporter.Core.Discord.Data.Embeds; + +// https://discord.com/developers/docs/resources/channel#embed-object-embed-types +public enum EmbedKind +{ + Rich, + Image, + Video, + Gifv, + Article, + Link +} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/GifvEmbedProjection.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/GifvEmbedProjection.cs deleted file mode 100644 index 7388b34..0000000 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/GifvEmbedProjection.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace DiscordChatExporter.Core.Discord.Data.Embeds; - -public partial record GifvEmbedProjection(string Url) -{ - public static GifvEmbedProjection? TryResolve(Embed embed) - { - if (string.IsNullOrWhiteSpace(embed.Url)) - return null; - - if (string.IsNullOrWhiteSpace(embed.Video?.Url)) - return null; - - if (!string.Equals(embed.Type, "gifv", StringComparison.OrdinalIgnoreCase)) - return null; - - return new GifvEmbedProjection(embed.Url); - } -} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/PlainImageEmbedProjection.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/PlainImageEmbedProjection.cs deleted file mode 100644 index 5fcfd66..0000000 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/PlainImageEmbedProjection.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using DiscordChatExporter.Core.Utils; - -namespace DiscordChatExporter.Core.Discord.Data.Embeds; - -public record PlainImageEmbedProjection(string Url) -{ - public static PlainImageEmbedProjection? TryResolve(Embed embed) - { - if (string.IsNullOrWhiteSpace(embed.Url)) - return null; - - // Has to be an embed without any data (except URL and image) - if (!string.IsNullOrWhiteSpace(embed.Title) || - embed.Timestamp is not null || - embed.Author is not null || - !string.IsNullOrWhiteSpace(embed.Description) || - embed.Fields.Any() || - embed.Footer is not null) - { - return null; - } - - // Has to be an image file - var fileName = Regex.Match(embed.Url, @".+/([^?]*)").Groups[1].Value; - if (string.IsNullOrWhiteSpace(fileName) || !FileFormat.IsImage(Path.GetExtension(fileName))) - return null; - - return new PlainImageEmbedProjection(embed.Url); - } -} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/SpotifyTrackEmbedProjection.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/SpotifyTrackEmbedProjection.cs index 2d5c6fa..ff48f6e 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/SpotifyTrackEmbedProjection.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/SpotifyTrackEmbedProjection.cs @@ -21,6 +21,9 @@ public partial record SpotifyTrackEmbedProjection public static SpotifyTrackEmbedProjection? TryResolve(Embed embed) { + if (embed.Kind != EmbedKind.Link) + return null; + if (string.IsNullOrWhiteSpace(embed.Url)) return null; diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs index 695bc69..cda1afb 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs @@ -42,6 +42,9 @@ public partial record YouTubeVideoEmbedProjection public static YouTubeVideoEmbedProjection? TryResolve(Embed embed) { + if (embed.Kind != EmbedKind.Video) + return null; + if (string.IsNullOrWhiteSpace(embed.Url)) return null; diff --git a/DiscordChatExporter.Core/Exporting/Writers/Html/MessageExtensions.cs b/DiscordChatExporter.Core/Exporting/Writers/Html/MessageExtensions.cs new file mode 100644 index 0000000..965f98a --- /dev/null +++ b/DiscordChatExporter.Core/Exporting/Writers/Html/MessageExtensions.cs @@ -0,0 +1,22 @@ +using System; +using DiscordChatExporter.Core.Discord.Data; +using DiscordChatExporter.Core.Discord.Data.Embeds; + +namespace DiscordChatExporter.Core.Exporting.Writers.Html; + +internal static class MessageExtensions +{ + // Message content is hidden if it's a link to an embedded media + // https://github.com/Tyrrrz/DiscordChatExporter/issues/682 + public static bool IsContentHidden(this Message message) + { + if (message.Embeds.Count != 1) + return false; + + var embed = message.Embeds[0]; + + return + string.Equals(message.Content.Trim(), embed.Url, StringComparison.OrdinalIgnoreCase) && + embed.Kind is EmbedKind.Image or EmbedKind.Gifv; + } +} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Exporting/Writers/Html/MessageGroupTemplate.cshtml b/DiscordChatExporter.Core/Exporting/Writers/Html/MessageGroupTemplate.cshtml index 2b3cfc0..8cf091a 100644 --- a/DiscordChatExporter.Core/Exporting/Writers/Html/MessageGroupTemplate.cshtml +++ b/DiscordChatExporter.Core/Exporting/Writers/Html/MessageGroupTemplate.cshtml @@ -48,22 +48,6 @@ { var isFirst = i == 0; - // Hide message content if it only contains a link to an embedded media, and nothing else - var isContentHidden = - message.Embeds.Count == 1 && - ( - message.Content.Trim() == PlainImageEmbedProjection.TryResolve(message.Embeds.Single())?.Url || - message.Content.Trim() == GifvEmbedProjection.TryResolve(message.Embeds.Single())?.Url - ); - - var isReferencedContentHidden = - message.ReferencedMessage is not null && - message.ReferencedMessage.Embeds.Count == 1 && - ( - message.ReferencedMessage.Content.Trim() == PlainImageEmbedProjection.TryResolve(message.ReferencedMessage.Embeds.Single())?.Url || - message.ReferencedMessage.Content.Trim() == GifvEmbedProjection.TryResolve(message.ReferencedMessage.Embeds.Single())?.Url - ); -
@{/* Left side */} @@ -99,7 +83,7 @@
@referencedUserNick
- @if (!string.IsNullOrWhiteSpace(message.ReferencedMessage.Content) && !isReferencedContentHidden) + @if (!string.IsNullOrWhiteSpace(message.ReferencedMessage.Content) && !message.ReferencedMessage.IsContentHidden()) { @Raw(FormatEmbedMarkdown(message.ReferencedMessage.Content)) } @@ -150,7 +134,7 @@ {
@{/* Text */} - @if (!isContentHidden) + @if (!message.IsContentHidden()) { @Raw(FormatMarkdown(message.Content)) } @@ -214,29 +198,8 @@ @{/* Embeds */} @foreach (var embed in message.Embeds) { - // Gifv embed - if (embed.TryGetGifv() is { } gifvEmbed) - { - @if (!string.IsNullOrWhiteSpace(embed.Video?.Url)) - { -
- -
- } - } - // Plain image embed - else if (embed.TryGetPlainImage() is { } plainImageEmbed) - { -
- - Embedded image - -
- } // Spotify embed - else if (embed.TryGetSpotifyTrack() is { } spotifyTrackEmbed) + if (embed.TryGetSpotifyTrack() is { } spotifyTrackEmbed) {
@@ -312,7 +275,25 @@
} - // Generic embed + // Generic image embed + else if (embed.Kind == EmbedKind.Image && !string.IsNullOrWhiteSpace(embed.Url)) + { +
+ + Embedded image + +
+ } + // Generic gifv embed + else if (embed.Kind == EmbedKind.Gifv && !string.IsNullOrWhiteSpace(embed.Video?.Url)) + { +
+ +
+ } + // Rich embed else {
diff --git a/DiscordChatExporter.Core/Exporting/Writers/Html/PreambleTemplate.cshtml b/DiscordChatExporter.Core/Exporting/Writers/Html/PreambleTemplate.cshtml index d94f021..e71f87f 100644 --- a/DiscordChatExporter.Core/Exporting/Writers/Html/PreambleTemplate.cshtml +++ b/DiscordChatExporter.Core/Exporting/Writers/Html/PreambleTemplate.cshtml @@ -540,7 +540,14 @@ font-weight: 500; } - .chatlog__embed-plainimage { + .chatlog__embed-generic-image { + max-width: 45vw; + max-height: 500px; + vertical-align: top; + border-radius: 3px; + } + + .chatlog__embed-generic-gifv { max-width: 45vw; max-height: 500px; vertical-align: top;