Skip to content

Commit 1c987a4

Browse files
committed
Remove unsupported video formats from extension options and refactor image downloading logic
1 parent 96c3d21 commit 1c987a4

2 files changed

Lines changed: 71 additions & 65 deletions

File tree

advanced.ui

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,6 @@
105105
<string>webm</string>
106106
</property>
107107
</item>
108-
<item>
109-
<property name="text">
110-
<string>mov</string>
111-
</property>
112-
</item>
113-
<item>
114-
<property name="text">
115-
<string>wmv</string>
116-
</property>
117-
</item>
118-
<item>
119-
<property name="text">
120-
<string>avi</string>
121-
</property>
122-
</item>
123108
<item>
124109
<property name="text">
125110
<string>mp3</string>
@@ -140,11 +125,6 @@
140125
<string>wav</string>
141126
</property>
142127
</item>
143-
<item>
144-
<property name="text">
145-
<string>ogg</string>
146-
</property>
147-
</item>
148128
</widget>
149129
<widget class="QPushButton" name="pushConfirm">
150130
<property name="geometry">

download_pyqt6.py

Lines changed: 71 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@
66
from ffmpeg import ensure_ffmpeg_ready
77
from PyQt6.QtWidgets import (
88
QApplication, QMainWindow, QPushButton, QProgressBar, QLabel, QLineEdit, QSlider, QCheckBox, QComboBox, QDoubleSpinBox,
9-
QMessageBox, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget, QHBoxLayout, QToolButton, QSpinBox, QGraphicsView, QTextEdit
9+
QMessageBox, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget, QToolButton, QSpinBox, QGraphicsView, QTextEdit
1010
)
1111
from PyQt6 import uic, QtWidgets
12-
from PyQt6.QtGui import QClipboard, QPixmap, QImage
12+
from PyQt6.QtGui import QPixmap
1313
from PyQt6.QtCore import Qt, QThread, pyqtSignal, QObject, QTimer
14-
from io import BytesIO
1514
import re
1615
import time
1716

1817

19-
URL = "https://youtu.be/njX2bu-_Vw4?si=DpqFGMkWUOU56A5g" #DEBUG - Remove in production
18+
URL = "https://youtu.be/jZhjqMMV1B4?si=QeTmdVjiTt-_xnuo"
2019
video_info = {}
2120
extensions = {}
2221
ERROR = False
@@ -36,6 +35,21 @@ def update_options(**kwargs):
3635
else:
3736
ydl_opts[key] = value
3837

38+
class ImageDownloader(QThread):
39+
image_downloaded = pyqtSignal(bytes)
40+
41+
def __init__(self, url, parent=None):
42+
super().__init__(parent)
43+
self.url = url
44+
45+
def run(self):
46+
try:
47+
response = requests.get(self.url)
48+
response.raise_for_status()
49+
self.image_downloaded.emit(response.content)
50+
except requests.exceptions.RequestException as e:
51+
print(f"Error downloading image: {e}")
52+
3953
class AdvancedWindow(QWidget):
4054
def __init__(self):
4155
super().__init__()
@@ -48,54 +62,73 @@ def __init__(self):
4862
ydl_opts.clear()
4963
self.qSlider = self.findChild(QSlider, 'qSlider')
5064
self.qSliderLabel = self.findChild(QLabel, 'qSliderLabel')
51-
5265
self.checkVerbose = self.findChild(QCheckBox, 'checkVerbose')
5366
self.checkSubtitle = self.findChild(QCheckBox, 'checkSubtitles')
5467
self.checkMetadata = self.findChild(QCheckBox, 'checkMetadata')
55-
5668
self.extensionBox = self.findChild(QComboBox, 'extensionBox')
5769
self.retryBox = self.findChild(QSpinBox, 'retryBox')
5870
self.checkRate = self.findChild(QCheckBox, 'checkRate')
5971
self.rateLimiterBox = self.findChild(QDoubleSpinBox, 'rateLimiterBox')
60-
self.rateLimiterBox.hide()
61-
#TODO -> Rate LImiter doesnt work
6272
self.graphicsView = self.findChild(QGraphicsView, 'graphicsView')
6373
self.pushConfirm = self.findChild(QPushButton, 'pushConfirm')
6474
self.pushReset = self.findChild(QPushButton, 'pushReset')
6575
self.pushConfirm.clicked.connect(self.confirm)
76+
self.pushReset.clicked.connect(self.close)
77+
78+
self.scene = QtWidgets.QGraphicsScene(self)
79+
self.graphicsView.setScene(self.scene)
6680

6781
self.qSlider.valueChanged.connect(self.update_slider_label)
6882

