const express = require('express'); const cors = require('cors'); const ytdl = require('ytdl-core'); // Popular YouTube downloader library const app = express(); // Allow your React Frontend to talk to this server app.use(cors()); // 1. Endpoint to get Video Metadata (Title, Formats, etc.) app.get('/api/info', async (req, res) => { try { const { url } = req.query; if (!ytdl.validateURL(url)) { return res.status(400).json({ error: 'Invalid YouTube URL' }); } const info = await ytdl.getInfo(url); // Filter and map formats to keep it simple for the frontend const formats = ytdl.filterFormats(info.formats, 'videoandaudio'); res.json({ title: info.videoDetails.title, thumbnail: info.videoDetails.thumbnails[0].url, author: info.videoDetails.author.name, duration: info.videoDetails.lengthSeconds, formats: formats.map(f => ({ itag: f.itag, quality: f.qualityLabel, container: f.container, hasAudio: f.hasAudio, hasVideo: f.hasVideo })) }); } catch (error) { console.error("Info Error:", error); res.status(500).json({ error: 'Failed to fetch video info' }); } }); // 2. Endpoint to Download the Video app.get('/api/download', async (req, res) => { try { const { url, itag, title } = req.query; if (!url) return res.status(400).send('URL is required'); // Set Headers to trigger browser download // Sanitize title to remove special characters const safeTitle = (title || 'video').replace(/[^a-zA-Z0-9 ]/g, ""); res.header('Content-Disposition', `attachment; filename="${safeTitle}.mp4"`); // Start the download stream ytdl(url, { filter: format => format.itag == itag }).pipe(res); } catch (error) { console.error("Download Error:", error); res.status(500).send('Download failed'); } }); const PORT = 4000; app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); });