From 0458b42937e2fc2aa1bf217c9335279219dcd601 Mon Sep 17 00:00:00 2001 From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com> Date: Mon, 4 Aug 2025 20:20:29 +0000 Subject: [PATCH] Display video previews correctly for videos with restricted access Implements a thumbnail proxy to fetch private BunnyCDN video thumbnails. Replit-Commit-Author: Agent Replit-Commit-Session-Id: aa92e7e2-ec62-4c92-b21b-02ef78a664c2 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/aa92e7e2-ec62-4c92-b21b-02ef78a664c2/PiJtjmP --- server/bunny.ts | 5 ++--- server/routes.ts | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/server/bunny.ts b/server/bunny.ts index d01406b..93ab345 100644 --- a/server/bunny.ts +++ b/server/bunny.ts @@ -52,9 +52,8 @@ export class BunnyService { } private bunnyVideoToVideo(bunnyVideo: BunnyVideo): Video { - // For private videos, use iframe embed or proxy approach - // Generate thumbnail URL from CDN (thumbnails are usually public) - const thumbnailUrl = `https://${this.hostname}/${bunnyVideo.guid}/thumbnail.jpg`; + // Use server-side proxy for thumbnails since they are private + const thumbnailUrl = `/thumbnail/${bunnyVideo.guid}`; // For private videos, we'll use an iframe embed URL which handles authentication const videoUrl = `https://iframe.mediadelivery.net/embed/${this.libraryId}/${bunnyVideo.guid}`; diff --git a/server/routes.ts b/server/routes.ts index ff022c8..94cc468 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -47,6 +47,44 @@ export async function registerRoutes(app: Express): Promise { } }); + // Proxy endpoint for thumbnails (since they are private) + app.get("/thumbnail/:id", async (req, res) => { + try { + const { id } = req.params; + const apiKey = process.env.BUNNY_API_KEY; + const libraryId = process.env.BUNNY_LIBRARY_ID; + + if (!apiKey || !libraryId) { + return res.status(500).json({ message: "Bunny.net configuration missing" }); + } + + // Try to get thumbnail from Bunny API + const thumbnailUrl = `https://video.bunnycdn.com/library/${libraryId}/videos/${id}/thumbnail`; + + const response = await fetch(thumbnailUrl, { + method: 'POST', + headers: { + 'AccessKey': apiKey, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ time: 10 }) // Get thumbnail at 10 seconds + }); + + if (response.ok) { + const thumbnailData = await response.arrayBuffer(); + res.set('Content-Type', 'image/jpeg'); + res.set('Cache-Control', 'public, max-age=3600'); // Cache for 1 hour + res.send(Buffer.from(thumbnailData)); + } else { + // If thumbnail generation fails, return a placeholder + res.redirect('https://via.placeholder.com/480x270/1a1a1a/ffffff?text=Video'); + } + } catch (error) { + console.error('Error proxying thumbnail:', error); + res.redirect('https://via.placeholder.com/480x270/1a1a1a/ffffff?text=Video'); + } + }); + const httpServer = createServer(app);