You have probably already come across a YouTube video download site, in this article I will show you how to write such a site and go through the concepts and solutions I used.
First of all, let's clarify what we want to achieve:
- providing a youtube link to download the video in mp4 or mp3 format and give real time feedback on the status of the download to make it cool.
Demo: https://youtube-downloader-app.netlify.app/
Api code: https://github.com/MaurerKrisztian/youtube-downloader-api
UI code: https://github.com/MaurerKrisztian/youtube-downloader-ui-vue
1. How to download a youtube video?
After a bit of searching, I found a couple of Linux cli tools that are just for this, most of them downloaded slowly, but luckily I found ytb-dl, which somehow bypasses the download restriction.
2. How to interact with a cli API via Node.js?
With nodejs you can run cli commands with the spawn built-in function that creates a child process.
const downloadProcess = spawn('yt-dlp', [link]);
downloadProcess.stdout.on('data', (data) => {
console.log(data);
});
The responses of the child process to the console, e.g. download percentage, speed, size... we can receive and process these outputs with stdout.on
3. CLI wrapper.
I built a wrapper around yt-dlp which essentially parameterizes the calls and formats the lines extracted from std-otut into json format with a couple of regexps so I can easily work with this in the future.
Events: The wrapper throws 4 types of events:
- start - when a download starts
- progress - information about the download progress (precent, speed..)
- error - if something went wrong
- close - if the process has ended
Wrapper file: https://github.com/MaurerKrisztian/youtube-downloader-api/blob/main/src/cli-wrapper/yt-downloader-wrapper.ts
As a result, this function call can be used to start a download of throw events from cli responses into a processable format:
process(link: string, id: string, path: string = './download', filename: string = "video", format: 'mp4' | 'mp3' = 'mp4') {...}
4. Event management
On the UI, the goal would be to have real-time feedback, so a REST API solution is not suitable, but the websocket is perfet, so I built a socket connection, the client can request a download and can subscribe to progress, error, done response that sends real time information.
5. UI
I'm writing UI in Vue (my first vue project). It essentially connects to the backend sockets and displays the returned data.
6. Deploy
We use the yt-dlp cli so the env need to contain this. I was able to deploy it to my own server, but I also tried to deploy here railway.app but this yt-dlp is a "banned dependency" due to the quality of shared hosting but we can include the yt-dlp binary among the files and use that or downolad the binary on the fly. I am currently working on it.
*NOTE: this is just an mvp (there are things to improve) in the future I will update the article and the project, if you find something to improve, feel free to submit a pull request or open an issue