Download song or video from Youtube using pytube

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite












I wrote a small program which downloads song or video from the given youtube link.
I used pytube library https://github.com/nficano/pytube and for GUI (Tkinter).



from pytube import YouTube
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
import re
import threading

"""Program downloads song or video
from youtube page using pytube library
more info about pytube
can be found here: https://github.com/nficano/pytube
GUI created with tkinter"""



# Main class where user inputs and choose available options
class MainApplication(tk.Frame):

def __init__(self, master=None, *args, **kwargs):
tk.Frame.__init__(self, master)
self.master = master

self.master.state("zoomed")

# Window layout
self.master.grid_rowconfigure(0, weight=2)
self.master.grid_columnconfigure(0, weight=1)

# Youtube link label
self.youtubeLinkLabel = ttk.Label(self.master, text="Please copy the youtube link: ", font=("Agency FB", 30))
self.youtubeLinkLabel.grid()

# Youtube entry where user inputs the youtube link
self.youtubeEntryVar = tk.StringVar()
self.youtubeEntry = ttk.Entry(self.master, width=50, textvariable=self.youtubeEntryVar)
self.youtubeEntry.grid(pady=(0,100))

# Entry error label if user inputs incorrect
# link the label will say wrong link
# checkYoutubeLink function
self.youtubeEntryError = tk.Label(self.master, text="", font=("Agency FB", 20))
self.youtubeEntryError.grid(pady=(0,30))

# Asking where to save file label
self.youtubeFileLocationLabel = ttk.Label(self.master, text="Please choose folder where to download file: ", font=("Agency FB", 30))
self.youtubeFileLocationLabel.grid()

# Button to open directory
# command = self.openDirectory
self.youtubeFileLocationEntry = ttk.Button(self.master, text="Directory", command=self.openDirectory)
self.youtubeFileLocationEntry.grid(pady=(20,40))

# Entry label if user don`t choose directory
# openDirectory func
self.fileLocationLabelError = tk.Label(self.master, text="", font=("Agency FB", 20))
self.fileLocationLabelError.grid()

# What to download MP3 or MP4 label
self.youtubeChooseLabel = ttk.Label(self.master, text="Please choose what to download: ", font=("Agency FB", 30))
self.youtubeChooseLabel.grid()

# RadioButton with two choices: MP3 or MP4
downloadChoices = [("Song MP3", 1), ("Video MP4", 2)]
self.ChoicesVar = tk.StringVar()
self.ChoicesVar.set(1)
for text, mode in downloadChoices:
self.youtubeChoices = ttk.Radiobutton(self.master, text=text, variable=self.ChoicesVar, value=mode).grid()

# Download button which at first checks if
# youtube link is correct then checks if Directory
# were chosen and if both is correct then start to
# download the file
self.nextButton = ttk.Button(self.master, text="Download", width=10, command=self.checkYoutubeLink)
self.nextButton.grid(pady=(180,80))

# This func opens the directory and
# checks if user chose directory or not
# if not the proper message is displayed
# if yes then directory is shown on gui
def openDirectory(self):

self.FolderName = filedialog.askdirectory()

if(len(self.FolderName) > 1):
self.fileLocationLabelError.config(text=self.FolderName, fg="green")
return True
else:
self.fileLocationLabelError.config(text="Please choose folder!", fg="red")

# This func checks if youtube link is correct with regex
# And checks if directory was chosen
# if both is correct the it proceeds with downloading the file
def checkYoutubeLink(self):

matchYoutubeLink = re.match('^https://www.youtube.com/.*', self.youtubeEntryVar.get())

if(not matchYoutubeLink):
self.youtubeEntryError.config(text="Wrong youtube link!", fg="red")

elif(not self.openDirectory):
self.fileLocationLabelError.config(text="Please choose folder!", fg="red")

elif(matchYoutubeLink) and self.openDirectory:
self.downloadWindow()

# Func hides the MainApplication window and goes to the SecondPage window
# 3 arguments are passed to the next class window
def downloadWindow(self):

self.newWindow = tk.Toplevel(self.master)
self.master.withdraw()
self.app = SecondPage(self.newWindow, self.youtubeEntryVar.get(), self.FolderName, self.ChoicesVar.get())



# This class shows downloading process
class SecondPage(tk.Frame):
def __init__(self, master, youtubeEntry, folderName, ChoicesVar):

tk.Frame.__init__(self, master)
self.master = master

self.master.state("zoomed")

self.master.grid_rowconfigure(0, weight=0)
self.master.grid_columnconfigure(0, weight=1)

