Support GIF embeds when exporting to HTML (#919)

pull/925/head
gan-of-culture 2 years ago committed by GitHub
parent a405ab184e
commit f28d662a71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -11,6 +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,
string? Url, string? Url,
DateTimeOffset? Timestamp, DateTimeOffset? Timestamp,
Color? Color, Color? Color,
@ -19,6 +20,7 @@ public partial record Embed(
IReadOnlyList<EmbedField> Fields, IReadOnlyList<EmbedField> Fields,
EmbedImage? Thumbnail, EmbedImage? Thumbnail,
IReadOnlyList<EmbedImage> Images, IReadOnlyList<EmbedImage> Images,
EmbedVideo? Video,
EmbedFooter? Footer) EmbedFooter? Footer)
{ {
public PlainImageEmbedProjection? TryGetPlainImage() => public PlainImageEmbedProjection? TryGetPlainImage() =>
@ -29,6 +31,9 @@ public partial record Embed(
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
@ -36,6 +41,7 @@ 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 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();
@ -59,10 +65,13 @@ public partial record Embed
json.GetPropertyOrNull("image")?.Pipe(EmbedImage.Parse).Enumerate().ToArray() ?? json.GetPropertyOrNull("image")?.Pipe(EmbedImage.Parse).Enumerate().ToArray() ??
Array.Empty<EmbedImage>(); Array.Empty<EmbedImage>();
var video = json.GetPropertyOrNull("video")?.Pipe(EmbedVideo.Parse);
var footer = json.GetPropertyOrNull("footer")?.Pipe(EmbedFooter.Parse); var footer = json.GetPropertyOrNull("footer")?.Pipe(EmbedFooter.Parse);
return new Embed( return new Embed(
title, title,
type,
url, url,
timestamp, timestamp,
color, color,
@ -71,6 +80,7 @@ public partial record Embed
fields, fields,
thumbnail, thumbnail,
images, images,
video,
footer footer
); );
} }

@ -0,0 +1,22 @@
using JsonExtensions.Reading;
using System.Text.Json;
namespace DiscordChatExporter.Core.Discord.Data.Embeds;
// https://discord.com/developers/docs/resources/channel#embed-object-embed-video-structure
public record EmbedVideo(
string? Url,
string? ProxyUrl,
int? Width,
int? Height)
{
public static EmbedVideo Parse(JsonElement json)
{
var url = json.GetPropertyOrNull("url")?.GetNonWhiteSpaceStringOrNull();
var proxyUrl = json.GetPropertyOrNull("proxy_url")?.GetNonWhiteSpaceStringOrNull();
var width = json.GetPropertyOrNull("width")?.GetInt32OrNull();
var height = json.GetPropertyOrNull("height")?.GetInt32OrNull();
return new EmbedVideo(url, proxyUrl, width, height);
}
}

@ -0,0 +1,21 @@
using System;
using System.Text.RegularExpressions;
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 (embed.Video is null || string.IsNullOrWhiteSpace(embed.Video.Url))
return null;
if (!string.Equals(embed.Type, "gifv", StringComparison.OrdinalIgnoreCase))
return null;
return new GifvEmbedProjection(embed.Url);
}
}

@ -208,8 +208,20 @@
@{/* Embeds */} @{/* Embeds */}
@foreach (var embed in message.Embeds) @foreach (var embed in message.Embeds)
{ {
// Gifv embed
if (embed.TryGetGifv() is { } gifvEmbed)
{
@if (embed.Video is not null && !string.IsNullOrWhiteSpace(embed.Video.Url) && embed.Thumbnail is not null)
{
<div class="chatlog__attachment">
<video class="chatlog__attachment-media" poster="@await ResolveUrlAsync(embed.Thumbnail.ProxyUrl ?? embed.Thumbnail.Url)" loop="" controls="" aria-label="GIF" width="@(embed.Video.Width)" height="@(embed.Video.Height)">
<source src="@await ResolveUrlAsync(embed.Video.ProxyUrl ?? embed.Video.Url)" alt="@(embed.Description ?? "Tenor GIF")" title="@embed.Title">
</video>
</div>
}
}
// Plain image embed // Plain image embed
if (embed.TryGetPlainImage() is { } plainImageEmbed) else if (embed.TryGetPlainImage() is { } plainImageEmbed)
{ {
<div class="chatlog__embed"> <div class="chatlog__embed">
<a href="@await ResolveUrlAsync(plainImageEmbed.Url)"> <a href="@await ResolveUrlAsync(plainImageEmbed.Url)">

Loading…
Cancel
Save