问题描述
我正在尝试在gui中显示下载的实时进度。我正在cmd中获得实时下载进度,但是gui仅在下载完成后才会更新。
def myhook(self,d):
self.percentage=QLabel(self)
self.d=d
if self.d['status']=='finished':
print("finished")
if self.d['status']=='downloading':
print(self.d['filename'],self.d['total_bytes'],self.d['downloaded_bytes'],self.d['elapsed'],self.d['eta'],str(str(self.d['speed']/1000)[0:5]+'KiB/s'),str((self.d['downloaded_bytes']*100)/self.d['total_bytes'])[0:5]+'%')
if self.d['total_bytes']>1048576:
total_size=self.d['total_bytes']/1048576
total_size=str(total_size)[0:5]+' MB'
if self.d['total_bytes']>1073741824:
total_size=self.d['total_bytes']/1073741824
total_size=str(total_size)[0:5]+' GB'
self.percentage.setText('{} {}'.format(total_size,str((self.d['downloaded_bytes']*100)/self.d['total_bytes'])[0:5]+' %'))
self.percentage.setStyleSheet('color:white;border-bottom:2px solid orange;')
self.percentage.setFont(QFont('Arial',15))
self.percentage.resize(500,30)
self.percentage.move(320,650)
self.percentage.show()
self.url=self.urlfield.text()
print("144p")
options={'format':'bestvideo[height=144]+bestaudio/best','noplaylist':True,'postprocessors':[{'key':'FFmpegMetadata'}],'noprogress':True,'progress_hooks':[self.myhook]}
with youtube_dl.YoutubedL(options) as ydll:
ydll.download(['{}'.format(self.url)])
解决方法
由于您多次想知道如何从youtube-dl获取信息并将其显示在用pyqt5编写的GUI中的正确方法,因此我将获得许可,以超越当前问题并显示更多内容。通用示例。
youtube_dl下载方法非常耗时,因此不应在主线程中执行,因为它会产生不必要的效果,例如窗口冻结。另一方面,youtube_dl提供了2种信息手段:钩子和记录器。而且这些媒体与下载方法在同一线程中执行,因此不应直接通过信号访问它们。
qyoutubedl.py
import threading
from PyQt5 import QtCore
import 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,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()
main.py
from PyQt5 import QtWidgets
from qyoutubedl import QLogger,QHook,QYoutubeDL
from hurry.filesize import size
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.progress_lbl = QtWidgets.QLabel()
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,1)
lay.addWidget(self.download_btn,2)
lay.addWidget(self.progress_lbl,1,2)
lay.addWidget(self.download_pgb,2,2)
lay.addWidget(self.log_edit,3,2)
self.progress_lbl.hide()
self.downloader = QYoutubeDL()
self.download_btn.clicked.connect(self.download)
self.url_le.setText("https://www.youtube.com/watch?v=BaW_jenozKc")
self.resize(640,480)
def download(self):
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 main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()