self.youtubeEntry = youtubeEntry
self.FolderLocation = folderName
self.ChoicesVar = ChoicesVar


# describe pytube with yt
self.yt = YouTube(self.youtubeEntry)

# Here we are checking what user chose
# song or video to download
if(self.ChoicesVar == "1"):
self.video_type = self.yt.streams.filter(only_audio = True).first()
self.MaxfileSize = self.video_type.filesize

elif(self.ChoicesVar == "2"):
self.video_type = self.yt.streams.first()
self.MaxfileSize = self.video_type.filesize

# Loading label
self.loadingLabel = ttk.Label(self.master, text="Loading...", font=("Agency FB", 30))
self.loadingLabel.grid(pady=(100,0))

# loading precent label which must show % donwloaded
self.loadingPercent = tk.Label(self.master, text="0", fg="green", font=("Agency FB", 30))
self.loadingPercent.grid(pady=(30,30))

# indeterminate progress bar
self.progressbar = ttk.Progressbar(self.master, orient="horizontal", length=500, mode='indeterminate')
self.progressbar.grid(pady=(50,0))
self.progressbar.start()

# I use threads here to call both functions because otherwise
# one function downloads the file and only then shows the gui window
# to solve this issue i used threads
threading.Thread(target=self.yt.register_on_progress_callback(self.show_progress_bar)).start()

# call Download file func
threading.Thread(target=self.DownloadFile).start()

# This function checks what user chose MP3 or MP4
# and downloads the file
def DownloadFile(self):
if(self.ChoicesVar == "1"):
self.yt.streams.filter(only_audio=True).first().download(self.FolderLocation)
elif(self.ChoicesVar == "2"):
self.yt.streams.first().download(self.FolderLocation)

# This function show the progress in %
# when 100% is reached then gui outputs
# the chosen folder location
# file title
# file size in MB
def show_progress_bar(self, stream=None, chunk=None, file_handle=None, bytes_remaining=None):

# loadingPercent label configure value %
percentCount = float("%0.2f"% (100 - (100*(bytes_remaining/self.MaxfileSize))))

if(percentCount < 100):
self.loadingPercent.config(text=str(percentCount)+"%")

else:
# When 100% is reached then forget loading
# labels and progress bar
self.progressbar.stop()

self.loadingLabel.grid_forget()
self.loadingPercent.grid_forget()
self.progressbar.grid_forget()

# finished label
self.downloadFinished = ttk.Label(self.master, text="Finished", font=("Agency FB", 30))
self.downloadFinished.grid(pady=(150,0))

# Folder location label
self.downloadLocation = ttk.Label(self.master, text=self.FolderLocation, font=("Agency FB", 30))
self.downloadLocation.grid(pady=(50,0))

# Title label
self.downloadedFileTitle = ttk.Label(self.master, text=self.yt.title, font=("Agency FB", 30))
self.downloadedFileTitle.grid(pady=(50,0))

# Label shows MB count
MB = float("%0.2f"% (self.MaxfileSize/1000000))
self.downloadedFileSize = ttk.Label(self.master, text=(str(MB) + "MB"), font=("Agency FB", 30))
self.downloadedFileSize.grid(pady=(50,0))

# Exit button
self.Exit_button = ttk.Button(self.master, text="Exit", command=quit)
self.Exit_button.grid(pady=(200,0))


if __name__ == "__main__":

root = tk.Tk()
root.title("Youtube program")
app = MainApplication(root)
root.mainloop()


Questions:



  1. In the MainApplication I have 60 lines of various widgets is there any convention to divide widgets to make code more readable? At this moment I am writing another program and there I will have 150-200 lines of various widgets on the main page.

  2. When user write something in the ttk.Entry I want to check if input is correct or not and go to the next Frame if correct. I wrote exactly that and it works fine, but perhaps is there are easier solution/convention?

I know that naming convention in this program is incorrect I will change that.
Any other thoughts/opinions is much appreciated, Thanks.







