-
Notifications
You must be signed in to change notification settings - Fork 1
/
pyTubeGUI.py
244 lines (227 loc) · 13.5 KB
/
pyTubeGUI.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# =============================================================================
# Created Syst: macOS Monterey 12.6 (21G115) Kernel: Darwin 21.6.0
# Created Plat: Python 3.10.8 ('v3.10.8:aaaf517424', 'Oct 11 2022 10:14:40')
# Created By : jayrizzo
# Created Date: Tue Dec 27 11:21:26 2022 CST
# Last ModDate: Tue Dec 27 15:51:10 2022 CST
# =============================================================================
# Notes:
# =============================================================================
"""Download Youtube Audio by providing the URL."""
from os.path import exists as filepathexist
from pytube import YouTube
from sys import argv
from os import getcwd
from os.path import dirname # Show the Script Path To This Script
from os.path import join # Joins folder names by Operating System
from os import makedirs # Make the Directories if they don't exist
from os.path import expanduser # Gets The Current Users Home Folder
import PySimpleGUI as sg
from time import sleep
# ========================================================================
# KNOWN ISSUES
# ========================================================================
# USE THIS IF FILE STRUCTURE IS NOT REFRESHING QUICKLY
# https://discussions.apple.com/thread/8584001
# ARCHIVE/DELETE ~/Library/Preferences/com.apple.finder.plist THEN while in FINDER app
# Navigate to the APPLE LOGO & HOLD CTRL + SHIFT Select "Force Quit Finder"
# ========================================================================
# Load Emoji Characters ==================================================
# ========================================================================
MUSICNOTE = '\U0001F3B5'
class App(object):
"""JayRizzo Youtube Downloader."""
def __init__(self):
"""JayRizzo Youtube Downloader Initial Launch Setup."""
super().__init__()
# ========================================================================
# ==================== Initialize the SimpleGUI Layout ===================
# ========================================================================
self.FILETOCONVERT = ''
self.OS_PATH = ''
self.YTVID_ID = ''
self.YTVID_DID = ''
self.YOUTUBE_URL = ''
self.YOUTUBE_URL_STREAM = ''
self.CURRENT_DIR = dirname(argv[0])
self.CURRENTHOME = expanduser('~')
self.DESKTOP_FOLDER = join(self.CURRENTHOME, "Desktop")
self.MUSIC_FOLDER = join(self.CURRENTHOME, "Music","JayRizzoDL")
self.VIDEO_FOLDER = join(self.CURRENTHOME, "Movies","JayRizzoDL")
self.DOWNLOAD_FILE_PATH = ''
self.MENU_DEF = [
['File',
['Open', 'Save', 'Exit',]
]
, ['Edit',
['Paste',
['Special', 'Normal',]
, 'Undo'
],
]
, ['Help', 'About...']
]
self.THEME = sg.ChangeLookAndFeel('Dark')
self.OPTION = sg.SetOptions (
background_color = 'Black'
, element_background_color = 'Black'
, text_element_background_color = 'Black'
, font = ('Arial', 12, 'bold')
, text_color = 'White'
, input_text_color = 'White'
, button_color = ('SkyBlue', 'SkyBlue')
)
self.BOX_FRAME_LAYOUT = [
[sg.T('Download Folder Locations:')]
, [sg.Text(f"MUSIC FOLDER: {self.MUSIC_FOLDER}", key='-MUSICFOLDERTEXT-', font='Consolas 11')]
, [sg.Text(f"VIDEO FOLDER: {self.VIDEO_FOLDER}", key='-VIDEOFOLDERTEXT-', font='Consolas 11')]
# , [sg.InputText(f"MUSIC FOLDER: {self.MUSIC_FOLDER}", key='-MUSICFOLDERTEXT-', font='Consolas 11', use_readonly_for_disable=True, disabled=True)]
# , [sg.InputText(f"VIDEO FOLDER: {self.VIDEO_FOLDER}", key='-VIDEOFOLDERTEXT-', font='Consolas 11', use_readonly_for_disable=True, disabled=True)]
# https://stackoverflow.com/a/69470136/1896134
# , [sg.T('Other Folder Locations:')]
# , [sg.Text(f"DESKTOP FOLDER: {self.DESKTOP_FOLDER}", key='-DESKTOPFOLDERTEXT-', font='Consolas 11')]
# , [sg.Text(f"SCRIPT PATH: {self.CURRENT_DIR}", key='-SCRIPTFOLDERTEXT-', font='Consolas 11')]
# , [sg.Text(f"CURRENT HOME PATH: {self.CURRENTHOME}", key='-CURRENTHOMEFOLDERTEXT-', font='Consolas 11')]
]
self.row1 = [sg.T('Enter YouTube URL'), sg.In(key='-ID-', expand_x=True)]
self.row2 = [ sg.B('Download Audio', button_color=(sg.YELLOWS[1], sg.BLUES[1]), key='-DLAUDIOBTN-', size=(20,1), expand_x=True)
, sg.VSep()
, sg.B('Download Video', button_color=(sg.YELLOWS[1], sg.BLUES[1]), key='-DLVIDEOBTN-', size=(20,1), expand_x=True)
]
self.row3 = [ sg.B('Clear Text', button_color=(sg.YELLOWS[1], sg.BLUES[1]), key='-CLRTXTBTN-', size=(20,1), expand_x=True)
, sg.VSep()
, sg.B('Exit', button_color=(sg.YELLOWS[1], sg.BLUES[1]), key='-EXITBTN-', size=(20,1), expand_x=True)]
self.row4 = [sg.Text('EXAMPLE URL: https://www.youtube.com/watch?v=RY9TbZMlTaI The extra URL ¶ms= do not cause issues.\n OR: RY9TbZMlTaI Both options will work.', key='-DISPLAYTEXT-')]
self.row5 = [sg.Frame('Info', self.BOX_FRAME_LAYOUT, element_justification='center', font='Consolas 22', title_color='SkyBlue', size=(250,80), expand_x=True, expand_y=True)]
self.LAYOUT = [
self.row1
, self.row2
, self.row3
, self.row4
, self.row5
]
self.WINDOW = sg.Window(F"{MUSICNOTE} JayRizzo's Youtube Downloader {MUSICNOTE}"
, [[sg.Menu(self.MENU_DEF)], self.LAYOUT]
, font = 'Arial 12'
, size=(700, 280)
, resizable = True
, grab_anywhere = False
, finalize=True
, keep_on_top=True # https://stackoverflow.com/a/58014474/1896134
)
def downloadYouTubeAudio(self, videourl):
self.YOUTUBE_URL = YouTube(videourl)
videourl = None
print(self.YOUTUBE_URL.title)
print(self.YOUTUBE_URL.author)
self.YOUTUBE_URL_STREAM = self.YOUTUBE_URL.streams.filter(only_audio=True, file_extension='mp4').order_by('abr').desc().first()
if not filepathexist(self.MUSIC_FOLDER):
makedirs(self.MUSIC_FOLDER)
self.DOWNLOAD_FILE_PATH = self.YOUTUBE_URL_STREAM.download(output_path=self.MUSIC_FOLDER)
print(f"self.DOWNLOAD_FILE_PATH: {self.DOWNLOAD_FILE_PATH}")
return self.DOWNLOAD_FILE_PATH
def downloadYouTubeVideo(self, videourl):
self.YOUTUBE_URL = YouTube(videourl)
videourl = None
self.YOUTUBE_URL_STREAM = self.YOUTUBE_URL.streams.filter(only_audio=False, progressive=True, file_extension='mp4').order_by('resolution').desc().first()
if not filepathexist(self.VIDEO_FOLDER):
makedirs(self.VIDEO_FOLDER)
self.DOWNLOAD_FILE_PATH = self.YOUTUBE_URL_STREAM.download(output_path=self.VIDEO_FOLDER)
print(f"self.DOWNLOAD_FILE_PATH: {self.DOWNLOAD_FILE_PATH}")
return self.DOWNLOAD_FILE_PATH
def clear_last_values(self):
self.WINDOW['-ID-'].Update('')
self.YOUTUBE_URL = None
self.YOUTUBE_URL_STREAM = None
self.DOWNLOAD_FILE_PATH = None
def main(self):
# Create an self.event loop
while True:
self.event, self.values = self.WINDOW.read()
if self.event == "-DLAUDIOBTN-":
self.WINDOW['-DISPLAYTEXT-'].Update(f"Starting The Audio Download")
sleep(0.5)
if len(self.values['-ID-']) == 11 and self.values['-ID-'] != 'DISPLAYTEXT':
self.YTVID_ID = self.values['-ID-']
b = "https://www.youtube.com/watch?v="
c = b + self.YTVID_ID
try:
self.DOWNLOAD_FILE_PATH = self.downloadYouTubeAudio(c)
self.WINDOW['-DISPLAYTEXT-'].Update(f"My Downloaded Song: {self.DOWNLOAD_FILE_PATH}")
self.clear_last_values()
except FileExistsError as e:
self.WINDOW['-DISPLAYTEXT-'].Update(f"Song Has Already Been Downloaded: {self.DOWNLOAD_FILE_PATH}")
self.clear_last_values()
except RegexMatchError as e:
self.WINDOW['-DISPLAYTEXT-'].Update(f"Something Went Wrong With the URL: {self.values['-ID-']}")
self.clear_last_values()
elif len(self.values['-ID-']) > 11 and '?v=' in self.values['-ID-']:
self.YTVID_ID = self.values['-ID-']
self.YTVID_DID = self.YTVID_ID.split('?v=')[1]
b = "https://www.youtube.com/watch?v="
c = b + self.YTVID_DID
try:
self.DOWNLOAD_FILE_PATH = self.downloadYouTubeAudio(c)
self.WINDOW['-DISPLAYTEXT-'].Update(f"My Downloaded Song: {self.DOWNLOAD_FILE_PATH}")
self.clear_last_values()
except FileExistsError as e:
self.WINDOW['-DISPLAYTEXT-'].Update(f"Song Has Already Been Downloaded: {self.DOWNLOAD_FILE_PATH}")
self.clear_last_values()
else:
self.WINDOW['-ID-'].Update('')
self.WINDOW['-DISPLAYTEXT-'].Update(f"The URL is Invalid: {self.values['-ID-']}")
self.clear_last_values()
if self.event == "-DLVIDEOBTN-":
self.WINDOW['-DISPLAYTEXT-'].Update(f"Starting The Video Download : {self.values}")
sleep(0.5)
if len(self.values['-ID-']) == 11 and self.values['-ID-'] != 'DISPLAYTEXT':
self.YTVID_ID = self.values['-ID-']
b = "https://www.youtube.com/watch?v="
c = b + self.YTVID_ID
try:
self.DOWNLOAD_FILE_PATH = self.downloadYouTubeVideo(c)
self.WINDOW['-DISPLAYTEXT-'].Update(f"My Downloaded Video: {self.DOWNLOAD_FILE_PATH}")
self.clear_last_values()
except FileExistsError as e:
self.WINDOW['-DISPLAYTEXT-'].Update(f"Video Has Already Been Downloaded: {self.DOWNLOAD_FILE_PATH}")
self.clear_last_values()
elif len(self.values['-ID-']) > 11 and '?v=' in self.values['-ID-']:
self.YTVID_ID = self.values['-ID-']
self.YTVID_DID = self.YTVID_ID.split('?v=')[1]
b = "https://www.youtube.com/watch?v="
c = b + self.YTVID_DID
try:
self.DOWNLOAD_FILE_PATH = self.downloadYouTubeVideo(c)
self.WINDOW['-DISPLAYTEXT-'].Update(f"My Downloaded Video: {self.DOWNLOAD_FILE_PATH}")
self.clear_last_values()
except FileExistsError as e:
self.WINDOW['-DISPLAYTEXT-'].Update(f"Video Has Already Been Downloaded: {self.DOWNLOAD_FILE_PATH}")
self.clear_last_values()
else:
self.WINDOW['-ID-'].Update('')
self.WINDOW['-DISPLAYTEXT-'].Update(f"The URL is Invalid: {self.values['-ID-']}")
self.clear_last_values()
if self.event == "-CLRTXTBTN-":
self.WINDOW['-ID-'].Update('')
self.WINDOW['-DISPLAYTEXT-'].Update('')
if self.event == "-EXITBTN-" or self.event == sg.WIN_CLOSED:
# END PROGRAM IF USER CLOSES WINDOW
break
if __name__ == "__main__":
app = App()
app.main()
# def Example():
# with sg.FlexForm('Facebook problem') as form:
# form_rows = [[sg.Text('Enter your name address and city')],
# [sg.Text('Name', size=(15, 1), justification='right'), sg.InputText('Name')],
# [sg.Text('Address', size=(15, 1), justification='right'), sg.InputText('Address')],
# [sg.Text('City', size=(15, 1), justification='right'), sg.InputText('City')],
# [sg.Ok(), sg.Cancel()]]
# button, (name, address, city) = form.LayoutAndRead(form_rows)
# if button == 'Ok':
# sg.MsgBox('You entered', name, address, city)
# else:
# sg.MsgBoxError('Cancelled', 'User Cancelled')
# Example()