Download song or video from Youtube using pytube
Clash 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:
- 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.
- 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.
python python-3.x tkinter
add a comment |Â
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:
- 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.
- 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.
python python-3.x tkinter
add a comment |Â
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:
- 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.
- 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.
python python-3.x tkinter
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:
- 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.
- 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.
python python-3.x tkinter
edited Apr 17 at 12:00
Deduplicator
9,8501744
9,8501744
asked Apr 17 at 11:24
Jonas.S.
113
113
add a comment |Â
add a comment |Â
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password