2

I have a Qt application to show videos from urls using:

player = QMediaPlayer()
...
player.setMedia(QMediaContent(QUrl(video.url)))
...

But unable to download the video using the same url with urllib.request, response code is always 200 but Content-Length is zero.

from urllib.request import urlopen, Request
rq = Request(video.url)
rp = urlopen(rq)
rp.headers["Content-Length"] # always 0

How Qt is able to show video when im failing to download?

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_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
err69
  • 317
  • 1
  • 7
  • Could you share the urls? – eyllanesc Jun 29 '20 at 21:31
  • @eyllanesc yes, its from tiktok app ```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``` – err69 Jun 29 '20 at 21:54
  • I can't reproduce anything with that url. On the other hand it seems that you have an XY problem, what is your basic objective? – eyllanesc Jun 29 '20 at 21:59
  • @eyllanesc I doing PC version of tiktok using Qt im stuck with ```save video``` button, Qt is able to show the video but when im requesting using ```urllib``` i get nothing. – err69 Jun 29 '20 at 22:17
  • mmmm, so a better question should be: how to download tiktok videos with Qt? and in the post you should explain that you can reproduce using QMediaContent (showing a real url as an example) but you have tried to download it with urllib but it fails. – eyllanesc Jun 29 '20 at 22:21
  • @eyllanesc I added working example see if it works. – err69 Jun 29 '20 at 22:32

1 Answers1

2

After several attempts I found that you must set the "user-agent". Qt does not directly handle QMediaPlayer requests but backends like gstreamer on Linux, and these set the user-agent so it works correctly.

I also found that you shouldn't be the user-agent of browsers like "Mozilla/5.0 ..." are probably rejected as a means of protection.

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)
eyllanesc
  • 235,170
  • 19
  • 170
  • 241