Download YouTube Videos Using Python - Your Own YouTube Downloader

Make YouTube Downloader in Under 10 Lines of Code.

Subscribe to my newsletter and never miss my upcoming articles

Do you find it troublesome to always look for a YouTube video downloader with your privacy at risk? Downloading a YouTube video using an external extension might be maddening because of the mouse click ads and other issues while using that extension.

So, why not we create our own bot that can download any YouTube video with just simply running a Python script? Everything would be in our control then, awesome, right?

In this article, we are going to see how we can make a Python script to automate the YouTube video downloading activity.

After going through this article, you can say NO to all those annoying ads, privacy issues, authorisation to different extensions and can finally have total control.

Let's get started!


What Are We Going To Use?

We are going to use Python and one of its amazing 3rd party library, pytube.

To install pytube:

$ pip install pytube
Collecting pytube
  Downloading pytube-10.7.2-py3-none-any.whl (42 kB)
     |████████████████████████████████| 42 kB 3.4 MB/s 
Installing collected packages: pytube
Successfully installed pytube-10.7.2
$

More on pytube:

  • pytube is a very serious, lightweight, dependency-free Python library (and command-line utility) for downloading YouTube Videos.
  • pytube is a lightweight library written in Python. It has no third-party dependencies and aims to be highly reliable.
  • pytube also makes pipelining easy, allowing you to specify callback functions for different download events, such as on progress or on complete.
  • Finally, pytube also includes a command-line utility, allowing you to quickly download videos right from the terminal.

Features:

  • Support for both progressive & DASH streams.
  • Support for downloading complete playlist.
  • Easily register on_download_progress & on_download_complete callbacks.
  • Command-line interfaced included.
  • Caption track support.
  • Outputs caption tracks to .srt format (SubRip Subtitle).
  • Ability to capture thumbnail URL.
  • Extensively documented source code.
  • No third-party dependencies (written in pure Python).

On a high level, to download a video using the library in a script, we'll need to first import the YouTube class from the library, and pass it an argument of the video URL. Then we can download different streams present on that YouTube object.

Now, let's move on to use this information to build our first YouTube video downloader.

Get The Streams

First, we will make a simple script to get all the available streams for the given YouTube video URL. Open a file name it whatever you like with the .py extension, let's say for our case we name it pytube_demo.py, add the following code in it and run:

# ./pytube_demo.py

from pytube import YouTube

video_url = input("Enter YouTube Video URL: ")
youtube_obj = YouTube(video_url)
print(youtube_obj.streams)

After you hit run, when the terminal prompts you to enter a video URL, enter this https://www.youtube.com/watch?v=fibIyvTleqc, it is one of my favourite songs Daydreamer by AURORA.

Note: You can enter any YouTube video URL here, what we are going to explore further doesn't depend on which URL you enter.

Enter YouTube Video URL: https://www.youtube.com/watch?v=fibIyvTleqc
[<Stream: itag="18" mime_type="video/mp4" res="360p" fps="25fps" vcodec="avc1.42001E" acodec="mp4a.40.2" progressive="True" type="video">, <Stream: itag="137" mime_type="video/mp4" res="1080p" fps="25fps" vcodec="avc1.640028" progressive="False" type="video">, <Stream: itag="248" mime_type="video/webm" res="1080p" fps="25fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="136" mime_type="video/mp4" res="720p" fps="25fps" vcodec="avc1.4d401f" progressive="False" type="video">, <Stream: itag="247" mime_type="video/webm" res="720p" fps="25fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="135" mime_type="video/mp4" res="480p" fps="25fps" vcodec="avc1.4d401e" progressive="False" type="video">, <Stream: itag="244" mime_type="video/webm" res="480p" fps="25fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="134" mime_type="video/mp4" res="360p" fps="25fps" vcodec="avc1.4d401e" progressive="False" type="video">, <Stream: itag="243" mime_type="video/webm" res="360p" fps="25fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="133" mime_type="video/mp4" res="240p" fps="25fps" vcodec="avc1.4d4015" progressive="False" type="video">, <Stream: itag="242" mime_type="video/webm" res="240p" fps="25fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="160" mime_type="video/mp4" res="144p" fps="25fps" vcodec="avc1.4d400c" progressive="False" type="video">, <Stream: itag="278" mime_type="video/webm" res="144p" fps="25fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2" progressive="False" type="audio">, <Stream: itag="249" mime_type="audio/webm" abr="50kbps" acodec="opus" progressive="False" type="audio">, <Stream: itag="250" mime_type="audio/webm" abr="70kbps" acodec="opus" progressive="False" type="audio">, <Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus" progressive="False" type="audio">]

So, we got a list of Stream objects, each stream object giving us information about different aspects of a video.

If we see res attribute of stream object, we see that we have 360p, 1080p, 720p, 480p, 240p and 144p with different vcodec attribute. This res represents the resolution of a video, we can select any stream of desired resolution to download.

Also, notice that we have only audio option streams available as well to download.

