1+ from  tkinter  import  * 
2+ from  tkinter  import  ttk 
3+ from  pytube  import  YouTube 
4+ from  tkinter .messagebox  import  showinfo , showerror , askokcancel 
5+ import  threading 
6+ 
7+ 
8+ 
9+ # the function to download the video 
10+ def  download_video ():
11+     # the try statement to excute the download the video code 
12+     try :
13+         # getting video url from entry 
14+         video_link  =  url_entry .get ()
15+         # getting video resolution from Combobox 
16+         resolution  =  video_resolution .get ()
17+         # checking if the entry and combobox is empty 
18+         if  resolution  ==  ''  and  video_link  ==  '' :
19+             # display error message when combobox is empty 
20+             showerror (title = 'Error' , message = 'Please enter both the video URL and resolution!!' )
21+         # checking if the resolution is empty 
22+         elif  resolution  ==  '' :
23+             # display error message when combobox is empty 
24+             showerror (title = 'Error' , message = 'Please select a video resolution!!' )
25+         # checking if the comboxbox value is None   
26+         elif  resolution  ==  'None' :
27+             # display error message when combobox value is None 
28+             showerror (title = 'Error' , message = 'None is an invalid video resolution!!\n ' \
29+                     'Please select a valid video resolution' )    
30+         # else let's download the video   
31+         else :
32+             # this try statement will run if the resolution exists for the video 
33+             try :   
34+                 # this function will track the video download progress 
35+                 def  on_progress (stream , chunk , bytes_remaining ):
36+                     # the total size of the video 
37+                     total_size  =  stream .filesize 
38+                     # this function will get the size of the video 
39+                     def  get_formatted_size (total_size , factor = 1024 , suffix = 'B' ):
40+                         # looping through the units 
41+                         for  unit  in  ["" , "K" , "M" , "G" , "T" , "P" , "E" , "Z" ]:
42+                             if  total_size  <  factor :
43+                                 return  f"{ total_size :.2f} { unit } { suffix }  " 
44+                             total_size  /=  factor 
45+                         # returning the formatted video size 
46+                         return  f"{ total_size :.2f}  Y{ suffix }  " 
47+                     
48+                     # getting the formatted video size calling the function 
49+                     formatted_size  =  get_formatted_size (total_size )
50+                     # the size downloaded after the start 
51+                     bytes_downloaded  =  total_size  -  bytes_remaining 
52+                     # the percentage downloaded after the start 
53+                     percentage_completed  =  round (bytes_downloaded  /  total_size  *  100 )
54+                     # updating the progress bar value 
55+                     progress_bar ['value' ] =  percentage_completed 
56+                     # updating the empty label with the percentage value 
57+                     progress_label .config (text = str (percentage_completed ) +  '%, File size:'  +  formatted_size )
58+                     # updating the main window of the app 
59+                     window .update ()
60+                 
61+                 # creating the YouTube object and passing the the on_progress function 
62+                 video  =  YouTube (video_link , on_progress_callback = on_progress )
63+                 # downlaoding the actual video   
64+                 video .streams .filter (res = resolution ).first ().download ()
65+                 # popup for dispalying the video downlaoded success message 
66+                 showinfo (title = 'Download Complete' , message = 'Video has been downloaded successfully.' )
67+                 # ressetting the progress bar and the progress label 
68+                 progress_label .config (text = '' )
69+                 progress_bar ['value' ] =  0 
70+             # the except will run when the resolution is not available or invalid 
71+             except :
72+                 showerror (title = 'Download Error' , message = 'Failed to download video for this resolution' )
73+                 # ressetting the progress bar and the progress label 
74+                 progress_label .config (text = '' )
75+                 progress_bar ['value' ] =  0 
76+         
77+     # the except statement to catch errors, URLConnectError, RegMatchError   
78+     except :
79+         # popup for displaying the error message 
80+         showerror (title = 'Download Error' , message = 'An error occurred while trying to '  \
81+                     'download the video\n The following could '  \
82+                     'be the causes:\n ->Invalid link\n ->No internet connection\n ' \
83+                      'Make sure you have stable internet connection and the video link is valid' )
84+         # ressetting the progress bar and the progress label 
85+         progress_label .config (text = '' )
86+         progress_bar ['value' ] =  0 
87+         
88+         
89+ 
90+ # function for searching video resolutions 
91+ def  searchResolution ():
92+     # getting video url from entry 
93+     video_link  =  url_entry .get ()
94+     # checking if the video link is empty 
95+     if  video_link  ==  '' :
96+         showerror (title = 'Error' , message = 'Provide the video link please!' )
97+     # if video link not empty search resolution   
98+     else :
99+         try :
100+             # creating a YouTube object 
101+             video  =  YouTube (video_link )
102+             # an empty list that will hold all the video resolutions 
103+             resolutions  =  []
104+             # looping through the video streams 
105+             for  i  in  video .streams .filter (file_extension = 'mp4' ):
106+                 # adding the video resolutions to the resolutions list 
107+                 resolutions .append (i .resolution )
108+             # adding the resolutions to the combobox 
109+             video_resolution ['values' ] =  resolutions 
110+             # when search is complete notify the user 
111+             showinfo (title = 'Search Complete' , message = 'Check the Combobox for the available video resolutions' )
112+         # catch any errors if they occur   
113+         except :
114+             # notify the user if errors are caught 
115+             showerror (title = 'Error' , message = 'An error occurred while searching for video resolutions!\n ' \
116+                 'Below might be the causes\n ->Unstable internet connection\n ->Invalid link' )
117+ 
118+ 
119+ 
120+ 
121+ 
122+ # the function to run the searchResolution function as a thread 
123+ def  searchThread ():
124+     t1  =  threading .Thread (target = searchResolution )
125+     t1 .start ()
126+     
127+     
128+ # the function to run the download_video function as a thread    
129+ def  downloadThread ():
130+     t2  =  threading .Thread (target = download_video )
131+     t2 .start ()
132+ 
133+ 
134+ 
135+ 
136+ # creates the window using Tk() fucntion 
137+ window  =  Tk ()
138+ 
139+ # creates title for the window 
140+ window .title ('YouTube Video Downloader' )
141+ # dimensions and position of the window 
142+ window .geometry ('500x460+430+180' )
143+ # makes the window non-resizable 
144+ window .resizable (height = FALSE , width = FALSE )
145+ 
146+ # creates the canvas for containing all the widgets 
147+ canvas  =  Canvas (window , width = 500 , height = 400 )
148+ canvas .pack ()
149+ 
150+ # loading the logo 
151+ logo  =  PhotoImage (file = 'youtubelogo.png' )
152+ # creates dimensions of the logo 
153+ logo  =  logo .subsample (10 , 10 )
154+ # adding the logo to the canvas 
155+ canvas .create_image (250 , 80 , image = logo )
156+ 
157+ 
158+ """Styles for the widgets""" 
159+ # style for the label  
160+ label_style  =  ttk .Style ()
161+ label_style .configure ('TLabel' , foreground = '#000000' , font = ('OCR A Extended' , 15 ))
162+ 
163+ # style for the entry 
164+ entry_style  =  ttk .Style ()
165+ entry_style .configure ('TEntry' , font = ('Dotum' , 15 ))
166+ 
167+ # style for the button 
168+ button_style  =  ttk .Style ()
169+ button_style .configure ('TButton' , foreground = '#000000' , font = 'DotumChe' )
170+ 
171+ 
172+ # creating a ttk label 
173+ url_label  =  ttk .Label (window , text = 'Enter Video URL:' , style = 'TLabel' )
174+ # creating a ttk entry 
175+ url_entry  =  ttk .Entry (window , width = 76 , style = 'TEntry' )
176+ 
177+ # adding the label to the canvas 
178+ canvas .create_window (114 , 200 , window = url_label )
179+ # adding the entry to the canvas 
180+ canvas .create_window (250 , 230 , window = url_entry )
181+ 
182+ 
183+ # creating resolution label 
184+ resolution_label  =  Label (window , text = 'Resolution:' )
185+ # adding the label to the canvas 
186+ canvas .create_window (50 , 260 , window = resolution_label )
187+ 
188+ 
189+ # creating a combobox to hold the video resolutions 
190+ video_resolution  =  ttk .Combobox (window , width = 10 )
191+ # adding the combobox to the canvas 
192+ canvas .create_window (60 , 280 , window = video_resolution )
193+ 
194+ 
195+ # creating a button for searching resolutions 
196+ search_resolution  =  ttk .Button (window , text = 'Search Resolution' , command = searchThread )
197+ # adding the button to the canvas 
198+ canvas .create_window (85 , 315 , window = search_resolution )
199+ 
200+ 
201+ # creating the empty label for displaying download progress 
202+ progress_label  =  Label (window , text = '' )
203+ # adding the label to the canvas 
204+ canvas .create_window (240 , 360 , window = progress_label )
205+ 
206+ # creating a progress bar to display progress 
207+ progress_bar  =  ttk .Progressbar (window , orient = HORIZONTAL , length = 450 , mode = 'determinate' )
208+ # adding the progress bar to the canvas 
209+ canvas .create_window (250 , 380 , window = progress_bar )
210+ 
211+ # creating the button 
212+ download_button  =  ttk .Button (window , text = 'Download Video' , style = 'TButton' , command = downloadThread )
213+ # adding the button to the canvas 
214+ canvas .create_window (240 , 410 , window = download_button )
215+ 
216+ 
217+ # runs the window infinitely 
218+ window .mainloop ()
0 commit comments