Complete YouTube Downloader

Full-stack implementation with Node.js, Express, and ytdlp-nodejs
warning Important Note
This implementation is for educational purposes only. Downloading YouTube videos may violate their Terms of Service. Ensure you comply with all applicable laws and regulations when using this code.
folder_open Project Structure
youtube-downloader/
├── package.json
├── server.js (Backend)
├── public/ (Frontend)
│ ├── index.html
│ ├── styles.css
│ └── script.js
└── downloads/ (Output folder)
code Implementation Code
Backend (server.js)
Frontend (HTML)
Frontend (JS)
// server.js - Backend Implementation
const 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;

// Middleware
app.use(cors());
app.use(express.json());
app.use(express.static('public'));
app.use('/downloads', express.static(path.join(__dirname, 'downloads')));

// API: Get Video Info
app.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 Video
app.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.js
const 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;
}
});
build Setup Instructions
1
Initialize Project
mkdir youtube-downloader && cd youtube-downloader
npm init -y
2
Install Dependencies
npm install express cors ytdlp-nodejs
3
Create Project Structure
mkdir public downloads
touch server.js public/index.html public/styles.css public/script.js
4
Copy the Code

Copy the code from the tabs above into the corresponding files.

  • server.js → Backend implementation
  • public/index.html → Frontend HTML structure
  • public/script.js → Frontend JavaScript logic
  • public/styles.css → (Optional) Add your own CSS styling
5
Run the Server
node server.js

Then open http://localhost:3000 in your browser.

bug_report Troubleshooting