How to create YouTube Video Downloader with Python – Python GUI Projects

Youtube Downloader using python

One of the biggest motivation for a programmer is creating amazing things using one’s programming skills. When a programmer starts building software and apps that he uses on a daily basis, he gets better at whatever he’s doing. How about creating a YouTube video and audio downloader on your own?

If you’re learning python, this could be an amazing project for you as a programmer. Creating something cool and bragging about it in front of your colleagues is actually a great feeling that everyone knows about. Most of us use YouTube video downloaders available on the internet but what if you have one of your own?

In this article, you’ll learn how to create YouTube video downloader with GUI in python. Here’s the code with only important details and explanations. I learned to create this a few weeks back.

Import required modules required to create YouTube video downloader with python:

from tkinter import *
from PIL import Image
from PIL import ImageTk
from tkinter import ttk
from pytube import *
import requests
import io
import os
import tkinter.messagebox
import webbrowser

Define a class for the project with a default constructor:

class YT_download:
    def __init__(self, root):
        self.root = root

The very next steps:

  1. Create root as the Tk() object.
  2. Create an object of the class.
  3. Close the root using mainloop().

So the code looks like this:

class YT_download:
    def __init__(self, root):
        self.root = root

root = Tk()
obj = YT_download(root)
root.mainloop()

Although this creating object and closing the root are last steps, but writing the basic skeletal syntax is always a smart thing to do.

Now, all the code that we write will be placed inside the class definition with proper indentation.

Define the default constructor __init__(self, root):

def __init__(self, root):
        self.root = root
        self.root.title("YouTube Video and Audio Downloader")
        self.root.geometry("500x420+300+50")
        self.root.resizable(False, False)
        self.root.config(bg = 'sky blue')
        header = Label(self.root,text = "YouTube Video and Audio Downloader", font = ("Times new roman", 17), bg = "gold", fg = "blue4", anchor = 'center').pack(side = TOP, fill = X)
        
        self.url = StringVar()
        urlLabel= Label(self.root,text = "Enter URL:", font = ("times new roman", 15), bg = "white").place(x = 10, y = 50)
        urlText= Entry(self.root, font = ("times new roman", 13), textvariable = self.url, bg = "pink").place(x = 115, y = 50, width = 270)


            
        #================ Programming Articles Website Link ==================
        
        #================ You can remove this code if you don't want to visit programming-articles.com  ==================

        webbrowser.open("https://programming-articles.com")



        #=========== Code ended for programming-articles.com ======================

        
       #================= Radio Buttons for choosing the filetype ====================
        
        self.file_type = StringVar()
        self.file_type.set('Video')
        vid_radio = Radiobutton(self.root,text = "Video", variable = self.file_type, value = "Video", font = ("times new roman", 12), bg = "light green", activebackground = 'white').place(x = 125, y = 83, height = 20)
        aud_radio = Radiobutton(self.root,text = "Audio", variable = self.file_type, value = "Audio", font = ("times new roman", 12), bg = "light green", activebackground = 'white').place(x = 210, y = 83, height = 20)

        
        #================== SEARCH BUTTON ===================================================
        search_button = Button(self.root, text = "Search", command = self.search,font= ("times new roman", 14), bg= "sky blue").place(x = 320, y = 80, height = 26, width = 65)
        
        #=================== SPACE FOR VIDEO DETAILS, i.e., TITLE, THUMBNAIL, DESCRIPTION, ETC. =====================
        
        frame = Frame(self.root, bd = 2, relief = RIDGE, bg = 'sandy brown')
        frame.place(x = 10, y = 115, width = 480, height = 190)

        self.file_title = Label(frame, text= "File Title", font = ("arial", 13), bg = "ivory2", anchor = 'c')
        self.file_title.place(x = 0, y = 0, relwidth = 1)

        self.thumbnail = Label(frame,text = "Video \nThumbnail", font = ("times new roman", 15), bg = "khaki1")
        self.thumbnail.place(x = 3, y = 28, width = 182, height = 154)
        
        desc_lbl = Label(frame,text = "Description", font = ("times new roman", 12), bg = "palegreen1").place(x = 190, y = 28)
        
        self.file_desc = Text(frame, font = ("times new roman", 13), bg = "lightyellow")
        self.file_desc.place(x = 190, y = 53, width = 283, height = 129)

        self.file_size= Label(self.root,text = "File Size: MB", font = ("times new roman", 12), bg = "red1")
        self.file_size.place(x = 10, y = 320)

        self.percentage_lbl= Label(self.root,text = "Downloading: 0%", font = ("times new roman", 12), bg = "red1")
        self.percentage_lbl.place(x = 158, y = 320)

        #========================= CLEAR AND DOWNLOAD BUTTON FOR RESETTING FRAME AND DOWNLOADING FILES ==========================
        
        reset_btn = Button(self.root, text = "Reset", command = self.reset, font= ("times new roman", 13), bg= "grey", fg = "white").place(x = 310, y = 320, height = 25, width = 60)
        
        self.download_btn = Button(self.root, text = "Download", state = DISABLED, command = self.download, font= ("times new roman", 13), bg= "red", fg = "white")
        self.download_btn.place(x = 390, y = 320, height = 25, width = 85)


        self.prog_Bar = ttk.Progressbar(self.root, orient = HORIZONTAL, length = 590, mode = "determinate")
        self.prog_Bar.place(x = 10, y = 360, width = 483, height = 20)


        self.msg= Label(self.root,text = "", font = ("times new roman", 16), bg = "sky blue")
        self.msg.place(x = 0, y = 385, relwidth = 1)
       
       
        #============ CREATING DIRECTORIES FOR DOWNLOADED FILES ========================

        if os.path.exists('Audios') == False:
            os.mkdir('Audios')
        if os.path.exists('Videos') == False:
            os.mkdir('Videos')

