import type { Express } from "express"; import { createServer, type Server } from "http"; import { storage } from "./storage"; import { z } from "zod"; export async function registerRoutes(app: Express): Promise { // Get videos with pagination and filtering app.get("/api/videos", async (req, res) => { try { const limit = parseInt(req.query.limit as string) || 20; const offset = parseInt(req.query.offset as string) || 0; const search = req.query.search as string; const videos = await storage.getVideos(limit, offset, search); const total = await storage.getVideoCount(search); res.json({ videos, total, hasMore: offset + limit < total }); } catch (error) { res.status(500).json({ message: "Failed to fetch videos" }); } }); // Get single video by ID app.get("/api/videos/:id", async (req, res) => { try { const video = await storage.getVideo(req.params.id); if (!video) { return res.status(404).json({ message: "Video not found" }); } res.json(video); } catch (error) { res.status(500).json({ message: "Failed to fetch video" }); } }); // Update video views app.post("/api/videos/:id/view", async (req, res) => { try { await storage.updateVideoViews(req.params.id); res.json({ success: true }); } catch (error) { res.status(500).json({ message: "Failed to update views" }); } }); // 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); return httpServer; }