-
Notifications
You must be signed in to change notification settings - Fork 4
/
gui.py
executable file
·306 lines (265 loc) · 15.2 KB
/
gui.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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
from logging.handlers import DEFAULT_TCP_LOGGING_PORT
import os, sys, glob, platform
if (platform.system().lower() == "windows"):
if (int(platform.version().split(".")[0]) < 10):
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtCore import QT_VERSION_STR #, Qt
try:
from PyQt6 import QtWidgets, uic
from PyQt6.QtWidgets import QMessageBox
from PyQt6.QtCore import QT_VERSION_STR #, Qt
except Exception as e:
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtCore import QT_VERSION_STR #, Qt
# Imports from this project
from release import year, lstupdt, spath, curb, ver, settingsPath, audioDirDefault, videoDirDefault
from gui.Audio import Audio, aud_playlist_bar_toggle
from gui.Video import Video, vid_quality, vid_playlist_bar_toggle, vid_quality_bar_toggle
from gui.Subs import Subs, sub_lang, sub_playlist_bar_toggle
from gui.ReEncode import Reencode, ree_settings, ree_settings_save, ree_choose
from gui.Update import Update, upd_auto_toggle, upd_button_change
from gui.Settings import set_save, set_load, set_makeScript, WriteDefaultJson
from shared.ReEncode import reencode_shared_settings
from shared.Config import Settings
# changing python working directory to script location to fix most path issues
os.chdir(os.path.dirname(__file__))
try:
if (sys.platform.startswith("win")): # win, linux, darwin, freebsd
import ctypes
myappid = 'HorseArmored.yt-dl.gui.'+ver # Program Sting
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
except Exception as e:
print(e)
class MainWindow(QtWidgets.QMainWindow):
# region ===== drag & drop =====
def dragEnterEvent(self, e):
if e.mimeData().hasText():
e.accept()
else:
e.ignore()
def dropEvent(self, e): # this thing is absolutely awful, I have no clue how could it work before
drag = "" # fixes a crash
if "file:///" in e.mimeData().text():
drag = e.mimeData().text().replace("file:///", "")
self.ree_location_bar.setText(drag) # dropping anywhere on the main window drops into ree_location_bar
# endregion
def closeEvent(self, e): # when closing the app it's size and position gets saved, there alsoe has to be "e" even if it's not used or it throws an error
self.settings.Window.windowWidth = self.geometry().width()
self.settings.Window.windowHeight = self.geometry().height()
self.settings.Window.windowPosX = self.pos().x()
self.settings.Window.windowPosY = self.pos().y()
self.settings.toJson(settingsPath)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
uic.loadUi(f"gui{os.path.sep}gui.ui", self)
if platform.system().lower() == "windows":
is_windows_11 = int(platform.version().split('.')[2]) > 20000
is_qt6 = QT_VERSION_STR[0] == '6'
color = "#ffffff" if (is_windows_11 and is_qt6) or not is_windows_11 else "#000000"
else:
color = "#ffffff"
self.tabWidget.setStyleSheet(f"""
QTabBar::tab:selected {{
background-color: #121212; /* Change to your desired color */
color: {color}
}}
QTabBar::tab {{
background-color: #383838; /* Color for unselected tabs */
color: {color}
}}
""")
#self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
self.show()
self.raise_()
self.activateWindow()
self.setAcceptDrops(True)
# region ===== startup =====
pffmpeg = glob.glob(f"{spath}ffmpeg*")
pffprobe = glob.glob(f"{spath}ffprobe*")
if (not pffmpeg and not pffprobe):
self.floc = False
else: # This code is absolutely terrible :)
directorySplit = pffmpeg[0]
directorySplit = directorySplit.split("\\")
directorySplit = directorySplit[:-1]
directorySplit = "\\".join(directorySplit)
self.floc = directorySplit
pgit = glob.glob(f"{spath}git{os.path.sep}bin{os.path.sep}git*")
if pgit: # using portable git
self.gloc = True
else: # using non portable git
self.gloc = False
if (os.path.exists(settingsPath)):
try:
self.settings = Settings.fromJson(settingsPath)
except KeyError as e:
print(e)
if QT_VERSION_STR[0] == '6':
self.messagePopup("Settings error", QMessageBox.Icon.Critical, "Your config file is not up to date,\nPress OK to load default config.", self.SaveDefaultConfig)
else:
self.messagePopup("Settings error", QMessageBox.Critical, "Your config file is not up to date,\nPress OK to load default config.", self.SaveDefaultConfig)
else:
if QT_VERSION_STR[0] == '6':
self.messagePopup("Settings error", QMessageBox.Icon.Critical, "You are missing a config file,\nPress OK to load default config.", self.SaveDefaultConfig)
else:
self.messagePopup("Settings error", QMessageBox.Critical, "You are missing a config file,\nPress OK to load default config.", self.SaveDefaultConfig)
self.setWindowTitle(f"yt-dl {ver}")
# this code is probably Windows only, and it's ugly af
python = os.path.dirname(sys.executable)+os.path.sep # location of the python yt-dl was started from
ytdlp = glob.glob(f"{python}Scripts{os.path.sep}yt-dlp*") # check if python that launch yt-dl has yt-dlp
if (not ytdlp):
ytdlp = glob.glob(f"{self.settings.Python.python[:-6]}Scripts{os.path.sep}yt-dlp*") # check if user configured python has yt-dlp, specific to Vista build
if (not ytdlp):
self.ytex = False
else:
self.ytex = [self.settings.Python.python, ytdlp[0]]
else:
self.ytex = [python+"python", ytdlp[0]]
# changing size and position of the window
if self.settings.Window.windowWidth != 0 or self.settings.Window.windowHeight != 0:
self.resize(self.settings.Window.windowWidth, self.settings.Window.windowHeight)
if self.settings.Window.windowPosX != 0 or self.settings.Window.windowPosY != 0:
self.move(self.settings.Window.windowPosX, self.settings.Window.windowPosY)
self.tabWidget.setCurrentIndex(self.settings.defaultTab) # the code will not get here if settings is undefined.
self.running = False
self.status("Ready.")
self.process = ""
# endregion
# region =====aud_controls=====
self.aud_folder_button.clicked.connect(lambda: self.openFolder(self.settings.Youtubedl.audioDir))
self.aud_download_button.clicked.connect(lambda: Audio(self))
self.aud_playlist_checkbox.clicked.connect(lambda: aud_playlist_bar_toggle(self))
self.aud_cookie_checkbox.setChecked(self.settings.Youtubedl.cookie)
self.aud_output_console.setHtml("#yt-dl# Welcome to yt-dl-gui (Audio) paste a link and hit download.")
# endregion
# region =====vid_controls=====
self.vid_folder_button.clicked.connect(lambda: self.openFolder(self.settings.Youtubedl.videoDir))
self.vid_download_button.clicked.connect(lambda: Video(self))
self.vid_quality_button.clicked.connect(lambda: vid_quality(self))
self.vid_playlist_checkbox.clicked.connect(lambda: vid_playlist_bar_toggle(self))
self.vid_custom_radio.toggled.connect(lambda: vid_quality_bar_toggle(self))
self.vid_cookie_checkbox.setChecked(self.settings.Youtubedl.cookie)
self.vid_output_console.setHtml("#yt-dl# Welcome to yt-dl-gui (Video) paste a link and hit download.")
# endregion
# region =====sub_controls=====
self.sub_folder_button.clicked.connect(lambda: self.openFolder(self.settings.Youtubedl.videoDir))
self.sub_download_button.clicked.connect(lambda: Subs(self))
self.sub_lang_button.clicked.connect(lambda: sub_lang(self))
self.sub_playlist_checkbox.toggled.connect(lambda: sub_playlist_bar_toggle(self))
self.sub_cookie_checkbox.setChecked(self.settings.Youtubedl.cookie)
self.sub_output_console.setHtml("#yt-dl# Welcome to yt-dl-gui (Subtitles) paste a link and hit download.")
# endregion
# region =====ree_controls=====
for i in range(0, int(reencode_shared_settings(self, "len"))):
setting = reencode_shared_settings(self, i)
if setting:
self.ree_settings_combobox.addItem(setting[5]) # writes name of the setting
ree_settings(self) # load option on startup
self.ree_choose_button.clicked.connect(lambda: ree_choose(self))
self.ree_reencode_button.clicked.connect(lambda: Reencode(self))
self.ree_folder_button.clicked.connect(lambda: self.openFolder(self.ree_location_bar.text()))
self.ree_settings_combobox.activated.connect(lambda: ree_settings(self))
self.ree_settings_button.clicked.connect(lambda: ree_settings_save(self))
self.ree_output_console.setHtml("#yt-dl# Welcome to yt-dl-gui (Re-encode) paste a link and hit download.")
self.ree_location_bar.setAcceptDrops(True)
# endregion
# region ======upd_controls======
self.upd_update_combobox.addItem("All") # setting up items in combo list
self.upd_update_combobox.addItem("yt-dl")
self.upd_update_combobox.addItem("Dependencies")
self.upd_update_combobox.addItem("List versions")
if (sys.platform.startswith("haiku")):
self.upd_update_combobox.setCurrentIndex(1)
QtWidgets.QApplication.processEvents()
if self.settings.autoUpdate:
self.tabWidget.setCurrentIndex(4)
Update(self)
self.upd_update_combobox.currentIndexChanged.connect(lambda: upd_button_change(self))
self.upd_update_button.clicked.connect(lambda: Update(self))
self.upd_auto_button.setText(f"Autoupdate=\"{self.settings.autoUpdate}\"")
self.upd_auto_button.clicked.connect(lambda: upd_auto_toggle(self))
self.upd_output_console.append("#yt-dl# Welcome to yt-dl-gui (Update) pick and option and click Update.")
# endregion
# region =====set_controls=====
self.set_loaddef_button.clicked.connect(lambda: WriteDefaultJson(self))
self.set_loadcur_button.clicked.connect(lambda: set_load(self, self.settings.Youtubedl.audioDir, self.settings.Youtubedl.videoDir, self.settings.Python.python, self.settings.Python.pip, self.settings.Youtubedl.fromPip, self.settings.autoUpdate, self.settings.Ffmpeg.audioCodec, self.settings.Ffmpeg.videoCodec, self.settings.Ffmpeg.audioBitrate, self.settings.Ffmpeg.videoQuality, self.settings.Ffmpeg.append, self.settings.defaultTab, self.settings.autoClose))
self.set_folder_button.clicked.connect(lambda: self.openFolder(spath))
self.set_launch_button.clicked.connect(lambda: set_makeScript(self))
self.set_save_button.clicked.connect(lambda: set_save(self))
self.set_Tab_combobox.addItem("Audio") # setting up items in combo list
self.set_Tab_combobox.addItem("Video")
self.set_Tab_combobox.addItem("Subs")
self.set_Tab_combobox.addItem("Re-encode")
self.set_Tab_combobox.addItem("Update")
self.set_Tab_combobox.addItem("Settings")
self.set_Tab_combobox.addItem("About")
set_load(self, self.settings.Youtubedl.audioDir, self.settings.Youtubedl.videoDir, self.settings.Python.python, self.settings.Python.pip, self.settings.Youtubedl.fromPip, self.settings.autoUpdate, self.settings.Ffmpeg.audioCodec, self.settings.Ffmpeg.videoCodec, self.settings.Ffmpeg.audioBitrate, self.settings.Ffmpeg.videoQuality, self.settings.Ffmpeg.append, self.settings.defaultTab, self.settings.autoClose)
# endregion
# region ==========🎓ABOUT🎓==========
self.about_box.setHtml(f"<p style=\"font-size: 18px; white-space: pre\">HorseArmored Inc. (C){year}<br>" +
f"Version: {ver} ({curb} branch)<br>" +
f"Last updated on: {lstupdt}<br>" +
f"My webpage: <a href=\"https://tiny.cc/koleq\">https://tiny.cc/koleq</a><br>" +
f"Project page: <a href=\"https://github.com/KoleckOLP/yt-dl\">https://github.com/KoleckOLP/yt-dl</a><br>" +
f"need help? ask here: <a href=\"https://discord.gg/W88375j\">https://discord.gg/W88375j</a><br>" +
f"yt-dlp (C)2021-{year} yt-dlp contributors<br>"
f"ffmpeg (C)2000-{year} FFmpeg team<br>" +
f"Thanks to <a href=\"https://github.com/kangalioo\">kangalioo</a> who always helps a ton!<br>" +
f"You can read the changelog: <a href=\"https://github.com/KoleckOLP/yt-dl/blob/testing/changelog.md\">here</a></pre></p>")
# endregion
# region ===== startup =====
def messagePopup(self, title, icon, text, callf=None):
msg = QMessageBox() # Pylance is being stupid, I had to disable Type checking.
msg.setWindowTitle(title)
msg.setIcon(icon)
msg.setText(text)
if callf is not None:
if QT_VERSION_STR[0] == '6':
msg.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel)
else:
msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg.buttonClicked.connect(callf)
button = msg.exec()
if QT_VERSION_STR[0] == '6':
if button == QMessageBox.StandardButton.Ok:
self.SaveDefaultConfig("ok")
else:
sys.exit()
def SaveDefaultConfig(self, i): # only exists for pyqt5 support, not needed in pyqt6
if QT_VERSION_STR[0] == '6':
text = i
else:
text: str = i.text().lower()
if "ok" in text:
WriteDefaultJson(self)
else:
sys.exit()
enabledColor = "#383838"
disabledColor = "#242424"
# endregion
# region ===== used by most =====
def status(self, s=""): # shows status message and changes color of the status bar.
self.statusBar().showMessage(s)
if s == "Ready.":
self.statusBar().setStyleSheet("background-color: #00BB00")
elif s == "Busy.":
self.statusBar().setStyleSheet("background-color: #FF6600")
else:
self.statusBar().setStyleSheet("background-color: #A9A9A9")
@staticmethod
def openFolder(loc: str):
loc = os.path.dirname(loc)
if not os.path.exists(loc):
loc = "." + os.path.sep # if path does not exist open installation folder
if (sys.platform.startswith("win")):
os.startfile(loc) # does not work on macOS, and codefactor is mad about this.
elif (sys.platform.startswith("darwin")):
os.system(f"open {loc}") # codefactor is also mad about this.
else: # linux haiku and others
print("sorry this platform is not supported yet")
# endregion
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
app.exec()