69-
#Fetch Thumbnail
7083
global thumbnail_url
71-
image_data = BytesIO(requests.get(thumbnail_url).content)
72-
image=QImage()
73-
image.loadFromData(image_data.getvalue())
74-
pixmap = QPixmap.fromImage(image)
75-
view_size = self.graphicsView.size()
76-
scaled_pixed = pixmap.scaled(view_size,Qt.AspectRatioMode.IgnoreAspectRatio, Qt.TransformationMode.SmoothTransformation)
77-
scene=QtWidgets.QGraphicsScene()
78-
scene.addPixmap(scaled_pixed)
79-
self.graphicsView.setScene(scene)
84+
if thumbnail_url:
85+
self.image_downloader = ImageDownloader(thumbnail_url)
86+
self.image_downloader.image_downloaded.connect(self.set_image)
87+
self.image_downloader.start()
88+
89+
def set_image(self, image_data):
90+
pixmap = QPixmap()
91+
pixmap.loadFromData(image_data)
92+
self.scene.addPixmap(pixmap)
93+
self.graphicsView.fitInView(self.scene.itemsBoundingRect(), Qt.AspectRatioMode.KeepAspectRatio)
8094

8195
def confirm(self):
82-
current_quality = self.qSliderLabel.text()
83-
print(f"Selected Quality: {current_quality}")
84-
current_retries = self.retryBox.value()
85-
print(f"Selected number of retries: {current_retries}")
86-
current_ext = self.extensionBox.currentText()
87-
print(f"Selected Extension: {current_ext}\n")
96+
val = self.qSlider.value()
97+
98+
if val >= 75:
99+
fmt = 'bestvideo+bestaudio/best'
100+
elif val >= 50:
101+
fmt = 'bestvideo[height<=1080]+bestaudio/best[height<=1080]'
102+
elif val >= 25:
103+
fmt = 'bestvideo[height<=720]+bestaudio/best[height<=720]'
104+
else:
105+
fmt = 'bestvideo[height<=360]+bestaudio/best[height<=360]'
106+
107+
new_opts = {
108+
'format': fmt,
109+
'retries': self.retryBox.value(),
110+
'merge_output_format': self.extensionBox.currentText(),
111+
}
112+
if self.checkSubtitle.isChecked():
113+
new_opts.update({
114+
'writesubtitles': True,
115+
'writeautomaticsub': True,
116+
'subtitlesformat': 'srt/best',
117+
'subtitleslangs': ['en']
118+
})
119+
update_options(**new_opts)
120+
self.close()
88121

89122
def update_slider_label(self):
90123
current_value = self.qSlider.value()
91-
labels = ["Worst", "Good", "Better", "Best"]
124+
labels = ["<=360p", "720p", "1080p", "Best"]
92125
index = current_value // 25
93126
self.qSliderLabel.setText(labels[index])
94127

95128
class DownloadWorker(QThread):
96129
progress_update=pyqtSignal(str,int)
97130
download_complete=pyqtSignal()
98-
sleep_for_item = pyqtSignal(str, int) # New signal: title, duration
131+
sleep_for_item = pyqtSignal(str, int)
99132

100133
def __init__(self,selected_videos,logger_var=None):
101134
super().__init__()
@@ -113,7 +146,7 @@ def run(self):
113146
global extensions
114147
try:
115148
for title,url in self.selected_videos:
116-
self.current_download_title = title # Set the current title
149+
self.current_download_title = title
117150
ext="mp4"
118151
if extensions[title]==False:
119152
ext="mp3"
@@ -129,12 +162,11 @@ def run(self):
129162

130163
def download_video_with_progress(self, title, url, ext):
131164
global ydl_opts
132-
ydl_opts.clear()
133165
ffmpeg_args = {'ffmpeg_location': './ffmpeg'} if sys.platform == "win32" else {}
134166
try:
135-
update_options(format='bestvideo+bestaudio/best',outtmpl=f'{title}.{ext}',progress_hooks=[lambda d: self.update_progress(d,title)], no_warnings=False, logger=self.logger_var2, **ffmpeg_args)
167+
update_options(outtmpl=f'{title}.{ext}',progress_hooks=[lambda d: self.update_progress(d,title)], no_warnings=False, logger=self.logger_var2, **ffmpeg_args)
136168
except Exception:
137-
update_options(format='bestvideo+bestaudio/best',outtmpl=f'{title}.{ext}',progress_hooks=[lambda d: self.update_progress(d,title)], no_warnings=False, **ffmpeg_args)
169+
update_options(outtmpl=f'{title}.{ext}',progress_hooks=[lambda d: self.update_progress(d,title)], no_warnings=False, **ffmpeg_args)
138170
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
139171
try:
140172
ydl.download([url])
@@ -174,7 +206,7 @@ def log_error(self, message):
174206

175207
class Logger(QObject):
176208
messageSignal=pyqtSignal(str)
177-
sleep_detected = pyqtSignal(str, int) # New signal: title, duration
209+
sleep_detected = pyqtSignal(str, int)
178210

