From 72f9e981de75ae28d29b96d9d01c150c53df7c43 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 19:04:17 +0200 Subject: [PATCH] Replace YouTube iframe embeds with clickable thumbnails (#1474) * Initial plan * Replace YouTube iframe with clickable thumbnail - Changed YouTube embed URL from embed format to watch format - Added ThumbnailUrl property to YouTubeVideoEmbedProjection using YouTube's standard thumbnail URL - Updated MessageGroupTemplate to render thumbnail image with link instead of iframe - Updated CSS to style thumbnail appropriately - Updated test to check for anchor link and thumbnail image instead of iframe Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> * Address code review feedback - Use hqdefault.jpg instead of maxresdefault.jpg (guaranteed to exist for all videos) - Extract thumbnail URL logic to GetThumbnailUrl method for better testability Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> * Simplify YouTube embed test to focus on data not structure - Remove checks for HTML structure (class names, nested elements) - Focus on verifying YouTube URL with correct video ID exists - Follow same pattern as other embed tests (Spotify, Twitch) Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> * Fix data-canonical-url and improve test specificity - Use canonical (non-proxy) URL for data-canonical-url attribute - Extract thumbnailUrl to local variable to avoid duplicate calls - Update test to check for img with video ID in src, avoiding false positives - Test now verifies the actual thumbnail data rather than any link Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> * Inline thumbnail URL logic directly into attributes - Remove GetThumbnailUrl method from YouTubeVideoEmbedProjection - Remove local variables from template - Put coalescing logic directly in src and data-canonical-url attributes Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> --- DiscordChatExporter.Cli.Tests/Specs/HtmlEmbedSpecs.cs | 10 ++++++++-- .../Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs | 5 ++++- .../Exporting/MessageGroupTemplate.cshtml | 6 ++++-- .../Exporting/PreambleTemplate.cshtml | 6 ++++-- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/DiscordChatExporter.Cli.Tests/Specs/HtmlEmbedSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/HtmlEmbedSpecs.cs index 207e8041..a959d462 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/HtmlEmbedSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/HtmlEmbedSpecs.cs @@ -181,8 +181,14 @@ public class HtmlEmbedSpecs ); // Assert - var iframeUrl = message.QuerySelector("iframe")?.GetAttribute("src"); - iframeUrl.Should().StartWith("https://www.youtube.com/embed/qOWW4OlgbvE"); + // Check that the YouTube video thumbnail image exists with the correct video ID + var youtubeThumbnailSrc = message + .QuerySelectorAll("img") + .Select(e => e.GetAttribute("src")) + .WhereNotNull() + .FirstOrDefault(s => s.Contains("qOWW4OlgbvE", StringComparison.Ordinal)); + + youtubeThumbnailSrc.Should().NotBeNull(); } [Fact] diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs index ce13bdfd..f6d095d2 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/YouTubeVideoEmbedProjection.cs @@ -2,7 +2,10 @@ public partial record YouTubeVideoEmbedProjection(string VideoId) { - public string Url { get; } = $"https://www.youtube.com/embed/{VideoId}"; + public string Url { get; } = $"https://www.youtube.com/watch?v={VideoId}"; + + // Using hqdefault.jpg which is guaranteed to exist for all YouTube videos + public string ThumbnailUrl { get; } = $"https://i.ytimg.com/vi/{VideoId}/hqdefault.jpg"; } public partial record YouTubeVideoEmbedProjection diff --git a/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml b/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml index e27fad2b..641c2ada 100644 --- a/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml +++ b/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml @@ -424,9 +424,11 @@ } - @* Video player *@ + @* Video thumbnail *@
diff --git a/DiscordChatExporter.Core/Exporting/PreambleTemplate.cshtml b/DiscordChatExporter.Core/Exporting/PreambleTemplate.cshtml index 9e746e16..792612c7 100644 --- a/DiscordChatExporter.Core/Exporting/PreambleTemplate.cshtml +++ b/DiscordChatExporter.Core/Exporting/PreambleTemplate.cshtml @@ -711,9 +711,11 @@ margin-top: 0.6rem; } - .chatlog__embed-youtube { - border: 0; + .chatlog__embed-youtube-thumbnail { + max-width: 400px; + max-height: 225px; border-radius: 3px; + cursor: pointer; } .chatlog__sticker {