Прогресс загрузки Youtube-dl
Создал загрузчик видео с YouTube с помощью PyQt5 в ООП стиле с классами. Добавил progressbar и хочу, чтобы при скачивании процент скачивания писался не только в консоль, но и в прогрессбар, соответственно его заполняя и обновляясь каждые 0.5 секунд.
from __future__ import unicode_literals
from PyQt5 import *
import sys
import youtube_dl
from ytdl import *
import os
class downloader(QtCore.QThread):
signal = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.link = None
def run(self):
with youtube_dl.YoutubeDL({}) as ydl:
ydl.download([self.link])
def init_args(self, link):
self.link = link
class gui(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.dl_folder = None
self.ui.pushButton_2.clicked.connect(self.start)
self.ui.pushButton.clicked.connect(self.get_folder)
self.mythread = downloader()
def start(self, d):
if len(self.ui.lineEdit.text()) > 5:
if self.dl_folder != None:
url = self.ui.lineEdit.text()
self.mythread.init_args(url)
self.mythread.start()
self.ui.progressBar.setValue(None)
else:
QtWidgets.QMessageBox.warning(self, "Ошибка", "Вы не выбрали папку!")
else:
QtWidgets.QMessageBox.warning(self, "Ошибка", "Ссылка на видео не указана!")
def get_folder(self):
self.dl_folder = QtWidgets.QFileDialog.getExistingDirectory(self, 'Выбрать папку для сохранения')
try:
os.chdir(self.dl_folder)
except:
pass
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
MainWindow = gui()
MainWindow.show()
sys.exit(app.exec_())
Ответы (1 шт):
Автор решения: S. Nick
→ Ссылка
Метод загрузки youtube_dl занимает много времени и должны запускаться в дополнительном потоке.
youtube_dl предоставляет два средства информации: hooks и logger.
Эти носители выполняются в том же потоке, что и метод загрузки,
поэтому к ним следует обращаться не напрямую, а через сигналы.
main.py
import os
from PyQt5 import QtWidgets
from qyoutubedl import QLogger, QHook, QYoutubeDL
# hurry.filesize простая библиотека Python, которая может принимать количество байтов
# и возвращать удобочитаемую строку с указанием размера в килобайтах(K), мегабайтах(M) и т.д.
from hurry.filesize import size # pip install hurry.filesize
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.url_le = QtWidgets.QLineEdit()
self.download_btn = QtWidgets.QPushButton(self.tr("Download"))
self.download_btn.clicked.connect(self.download)
self.progress_lbl = QtWidgets.QLabel()
self.progress_lbl.setFixedWidth(80)
self.lineEdit = QtWidgets.QLineEdit()
self.pushButton = QtWidgets.QPushButton('Get folder')
self.pushButton.clicked.connect(self.get_folder)
self.download_pgb = QtWidgets.QProgressBar()
self.log_edit = QtWidgets.QPlainTextEdit(readOnly=True)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QGridLayout(central_widget)
lay.addWidget(QtWidgets.QLabel(self.tr("url:")))
lay.addWidget(self.url_le, 0, 1)
lay.addWidget(self.download_btn, 0, 2)
lay.addWidget(QtWidgets.QLabel(self.tr("папка для Save:")), 1, 0)
lay.addWidget(self.lineEdit, 1, 1)
lay.addWidget(self.pushButton, 1, 2)
lay.addWidget(self.progress_lbl, 2, 0)
lay.addWidget(self.download_pgb, 2, 1, 1, 2)
lay.addWidget(self.log_edit, 3, 1, 1, 2)
self.progress_lbl.hide()
self.downloader = QYoutubeDL()
self.url_le.setText("https://www.youtube.com/watch?v=ZSMDjea93Qw")
def download(self):
if not self.lineEdit.text():
QtWidgets.QMessageBox.warning(self, "Ошибка", "Вы не выбрали папку!")
return
if len(self.url_le.text()) < 10:
QtWidgets.QMessageBox.warning(self, "Ошибка", "Ссылка на видео указана \n неправильно!")
return
os.chdir(self.lineEdit.text())
qhook = QHook()
qlogger = QLogger()
url = self.url_le.text()
options = {
"format": "bestvideo[height=144]+bestaudio/best",
"noplaylist": True,
"postprocessors": [{"key": "FFmpegMetadata"}],
"noprogress": True,
"logger": qlogger,
"progress_hooks": [qhook],
}
self.downloader.download([url], options)
qhook.infoChanged.connect(self.handle_info_changed)
qlogger.messageChanged.connect(self.log_edit.appendPlainText)
self.download_pgb.setRange(0, 1)
def handle_info_changed(self, d):
if d["status"] == "downloading":
self.progress_lbl.show()
total = d["total_bytes"]
downloaded = d["downloaded_bytes"]
self.progress_lbl.setText("{} of {}".format(size(downloaded), size(total)))
self.download_pgb.setMaximum(total)
self.download_pgb.setValue(downloaded)
def get_folder(self):
self.dl_folder = QtWidgets.QFileDialog.getExistingDirectory(
self, 'Выбрать папку для сохранения')
if self.dl_folder:
self.lineEdit.setText(self.dl_folder)
else: self.lineEdit.clear()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
qyoutubedl.py
import threading
from PyQt5 import QtCore
import youtube_dl # pip install youtube_dl
class QLogger(QtCore.QObject):
messageChanged = QtCore.pyqtSignal(str)
def debug(self, msg):
self.messageChanged.emit(msg)
def warning(self, msg):
self.messageChanged.emit(msg)
def error(self, msg):
self.messageChanged.emit(msg)
class QHook(QtCore.QObject):
infoChanged = QtCore.pyqtSignal(dict)
def __call__(self, d):
self.infoChanged.emit(d.copy())
class QYoutubeDL(QtCore.QObject):
def download(self, urls, options):
threading.Thread(
target=self._execute, args=(urls, options), daemon=True
).start()
def _execute(self, urls, options):
with youtube_dl.YoutubeDL(options) as ydl:
ydl.download(urls)
for hook in options.get("progress_hooks", []):
if isinstance(hook, QHook):
hook.deleteLater()
logger = options.get("logger")
if isinstance(logger, QLogger):
logger.deleteLater()
