From a8eb404ff3c1cab755bedba129209caa2b3f3137 Mon Sep 17 00:00:00 2001 From: Max Litruv Boonzaayer Date: Tue, 24 Mar 2026 00:14:53 +1100 Subject: [PATCH] feat: add TikTok embed support --- src/app/components/RenderMessageContent.tsx | 75 ++++-- .../message/content/AudioContent.tsx | 1 + .../message/content/ThumbnailContent.tsx | 19 +- .../message/content/VideoContent.tsx | 1 + .../message/content/VideoFrameThumbnail.tsx | 132 ++++++++++ src/app/components/message/content/index.ts | 1 + .../url-preview/TikTokEmbed.css.tsx | 116 +++++++++ .../components/url-preview/TikTokEmbed.tsx | 245 ++++++++++++++++++ .../components/url-preview/UrlPreviewCard.tsx | 34 ++- src/app/components/url-preview/index.ts | 1 + 10 files changed, 589 insertions(+), 36 deletions(-) create mode 100644 src/app/components/message/content/VideoFrameThumbnail.tsx create mode 100644 src/app/components/url-preview/TikTokEmbed.css.tsx create mode 100644 src/app/components/url-preview/TikTokEmbed.tsx diff --git a/src/app/components/RenderMessageContent.tsx b/src/app/components/RenderMessageContent.tsx index c29628e..49fdf00 100644 --- a/src/app/components/RenderMessageContent.tsx +++ b/src/app/components/RenderMessageContent.tsx @@ -23,8 +23,9 @@ import { ThumbnailContent, UnsupportedContent, VideoContent, + VideoFrameThumbnail, } from './message'; -import { UrlPreviewCard, UrlPreviewHolder, YouTubeEmbed, isYouTubeUrl } from './url-preview'; +import { UrlPreviewCard, UrlPreviewHolder, YouTubeEmbed, isYouTubeUrl, TikTokEmbed, isTikTokUrl } from './url-preview'; import { Image, MediaControl, Video } from './media'; import { ImageViewer } from './image-viewer'; import { PdfViewer } from './Pdf-viewer'; @@ -66,16 +67,21 @@ export function RenderMessageContent({ filteredUrls = filterDisabledUrls(filteredUrls, disabledEmbedPatterns ?? []); if (filteredUrls.length === 0) return undefined; - // Separate YouTube URLs from other URLs + // Separate special URLs from generic ones const youtubeUrls = filteredUrls.filter(isYouTubeUrl); - const otherUrls = filteredUrls.filter((url) => !isYouTubeUrl(url)); + const tiktokUrls = filteredUrls.filter(isTikTokUrl); + const otherUrls = filteredUrls.filter((url) => !isYouTubeUrl(url) && !isTikTokUrl(url)); return ( <> - {/* Render YouTube embeds (ad-free via Piped) */} + {/* Render YouTube embeds (ad-free via yt-dlp) */} {youtubeUrls.map((url) => ( ))} + {/* Render TikTok embeds */} + {tiktokUrls.map((url) => ( + + ))} {/* Render standard URL previews for other links */} {otherUrls.length > 0 && ( @@ -227,26 +233,47 @@ export function RenderMessageContent({ ( - ( - ( - {body} - )} - /> - ) - : undefined - } - renderVideo={(p) =>