diff --git a/DiscordChatExporter.Cli.Tests/EmbedSpecs.cs b/DiscordChatExporter.Cli.Tests/EmbedSpecs.cs index 9a86b70e..e35b1303 100644 --- a/DiscordChatExporter.Cli.Tests/EmbedSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/EmbedSpecs.cs @@ -140,7 +140,41 @@ namespace DiscordChatExporter.Cli.Tests } [Fact] - public async Task Message_with_YouTube_video_is_rendered_using_an_iframe_player_in_HTML() + public async Task Message_with_a_Spotify_track_is_rendered_using_an_iframe_in_HTML() + { + // Arrange + var outputFilePath = _tempOutput.GetTempFilePath("html"); + + // Act + var htmlData = await GlobalCache.WrapAsync("embed-specs-output-html", async () => + { + await new ExportChannelsCommand + { + TokenValue = Secrets.DiscordToken, + IsBotToken = Secrets.IsDiscordTokenBot, + ChannelIds = new[] {Snowflake.Parse(ChannelIds.EmbedTestCases)}, + ExportFormat = ExportFormat.HtmlDark, + OutputPath = outputFilePath + }.ExecuteAsync(new FakeConsole()); + + return await File.ReadAllTextAsync(outputFilePath); + }); + + _testOutput.WriteLine(htmlData); + + var html = Html.Parse(htmlData); + + var messageHtml = html.QuerySelector("#message-867886632203976775"); + var iframeHtml = messageHtml?.QuerySelector("iframe"); + + // Assert + iframeHtml.Should().NotBeNull(); + iframeHtml?.GetAttribute("src").Should() + .StartWithEquivalent("https://open.spotify.com/embed/track/1LHZMWefF9502NPfArRfvP"); + } + + [Fact] + public async Task Message_with_a_YouTube_video_is_rendered_using_an_iframe_in_HTML() { // Arrange var outputFilePath = _tempOutput.GetTempFilePath("html"); diff --git a/DiscordChatExporter.Core/Discord/Data/Embed.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs similarity index 94% rename from DiscordChatExporter.Core/Discord/Data/Embed.cs rename to DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs index 21a29f1d..e826267e 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embed.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs @@ -7,7 +7,7 @@ using System.Text.Json; using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; -namespace DiscordChatExporter.Core.Discord.Data +namespace DiscordChatExporter.Core.Discord.Data.Embeds { // https://discord.com/developers/docs/resources/channel#embed-object public partial class Embed @@ -56,6 +56,8 @@ namespace DiscordChatExporter.Core.Discord.Data Footer = footer; } + public SpotifyTrackEmbedProjection? TryGetSpotifyTrack() => SpotifyTrackEmbedProjection.TryResolve(this); + public YouTubeVideoEmbedProjection? TryGetYouTubeVideo() => YouTubeVideoEmbedProjection.TryResolve(this); [ExcludeFromCodeCoverage] diff --git a/DiscordChatExporter.Core/Discord/Data/EmbedAuthor.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs similarity index 95% rename from DiscordChatExporter.Core/Discord/Data/EmbedAuthor.cs rename to DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs index 825bfa0e..c420a991 100644 --- a/DiscordChatExporter.Core/Discord/Data/EmbedAuthor.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs @@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; using JsonExtensions.Reading; -namespace DiscordChatExporter.Core.Discord.Data +namespace DiscordChatExporter.Core.Discord.Data.Embeds { // https://discord.com/developers/docs/resources/channel#embed-object-embed-author-structure public partial class EmbedAuthor diff --git a/DiscordChatExporter.Core/Discord/Data/EmbedField.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedField.cs similarity index 94% rename from DiscordChatExporter.Core/Discord/Data/EmbedField.cs rename to DiscordChatExporter.Core/Discord/Data/Embeds/EmbedField.cs index 39ed9f1e..1e21c642 100644 --- a/DiscordChatExporter.Core/Discord/Data/EmbedField.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedField.cs @@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; using JsonExtensions.Reading; -namespace DiscordChatExporter.Core.Discord.Data +namespace DiscordChatExporter.Core.Discord.Data.Embeds { // https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure public partial class EmbedField diff --git a/DiscordChatExporter.Core/Discord/Data/EmbedFooter.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedFooter.cs similarity index 95% rename from DiscordChatExporter.Core/Discord/Data/EmbedFooter.cs rename to DiscordChatExporter.Core/Discord/Data/Embeds/EmbedFooter.cs index a405454c..931f15ef 100644 --- a/DiscordChatExporter.Core/Discord/Data/EmbedFooter.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedFooter.cs @@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; using JsonExtensions.Reading; -namespace DiscordChatExporter.Core.Discord.Data +namespace DiscordChatExporter.Core.Discord.Data.Embeds { // https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure public partial class EmbedFooter diff --git a/DiscordChatExporter.Core/Discord/Data/EmbedImage.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedImage.cs similarity index 94% rename from DiscordChatExporter.Core/Discord/Data/EmbedImage.cs rename to DiscordChatExporter.Core/Discord/Data/Embeds/EmbedImage.cs index 0ec33e19..6f0569c4 100644 --- a/DiscordChatExporter.Core/Discord/Data/EmbedImage.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedImage.cs @@ -1,7 +1,7 @@ using System.Text.Json; using JsonExtensions.Reading; -namespace DiscordChatExporter.Core.Discord.Data +namespace DiscordChatExporter.Core.Discord.Data.Embeds { // https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure public partial class EmbedImage diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/SpotifyTrackEmbedProjection.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/SpotifyTrackEmbedProjection.cs new file mode 100644 index 00000000..ca77d859 --- /dev/null +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/SpotifyTrackEmbedProjection.cs @@ -0,0 +1,42 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; + +namespace DiscordChatExporter.Core.Discord.Data.Embeds +{ + public partial class SpotifyTrackEmbedProjection + { + public string TrackId { get; } + + public string Url => $"https://open.spotify.com/embed/track/{TrackId}"; + + public SpotifyTrackEmbedProjection(string trackId) => TrackId = trackId; + + [ExcludeFromCodeCoverage] + public override string ToString() => Url; + } + + public partial class SpotifyTrackEmbedProjection + { + private static string? TryParseTrackId(string embedUrl) + { + // https://open.spotify.com/track/1LHZMWefF9502NPfArRfvP?si=3efac6ce9be04f0a + var trackId = Regex.Match(embedUrl, @"spotify\.com/track/(.*?)(?:\?|&|/|$)").Groups[1].Value; + if (!string.IsNullOrWhiteSpace(trackId)) + return trackId; + + return null; + } + + public static SpotifyTrackEmbedProjection? TryResolve(Embed embed) + { + if (string.IsNullOrWhiteSpace(embed.Url)) + return null; + + var trackId = TryParseTrackId(embed.Url); + if (string.IsNullOrWhiteSpace(trackId)) + return null; + + return new SpotifyTrackEmbedProjection(trackId); + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Discord/Data/YouTubeVideoEmbedProjection.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs similarity index 97% rename from DiscordChatExporter.Core/Discord/Data/YouTubeVideoEmbedProjection.cs rename to DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs index 90db28cf..bb48448e 100644 --- a/DiscordChatExporter.Core/Discord/Data/YouTubeVideoEmbedProjection.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; -namespace DiscordChatExporter.Core.Discord.Data +namespace DiscordChatExporter.Core.Discord.Data.Embeds { public partial class YouTubeVideoEmbedProjection { diff --git a/DiscordChatExporter.Core/Discord/Data/Message.cs b/DiscordChatExporter.Core/Discord/Data/Message.cs index 6ea4f403..55042715 100644 --- a/DiscordChatExporter.Core/Discord/Data/Message.cs +++ b/DiscordChatExporter.Core/Discord/Data/Message.cs @@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; +using DiscordChatExporter.Core.Discord.Data.Embeds; using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; diff --git a/DiscordChatExporter.Core/Exporting/Writers/Html/MessageGroupTemplate.cshtml b/DiscordChatExporter.Core/Exporting/Writers/Html/MessageGroupTemplate.cshtml index 9f18e397..e34709cc 100644 --- a/DiscordChatExporter.Core/Exporting/Writers/Html/MessageGroupTemplate.cshtml +++ b/DiscordChatExporter.Core/Exporting/Writers/Html/MessageGroupTemplate.cshtml @@ -176,157 +176,230 @@ @{/* Embeds */} @foreach (var embed in message.Embeds) { - var youTubeVideo = embed.TryGetYouTubeVideo(); + // Spotify embed + if (embed.TryGetSpotifyTrack() is { } spotifyTrackEmbed) + { +
+ } + // YouTube embed + else if (embed.TryGetYouTubeVideo() is { } youTubeVideoEmbed) + { +