Next, we will create a filter for video resolution and to keep it simple we will not dive into audio downloadable streams.

Filter Stream Based On Resolution

Update the code in the pytube_demo.py file to the below code:

# ./pytube_demo.py

from pytube import YouTube

def get_stream_for_res(streams, res):
    """
    Filter on the basis of a given resolution. Return a list of filtered streams.
    """
    stream = list(filter(lambda x: x.resolution == res, streams))
    return stream

video_url = input("Enter YouTube Video URL: ").strip()
youtube_obj = YouTube(video_url)

video_res = input(f"Enter YouTube Video Resolution for {youtube_obj.title}: ").strip()
req_stream_obj = get_stream_for_res(youtube_obj.streams, video_res)
print(req_stream_obj)

Hit run and we can see following output in the terminal:

Enter YouTube Video URL: https://www.youtube.com/watch?v=fibIyvTleqc
Enter YouTube Video Resolution for AURORA - Daydreamer (Audio): 720p
[<Stream: itag="136" mime_type="video/mp4" res="720p" fps="25fps" vcodec="avc1.4d401f" progressive="False" type="video">, <Stream: itag="247" mime_type="video/webm" res="720p" fps="25fps" vcodec="vp9" progressive="False" type="video">]

First, we take the video URL and creates the YouTube object, then we take custom input from the user while displaying the title of the video using youtube_obj.title. After receiving the resolution, say 720p, we call the function get_stream_for_res that filters the given list of streams on the given resolution. At last, we can see the output, it contains 2 stream objects in a list, both objects have different values for some attributes but have the same resolution.

Without diving deep on what all other attribute means, let's just simply take the first element of the list and download the video.

Download Stream Based On Resolution

Now update the code to the following to download the YouTube video (complete script):

# ./pytube_demo.py

from pytube import YouTube

def get_stream_for_res(streams, res):
    stream = list(filter(lambda x: x.resolution == res, streams))
    return stream

video_url = input("Enter YouTube Video URL: ").strip()
youtube_obj = YouTube(video_url)

video_res = input(f"Enter YouTube Video Resolution for {youtube_obj.title}: ").strip()
req_stream_obj = get_stream_for_res(youtube_obj.streams, video_res)[0]

req_stream_obj.download()
print(f"YouTube Video {youtube_obj.title} Downloaded With Resolution {video_res}")

When we run the above script, we get the following output and a downloaded video:

Enter YouTube Video URL: https://www.youtube.com/watch?v=fibIyvTleqc
Enter YouTube Video Resolution for AURORA - Daydreamer (Audio): 720p
YouTube Video AURORA - Daydreamer (Audio) Downloaded With Resolution 720p

Now, if we check our directory where we ran the script, we can find the downloaded video.

Note:

You may notice that some streams listed have both a video codec and audio codec, while others have just video or just audio, this is a result of YouTube supporting a streaming technique called Dynamic Adaptive Streaming over HTTP (DASH).

In the context of pytube, the implications are for the highest quality streams; you now need to download both the audio and video tracks and then post-process them with software like FFmpeg to merge them.

The legacy streams that contain the audio and video in a single file (referred to as “progressive download”) are still available, but only for resolutions 720p and below.

The video downloaded from the given code has a Stream object whose attribute progressive is False. The given video URL does not have legacy streams available for 720p but if you notice there is one stream with progressive as True and res as 360p.

<Stream: itag="18" mime_type="video/mp4" res="360p" fps="25fps" vcodec="avc1.42001E" acodec="mp4a.40.2" progressive="True" type="video">

So, go ahead and experiment with it and don't forget to check out the progressive attribute.

What Next?

Well, that's it from me. If you followed this and ran the final script, you would be seeing a downloaded video in your working directory.

You can take it to the next level by creating a UI for this utility. You can host this as a service that would be strictly private to you.

What are you waiting for then? Use Tkinter, PyQT, Kivy, Flask or Django and make a UI with more functions like a select option for audio and video, for video resolution and for audio ABR, etc. and say NO to all those annoying ads, privacy issues, several authorisations to different extensions and have total control over your downloaded videos.


  • Just starting your Open Source Journey? Don't forget to check Hello Open Source

  • Want to showcase your Python project or just out there to explore? Check Awesome Python Repos

  • Want to make a simple and awesome game from scratch? Check out PongPong

  • Want to ++ your GitHub Profile README? Check out Quote - README

Till next time!

Namaste 🙏

Khushi Pratap's photo

Bookmarked, awesome explanation Siddharth Chandra, keep sharing!

Siddharth Chandra's photo

Thank you so much!

Olubisi Idris Ayinde's photo

Nice article!

Siddharth Chandra's photo

Thank you so much!

Pranav Goyal's photo

Awesome write-up, never knew about pytube, going to explore it this weekend. Thanks for sharing.

Siddharth Chandra's photo

Sure, thank you so much!

Sweta Shaw's photo

That's an awesome write-up. Thanks for sharing the knowledge. :)