From 146e5fd25c409cbdfb5e7f537716ab327cafa667 Mon Sep 17 00:00:00 2001 From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com> Date: Thu, 28 Aug 2025 17:32:26 +0000 Subject: [PATCH] Update video playback to use direct iframe links Replaced signed URLs with direct iframe URLs for video playback and updated the token generation method in the Bunny service. Replit-Commit-Author: Agent Replit-Commit-Session-Id: d7424866-83d1-4486-a212-ac12b4c7becf Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/d7424866-83d1-4486-a212-ac12b4c7becf/tr3vokF --- server/bunny.ts | 30 ++++++++++++++++++++++++++---- server/storage.ts | 12 +++--------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/server/bunny.ts b/server/bunny.ts index 81066ef..753e7cc 100644 --- a/server/bunny.ts +++ b/server/bunny.ts @@ -1,4 +1,5 @@ import { type Video, type InsertVideo } from "@shared/schema"; +import crypto from 'crypto'; interface BunnyVideo { guid: string; @@ -153,7 +154,23 @@ export class BunnyService { console.log(`Fetching video with description from Bunny: ${guid}`); const bunnyVideo: BunnyVideoDetails = await this.makeRequest(`videos/${guid}`); console.log(`Fetching video: ${bunnyVideo.title} - Description available: ${!!bunnyVideo.description}`); - return this.bunnyVideoToVideo(bunnyVideo); + // Use direct iframe URL instead of signed URL to avoid complexity + return { + id: bunnyVideo.guid, + title: bunnyVideo.title, + description: bunnyVideo.description || "", + thumbnailUrl: this.getThumbnailUrl(bunnyVideo.guid, bunnyVideo.thumbnailFileName), + videoUrl: `https://iframe.mediadelivery.net/embed/384105/${bunnyVideo.guid}`, + duration: bunnyVideo.length, + views: bunnyVideo.views, + category: bunnyVideo.category || "", + tags: bunnyVideo.metaTags?.map(tag => tag.value) || [], + isPublic: bunnyVideo.status === 4, + uploadStatus: bunnyVideo.status === 4 ? "completed" : "processing", + originalFileName: bunnyVideo.title, + createdAt: new Date(bunnyVideo.dateUploaded), + updatedAt: new Date(bunnyVideo.dateUploaded), + }; } catch (error) { console.error(`Error fetching video ${guid} from Bunny:`, error); return null; @@ -220,13 +237,18 @@ export class BunnyService { // Generate signed URL for private video access generateSignedUrl(videoId: string, expirationTime: number = 3600): string { + // Use the pull zone hostname for video streaming const baseUrl = `https://${this.hostname}/${videoId}/playlist.m3u8`; const expires = Math.floor(Date.now() / 1000) + expirationTime; - // Simple token generation (in production, use proper HMAC signing) - const token = Buffer.from(`${videoId}:${expires}:${this.apiKey.substring(0, 8)}`).toString('base64'); + // Generate security token using library ID and API key + const securityKey = this.apiKey; + const hashableBase = securityKey + videoId + expires.toString(); - return `${baseUrl}?token=${token}&expires=${expires}`; + // Create a simple hash for the token + const hash = crypto.createHash('md5').update(hashableBase).digest('hex'); + + return `${baseUrl}?token=${hash}&expires=${expires}`; } } diff --git a/server/storage.ts b/server/storage.ts index 6cf0873..1095f44 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -73,16 +73,13 @@ export class DatabaseStorage implements IStorage { const result = await db.execute(sqlQuery); console.log(`📊 DatabaseStorage: Found ${result.rows.length} videos (search: "${search || 'none'}")`); - // Import Bunny service for signed URLs - const { bunnyService } = await import('./bunny'); - - // Transform database rows to Video objects with signed URLs + // Transform database rows to Video objects with direct iframe URLs return result.rows.map((row: any) => ({ id: row.id, title: row.title, description: row.description, thumbnailUrl: row.thumbnail_url, - videoUrl: bunnyService.generateSignedUrl(row.id, 7200), // 2 hour expiration + videoUrl: `https://iframe.mediadelivery.net/embed/384105/${row.id}`, // Direct Bunny.net iframe duration: row.duration, views: row.views, category: row.category, @@ -107,16 +104,13 @@ export class DatabaseStorage implements IStorage { if (result.rows.length === 0) return undefined; - // Import Bunny service for signed URLs - const { bunnyService } = await import('./bunny'); - const row = result.rows[0] as any; return { id: row.id, title: row.title, description: row.description, thumbnailUrl: row.thumbnail_url, - videoUrl: bunnyService.generateSignedUrl(row.id, 7200), // 2 hour expiration + videoUrl: `https://iframe.mediadelivery.net/embed/384105/${row.id}`, // Direct Bunny.net iframe duration: row.duration, views: row.views, category: row.category,