mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2025-05-22 10:55:15 -04:00
More refactoring
This commit is contained in:
parent
9c2a26aa82
commit
57c849d0f8
9 changed files with 84 additions and 105 deletions
|
@ -11,7 +11,7 @@ namespace DiscordChatExporter.Core.Discord.Data.Embeds;
|
||||||
// https://discord.com/developers/docs/resources/channel#embed-object
|
// https://discord.com/developers/docs/resources/channel#embed-object
|
||||||
public partial record Embed(
|
public partial record Embed(
|
||||||
string? Title,
|
string? Title,
|
||||||
string? Type,
|
EmbedKind Kind,
|
||||||
string? Url,
|
string? Url,
|
||||||
DateTimeOffset? Timestamp,
|
DateTimeOffset? Timestamp,
|
||||||
Color? Color,
|
Color? Color,
|
||||||
|
@ -23,17 +23,11 @@ public partial record Embed(
|
||||||
EmbedVideo? Video,
|
EmbedVideo? Video,
|
||||||
EmbedFooter? Footer)
|
EmbedFooter? Footer)
|
||||||
{
|
{
|
||||||
public PlainImageEmbedProjection? TryGetPlainImage() =>
|
|
||||||
PlainImageEmbedProjection.TryResolve(this);
|
|
||||||
|
|
||||||
public SpotifyTrackEmbedProjection? TryGetSpotifyTrack() =>
|
public SpotifyTrackEmbedProjection? TryGetSpotifyTrack() =>
|
||||||
SpotifyTrackEmbedProjection.TryResolve(this);
|
SpotifyTrackEmbedProjection.TryResolve(this);
|
||||||
|
|
||||||
public YouTubeVideoEmbedProjection? TryGetYouTubeVideo() =>
|
public YouTubeVideoEmbedProjection? TryGetYouTubeVideo() =>
|
||||||
YouTubeVideoEmbedProjection.TryResolve(this);
|
YouTubeVideoEmbedProjection.TryResolve(this);
|
||||||
|
|
||||||
public GifvEmbedProjection? TryGetGifv() =>
|
|
||||||
GifvEmbedProjection.TryResolve(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial record Embed
|
public partial record Embed
|
||||||
|
@ -41,10 +35,20 @@ public partial record Embed
|
||||||
public static Embed Parse(JsonElement json)
|
public static Embed Parse(JsonElement json)
|
||||||
{
|
{
|
||||||
var title = json.GetPropertyOrNull("title")?.GetStringOrNull();
|
var title = json.GetPropertyOrNull("title")?.GetStringOrNull();
|
||||||
var type = json.GetPropertyOrNull("type")?.GetStringOrNull();
|
|
||||||
|
var kind =
|
||||||
|
json.GetPropertyOrNull("type")?.GetStringOrNull()?.Pipe(s => Enum.Parse<EmbedKind>(s, true)) ??
|
||||||
|
EmbedKind.Rich;
|
||||||
|
|
||||||
var url = json.GetPropertyOrNull("url")?.GetNonWhiteSpaceStringOrNull();
|
var url = json.GetPropertyOrNull("url")?.GetNonWhiteSpaceStringOrNull();
|
||||||
var timestamp = json.GetPropertyOrNull("timestamp")?.GetDateTimeOffset();
|
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 author = json.GetPropertyOrNull("author")?.Pipe(EmbedAuthor.Parse);
|
||||||
var description = json.GetPropertyOrNull("description")?.GetStringOrNull();
|
var description = json.GetPropertyOrNull("description")?.GetStringOrNull();
|
||||||
|
|
||||||
|
@ -71,7 +75,7 @@ public partial record Embed
|
||||||
|
|
||||||
return new Embed(
|
return new Embed(
|
||||||
title,
|
title,
|
||||||
type,
|
kind,
|
||||||
url,
|
url,
|
||||||
timestamp,
|
timestamp,
|
||||||
color,
|
color,
|
||||||
|
|
12
DiscordChatExporter.Core/Discord/Data/Embeds/EmbedKind.cs
Normal file
12
DiscordChatExporter.Core/Discord/Data/Embeds/EmbedKind.cs
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,6 +21,9 @@ public partial record SpotifyTrackEmbedProjection
|
||||||
|
|
||||||
public static SpotifyTrackEmbedProjection? TryResolve(Embed embed)
|
public static SpotifyTrackEmbedProjection? TryResolve(Embed embed)
|
||||||
{
|
{
|
||||||
|
if (embed.Kind != EmbedKind.Link)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(embed.Url))
|
if (string.IsNullOrWhiteSpace(embed.Url))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ public partial record YouTubeVideoEmbedProjection
|
||||||
|
|
||||||
public static YouTubeVideoEmbedProjection? TryResolve(Embed embed)
|
public static YouTubeVideoEmbedProjection? TryResolve(Embed embed)
|
||||||
{
|
{
|
||||||
|
if (embed.Kind != EmbedKind.Video)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(embed.Url))
|
if (string.IsNullOrWhiteSpace(embed.Url))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,22 +48,6 @@
|
||||||
{
|
{
|
||||||
var isFirst = i == 0;
|
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
|
|
||||||
);
|
|
||||||
|
|
||||||
<div id="chatlog__message-container-@message.Id" class="chatlog__message-container @(message.IsPinned ? "chatlog__message-container--pinned" : null)" data-message-id="@message.Id">
|
<div id="chatlog__message-container-@message.Id" class="chatlog__message-container @(message.IsPinned ? "chatlog__message-container--pinned" : null)" data-message-id="@message.Id">
|
||||||
<div class="chatlog__message">
|
<div class="chatlog__message">
|
||||||
@{/* Left side */}
|
@{/* Left side */}
|
||||||
|
@ -99,7 +83,7 @@
|
||||||
<div class="chatlog__reference-author" style="@(referencedUserColor is not null ? $"color: rgb({referencedUserColor.Value.R}, {referencedUserColor.Value.G}, {referencedUserColor.Value.B})" : null)" title="@message.ReferencedMessage.Author.FullName">@referencedUserNick</div>
|
<div class="chatlog__reference-author" style="@(referencedUserColor is not null ? $"color: rgb({referencedUserColor.Value.R}, {referencedUserColor.Value.G}, {referencedUserColor.Value.B})" : null)" title="@message.ReferencedMessage.Author.FullName">@referencedUserNick</div>
|
||||||
<div class="chatlog__reference-content">
|
<div class="chatlog__reference-content">
|
||||||
<span class="chatlog__reference-link" onclick="scrollToMessage(event, '@message.ReferencedMessage.Id')">
|
<span class="chatlog__reference-link" onclick="scrollToMessage(event, '@message.ReferencedMessage.Id')">
|
||||||
@if (!string.IsNullOrWhiteSpace(message.ReferencedMessage.Content) && !isReferencedContentHidden)
|
@if (!string.IsNullOrWhiteSpace(message.ReferencedMessage.Content) && !message.ReferencedMessage.IsContentHidden())
|
||||||
{
|
{
|
||||||
<!--wmm:ignore-->@Raw(FormatEmbedMarkdown(message.ReferencedMessage.Content))<!--/wmm:ignore-->
|
<!--wmm:ignore-->@Raw(FormatEmbedMarkdown(message.ReferencedMessage.Content))<!--/wmm:ignore-->
|
||||||
}
|
}
|
||||||
|
@ -150,7 +134,7 @@
|
||||||
{
|
{
|
||||||
<div class="chatlog__content chatlog__markdown">
|
<div class="chatlog__content chatlog__markdown">
|
||||||
@{/* Text */}
|
@{/* Text */}
|
||||||
@if (!isContentHidden)
|
@if (!message.IsContentHidden())
|
||||||
{
|
{
|
||||||
<span class="chatlog__markdown-preserve"><!--wmm:ignore-->@Raw(FormatMarkdown(message.Content))<!--/wmm:ignore--></span>
|
<span class="chatlog__markdown-preserve"><!--wmm:ignore-->@Raw(FormatMarkdown(message.Content))<!--/wmm:ignore--></span>
|
||||||
}
|
}
|
||||||
|
@ -214,29 +198,8 @@
|
||||||
@{/* Embeds */}
|
@{/* Embeds */}
|
||||||
@foreach (var embed in message.Embeds)
|
@foreach (var embed in message.Embeds)
|
||||||
{
|
{
|
||||||
// Gifv embed
|
|
||||||
if (embed.TryGetGifv() is { } gifvEmbed)
|
|
||||||
{
|
|
||||||
@if (!string.IsNullOrWhiteSpace(embed.Video?.Url))
|
|
||||||
{
|
|
||||||
<div class="chatlog__attachment">
|
|
||||||
<video class="chatlog__attachment-media" loop width="@embed.Video.Width" height="@embed.Video.Height" onmouseover="this.play()" onmouseout="this.pause()">
|
|
||||||
<source src="@await ResolveUrlAsync(embed.Video.ProxyUrl ?? embed.Video.Url)" alt="Embedded video">
|
|
||||||
</video>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Plain image embed
|
|
||||||
else if (embed.TryGetPlainImage() is { } plainImageEmbed)
|
|
||||||
{
|
|
||||||
<div class="chatlog__embed">
|
|
||||||
<a href="@await ResolveUrlAsync(plainImageEmbed.Url)">
|
|
||||||
<img class="chatlog__embed-plainimage" src="@await ResolveUrlAsync(plainImageEmbed.Url)" alt="Embedded image" loading="lazy">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
// Spotify embed
|
// Spotify embed
|
||||||
else if (embed.TryGetSpotifyTrack() is { } spotifyTrackEmbed)
|
if (embed.TryGetSpotifyTrack() is { } spotifyTrackEmbed)
|
||||||
{
|
{
|
||||||
<div class="chatlog__embed">
|
<div class="chatlog__embed">
|
||||||
<div class="chatlog__embed-spotify-container">
|
<div class="chatlog__embed-spotify-container">
|
||||||
|
@ -312,7 +275,25 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
// Generic embed
|
// Generic image embed
|
||||||
|
else if (embed.Kind == EmbedKind.Image && !string.IsNullOrWhiteSpace(embed.Url))
|
||||||
|
{
|
||||||
|
<div class="chatlog__embed">
|
||||||
|
<a href="@await ResolveUrlAsync(embed.Url)">
|
||||||
|
<img class="chatlog__embed-generic-image" src="@await ResolveUrlAsync(embed.Url)" alt="Embedded image" loading="lazy">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
// Generic gifv embed
|
||||||
|
else if (embed.Kind == EmbedKind.Gifv && !string.IsNullOrWhiteSpace(embed.Video?.Url))
|
||||||
|
{
|
||||||
|
<div class="chatlog__embed">
|
||||||
|
<video class="chatlog__embed-generic-gifv" loop width="@embed.Video.Width" height="@embed.Video.Height" onmouseover="this.play()" onmouseout="this.pause()">
|
||||||
|
<source src="@await ResolveUrlAsync(embed.Video.ProxyUrl ?? embed.Video.Url)" alt="Embedded video">
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
// Rich embed
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="chatlog__embed">
|
<div class="chatlog__embed">
|
||||||
|
|
|
@ -540,7 +540,14 @@
|
||||||
font-weight: 500;
|
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-width: 45vw;
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue