From a0e06e1c121a37ff2a93868945dba4effb8aea58 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Wed, 25 Jun 2025 13:56:37 -0700 Subject: render video attachments and video urls --- src/renderer/index.html | 2 +- src/renderer/src/components/Message.tsx | 61 ++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/renderer/index.html b/src/renderer/index.html index edffc05..a2eebe4 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -6,7 +6,7 @@ diff --git a/src/renderer/src/components/Message.tsx b/src/renderer/src/components/Message.tsx index 0fc0c68..2dcda4e 100644 --- a/src/renderer/src/components/Message.tsx +++ b/src/renderer/src/components/Message.tsx @@ -13,14 +13,16 @@ const avatarBaseUrl = 'https://cdn.discordapp.com/avatars/' interface ParsedContent { html: string imageUrls: string[] + videoUrls: string[] } -const parseMentionsAndEmotes = ( +const processRenderedContent = ( content: string, mentions?: DiscordUserMention[] ): ParsedContent => { let parsedContent = content const imageUrls: string[] = [] + const videoUrls: string[] = [] // Replace user mentions <@user_id> with usernames if (mentions && mentions.length > 0) { @@ -80,6 +82,11 @@ const parseMentionsAndEmotes = ( parsedContent = parsedContent.replace(urlRegex, (url) => { // Check if URL ends with image extension const imageExtensions = /\.(png|jpe?g|gif|webp)(\?[^\s]*)?$/i + const videoExtensions = /\.(mp4|webm|mov|avi|mkv|flv|wmv|m4v)(\?[^\s]*)?$/i + if (videoExtensions.test(url)) { + videoUrls.push(url) + return '' // Remove video URL from content + } if (imageExtensions.test(url)) { imageUrls.push(url) return '' // Remove image URL from content @@ -92,11 +99,10 @@ const parseMentionsAndEmotes = ( const placeholder = `__IMG_PLACEHOLDER_${index}__` parsedContent = parsedContent.replace(placeholder, imgTag) }) - // Convert newlines to HTML line breaks parsedContent = parsedContent.replace(/\n/g, '
') - return { html: parsedContent, imageUrls } + return { html: parsedContent, imageUrls, videoUrls } } const Message: React.FC = ({ message, channelNickname }) => { @@ -126,8 +132,12 @@ const Message: React.FC = ({ message, channelNickname }) => { // Separate image and non-image attachments const imageAttachments = attachments?.filter((att) => att.content_type?.startsWith('image/')) || [] + const videoAttachments = + attachments?.filter((att) => att.content_type?.startsWith('video/')) || [] const nonImageAttachments = - attachments?.filter((att) => !att.content_type?.startsWith('image/')) || [] + attachments?.filter( + (att) => !att.content_type?.startsWith('image/') && !att.content_type?.startsWith('video/') + ) || [] const renderSticker = (): React.JSX.Element | null => { if (!sticker_id || sticker_type === undefined) return null @@ -179,7 +189,7 @@ const Message: React.FC = ({ message, channelNickname }) => { {(() => { if (!content) return null - const parsed = parseMentionsAndEmotes(content, mentions) + const parsed = processRenderedContent(content, mentions) return ( <> @@ -204,6 +214,26 @@ const Message: React.FC = ({ message, channelNickname }) => { /> ))} + + {/* Render extracted video URLs as React components */} + {parsed.videoUrls.map((videoUrl, index) => ( +
+
+ ))} ) })()} @@ -231,6 +261,27 @@ const Message: React.FC = ({ message, channelNickname }) => { ))} + {/* Render all video attachments */} + {videoAttachments.map((attachment, index) => ( +
+
+ ))} + {/* Render non-image attachments as clickable links */} {nonImageAttachments.map((attachment, index) => (
-- cgit v1.2.3