179211
def debug(self,msg):
180212
self.messageSignal.emit(msg)
@@ -192,8 +224,8 @@ def _check_for_sleep_message(self, msg):
192224
match = re.search(r"^\[download\] Sleeping (\d+\.?\d*) seconds as required by the site\.\.\.", msg)
193225
if match:
194226
duration = int(float(match.group(1)))
195-
# We'll use a placeholder for now, actual title will be handled in DownloadWorker
196227
self.sleep_detected.emit("GLOBAL_SLEEP", duration)
228+
197229
class ResultWindow(QWidget):
198230
def __init__(self,results):
199231
super().__init__()
@@ -209,31 +241,26 @@ def __init__(self,results):
209241
self.sleep_timers = {}
210242
self.current_sleep_durations = {}
211243
for row, (title, ext) in enumerate(results):
212-
#CheckBox Item Setup
213244
checkbox_item = QTableWidgetItem()
214245
checkbox_item.setFlags(checkbox_item.flags() | Qt.ItemFlag.ItemIsUserCheckable)
215246
checkbox_item.setCheckState(Qt.CheckState.Unchecked)
216247
self.table.setItem(row, 0, checkbox_item)
217248
self.table.item(row, 0).setFlags(self.table.item(row, 0).flags() & ~Qt.ItemFlag.ItemIsEditable)
218249

219-
#Title Item Setup
220250
self.table.setItem(row, 1, QTableWidgetItem(title))
221251
self.table.item(row, 1).setFlags(self.table.item(row, 1).flags() & ~Qt.ItemFlag.ItemIsEditable)
222252

223-
#Toggle Button Setup
224253
toggle_button = QPushButton('Video (mp4)')
225254
toggle_button.setCheckable(True)
226255
extensions[title]=True
227256
toggle_button.clicked.connect(lambda checked, btn=toggle_button, r=row: self.toggle_value(btn,r))
228257
self.table.setCellWidget(row, 2, toggle_button)
229258

230-
#Progress Bars Setup
231259
progress_bar=QProgressBar()
232260
progress_bar.setValue(0)
233261
self.progress_bars[title]=progress_bar
234262
self.table.setCellWidget(row, 3, progress_bar)
235263

236-
#Logger Setup
237264
logger = QTextEdit()
238265
logger.setReadOnly(True)
239266
self.loggers[title]=logger
@@ -243,7 +270,6 @@ def __init__(self,results):
243270
self.downloadButtonPlayList = QPushButton("Download Selected")
244271
self.downloadButtonPlayList.clicked.connect(self.search_and_download)
245272

246-
#Table Config
247273
self.table.setAlternatingRowColors(True)
248274
self.table.setColumnWidth(0,25)
249275
self.table.setColumnWidth(1,200)
@@ -286,7 +312,7 @@ def search_and_download(self):
286312
self.worker=DownloadWorker(self.selected_videos,self.logger_var)
287313
self.worker.progress_update.connect(self.update_progress)
288314
self.worker.download_complete.connect(self.on_download_complete)
289-
self.worker.sleep_for_item.connect(self.handle_sleep_countdown) # Connect new signal
315+
self.worker.sleep_for_item.connect(self.handle_sleep_countdown)
290316
self.worker.start()
291317

292318
def handle_sleep_countdown(self, title, duration):
@@ -299,14 +325,14 @@ def handle_sleep_countdown(self, title, duration):
299325
logger = self.loggers.get(title)
300326
if progress_bar and logger:
301327
progress_bar.setMaximum(duration)
302-
progress_bar.setValue(duration) # Start at max for reverse progress
328+
progress_bar.setValue(duration)
303329
logger.clear()
304330
logger.insertPlainText(f"Sleeping {duration} seconds...")
305331

306332
self.current_sleep_durations[title] = duration
307333
timer = QTimer(self)
308-
timer.timeout.connect(lambda: self._update_sleep_progress(title)) # Use lambda to pass title
309-
timer.start(1000) # Update every second
334+
timer.timeout.connect(lambda: self._update_sleep_progress(title))
335+
timer.start(1000)
310336
self.sleep_timers[title] = timer
311337

312338
def _update_sleep_progress(self, title):
@@ -326,16 +352,16 @@ def _update_sleep_progress(self, title):
326352
self.sleep_timers[title].stop()
327353
del self.sleep_timers[title]
328354
del self.current_sleep_durations[title]
329-
progress_bar.setValue(0) # Reset to 0 after sleep
355+
progress_bar.setValue(0)
330356
logger.clear()
331-
logger.insertPlainText('Downloading...') # Or whatever the next status is
357+
logger.insertPlainText('Downloading...')
332358

333359
def update_progress(self,title,percent):
334360
if title in self.progress_bars:
335361
self.progress_bars[title].setValue(percent)
336362
if percent >= 0:
337363
self.loggers[title].clear()
338-
self.loggers[title].insertPlainText('Downloading...')
364+
self.loggers[title].insertPlainText(f"{percent}% Complete")
339365

340366
def on_download_complete(self):
341367
global ERROR

0 commit comments

Comments
 (0)