如何在 PyQt5 中集成 youtube-dl
How to integrate youtube-dl in PyQt5
我正在尝试在图形用户界面中显示实时下载进度。我在 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 下载方法非常耗时,因此不应在主线程中执行,因为它会产生不需要的效果,例如 window 冻结。另一方面,youtube_dl 提供了两种信息获取方式:钩子和记录器。并且这些媒体与下载方法在同一个线程中执行,因此不应直接访问它们,而应通过信号访问。
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, 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()
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, 0, 1)
lay.addWidget(self.download_btn, 0, 2)
lay.addWidget(self.progress_lbl, 1, 1, 1, 2)
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.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()
我正在尝试在图形用户界面中显示实时下载进度。我在 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 下载方法非常耗时,因此不应在主线程中执行,因为它会产生不需要的效果,例如 window 冻结。另一方面,youtube_dl 提供了两种信息获取方式:钩子和记录器。并且这些媒体与下载方法在同一个线程中执行,因此不应直接访问它们,而应通过信号访问。
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, 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()
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, 0, 1)
lay.addWidget(self.download_btn, 0, 2)
lay.addWidget(self.progress_lbl, 1, 1, 1, 2)
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.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()