Create Youtube Video Downloader
By Prgmaz 10 May 2021

alt text

What we need for this tutorial

  • NodeJS and NPM
  • Express (For creating Web Server)
  • ytdl-core (npm module to get info of youtube video)
  • ejs (templating engine)

Setup our Project

Create a directory named yt_downloader and initialize a node project in that folder with npm init. Now Open Visual Studio Code or any other editor in that folder. Install all the modules needed with npm install ytdl-core express ejs

Project setup

Now that we have our project setup, Let’s write some code.

Setting up our Server

Create file named index.js in that folder and write code.

const express = require("express");
const app = express();
const ytdl = require("ytdl-core");

app.set("view engine", "ejs");

// OUR ROUTES WILL GO HERE


app.listen(3000, () => {
	console.log("Server is running on http://localhost:3000");
});

You can run this server by typing nodemon . in your terminal. Server

Creating Simple GUI with EJS

Create a folder named views and inside it create a file named index.ejs and Create your GUI by writing simple HTML.

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Youtube Downloader</title>
		<link
			rel="stylesheet"
			href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
			integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l"
			crossorigin="anonymous"
		/>
	</head>
	<body>
		<div class="container my-5">
			<h1><strong>Youtube Downloader</strong></h1>
			<form method="GET" action='/download' class="my-5">
				<div class="form-group">
					<label for="videoURL"
						>Video Link from Youtube</label
					>
					<input
						type="text"
						class="form-control"
						placeholder="Enter Video URL"
                        name="url"
					/>
				</div>
				<button type="submit" class="btn btn-primary">Download</button>
			</form>
		</div>
	</body>
</html>

Here our form will make GET request with parameter of url to \download.

I used Bootstrap but you can use css, Just remember you have to serve the /assets files.

INDEX VIEW

Create a new route \ to serve this index.ejs in your index.js

app.get("/", (req, res) => {
	return res.render("index");
});

Creating \download Route.

Create a route that will pass the parameter url to download view.

app.get('\download' , (req, res) => {
    const v_id = req.query.url.split('v=')[1];
    return res.render('download', {
        url: "https://www.youtube.com/embed/" + v_id,
    });
});

In above code, I am getting the video id and passing custom embed to the url. (Youtube denies it’s embed to non-trusted websites)

Create new file download.ejs in your views directory.

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Download Options for the link</title>
		<link
			rel="stylesheet"
			href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
			integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l"
			crossorigin="anonymous"
		/>
		<link
			rel="stylesheet"
			href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
			integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
			crossorigin="anonymous"
		/>
		<script
			src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
			integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
			crossorigin="anonymous"
		></script>
		<script
			src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
			integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
			crossorigin="anonymous"
		></script>
		<script
			src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
			integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
			crossorigin="anonymous"
		></script>
	</head>
	<body>
		<div class="container">
			<iframe class="d-flex" width="640" height="480" src="<%= url %>">
			</iframe>
		</div>
		<div class="container">
			
		</div>
	</body>
</html>

Now let’s get our video info with ytdl-core module in our route. Since our ytdl-core library is async, we will create our route to async. I’m sorting my formats of the video by their mime types like video/webm and video/mp4.

app.get("/download", async (req, res) => {
	const v_id = req.query.url.split('v=')[1];
    const info = await ytdl.getInfo(req.query.url);

	return res.render("download", {
		url: "https://www.youtube.com/embed/" + v_id,
        info: info.formats.sort((a, b) => {
            return a.mimeType < b.mimeType;
        }),
	});
});

Now displaying the download button with EJS in our download.ejs file.

    ...
            </iframe>
        </div>
        <div class="container">
			<div class="btn-group">
				<button
					type="button"
					class="btn btn-success dropdown-toggle"
					data-toggle="dropdown"
					aria-haspopup="true"
					aria-expanded="false"
				>
					Download
				</button>
				<div class="dropdown-menu">
					<% info.forEach((format) => { %>
					<a class="dropdown-item" href="<%= format.url %>">
						<%= format.mimeType.split(";")[0] %> <%= format.hasVideo
						? format.height + "p" : "" %> <% if(!format.hasAudio) {
						%>
						<i class="fas fa-volume-mute text-danger"></i>
						<% } %>
					</a>
					<% }); %>
				</div>
			</div>
		</div>
	</body>
</html>

DOWNLOAD VIEW

Now our video downloader is complete, if you click on download button, you can select which video to download.

You can download this project from my Github.

Visit this Project on Github

Naman Baranwal
Hi, I’m Prgmaz. I’m a Web, Game and App Developer.

Tags