QMediaContent 如何在 urllib 无法下载时显示视频?
How QMediaContent able to show a video when urllib unable to download?
我有一个 Qt 应用程序可以显示来自 urls 的视频,使用:
player = QMediaPlayer()
...
player.setMedia(QMediaContent(QUrl(video.url)))
...
但无法使用与 urllib.request
相同的 url 下载视频,响应代码总是 200
但 Content-Length
为零。
from urllib.request import urlopen, Request
rq = Request(video.url)
rp = urlopen(rq)
rp.headers["Content-Length"] # always 0
Qt 如何在下载失败时显示视频?
MWE
from PyQt5.QtWidgets import QApplication
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtCore import QUrl
from urllib.request import urlopen
import sys
class Test(QVideoWidget):
def __init__(self, *args, **kwargs):
QVideoWidget.__init__(self, *args, **kwargs)
self.player = QMediaPlayer()
self.player.setVideoOutput(self)
self.player.mediaStatusChanged.connect(self.statusChanged)
self.url = "https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/play/?video_id=v09044190000brfkq160bkbi3ui1oko0&line=0&ratio=540p&media_type=4&vr_type=0&improve_bitrate=0&logo_name=tiktok_m&quality_type=11&source=PackSourceEnum_AWEME_DETAIL"
self.player.setMedia(QMediaContent(QUrl(self.url)))
def statusChanged(self, status):
if status == QMediaPlayer.LoadedMedia:
self.player.play()
elif status == QMediaPlayer.EndOfMedia:
self.player.play()
def download(self):
rp = urlopen(self.url)
if int(rp.headers["Content-Length"]) != 0:
with open("test.mp4", "wb") as mp4:
while True:
chunk = rp.read(1024)
if not chunk: break
mp4.write(chunk)
else:
raise Exception("Content-Length is Zero")
if __name__ == "__main__":
app = QApplication(sys.argv)
test = Test()
test.show()
# uncomment to download
# test.download()
sys.exit(app.exec_())
经过多次尝试,我发现您必须设置“用户代理”。 Qt 不直接处理 QMediaPlayer 请求,而是像 Linux 上的 gstreamer 这样的后端,这些设置用户代理以使其正常工作。
我还发现你不应该是像“Mozilla/5.0 ...”这样的浏览器的用户代理可能被拒绝作为一种保护手段。
from urllib.request import Request, urlopen
# ...
class Test(QVideoWidget):
# ...
def download(self):
rq = Request(self.url, headers={"user-agent": "MyApp/1.0"})
with urlopen(rq) as rp:
with open("test.mp4", "wb") as mp4:
while True:
chunk = rp.read(1024)
if not chunk:
break
mp4.write(chunk)
我有一个 Qt 应用程序可以显示来自 urls 的视频,使用:
player = QMediaPlayer()
...
player.setMedia(QMediaContent(QUrl(video.url)))
...
但无法使用与 urllib.request
相同的 url 下载视频,响应代码总是 200
但 Content-Length
为零。
from urllib.request import urlopen, Request
rq = Request(video.url)
rp = urlopen(rq)
rp.headers["Content-Length"] # always 0
Qt 如何在下载失败时显示视频?
MWE
from PyQt5.QtWidgets import QApplication
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtCore import QUrl
from urllib.request import urlopen
import sys
class Test(QVideoWidget):
def __init__(self, *args, **kwargs):
QVideoWidget.__init__(self, *args, **kwargs)
self.player = QMediaPlayer()
self.player.setVideoOutput(self)
self.player.mediaStatusChanged.connect(self.statusChanged)
self.url = "https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/play/?video_id=v09044190000brfkq160bkbi3ui1oko0&line=0&ratio=540p&media_type=4&vr_type=0&improve_bitrate=0&logo_name=tiktok_m&quality_type=11&source=PackSourceEnum_AWEME_DETAIL"
self.player.setMedia(QMediaContent(QUrl(self.url)))
def statusChanged(self, status):
if status == QMediaPlayer.LoadedMedia:
self.player.play()
elif status == QMediaPlayer.EndOfMedia:
self.player.play()
def download(self):
rp = urlopen(self.url)
if int(rp.headers["Content-Length"]) != 0:
with open("test.mp4", "wb") as mp4:
while True:
chunk = rp.read(1024)
if not chunk: break
mp4.write(chunk)
else:
raise Exception("Content-Length is Zero")
if __name__ == "__main__":
app = QApplication(sys.argv)
test = Test()
test.show()
# uncomment to download
# test.download()
sys.exit(app.exec_())
经过多次尝试,我发现您必须设置“用户代理”。 Qt 不直接处理 QMediaPlayer 请求,而是像 Linux 上的 gstreamer 这样的后端,这些设置用户代理以使其正常工作。
我还发现你不应该是像“Mozilla/5.0 ...”这样的浏览器的用户代理可能被拒绝作为一种保护手段。
from urllib.request import Request, urlopen
# ...
class Test(QVideoWidget):
# ...
def download(self):
rq = Request(self.url, headers={"user-agent": "MyApp/1.0"})
with urlopen(rq) as rp:
with open("test.mp4", "wb") as mp4:
while True:
chunk = rp.read(1024)
if not chunk:
break
mp4.write(chunk)