share|improve this question



























    up vote
    2
    down vote

    favorite












    I wrote a small program which downloads song or video from the given youtube link.
    I used pytube library https://github.com/nficano/pytube and for GUI (Tkinter).



    from pytube import YouTube
    import tkinter as tk
    from tkinter import ttk
    from tkinter import filedialog
    import re
    import threading

    """Program downloads song or video
    from youtube page using pytube library
    more info about pytube
    can be found here: https://github.com/nficano/pytube
    GUI created with tkinter"""



    # Main class where user inputs and choose available options
    class MainApplication(tk.Frame):

    def __init__(self, master=None, *args, **kwargs):
    tk.Frame.__init__(self, master)
    self.master = master

    self.master.state("zoomed")

    # Window layout
    self.master.grid_rowconfigure(0, weight=2)
    self.master.grid_columnconfigure(0, weight=1)

    # Youtube link label
    self.youtubeLinkLabel = ttk.Label(self.master, text="Please copy the youtube link: ", font=("Agency FB", 30))
    self.youtubeLinkLabel.grid()

    # Youtube entry where user inputs the youtube link
    self.youtubeEntryVar = tk.StringVar()
    self.youtubeEntry = ttk.Entry(self.master, width=50, textvariable=self.youtubeEntryVar)
    self.youtubeEntry.grid(pady=(0,100))

    # Entry error label if user inputs incorrect
    # link the label will say wrong link
    # checkYoutubeLink function
    self.youtubeEntryError = tk.Label(self.master, text="", font=("Agency FB", 20))
    self.youtubeEntryError.grid(pady=(0,30))

    # Asking where to save file label
    self.youtubeFileLocationLabel = ttk.Label(self.master, text="Please choose folder where to download file: ", font=("Agency FB", 30))
    self.youtubeFileLocationLabel.grid()

    # Button to open directory
    # command = self.openDirectory
    self.youtubeFileLocationEntry = ttk.Button(self.master, text="Directory", command=self.openDirectory)
    self.youtubeFileLocationEntry.grid(pady=(20,40))

    # Entry label if user don`t choose directory
    # openDirectory func
    self.fileLocationLabelError = tk.Label(self.master, text="", font=("Agency FB", 20))
    self.fileLocationLabelError.grid()

    # What to download MP3 or MP4 label
    self.youtubeChooseLabel = ttk.Label(self.master, text="Please choose what to download: ", font=("Agency FB", 30))
    self.youtubeChooseLabel.grid()

    # RadioButton with two choices: MP3 or MP4
    downloadChoices = [("Song MP3", 1), ("Video MP4", 2)]
    self.ChoicesVar = tk.StringVar()
    self.ChoicesVar.set(1)
    for text, mode in downloadChoices:
    self.youtubeChoices = ttk.Radiobutton(self.master, text=text, variable=self.ChoicesVar, value=mode).grid()

    # Download button which at first checks if
    # youtube link is correct then checks if Directory
    # were chosen and if both is correct then start to
    # download the file
    self.nextButton = ttk.Button(self.master, text="Download", width=10, command=self.checkYoutubeLink)
    self.nextButton.grid(pady=(180,80))

    # This func opens the directory and
    # checks if user chose directory or not
    # if not the proper message is displayed
    # if yes then directory is shown on gui
    def openDirectory(self):

    self.FolderName = filedialog.askdirectory()

    if(len(self.FolderName) > 1):
    self.fileLocationLabelError.config(text=self.FolderName, fg="green")
    return True
    else:
    self.fileLocationLabelError.config(text="Please choose folder!", fg="red")

    # This func checks if youtube link is correct with regex
    # And checks if directory was chosen
    # if both is correct the it proceeds with downloading the file
    def checkYoutubeLink(self):

    matchYoutubeLink = re.match('^https://www.youtube.com/.*', self.youtubeEntryVar.get())

    if(not matchYoutubeLink):
    self.youtubeEntryError.config(text="Wrong youtube link!", fg="red")

    elif(not self.openDirectory):
    self.fileLocationLabelError.config(text="Please choose folder!", fg="red")

    elif(matchYoutubeLink) and self.openDirectory:
    self.downloadWindow()

    # Func hides the MainApplication window and goes to the SecondPage window
    # 3 arguments are passed to the next class window
    def downloadWindow(self):

    self.newWindow = tk.Toplevel(self.master)
    self.master.withdraw()
    self.app = SecondPage(self.newWindow, self.youtubeEntryVar.get(), self.FolderName, self.ChoicesVar.get())



    # This class shows downloading process
    class SecondPage(tk.Frame):
    def __init__(self, master, youtubeEntry, folderName, ChoicesVar):

    tk.Frame.__init__(self, master)
    self.master = master

    self.master.state("zoomed")

    self.master.grid_rowconfigure(0, weight=0)
    self.master.grid_columnconfigure(0, weight=1)

    self.youtubeEntry = youtubeEntry
    self.FolderLocation = folderName
    self.ChoicesVar = ChoicesVar


    # describe pytube with yt
    self.yt = YouTube(self.youtubeEntry)

    # Here we are checking what user chose
    # song or video to download
    if(self.ChoicesVar == "1"):
    self.video_type = self.yt.streams.filter(only_audio = True).first()
    self.MaxfileSize = self.video_type.filesize

    elif(self.ChoicesVar == "2"):
    self.video_type = self.yt.streams.first()
    self.MaxfileSize = self.video_type.filesize

    # Loading label
    self.loadingLabel = ttk.Label(self.master, text="Loading...", font=("Agency FB", 30))
    self.loadingLabel.grid(pady=(100,0))

    # loading precent label which must show % donwloaded
    self.loadingPercent = tk.Label(self.master, text="0", fg="green", font=("Agency FB", 30))
    self.loadingPercent.grid(pady=(30,30))

    # indeterminate progress bar
    self.progressbar = ttk.Progressbar(self.master, orient="horizontal", length=500, mode='indeterminate')
    self.progressbar.grid(pady=(50,0))
    self.progressbar.start()

    # I use threads here to call both functions because otherwise
    # one function downloads the file and only then shows the gui window
    # to solve this issue i used threads
    threading.Thread(target=self.yt.register_on_progress_callback(self.show_progress_bar)).start()

    # call Download file func
    threading.Thread(target=self.DownloadFile).start()

    # This function checks what user chose MP3 or MP4
    # and downloads the file
    def DownloadFile(self):
    if(self.ChoicesVar == "1"):
    self.yt.streams.filter(only_audio=True).first().download(self.FolderLocation)
    elif(self.ChoicesVar == "2"):
    self.yt.streams.first().download(self.FolderLocation)

    # This function show the progress in %
    # when 100% is reached then gui outputs
    # the chosen folder location
    # file title
    # file size in MB
    def show_progress_bar(self, stream=None, chunk=None, file_handle=None, bytes_remaining=None):

    # loadingPercent label configure value %
    percentCount = float("%0.2f"% (100 - (100*(bytes_remaining/self.MaxfileSize))))

    if(percentCount < 100):
    self.loadingPercent.config(text=str(percentCount)+"%")

    else:
    # When 100% is reached then forget loading
    # labels and progress bar
    self.progressbar.stop()

    self.loadingLabel.grid_forget()
    self.loadingPercent.grid_forget()
    self.progressbar.grid_forget()

    # finished label
    self.downloadFinished = ttk.Label(self.master, text="Finished", font=("Agency FB", 30))
    self.downloadFinished.grid(pady=(150,0))

    # Folder location label
    self.downloadLocation = ttk.Label(self.master, text=self.FolderLocation, font=("Agency FB", 30))
    self.downloadLocation.grid(pady=(50,0))

    # Title label
    self.downloadedFileTitle = ttk.Label(self.master, text=self.yt.title, font=("Agency FB", 30))
    self.downloadedFileTitle.grid(pady=(50,0))

    # Label shows MB count
    MB = float("%0.2f"% (self.MaxfileSize/1000000))
    self.downloadedFileSize = ttk.Label(self.master, text=(str(MB) + "MB"), font=("Agency FB", 30))
    self.downloadedFileSize.grid(pady=(50,0))

    # Exit button
    self.Exit_button = ttk.Button(self.master, text="Exit", command=quit)
    self.Exit_button.grid(pady=(200,0))


    if __name__ == "__main__":

    root = tk.Tk()
    root.title("Youtube program")
    app = MainApplication(root)
    root.mainloop()


    Questions:



    1. In the MainApplication I have 60 lines of various widgets is there any convention to divide widgets to make code more readable? At this moment I am writing another program and there I will have 150-200 lines of various widgets on the main page.

    2. When user write something in the ttk.Entry I want to check if input is correct or not and go to the next Frame if correct. I wrote exactly that and it works fine, but perhaps is there are easier solution/convention?

    I know that naming convention in this program is incorrect I will change that.
    Any other thoughts/opinions is much appreciated, Thanks.







    share|improve this question























      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      I wrote a small program which downloads song or video from the given youtube link.
      I used pytube library https://github.com/nficano/pytube and for GUI (Tkinter).



      from pytube import YouTube
      import tkinter as tk
      from tkinter import ttk
      from tkinter import filedialog
      import re
      import threading

      """Program downloads song or video
      from youtube page using pytube library
      more info about pytube
      can be found here: https://github.com/nficano/pytube
      GUI created with tkinter"""



      # Main class where user inputs and choose available options
      class MainApplication(tk.Frame):

      def __init__(self, master=None, *args, **kwargs):
      tk.Frame.__init__(self, master)
      self.master = master

      self.master.state("zoomed")

      # Window layout
      self.master.grid_rowconfigure(0, weight=2)
      self.master.grid_columnconfigure(0, weight=1)

      # Youtube link label
      self.youtubeLinkLabel = ttk.Label(self.master, text="Please copy the youtube link: ", font=("Agency FB", 30))
      self.youtubeLinkLabel.grid()

      # Youtube entry where user inputs the youtube link
      self.youtubeEntryVar = tk.StringVar()
      self.youtubeEntry = ttk.Entry(self.master, width=50, textvariable=self.youtubeEntryVar)
      self.youtubeEntry.grid(pady=(0,100))

      # Entry error label if user inputs incorrect
      # link the label will say wrong link
      # checkYoutubeLink function
      self.youtubeEntryError = tk.Label(self.master, text="", font=("Agency FB", 20))
      self.youtubeEntryError.grid(pady=(0,30))

      # Asking where to save file label
      self.youtubeFileLocationLabel = ttk.Label(self.master, text="Please choose folder where to download file: ", font=("Agency FB", 30))
      self.youtubeFileLocationLabel.grid()

      # Button to open directory
      # command = self.openDirectory
      self.youtubeFileLocationEntry = ttk.Button(self.master, text="Directory", command=self.openDirectory)
      self.youtubeFileLocationEntry.grid(pady=(20,40))

      # Entry label if user don`t choose directory
      # openDirectory func
      self.fileLocationLabelError = tk.Label(self.master, text="", font=("Agency FB", 20))
      self.fileLocationLabelError.grid()

      # What to download MP3 or MP4 label
      self.youtubeChooseLabel = ttk.Label(self.master, text="Please choose what to download: ", font=("Agency FB", 30))
      self.youtubeChooseLabel.grid()

      # RadioButton with two choices: MP3 or MP4
      downloadChoices = [("Song MP3", 1), ("Video MP4", 2)]
      self.ChoicesVar = tk.StringVar()
      self.ChoicesVar.set(1)
      for text, mode in downloadChoices:
      self.youtubeChoices = ttk.Radiobutton(self.master, text=text, variable=self.ChoicesVar, value=mode).grid()

      # Download button which at first checks if
      # youtube link is correct then checks if Directory
      # were chosen and if both is correct then start to
      # download the file
      self.nextButton = ttk.Button(self.master, text="Download", width=10, command=self.checkYoutubeLink)
      self.nextButton.grid(pady=(180,80))

      # This func opens the directory and
      # checks if user chose directory or not
      # if not the proper message is displayed
      # if yes then directory is shown on gui
      def openDirectory(self):

      self.FolderName = filedialog.askdirectory()

      if(len(self.FolderName) > 1):
      self.fileLocationLabelError.config(text=self.FolderName, fg="green")
      return True
      else:
      self.fileLocationLabelError.config(text="Please choose folder!", fg="red")

      # This func checks if youtube link is correct with regex
      # And checks if directory was chosen
      # if both is correct the it proceeds with downloading the file
      def checkYoutubeLink(self):

      matchYoutubeLink = re.match('^https://www.youtube.com/.*', self.youtubeEntryVar.get())

      if(not matchYoutubeLink):
      self.youtubeEntryError.config(text="Wrong youtube link!", fg="red")

      elif(not self.openDirectory):
      self.fileLocationLabelError.config(text="Please choose folder!", fg="red")

      elif(matchYoutubeLink) and self.openDirectory:
      self.downloadWindow()

      # Func hides the MainApplication window and goes to the SecondPage window
      # 3 arguments are passed to the next class window
      def downloadWindow(self):

      self.newWindow = tk.Toplevel(self.master)
      self.master.withdraw()
      self.app = SecondPage(self.newWindow, self.youtubeEntryVar.get(), self.FolderName, self.ChoicesVar.get())



      # This class shows downloading process
      class SecondPage(tk.Frame):
      def __init__(self, master, youtubeEntry, folderName, ChoicesVar):

      tk.Frame.__init__(self, master)
      self.master = master

      self.master.state("zoomed")

      self.master.grid_rowconfigure(0, weight=0)
      self.master.grid_columnconfigure(0, weight=1)

      self.youtubeEntry = youtubeEntry
      self.FolderLocation = folderName
      self.ChoicesVar = ChoicesVar


      # describe pytube with yt
      self.yt = YouTube(self.youtubeEntry)

      # Here we are checking what user chose
      # song or video to download
      if(self.ChoicesVar == "1"):
      self.video_type = self.yt.streams.filter(only_audio = True).first()
      self.MaxfileSize = self.video_type.filesize

      elif(self.ChoicesVar == "2"):
      self.video_type = self.yt.streams.first()
      self.MaxfileSize = self.video_type.filesize

      # Loading label
      self.loadingLabel = ttk.Label(self.master, text="Loading...", font=("Agency FB", 30))
      self.loadingLabel.grid(pady=(100,0))

      # loading precent label which must show % donwloaded
      self.loadingPercent = tk.Label(self.master, text="0", fg="green", font=("Agency FB", 30))
      self.loadingPercent.grid(pady=(30,30))

      # indeterminate progress bar
      self.progressbar = ttk.Progressbar(self.master, orient="horizontal", length=500, mode='indeterminate')
      self.progressbar.grid(pady=(50,0))
      self.progressbar.start()

      # I use threads here to call both functions because otherwise
      # one function downloads the file and only then shows the gui window
      # to solve this issue i used threads
      threading.Thread(target=self.yt.register_on_progress_callback(self.show_progress_bar)).start()

      # call Download file func
      threading.Thread(target=self.DownloadFile).start()

      # This function checks what user chose MP3 or MP4
      # and downloads the file
      def DownloadFile(self):
      if(self.ChoicesVar == "1"):
      self.yt.streams.filter(only_audio=True).first().download(self.FolderLocation)
      elif(self.ChoicesVar == "2"):
      self.yt.streams.first().download(self.FolderLocation)

      # This function show the progress in %
      # when 100% is reached then gui outputs
      # the chosen folder location
      # file title
      # file size in MB
      def show_progress_bar(self, stream=None, chunk=None, file_handle=None, bytes_remaining=None):

      # loadingPercent label configure value %
      percentCount = float("%0.2f"% (100 - (100*(bytes_remaining/self.MaxfileSize))))

      if(percentCount < 100):
      self.loadingPercent.config(text=str(percentCount)+"%")

      else:
      # When 100% is reached then forget loading
      # labels and progress bar
      self.progressbar.stop()

      self.loadingLabel.grid_forget()
      self.loadingPercent.grid_forget()
      self.progressbar.grid_forget()

      # finished label
      self.downloadFinished = ttk.Label(self.master, text="Finished", font=("Agency FB", 30))
      self.downloadFinished.grid(pady=(150,0))

      # Folder location label
      self.downloadLocation = ttk.Label(self.master, text=self.FolderLocation, font=("Agency FB", 30))
      self.downloadLocation.grid(pady=(50,0))

      # Title label
      self.downloadedFileTitle = ttk.Label(self.master, text=self.yt.title, font=("Agency FB", 30))
      self.downloadedFileTitle.grid(pady=(50,0))

      # Label shows MB count
      MB = float("%0.2f"% (self.MaxfileSize/1000000))
      self.downloadedFileSize = ttk.Label(self.master, text=(str(MB) + "MB"), font=("Agency FB", 30))
      self.downloadedFileSize.grid(pady=(50,0))

      # Exit button
      self.Exit_button = ttk.Button(self.master, text="Exit", command=quit)
      self.Exit_button.grid(pady=(200,0))


      if __name__ == "__main__":

      root = tk.Tk()
      root.title("Youtube program")
      app = MainApplication(root)
      root.mainloop()


      Questions:



      1. In the MainApplication I have 60 lines of various widgets is there any convention to divide widgets to make code more readable? At this moment I am writing another program and there I will have 150-200 lines of various widgets on the main page.

      2. When user write something in the ttk.Entry I want to check if input is correct or not and go to the next Frame if correct. I wrote exactly that and it works fine, but perhaps is there are easier solution/convention?

      I know that naming convention in this program is incorrect I will change that.
      Any other thoughts/opinions is much appreciated, Thanks.







      share|improve this question













      I wrote a small program which downloads song or video from the given youtube link.
      I used pytube library https://github.com/nficano/pytube and for GUI (Tkinter).



      from pytube import YouTube
      import tkinter as tk
      from tkinter import ttk
      from tkinter import filedialog
      import re
      import threading

      """Program downloads song or video
      from youtube page using pytube library
      more info about pytube
      can be found here: https://github.com/nficano/pytube
      GUI created with tkinter"""



      # Main class where user inputs and choose available options
      class MainApplication(tk.Frame):

      def __init__(self, master=None, *args, **kwargs):
      tk.Frame.__init__(self, master)
      self.master = master

      self.master.state("zoomed")

      # Window layout
      self.master.grid_rowconfigure(0, weight=2)
      self.master.grid_columnconfigure(0, weight=1)

      # Youtube link label
      self.youtubeLinkLabel = ttk.Label(self.master, text="Please copy the youtube link: ", font=("Agency FB", 30))
      self.youtubeLinkLabel.grid()

      # Youtube entry where user inputs the youtube link
      self.youtubeEntryVar = tk.StringVar()
      self.youtubeEntry = ttk.Entry(self.master, width=50, textvariable=self.youtubeEntryVar)
      self.youtubeEntry.grid(pady=(0,100))

      # Entry error label if user inputs incorrect
      # link the label will say wrong link
      # checkYoutubeLink function
      self.youtubeEntryError = tk.Label(self.master, text="", font=("Agency FB", 20))
      self.youtubeEntryError.grid(pady=(0,30))

      # Asking where to save file label
      self.youtubeFileLocationLabel = ttk.Label(self.master, text="Please choose folder where to download file: ", font=("Agency FB", 30))
      self.youtubeFileLocationLabel.grid()

      # Button to open directory
      # command = self.openDirectory
      self.youtubeFileLocationEntry = ttk.Button(self.master, text="Directory", command=self.openDirectory)
      self.youtubeFileLocationEntry.grid(pady=(20,40))

      # Entry label if user don`t choose directory
      # openDirectory func
      self.fileLocationLabelError = tk.Label(self.master, text="", font=("Agency FB", 20))
      self.fileLocationLabelError.grid()

      # What to download MP3 or MP4 label
      self.youtubeChooseLabel = ttk.Label(self.master, text="Please choose what to download: ", font=("Agency FB", 30))
      self.youtubeChooseLabel.grid()

      # RadioButton with two choices: MP3 or MP4
      downloadChoices = [("Song MP3", 1), ("Video MP4", 2)]
      self.ChoicesVar = tk.StringVar()
      self.ChoicesVar.set(1)
      for text, mode in downloadChoices:
      self.youtubeChoices = ttk.Radiobutton(self.master, text=text, variable=self.ChoicesVar, value=mode).grid()

      # Download button which at first checks if
      # youtube link is correct then checks if Directory
      # were chosen and if both is correct then start to
      # download the file
      self.nextButton = ttk.Button(self.master, text="Download", width=10, command=self.checkYoutubeLink)
      self.nextButton.grid(pady=(180,80))

      # This func opens the directory and
      # checks if user chose directory or not
      # if not the proper message is displayed
      # if yes then directory is shown on gui
      def openDirectory(self):

      self.FolderName = filedialog.askdirectory()

      if(len(self.FolderName) > 1):
      self.fileLocationLabelError.config(text=self.FolderName, fg="green")
      return True
      else:
      self.fileLocationLabelError.config(text="Please choose folder!", fg="red")

      # This func checks if youtube link is correct with regex
      # And checks if directory was chosen
      # if both is correct the it proceeds with downloading the file
      def checkYoutubeLink(self):

      matchYoutubeLink = re.match('^https://www.youtube.com/.*', self.youtubeEntryVar.get())

      if(not matchYoutubeLink):
      self.youtubeEntryError.config(text="Wrong youtube link!", fg="red")

      elif(not self.openDirectory):
      self.fileLocationLabelError.config(text="Please choose folder!", fg="red")

      elif(matchYoutubeLink) and self.openDirectory:
      self.downloadWindow()

      # Func hides the MainApplication window and goes to the SecondPage window
      # 3 arguments are passed to the next class window
      def downloadWindow(self):

      self.newWindow = tk.Toplevel(self.master)
      self.master.withdraw()
      self.app = SecondPage(self.newWindow, self.youtubeEntryVar.get(), self.FolderName, self.ChoicesVar.get())



      # This class shows downloading process
      class SecondPage(tk.Frame):
      def __init__(self, master, youtubeEntry, folderName, ChoicesVar):

      tk.Frame.__init__(self, master)
      self.master = master

      self.master.state("zoomed")

      self.master.grid_rowconfigure(0, weight=0)
      self.master.grid_columnconfigure(0, weight=1)

      self.youtubeEntry = youtubeEntry
      self.FolderLocation = folderName
      self.ChoicesVar = ChoicesVar


      # describe pytube with yt
      self.yt = YouTube(self.youtubeEntry)

      # Here we are checking what user chose
      # song or video to download
      if(self.ChoicesVar == "1"):
      self.video_type = self.yt.streams.filter(only_audio = True).first()
      self.MaxfileSize = self.video_type.filesize

      elif(self.ChoicesVar == "2"):
      self.video_type = self.yt.streams.first()
      self.MaxfileSize = self.video_type.filesize

      # Loading label
      self.loadingLabel = ttk.Label(self.master, text="Loading...", font=("Agency FB", 30))
      self.loadingLabel.grid(pady=(100,0))

      # loading precent label which must show % donwloaded
      self.loadingPercent = tk.Label(self.master, text="0", fg="green", font=("Agency FB", 30))
      self.loadingPercent.grid(pady=(30,30))

      # indeterminate progress bar
      self.progressbar = ttk.Progressbar(self.master, orient="horizontal", length=500, mode='indeterminate')
      self.progressbar.grid(pady=(50,0))
      self.progressbar.start()

      # I use threads here to call both functions because otherwise
      # one function downloads the file and only then shows the gui window
      # to solve this issue i used threads
      threading.Thread(target=self.yt.register_on_progress_callback(self.show_progress_bar)).start()

      # call Download file func
      threading.Thread(target=self.DownloadFile).start()

      # This function checks what user chose MP3 or MP4
      # and downloads the file
      def DownloadFile(self):
      if(self.ChoicesVar == "1"):
      self.yt.streams.filter(only_audio=True).first().download(self.FolderLocation)
      elif(self.ChoicesVar == "2"):
      self.yt.streams.first().download(self.FolderLocation)

      # This function show the progress in %
      # when 100% is reached then gui outputs
      # the chosen folder location
      # file title
      # file size in MB
      def show_progress_bar(self, stream=None, chunk=None, file_handle=None, bytes_remaining=None):

      # loadingPercent label configure value %
      percentCount = float("%0.2f"% (100 - (100*(bytes_remaining/self.MaxfileSize))))

      if(percentCount < 100):
      self.loadingPercent.config(text=str(percentCount)+"%")

      else:
      # When 100% is reached then forget loading
      # labels and progress bar
      self.progressbar.stop()

      self.loadingLabel.grid_forget()
      self.loadingPercent.grid_forget()
      self.progressbar.grid_forget()

      # finished label
      self.downloadFinished = ttk.Label(self.master, text="Finished", font=("Agency FB", 30))
      self.downloadFinished.grid(pady=(150,0))

      # Folder location label
      self.downloadLocation = ttk.Label(self.master, text=self.FolderLocation, font=("Agency FB", 30))
      self.downloadLocation.grid(pady=(50,0))

      # Title label
      self.downloadedFileTitle = ttk.Label(self.master, text=self.yt.title, font=("Agency FB", 30))
      self.downloadedFileTitle.grid(pady=(50,0))

      # Label shows MB count
      MB = float("%0.2f"% (self.MaxfileSize/1000000))
      self.downloadedFileSize = ttk.Label(self.master, text=(str(MB) + "MB"), font=("Agency FB", 30))
      self.downloadedFileSize.grid(pady=(50,0))

      # Exit button
      self.Exit_button = ttk.Button(self.master, text="Exit", command=quit)
      self.Exit_button.grid(pady=(200,0))


      if __name__ == "__main__":

      root = tk.Tk()
      root.title("Youtube program")
      app = MainApplication(root)
      root.mainloop()


      Questions:



      1. In the MainApplication I have 60 lines of various widgets is there any convention to divide widgets to make code more readable? At this moment I am writing another program and there I will have 150-200 lines of various widgets on the main page.

      2. When user write something in the ttk.Entry I want to check if input is correct or not and go to the next Frame if correct. I wrote exactly that and it works fine, but perhaps is there are easier solution/convention?

      I know that naming convention in this program is incorrect I will change that.
      Any other thoughts/opinions is much appreciated, Thanks.









      share|improve this question












      share|improve this question




      share|improve this question








      edited Apr 17 at 12:00









      Deduplicator

      9,8501744




      9,8501744









      asked Apr 17 at 11:24









      Jonas.S.

      113




      113

























          active

          oldest

          votes











          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f192281%2fdownload-song-or-video-from-youtube-using-pytube%23new-answer', 'question_page');

          );

          Post as a guest



































          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes










           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f192281%2fdownload-song-or-video-from-youtube-using-pytube%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Greedy Best First Search implementation in Rust

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          C++11 CLH Lock Implementation