I’ve added comments in between to add some details to the code, will be adding more details soon.

Define the method for search in the youtube video downloader using python:

def search(self):
        try:
            yt = YouTube(self.url.get())
        
        #============= CONVERT IMAGE-URL INTO IMAGE =======

            
            response = requests.get(yt.thumbnail_url)
            img_byte = io.BytesIO(response.content)
            self.img = Image.open(img_byte)
            self.img = self.img.resize((180, 140), Image.ANTIALIAS)
            self.img = ImageTk.PhotoImage(self.img)
            self.thumbnail.config(image = self.img)

            #======== Fetch size as per file type =======


            if self.file_type.get() == 'Video':
                select_file = yt.streams.filter(progressive= True).first()
            if self.file_type.get() == 'Audio':
                select_file = yt.streams.filter(type="audio").first()
            
            self.size_inBytes = select_file.filesize
            max_size = self.size_inBytes/1024000
            self.mb = str(round(max_size, 2)) + 'MB'
            
            #======== Updating the frame elements=======

            
            self.file_size.config(text = "Total Size: " + self.mb)

            self.file_title.config(text = yt.title[:50])
            self.file_desc.delete('1.0', END)
            self.file_desc.insert(END, yt.description[:200])
            self.download_btn.config(state = NORMAL)
        
        #===== popup error message in case wrong URL is entered ========
        except:
            tkinter.messagebox.showinfo("Error", "Enter Valid URL")

Define a method for downloading the searched files using pytube:

    #================= METHOD FOR DOWNLOADING FILES ================
 
def download(self):
        yt = YouTube(self.url.get(), on_progress_callback=self.progress_)
        #======== Fetch size as per file type =======

        if self.file_type.get() == 'Video':
            select_file = yt.streams.filter(progressive= True).first()
            select_file.download('Videos/')
        if self.file_type.get() == 'Audio':
            select_file = yt.streams.filter(type="audio").first()
            select_file.download('Audios/')

Define a method for keeping track of the download progress:

 #=================== METHOD FOR DOWNLOAD PROGRESS UPDATE =============================

    def progress_(self,streams,chunk,bytes_remaining):
        percentage = (float(abs(bytes_remaining-self.size_inBytes)/self.size_inBytes))*(100)
        self.prog_Bar['value'] = percentage
        self.prog_Bar.update()
        self.percentage_lbl.config(text = f"Downloading: {str(round(percentage,2))}%")
        if round(percentage,2) == 100:
            self.msg.config(text = 'Download Complete', fg = "blue")
            self.download_btn.config(state = DISABLED)

Define a method for resetting/clearing the window:

    #======================= METHOD FOR RESETTING THE WINDOW =====================

def reset(self):
        self.file_type.set('Video')
        self.url.set('')
        self.prog_Bar['value']=0
        self.download_btn.config(state=DISABLED)
        self.msg.config(text = '')
        self.file_title.config(text = 'File Title')
        self.thumbnail.config(image = '')
        self.file_desc.delete('1.0', END)
        self.file_size.config(text = 'Total Size: Unknown')
        self.percentage_lbl.config(text = 'Downloaded: 0%')

You can download complete project from the link below:

Final Result: YouTube video and audio downloader with python

Summary

In this programming article, you learnt how to create GUI YouTube downloader with python. This project is intended to motivate and benefit beginner and intermediate python programmers.

About ᴾᴿᴼᵍʳᵃᵐᵐᵉʳ

Linux and Python enthusiast, in love with open source since 2014, Writer at programming-articles.com, India.

View all posts by ᴾᴿᴼᵍʳᵃᵐᵐᵉʳ →

Leave a Reply

Your email address will not be published. Required fields are marked *