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
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.
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.
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>
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.