youtube-downloader/├── package.json├── server.js (Backend)├── public/ (Frontend)│ ├── index.html│ ├── styles.css│ └── script.js└── downloads/ (Output folder)
// server.js - Backend Implementationconst express = require('express');const { YtDlp } = require('ytdlp-nodejs');const path = require('path');const cors = require('cors');const app = express();const ytdlp = new YtDlp();const PORT = process.env.PORT || 3000;// Middlewareapp.use(cors());app.use(express.json());app.use(express.static('public'));app.use('/downloads', express.static(path.join(__dirname, 'downloads')));// API: Get Video Infoapp.post('/api/info', async (req, res) => { try { const { url } = req.body; const info = await ytdlp.getInfoAsync(url); res.json(info); } catch (error) { res.status(500).json({ error: error.message }); }});// API: Download Videoapp.post('/api/download', async (req, res) => { try { const { url, format } = req.body; const fileName = `video_${Date.now()}.${format}`; const outputPath = path.join(__dirname, 'downloads', fileName); const stream = ytdlp.stream(url, { format: 'best', output: outputPath, onProgress: (progress) => console.log(progress) }); res.setHeader('Content-Type', 'video/mp4'); res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`); await stream.pipeAsync(res); } catch (error) { res.status(500).json({ error: error.message }); }});app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
<!-- public/index.html --><!DOCTYPE html><html><head> <title>YouTube Downloader</title> <link rel="stylesheet" href="styles.css"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"></head><body> <div class="container"> <header> <h1>YouTube Downloader</h1> </header> <div class="input-section"> <input type="text" id="urlInput" placeholder="Paste YouTube URL here..."> <select id="formatSelect"> <option value="mp4">MP4</option> <option value="mp3">MP3</option> </select> <button id="downloadBtn">Download</button> </div> <div id="progressArea" class="hidden"> <div class="progress-bar"> <div id="progressFill"></div> </div> <p id="statusText"></p> </div> <div id="resultArea" class="hidden"> <img id="thumbnail" alt="Video thumbnail"> <p id="videoTitle"></p> </div> </div> <script src="script.js"></script></body></html>
// public/script.jsconst urlInput = document.getElementById('urlInput');const formatSelect = document.getElementById('formatSelect');const downloadBtn = document.getElementById('downloadBtn');const progressArea = document.getElementById('progressArea');const progressFill = document.getElementById('progressFill');const statusText = document.getElementById('statusText');const resultArea = document.getElementById('resultArea');const thumbnail = document.getElementById('thumbnail');const videoTitle = document.getElementById('videoTitle');downloadBtn.addEventListener('click', async () => { const url = urlInput.value.trim(); const format = formatSelect.value; if (!url) return alert('Please enter a URL'); try { // Show progress progressArea.classList.remove('hidden'); statusText.textContent = 'Fetching video info...'; // Get video info const infoResponse = await fetch('/api/info', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url }) }); const info = await infoResponse.json(); // Update UI with video info thumbnail.src = info.thumbnails[info.thumbnails.length - 1].url; videoTitle.textContent = info.title; // Download video statusText.textContent = 'Starting download...'; const downloadResponse = await fetch('/api/download', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url, format }) }); const blob = await downloadResponse.blob(); const downloadUrl = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = downloadUrl; a.download = `video.${format}`; a.click(); // Show result resultArea.classList.remove('hidden'); statusText.textContent = 'Download complete!'; } catch (error) { console.error(error); statusText.textContent = 'Error: ' + error.message; }});
mkdir youtube-downloader && cd youtube-downloadernpm init -y
npm install express cors ytdlp-nodejs
mkdir public downloadstouch server.js public/index.html public/styles.css public/script.js
Copy the code from the tabs above into the corresponding files.
node server.js
Then open http://localhost:3000 in your browser.