Skip to content

Commit 0d5dbfd

Browse files
committed
New platform-independent Qt-based downloader
1 parent 62905e1 commit 0d5dbfd

File tree

1 file changed

+74
-32
lines changed

1 file changed

+74
-32
lines changed

com.mpvnet.loader.py

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,91 @@
22

33
import os
44
import sys
5-
import dbus
65
import struct
76
import yt_dlp
87

98
import subprocess as sp
109

1110
from multiprocessing import Process
12-
from PyQt5.QtWidgets import QApplication, QFileDialog
11+
12+
from PyQt5.QtCore import (
13+
QThread,
14+
pyqtSignal
15+
)
16+
17+
from PyQt5.QtWidgets import(
18+
QLabel,
19+
QWidget,
20+
QFileDialog,
21+
QPushButton,
22+
QVBoxLayout,
23+
QProgressBar,
24+
QApplication
25+
)
1326

1427
PREFER_EXT = {
1528
'video': 'mp4',
1629
'audio': 'mp3'
1730
}
1831

19-
class DLoadTracker:
20-
def __init__ (self):
21-
self.bus = dbus.SessionBus()
22-
self.interface = 'org.kde.JobViewV2'
23-
self.server = self.bus.get_object('org.kde.kuiserver', '/JobViewServer')
24-
self.path = self.server.requestView('mpvnet', 'download', 1)
25-
self.job = self.bus.get_object('org.kde.kuiserver', self.path)
26-
self.set_info('Initializing...')
32+
class DLoader (QWidget):
33+
def __init__ (self, url, ydl_opts, info):
34+
super().__init__()
35+
self.info_label = QLabel()
36+
self.info_label.setText(info)
37+
self.progress_bar = QProgressBar()
38+
self.progress_bar.setValue(0)
39+
self.cancel_button = QPushButton('Cancel')
40+
self.cancel_button.clicked.connect(self.cancel_download)
41+
self.vbox = QVBoxLayout()
42+
self.vbox.addWidget(self.info_label)
43+
self.vbox.addWidget(self.progress_bar)
44+
self.vbox.addWidget(self.cancel_button)
45+
self.thread = DLoaderThread(url, ydl_opts)
46+
self.thread.signal_progress.connect(self.set_progress)
47+
self.setWindowTitle('mpvnet')
48+
self.setFixedSize(self.sizeHint())
49+
self.setLayout(self.vbox)
50+
self.show()
51+
52+
def start_download (self):
53+
self.thread.start()
54+
55+
def cancel_download (self):
56+
self.thread.interrupt = True
2757

2858
def set_progress (self, progress):
29-
self.job.setPercent(progress, dbus_interface=self.interface)
30-
31-
def set_info (self, info):
32-
self.job.setInfoMessage(info, dbus_interface=self.interface)
59+
self.progress_bar.setValue(progress)
60+
61+
class DLoaderThread (QThread):
62+
signal_progress = pyqtSignal(int)
63+
def __init__ (self, url, ydl_opts):
64+
super().__init__()
65+
self.url = url
66+
self.ydl_opts = ydl_opts
67+
self.ydl_opts.update({
68+
'progress_hooks': [self.progress_hook],
69+
})
70+
self.interrupt = False
3371

34-
def terminate (self, info):
35-
self.job.terminate(info, dbus_interface=self.interface)
72+
def run (self):
73+
with yt_dlp.YoutubeDL(self.ydl_opts.copy()) as ydl:
74+
try:
75+
ydl.download(self.url)
76+
except yt_dlp.DownloadCancelled:
77+
pass
78+
finally:
79+
QApplication.quit()
3680

3781
def progress_hook (self, stream):
3882
if stream['status'] == 'downloading':
83+
if self.interrupt:
84+
raise yt_dlp.DownloadCancelled
3985
progress = int(float(stream['_percent_str'].replace('%', '')))
4086
if progress >= 0 and progress <= 100:
41-
self.set_progress(progress)
87+
self.signal_progress.emit(progress)
4288

43-
class DLoadPathChooser:
89+
class DLoaderPathChooser:
4490
def __init__ (self, default_path):
4591
self.path = None
4692
self.default_path = default_path
@@ -50,7 +96,7 @@ def choose_path (self):
5096
dialog = QFileDialog()
5197
dialog.setAcceptMode(QFileDialog.AcceptSave)
5298
dialog.selectFile(self.default_path)
53-
if dialog.exec_():
99+
if dialog.exec():
54100
self.path = dialog.selectedFiles()[0]
55101

56102
def recv_msg():
@@ -71,6 +117,7 @@ def run_loader(loader_args_raw):
71117
os.environ['LD_PRELOAD'] = '/usr/lib/libvulkan.so.1'
72118
os.chdir(os.path.expanduser("~"))
73119
loader_args = loader_args_raw.split()
120+
mpv_head = f'mpv --profile=pseudo-gui --geometry=x50%'
74121
mpv_tail = f'--ytdl-format=\'{loader_args[2]}\' \'{loader_args[3]}\''
75122
ydl_opts = {
76123
'quiet': True,
@@ -83,22 +130,19 @@ def run_loader(loader_args_raw):
83130
stop_loader(0, 'return_error_invalid_url')
84131
if loader_args[0] == 'mpv':
85132
if loader_args[1] == 'video':
86-
sp.Popen(f'mpv --geometry=x50% {mpv_tail}', shell=True)
133+
sp.Popen(f'{mpv_head} {mpv_tail}', shell=True)
87134
else:
88-
sp.Popen(f'konsole -e "mpv --no-video {mpv_tail}"', shell=True)
135+
sp.Popen(f'{mpv_head} --no-video {mpv_tail}', shell=True)
89136
else:
90-
tracker = DLoadTracker()
91137
title = media_info['title']
92138
for symbol in ['/', '"', '\'']:
93139
title = title.replace(symbol, '_')
94-
path_chooser = DLoadPathChooser(title)
140+
path_chooser = DLoaderPathChooser(title)
95141
path_chooser.choose_path()
96142
if not path_chooser.path:
97-
tracker.terminate('Action cancelled')
98143
stop_loader(0, 'return_normal')
99144
ydl_opts.update({
100145
'format': loader_args[2],
101-
'progress_hooks': [tracker.progress_hook],
102146
'outtmpl': f'{path_chooser.path}.%(ext)s',
103147
})
104148
if loader_args[1] == 'video':
@@ -112,16 +156,14 @@ def run_loader(loader_args_raw):
112156
'preferredcodec': PREFER_EXT['audio'],
113157
}]
114158
})
115-
tracker.set_info(
159+
info_str = str(
116160
f'Downloading {loader_args[1]}: ' +
117161
f'"{path_chooser.path}.{PREFER_EXT[loader_args[1]]}"'
118162
)
119-
with yt_dlp.YoutubeDL(ydl_opts.copy()) as ydl:
120-
try:
121-
ydl.download(loader_args[3])
122-
except dbus.exceptions.DBusException:
123-
stop_loader(0, 'return_normal')
124-
tracker.terminate('Download complete')
163+
app = QApplication([])
164+
downloader = DLoader(loader_args[3], ydl_opts, info_str)
165+
downloader.start_download()
166+
app.exec()
125167
stop_loader(0, 'return_normal')
126168

127169
def stop_loader (return_code, return_msg):

0 commit comments

Comments
 (0)