Skip to main content

Building a Simple CLI Youtube Video Downloader in NodeJS

Building a Simple CLI Youtube Video Downloader in NodeJS
Building a Simple CLI Youtube Video Downloader in NodeJS
Command Line Interfaces (CLIs) have been around for close to 50 years now, and still seem to be going strong. Even in the age of amazing libraries like React, VueJS, and Angular, text-based terminals remain the best way to accomplish a multitude of tasks.
CLIs are incredibly useful for developers seeking to automate workloads, e.g. when deploying new applications, running tests and migrating data. Besides, a lot of times, building a Graphical User Interface (GUI) is complete overkill for something that could be easily accomplished with just a few lines of code.
NodeJS is the perfect language for writing CLI apps thanks to the multitude of built-in libraries available for everything from network communication to reading and writing files. If you’re feeling lazy like every developer does every once in a while, the million of packages available on registries like NPM and YARN will definitely come in handy.
In this tutorial, we create a basic NodeJS CLI app for downloading music files from Youtube and converting them to MP3. This will serve as an introduction on how to interact with web interfaces through the CLI, style the output and accept arguments through the command line.

Setting Up the Project

First things first, we’ll set up our project by initializing NPM (which creates a ‘package.json’ file for us) and ‘git’ (because every project needs git).
Assuming you already created a project folder, simply run

Then let’s get all the dependencies out of the way. Each of them will be covered in more specific detail later on in this guide.
  • Commander is a library that takes care of a lot of CLI boilerplate. It’s incredibly useful when you just want to get a project running in the shortest time possible.
  • Ora adds styling to our command line output
  • Youtube-mp3-downloader does what the package name suggests – it pulls videos from Youtube and converts them to mp3 files.

Downloading Files from Youtube

First, let’s create a ‘downloader.js’ file in ‘src/downloader.js.’ This will be responsible for handling downloads and storage locations.
It takes the following options:
  • ffmpegPath: ffmpeg installation location. ffmpeg is a large open-source program used for handling audio and video files. In our case, it’s responsible for converting video files to mp3 format. If you don’t have it installed, run sudo apt install ffmpeg To check the installation location on your system, run which ffmpeg
  • outputPath: where music files will be saved
  • youtubeVideoQuality: download quality. “highest”, “lowest” or a number from 1-10
  • queueParallelism: how many files can be converted consecutively
  • progressTimeout: how often the progress indicator should be updated

The ‘downloader’ instance accepts two arguments – the Youtube video id and the name of the file once downloaded. The second argument is optional.
Let’s export a function that will make the downloader option accessible to other files.

First, copy-pasting the video id from every link we want to download is a little cumbersome. Instead, we check if whatever has been input by the user is a URL, and if so, extract the ‘v’ query from the Youtube URL.
Recall that Youtube URLs typically look like this: https://www.youtube.com/watch?v=4l1gNOocZu8. The id is the 4l1gNOocZu8 part.
The isURL helper is borrowed from Stackoverflow and looks like this:

url.parse is taken from the built-in NodeJS library and accepts two parameters – the url and a boolean indicating whether it should parse for query strings (which we want in this case). It then returns an object with all the queries.
Finally, we call the download function with the now-extracted video id.
Now comes the fun part.

Interacting With a NodeJS App Through the Command Line

While it’s entirely possible to write a NodeJS CLI app with Vanilla Javascript, Commander makes it much easier to do so.

Let’s go over the above code:
version indicates what version of our CLI app we are running.
description provides a description of our app.
command adds a new command that we can run different programs through. For instance, adding ytd , in this case, allows us to run

If we wanted a different app that would say, download videos from Instagram, we might also add

And run the code as

option is used to add different options to our app. The above code might be refactored to read

So that downloading would just be as simple as

However, using arguments makes the code a lot clearer.

Optional arguments can also be indicated using square brackets [] and required arguments using ‘<>’
action is where all the magic happens. Our callback function might look like

Note that the commander makes all details about the argument that’s been called available through the callback function.
The final line parses all arguments we’ve passed for us.
While this actually works, it’s all a bit boring. Besides, we have no way of knowing whether the program has stalled or is still working, so let’s add some spinners.

Adding Loading Spinners to Our Node CLI App

To create a simple CLI spinner, we’re going to use ora.
Initializing it needs just three lines:

And our ‘action’ callback can be changed to

Now, running our Node CLI app:
Running Node CLI app
Running Node CLI app

Conclusion

Command line apps have an almost unlimited number of uses, and this app just scratches the surface of all the amazing things you can build using NodeJS and a few related libraries.

Comments

Popular posts from this blog

Understand Angular’s forRoot and forChild

  forRoot   /   forChild   is a pattern for singleton services that most of us know from routing. Routing is actually the main use case for it and as it is not commonly used outside of it, I wouldn’t be surprised if most Angular developers haven’t given it a second thought. However, as the official Angular documentation puts it: “Understanding how  forRoot()  works to make sure a service is a singleton will inform your development at a deeper level.” So let’s go. Providers & Injectors Angular comes with a dependency injection (DI) mechanism. When a component depends on a service, you don’t manually create an instance of the service. You  inject  the service and the dependency injection system takes care of providing an instance. import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.compon...

How to use Ngx-Charts in Angular ?

Charts helps us to visualize large amount of data in an easy to understand and interactive way. This helps businesses to grow more by taking important decisions from the data. For example, e-commerce can have charts or reports for product sales, with various categories like product type, year, etc. In angular, we have various charting libraries to create charts.  Ngx-charts  is one of them. Check out the list of  best angular chart libraries .  In this article, we will see data visualization with ngx-charts and how to use ngx-charts in angular application ? We will see, How to install ngx-charts in angular ? Create a vertical bar chart Create a pie chart, advanced pie chart and pie chart grid Introduction ngx-charts  is an open-source and declarative charting framework for angular2+. It is maintained by  Swimlane . It is using Angular to render and animate the SVG elements with all of its binding and speed goodness and uses d3 for the excellent math functio...

How to solve Puppeteer TimeoutError: Navigation timeout of 30000 ms exceeded

During the automation of multiple tasks on my job and personal projects, i decided to move on  Puppeteer  instead of the old school PhantomJS. One of the most usual problems with pages that contain a lot of content, because of the ads, images etc. is the load time, an exception is thrown (specifically the TimeoutError) after a page takes more than 30000ms (30 seconds) to load totally. To solve this problem, you will have 2 options, either to increase this timeout in the configuration or remove it at all. Personally, i prefer to remove the limit as i know that the pages that i work with will end up loading someday. In this article, i'll explain you briefly 2 ways to bypass this limitation. A. Globally on the tab The option that i prefer, as i browse multiple pages in the same tab, is to remove the timeout limit on the tab that i use to browse. For example, to remove the limit you should add: await page . setDefaultNavigationTimeout ( 0 ) ;  COPY SNIPPET The setDefaultNav...