Ejemplo n.º 1
0
    def test_stream_open_video_only(self, muxer, reader):
        stream = DASHStream(self.session, Mock(),
                            Mock(id=1, mimeType="video/mp4"))
        open_reader = reader.return_value = Mock()

        stream.open()

        reader.assert_called_with(stream, 1, "video/mp4")
        open_reader.open.assert_called_with()
        muxer.assert_not_called()
Ejemplo n.º 2
0
    def _parse_streams(self, res):
        stream_url = validate.Schema(
            validate.parse_html(),
            validate.xml_xpath_string(
                ".//head/meta[@property='og:video:url'][@content][1]/@content")
        ).validate(res.text)
        if not stream_url:
            log.debug("No meta og:video:url")
        else:
            if ".mpd" in stream_url:
                for s in DASHStream.parse_manifest(self.session,
                                                   stream_url).items():
                    yield s
                return
            elif ".mp4" in stream_url:
                yield "vod", HTTPStream(self.session, stream_url)
                return

        for match in self._src_re.finditer(res.text):
            stream_url = match.group("url")
            if "\\/" in stream_url:
                # if the URL is json encoded, decode it
                stream_url = parse_json("\"{}\"".format(stream_url))
            if ".mpd" in stream_url:
                for s in DASHStream.parse_manifest(self.session,
                                                   stream_url).items():
                    yield s
            elif ".mp4" in stream_url:
                yield match.group(1), HTTPStream(self.session, stream_url)
            else:
                log.debug("Non-dash/mp4 stream: {0}".format(stream_url))

        match = self._dash_manifest_re.search(res.text)
        if match:
            # facebook replaces "<" characters with the substring "\\x3C"
            manifest = match.group("manifest").replace("\\/", "/")
            if is_py3:
                manifest = bytes(unquote_plus(manifest),
                                 "utf-8").decode("unicode_escape")
            else:
                manifest = unquote_plus(manifest).decode("string_escape")
            # Ignore unsupported manifests until DASH SegmentBase support is implemented
            if "SegmentBase" in manifest:
                log.error("Skipped DASH manifest with SegmentBase streams")
            else:
                for s in DASHStream.parse_manifest(self.session,
                                                   manifest).items():
                    yield s
Ejemplo n.º 3
0
    def _get_streams(self):
        streamdata = None
        if self.get_option("email"):
            if self.login(self.get_option("email"), self.get_option("password")):
                log.info("Logged in as {0}".format(self.get_option("email")))
                self.save_cookies(lambda c: "steamMachineAuth" in c.name)

        # Handle steam.tv URLs
        if self._steamtv_url_re.match(self.url) is not None:
            # extract the steam ID from the page
            res = self.session.http.get(self.url)
            for div in itertags(res.text, 'div'):
                if div.attributes.get("id") == "webui_config":
                    broadcast_data = html_unescape(div.attributes.get("data-broadcast"))
                    steamid = parse_json(broadcast_data).get("steamid")
                    self.url = self._watch_broadcast_url + steamid

        # extract the steam ID from the URL
        steamid = self._url_re.match(self.url).group(1)
        res = self.session.http.get(self.url)  # get the page to set some cookies
        sessionid = res.cookies.get('sessionid')

        while streamdata is None or streamdata[u"success"] in ("waiting", "waiting_for_start"):
            streamdata = self._get_broadcast_stream(steamid,
                                                    sessionid=sessionid)

            if streamdata[u"success"] == "ready":
                return DASHStream.parse_manifest(self.session, streamdata["url"])
            elif streamdata[u"success"] == "unavailable":
                log.error("This stream is currently unavailable")
                return
            else:
                r = streamdata[u"retry"] / 1000.0
                log.info("Waiting for stream, will retry again in {} seconds...".format(r))
                time.sleep(r)
Ejemplo n.º 4
0
    def _get_streams(self):
        self.session.http.headers["User-Agent"] = "streamlink/{0}".format(self.session.version)

        email = self.get_option("email")
        if email:
            log.info("Attempting to login to Steam as {0}".format(email))
            if self.dologin(email, self.get_option("password")):
                log.info("Logged in as {0}".format(email))
                self.save_cookies(lambda c: "steamMachineAuth" in c.name)

        if self.matches[1] is None:
            steamid = self.match.group(1)
        else:
            steamid = self._find_steamid(self.url)
            if not steamid:
                return
            self.url = self._watch_broadcast_url.format(steamid=steamid)

        res = self.session.http.get(self.url)  # get the page to set some cookies
        sessionid = res.cookies.get("sessionid")

        streamdata = None
        while streamdata is None or streamdata["success"] in ("waiting", "waiting_for_start"):
            streamdata = self._get_broadcast_stream(steamid, sessionid=sessionid)

            if streamdata["success"] == "ready":
                return DASHStream.parse_manifest(self.session, streamdata["url"])

            if streamdata["success"] == "unavailable":
                log.error("This stream is currently unavailable")
                return

            r = streamdata["retry"] / 1000.0
            log.info("Waiting for stream, will retry again in {0:.1f} seconds...".format(r))
            time.sleep(r)
Ejemplo n.º 5
0
    def mediaselector(self, vpid):
        urls = defaultdict(set)
        for platform in self.platforms:
            url = self.api_url.format(vpid=vpid,
                                      vpid_hash=self._hash_vpid(vpid),
                                      platform=platform)
            self.logger.debug("Info API request: {0}", url)
            medias = http.get(url, schema=self.mediaselector_schema)
            for media in medias:
                for connection in media["connection"]:
                    urls[connection.get("transferFormat")].add(
                        connection["href"])

        for stream_type, urls in urls.items():
            self.logger.debug("{0} {1} streams", len(urls), stream_type)
            for url in list(urls):
                self.logger.debug("  {0}", url)
                if stream_type == "hds":
                    for s in HDSStream.parse_manifest(self.session,
                                                      url).items():
                        yield s
                if stream_type == "hls":
                    for s in HLSStream.parse_variant_playlist(
                            self.session, url).items():
                        yield s
                if connection.get("transferFormat") == "dash":
                    for s in DASHStream.parse_manifest(
                            self.session, connection["href"]).items():
                        yield s
Ejemplo n.º 6
0
    def test_parse_manifest_audio_multi(self, mpdClass):
        mpdClass.return_value = Mock(periods=[
            Mock(adaptationSets=[
                Mock(contentProtection=None,
                     representations=[
                         Mock(id=1, mimeType="video/mp4", height=720),
                         Mock(id=2, mimeType="video/mp4", height=1080),
                         Mock(id=3,
                              mimeType="audio/aac",
                              bandwidth=128.0,
                              lang='en'),
                         Mock(id=4,
                              mimeType="audio/aac",
                              bandwidth=256.0,
                              lang='en')
                     ])
            ])
        ])

        streams = DASHStream.parse_manifest(self.session, self.test_url)
        mpdClass.assert_called_with(ANY,
                                    base_url="http://test.bar",
                                    url="http://test.bar/foo.mpd")

        self.assertSequenceEqual(
            sorted(list(streams.keys())),
            sorted(["720p+a128k", "1080p+a128k", "720p+a256k", "1080p+a256k"]))
Ejemplo n.º 7
0
    def test_parse_manifest_with_duplicated_resolutions(self, mpdClass):
        """
            Verify the fix for https://github.com/streamlink/streamlink/issues/3365
        """
        mpdClass.return_value = Mock(periods=[
            Mock(adaptationSets=[
                Mock(contentProtection=None,
                     representations=[
                         Mock(id=1,
                              mimeType="video/mp4",
                              height=1080,
                              bandwidth=128.0),
                         Mock(id=2,
                              mimeType="video/mp4",
                              height=1080,
                              bandwidth=64.0),
                         Mock(id=3,
                              mimeType="video/mp4",
                              height=1080,
                              bandwidth=32.0),
                         Mock(id=4, mimeType="video/mp4", height=720),
                     ])
            ])
        ])

        streams = DASHStream.parse_manifest(self.session, self.test_url)
        mpdClass.assert_called_with(ANY,
                                    base_url="http://test.bar",
                                    url="http://test.bar/foo.mpd")

        self.assertSequenceEqual(
            sorted(list(streams.keys())),
            sorted(["720p", "1080p", "1080p_alt", "1080p_alt2"]))
Ejemplo n.º 8
0
    def _get_streams(self):
        streamdata = None
        if self.get_option("email"):
            if self.login(self.get_option("email"), self.get_option("password")):
                log.info("Logged in as {0}".format(self.get_option("email")))
                self.save_cookies(lambda c: "steamMachineAuth" in c.name)

        # Handle steam.tv URLs
        if self.matches[1] is not None:
            # extract the steam ID from the page
            res = self.session.http.get(self.url)
            for div in itertags(res.text, 'div'):
                if div.attributes.get("id") == "webui_config":
                    broadcast_data = html_unescape(div.attributes.get("data-broadcast"))
                    steamid = parse_json(broadcast_data).get("steamid")
                    self.url = self._watch_broadcast_url + steamid

        # extract the steam ID from the URL
        steamid = self.match.group(1)
        res = self.session.http.get(self.url)  # get the page to set some cookies
        sessionid = res.cookies.get('sessionid')

        while streamdata is None or streamdata["success"] in ("waiting", "waiting_for_start"):
            streamdata = self._get_broadcast_stream(steamid,
                                                    sessionid=sessionid)

            if streamdata["success"] == "ready":
                return DASHStream.parse_manifest(self.session, streamdata["url"])
            elif streamdata["success"] == "unavailable":
                log.error("This stream is currently unavailable")
                return
            else:
                r = streamdata["retry"] / 1000.0
                log.info("Waiting for stream, will retry again in {} seconds...".format(r))
                time.sleep(r)
Ejemplo n.º 9
0
    def _get_streams(self):
        data = self.match.groupdict()
        url = update_scheme("https://", data.get("url"), force=False)
        params = parse_params(data.get("params"))
        log.debug(f"URL={url}; params={params}")

        return DASHStream.parse_manifest(self.session, url, **params)
Ejemplo n.º 10
0
def test_dash_stream_url(session, common_args, expected_headers):
    # DASHStream requires an MPD instance as input:
    # The URL of the MPD instance was already prepared by DASHStream.parse_manifest, so copy this behavior here.
    # This test verifies that session params, headers, etc. are added to the JSON data, without duplicates.
    args = common_args.copy()
    args.update(url="http://host/stream.mpd?foo=bar")
    url = session.http.prepare_new_request(**args).url

    mpd = Mock(url=url)
    stream = DASHStream(session, mpd, **common_args)
    assert stream.__json__() == {
        "type": "dash",
        "url":
        "http://host/stream.mpd?foo=bar&sessionqueryparamkey=sessionqueryparamval&queryparamkey=queryparamval",
        "headers": expected_headers,
    }
Ejemplo n.º 11
0
    def test_parse_manifest_audio_multi_lang_locale(self, mpdClass):
        self.session.localization.language.alpha2 = "es"
        self.session.localization.explicit = True

        mpdClass.return_value = Mock(periods=[
            Mock(adaptationSets=[
                Mock(contentProtection=None,
                     representations=[
                         Mock(id=1, mimeType="video/mp4", height=720),
                         Mock(id=2, mimeType="video/mp4", height=1080),
                         Mock(id=3,
                              mimeType="audio/aac",
                              bandwidth=128.0,
                              lang='en'),
                         Mock(id=4,
                              mimeType="audio/aac",
                              bandwidth=128.0,
                              lang='es')
                     ])
            ])
        ])

        streams = DASHStream.parse_manifest(self.session, self.test_url)
        mpdClass.assert_called_with(ANY,
                                    base_url="http://test.bar",
                                    url="http://test.bar/foo.mpd")

        self.assertSequenceEqual(sorted(list(streams.keys())),
                                 sorted(["720p", "1080p"]))

        self.assertEqual(streams["720p"].audio_representation.lang, "es")
        self.assertEqual(streams["1080p"].audio_representation.lang, "es")
Ejemplo n.º 12
0
    def mediaselector(self, vpid):
        urls = defaultdict(set)
        for platform in self.platforms:
            url = self.api_url.format(vpid=vpid, vpid_hash=self._hash_vpid(vpid),
                                      platform=platform)
            log.debug("Info API request: {0}", url)
            medias = self.session.http.get(url, schema=self.mediaselector_schema)
            for media in medias:
                for connection in media["connection"]:
                    urls[connection.get("transferFormat")].add(connection["href"])

        for stream_type, urls in urls.items():
            log.debug("{0} {1} streams", len(urls), stream_type)
            for url in list(urls):
                try:
                    if stream_type == "hds":
                        for s in HDSStream.parse_manifest(self.session,
                                                          url).items():
                            yield s
                    if stream_type == "hls":
                        for s in HLSStream.parse_variant_playlist(self.session,
                                                                  url).items():
                            yield s
                    if stream_type == "dash":
                        for s in DASHStream.parse_manifest(self.session,
                                                           url).items():
                            yield s
                    log.debug("  OK:   {0}", url)
                except:
                    log.debug("  FAIL: {0}", url)
Ejemplo n.º 13
0
    def _get_streams(self):
        api_urls = self.session.http.get(self.url,
                                         schema=self.channel_id_schema)
        _api_url = list(api_urls)[0]
        log.debug("API URL: {0}".format(_api_url))
        player_api_url = self.session.http.get(_api_url,
                                               schema=self.player_api_schema)
        for api_url in player_api_url:
            log.debug("Player API URL: {0}".format(api_url))
            for source in self.session.http.get(api_url,
                                                schema=self.stream_schema):
                log.debug("Stream source: {0} ({1})".format(
                    source['src'], source.get("type", "n/a")))

                if "type" not in source or source[
                        "type"] == "application/vnd.apple.mpegurl":
                    streams = HLSStream.parse_variant_playlist(
                        self.session, source["src"])
                    if not streams:
                        yield "live", HLSStream(self.session, source["src"])
                    else:
                        yield from streams.items()
                elif source["type"] == "application/dash+xml":
                    yield from DASHStream.parse_manifest(
                        self.session, source["src"]).items()
Ejemplo n.º 14
0
    def mediaselector(self, vpid):
        urls = defaultdict(set)
        for platform in self.platforms:
            url = self.api_url.format(vpid=vpid,
                                      vpid_hash=self._hash_vpid(vpid),
                                      platform=platform)
            log.debug(f"Info API request: {url}")
            medias = self.session.http.get(url,
                                           schema=self.mediaselector_schema)
            for media in medias:
                for connection in media["connection"]:
                    urls[connection.get("transferFormat")].add(
                        connection["href"])

        for stream_type, urls in urls.items():
            log.debug(f"{len(urls)} {stream_type} streams")
            for url in list(urls):
                try:
                    if stream_type == "hds":
                        yield from HDSStream.parse_manifest(self.session,
                                                            url).items()
                    if stream_type == "hls":
                        yield from HLSStream.parse_variant_playlist(
                            self.session, url).items()
                    if stream_type == "dash":
                        yield from DASHStream.parse_manifest(
                            self.session, url).items()
                    log.debug(f"  OK:   {url}")
                except Exception:
                    log.debug(f"  FAIL: {url}")
def test_dash_stream_url(session, common_args):
    # DASHStream requires an MPD instance as input:
    # The URL of the MPD instance was already prepared by DASHStream.parse_manifest, so copy this behavior here.
    # This test verifies that session params are added to the URL, without duplicates.
    args = common_args.copy()
    args.update(url="http://host/stream.mpd?foo=bar")
    url = session.http.prepare_new_request(**args).url
    mpd = Mock(url=url)
    stream = DASHStream(session, mpd, **common_args)
    assert stream.to_url(
    ) == "http://host/stream.mpd?foo=bar&queryparamkey=queryparamval"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(
        cm.value
    ) == "<DASHStream [dash]> cannot be translated to a manifest URL"
Ejemplo n.º 16
0
 def _get_streams(self):
     m = self.match
     if m:
         channel = m.group(1) or m.group(2)
         log.debug("Found channel {0}".format(channel))
         for sformat, url in self.get_stream_urls(channel):
             try:
                 if sformat == "dash":
                     yield from DASHStream.parse_manifest(
                         self.session,
                         url,
                         headers={
                             "User-Agent": useragents.CHROME
                         }).items()
                 if sformat == "hls":
                     yield from HLSStream.parse_variant_playlist(
                         self.session,
                         url,
                         headers={
                             "User-Agent": useragents.IPHONE
                         },
                     ).items()
             except PluginError as e:
                 log.error("Could not open {0} stream".format(sformat))
                 log.debug("Failed with error: {0}".format(e))
Ejemplo n.º 17
0
    def _get_streams(self):
        streamdata = None
        if self.get_option("email"):
            if self.login(self.get_option("email"),
                          self.get_option("password")):
                log.info("Logged in as {0}".format(self.get_option("email")))
                self.save_cookies(lambda c: "steamMachineAuth" in c.name)

        # extract the steam ID from the URL
        steamid = self._url_re.match(self.url).group(1)

        while streamdata is None or streamdata[u"success"] in (
                "waiting", "waiting_for_start"):
            streamdata = self._get_broadcast_stream(steamid)

            if streamdata[u"success"] == "ready":
                return DASHStream.parse_manifest(self.session,
                                                 streamdata["url"])
            elif streamdata[u"success"] == "unavailable":
                log.error("This stream is currently unavailable")
                return
            else:
                r = streamdata[u"retry"] / 1000.0
                log.info(
                    "Waiting for stream, will retry again in {} seconds...".
                    format(r))
                time.sleep(r)
Ejemplo n.º 18
0
    def _get_video_streams(self):
        res = self.session.http.get(self.url)
        match = self._video_player_re.search(res.text)
        if match is None:
            return
        player_url = match.group('player_url')
        stream_data = self.session.http.get(player_url, schema=self._video_stream_schema)
        if stream_data is None:
            return

        # Check geolocation to prevent further errors when stream is parsed
        if not self.check_geolocation(stream_data['geoLocRestriction']):
            log.error('Stream is geo-restricted')
            return

        # Check whether streams are DRM-protected
        if stream_data.get('drm', False):
            log.error('Stream is DRM-protected')
            return

        now = datetime.datetime.now()
        try:
            if isinstance(stream_data['sources'], dict):
                urls = []
                for profile, url in stream_data['sources'].items():
                    if not url or url in urls:
                        continue
                    match = self._stream_size_re.match(url)
                    if match is not None:
                        quality = match.group('size')
                    else:
                        quality = profile
                    yield quality, HTTPStream(self.session, url)
                    urls.append(url)

            hls_url = stream_data.get('urlHls') or stream_data.get('streamUrlHls')
            if hls_url:
                if stream_data.get('isLive', False):
                    # Live streams require a token
                    hls_url = self.tokenize_stream(hls_url)
                yield from HLSStream.parse_variant_playlist(self.session, hls_url).items()

            dash_url = stream_data.get('urlDash') or stream_data.get('streamUrlDash')
            if dash_url:
                if stream_data.get('isLive', False):
                    # Live streams require a token
                    dash_url = self.tokenize_stream(dash_url)
                yield from DASHStream.parse_manifest(self.session, dash_url).items()

        except OSError as err:
            if '403 Client Error' in str(err):
                # Check whether video is expired
                if 'startDate' in stream_data:
                    if now < self.iso8601_to_epoch(stream_data['startDate']):
                        log.error('Stream is not yet available')
                elif 'endDate' in stream_data:
                    if now > self.iso8601_to_epoch(stream_data['endDate']):
                        log.error('Stream has expired')
Ejemplo n.º 19
0
    def _parse_streams(self, res):
        _found_stream_url = False
        for meta in itertags(res.text, "meta"):
            if meta.attributes.get("property") == "og:video:url":
                stream_url = html_unescape(meta.attributes.get("content"))
                if ".mpd" in stream_url:
                    for s in DASHStream.parse_manifest(self.session,
                                                       stream_url).items():
                        yield s
                        _found_stream_url = True
                elif ".mp4" in stream_url:
                    yield "vod", HTTPStream(self.session, stream_url)
                    _found_stream_url = True
                break
        else:
            log.debug("No meta og:video:url")

        if _found_stream_url:
            return

        for match in self._src_re.finditer(res.text):
            stream_url = match.group("url")
            if "\\/" in stream_url:
                # if the URL is json encoded, decode it
                stream_url = parse_json("\"{}\"".format(stream_url))
            if ".mpd" in stream_url:
                yield from DASHStream.parse_manifest(self.session,
                                                     stream_url).items()
            elif ".mp4" in stream_url:
                yield match.group(1), HTTPStream(self.session, stream_url)
            else:
                log.debug("Non-dash/mp4 stream: {0}".format(stream_url))

        match = self._dash_manifest_re.search(res.text)
        if match:
            # facebook replaces "<" characters with the substring "\\x3C"
            manifest = match.group("manifest").replace("\\/", "/")
            manifest = bytes(unquote_plus(manifest),
                             "utf-8").decode("unicode_escape")
            # Ignore unsupported manifests until DASH SegmentBase support is implemented
            if "SegmentBase" in manifest:
                log.error("Skipped DASH manifest with SegmentBase streams")
            else:
                yield from DASHStream.parse_manifest(self.session,
                                                     manifest).items()
Ejemplo n.º 20
0
    def _get_streams(self):
        if "player.vimeo.com" in self.url:
            data = self.session.http.get(self.url, schema=self._player_schema)
        else:
            api_url = self.session.http.get(self.url,
                                            schema=self._config_url_schema)
            if not api_url:
                return
            data = self.session.http.get(api_url, schema=self._config_schema)

        videos = data["request"]["files"]
        streams = []

        for stream_type in ("hls", "dash"):
            if stream_type not in videos:
                continue
            for _, video_data in videos[stream_type]["cdns"].items():
                log.trace("{0!r}".format(video_data))
                url = video_data.get("url")
                if stream_type == "hls":
                    for stream in HLSStream.parse_variant_playlist(
                            self.session, url).items():
                        streams.append(stream)
                elif stream_type == "dash":
                    p = urlparse(url)
                    if p.path.endswith("dash.mpd"):
                        # LIVE
                        url = self.session.http.get(url).json()["url"]
                    elif p.path.endswith("master.json"):
                        # VOD
                        url = url.replace("master.json", "master.mpd")
                    else:
                        log.error("Unsupported DASH path: {0}".format(p.path))
                        continue

                    for stream in DASHStream.parse_manifest(self.session,
                                                            url).items():
                        streams.append(stream)

        for stream in videos.get("progressive", []):
            streams.append(
                (stream["quality"], HTTPStream(self.session, stream["url"])))

        if self.get_option("mux_subtitles") and data["request"].get(
                "text_tracks"):
            substreams = {
                s["lang"]: HTTPStream(self.session,
                                      "https://vimeo.com" + s["url"])
                for s in data["request"]["text_tracks"]
            }
            for quality, stream in streams:
                yield quality, MuxedStream(self.session,
                                           stream,
                                           subtitles=substreams)
        else:
            for stream in streams:
                yield stream
Ejemplo n.º 21
0
    def test_stream_open_video_audio(self, muxer, reader):
        stream = DASHStream(self.session, Mock(),
                            Mock(id=1, mimeType="video/mp4"),
                            Mock(id=2, mimeType="audio/mp3", lang='en'))
        open_reader = reader.return_value = Mock()

        stream.open()

        self.assertSequenceEqual(reader.mock_calls, [
            call(stream, 1, "video/mp4"),
            call().open(),
            call(stream, 2, "audio/mp3"),
            call().open()
        ])
        self.assertSequenceEqual(muxer.mock_calls, [
            call(self.session, open_reader, open_reader, copyts=True),
            call().open()
        ])
Ejemplo n.º 22
0
    def test_segments_number_time(self, mpdClass):
        with xml("dash/test_9.mpd") as mpd_xml:
            mpdClass.return_value = MPD(mpd_xml,
                                        base_url="http://test.bar",
                                        url="http://test.bar/foo.mpd")

            streams = DASHStream.parse_manifest(self.session, self.test_url)
            mpdClass.assert_called_with(ANY,
                                        base_url="http://test.bar",
                                        url="http://test.bar/foo.mpd")

            self.assertSequenceEqual(list(streams.keys()), ['2500k'])
Ejemplo n.º 23
0
    def _get_streams(self):
        self._get_cookies()
        self.follow_vk_redirect()

        video_id = self.match.group("video_id")
        if not video_id:
            return

        log.debug(f"Video ID: {video_id}")
        try:
            data = self.session.http.post(
                self.API_URL,
                params={"act": "show"},
                data={
                    "act": "show",
                    "al": "1",
                    "video": video_id
                },
                headers={"Referer": self.url},
                schema=validate.Schema(
                    validate.transform(
                        lambda text: re.sub(r"^\s*<!--\s*", "", text)),
                    validate.parse_json(), {"payload": list},
                    validate.get(("payload", -1)), list, validate.get(-1),
                    {"player": {
                        "params": [dict]
                    }}, validate.get(("player", "params", 0)), {
                        validate.optional("hls"): validate.url(),
                        validate.optional("manifest"):
                        validate.startswith("<?xml"),
                        validate.optional("md_author"): validate.any(
                            str, None),
                        validate.optional("md_title"): validate.any(str, None),
                    }))
        except PluginError:
            log.error("Could not parse API response")
            return

        self.id = video_id
        self.author = data.get("md_author")
        self.title = data.get("md_title")

        hls = data.get("hls")
        if hls:
            return HLSStream.parse_variant_playlist(self.session, hls)

        dash_manifest = data.get("manifest")
        if dash_manifest:
            return DASHStream.parse_manifest(self.session, dash_manifest)
Ejemplo n.º 24
0
    def _get_streams(self):
        root = self.session.http.get(self.url,
                                     schema=validate.Schema(
                                         validate.parse_html()))

        for needle, errormsg in (
            (
                "This service is not available in your Country",
                "The content is not available in your region",
            ),
            (
                "Silahkan login Menggunakan akun MyIndihome dan berlangganan minipack",
                "The content is not available without a subscription",
            ),
        ):
            if validate.Schema(
                    validate.xml_xpath(
                        """.//script[contains(text(), '"{0}"')]""".format(
                            needle))).validate(root):
                log.error(errormsg)
                return

        url = validate.Schema(
            validate.any(
                validate.all(
                    validate.xml_xpath_string("""
                        .//script[contains(text(), 'laylist.m3u8') or contains(text(), 'manifest.mpd')][1]/text()
                    """),
                    validate.text,
                    validate.transform(
                        re.compile(
                            r"""(?P<q>['"])(?P<url>https://.*?/(?:[Pp]laylist\.m3u8|manifest\.mpd).+?)(?P=q)"""
                        ).search),
                    validate.any(
                        None, validate.all(validate.get("url"),
                                           validate.url())),
                ),
                validate.all(
                    validate.xml_xpath_string(
                        ".//video[@id='video-player']/source/@src"),
                    validate.any(None, validate.url()),
                ),
            )).validate(root)

        if url and ".m3u8" in url:
            return HLSStream.parse_variant_playlist(self.session, url)
        elif url and ".mpd" in url:
            return DASHStream.parse_manifest(self.session, url)
def test_dash_stream(session):
    mpd = Mock(url=None)
    stream = DASHStream(session, mpd)
    with pytest.raises(TypeError) as cm:
        stream.to_url()
    assert str(cm.value) == "<DASHStream [dash]> cannot be translated to a URL"
    with pytest.raises(TypeError) as cm:
        stream.to_manifest_url()
    assert str(
        cm.value
    ) == "<DASHStream [dash]> cannot be translated to a manifest URL"
Ejemplo n.º 26
0
    def _get_live(self, path):
        match = self.live_id_re.search(path)
        if match is None:
            return

        live_id = "ch-{0}".format(match.group('live_id'))
        log.debug("Live ID={0}".format(live_id))

        res = self.session.http.get(self.api_url.format(live_id))
        api_data = self.session.http.json(res, schema=self._video_schema)

        self._set_metadata(api_data, 'Live')

        for playlist in api_data['videoReferences']:
            if playlist['format'] == 'dashhbbtv':
                yield from DASHStream.parse_manifest(self.session,
                                                     playlist['url']).items()
Ejemplo n.º 27
0
    def test_parse_manifest_video_only(self, mpdClass):
        mpdClass.return_value = Mock(periods=[
            Mock(adaptationSets=[
                Mock(contentProtection=None,
                     representations=[
                         Mock(id=1, mimeType="video/mp4", height=720),
                         Mock(id=2, mimeType="video/mp4", height=1080)
                     ])
            ])
        ])

        streams = DASHStream.parse_manifest(self.session, self.test_url)
        mpdClass.assert_called_with(ANY,
                                    base_url="http://test.bar",
                                    url="http://test.bar/foo.mpd")

        self.assertSequenceEqual(sorted(list(streams.keys())),
                                 sorted(["720p", "1080p"]))
Ejemplo n.º 28
0
 def _get_streams_api(self, video_id):
     res = self.session.http.get(self.api_server,
                                 params=dict(video_id=video_id))
     data = self.session.http.json(res)
     if data["success"]:
         for x in itertools.chain(*data['data']['versions'].values()):
             src = update_scheme("https://", x["src"], force=False)
             if x['type'] == "application/x-mpegurl":
                 yield from HLSStream.parse_variant_playlist(
                     self.session, src).items()
             elif x['type'] == "application/dash+xml":
                 yield from DASHStream.parse_manifest(self.session,
                                                      src).items()
             elif x['type'] == "video/mp4":
                 yield "{0}p".format(x['res']), HTTPStream(
                     self.session, src)
     else:
         log.error("Failed to get streams: {0} ({1})".format(
             data['message'], data['code']))
Ejemplo n.º 29
0
    def _get_streams(self):
        stream_id, has_token, hls_url, dash_url = self.session.http.get(
            self.url,
            schema=validate.Schema(
                validate.parse_html(),
                validate.xml_find(".//*[@data-video-id]"),
                validate.union((
                    validate.get("data-video-id"),
                    validate.all(
                        validate.get("data-video-has-token"),
                        validate.transform(lambda val: val and val != "false"),
                    ),
                    validate.get("data-vjs-clip-hls-url"),
                    validate.get("data-vjs-clip-dash-url"),
                )),
            ),
        )

        if dash_url and has_token:
            token = self._get_stream_token(stream_id, "dash")
            parsed = urlsplit(dash_url)
            dash_url = urlunsplit(
                parsed._replace(path=f"{token}{parsed.path}"))
            return DASHStream.parse_manifest(
                self.session,
                dash_url,
                headers={"Referer": self.url},
            )

        if not hls_url:
            return

        if has_token:
            token = self._get_stream_token(stream_id, "hls")
            hls_url = f"{hls_url}?{token}"

        return HLSStream.parse_variant_playlist(
            self.session,
            hls_url,
            headers={"Referer": self.url},
        )
Ejemplo n.º 30
0
    def _get_vod(self):
        vod_id = self._get_vod_id(self.url)

        if vod_id is None:
            res = self.session.http.get(self.url)
            match = self.latest_episode_url_re.search(res.text)
            if match is None:
                return
            vod_id = self._get_vod_id(match.group("url"))

        if vod_id is None:
            return

        log.debug("VOD ID={0}".format(vod_id))

        res = self.session.http.get(self.api_url.format(vod_id))
        api_data = self.session.http.json(res, schema=self._video_schema)

        self._set_metadata(api_data, 'VOD')

        substreams = {}
        if 'subtitleReferences' in api_data:
            for subtitle in api_data['subtitleReferences']:
                if subtitle['format'] == 'webvtt':
                    log.debug("Subtitle={0}".format(subtitle['url']))
                    substreams[subtitle['format']] = HTTPStream(
                        self.session,
                        subtitle['url'],
                    )

        for manifest in api_data['videoReferences']:
            if manifest['format'] == 'dashhbbtv':
                for q, s in DASHStream.parse_manifest(self.session,
                                                      manifest['url']).items():
                    if self.get_option('mux_subtitles') and substreams:
                        yield q, MuxedStream(self.session,
                                             s,
                                             subtitles=substreams)
                    else:
                        yield q, s
Ejemplo n.º 31
0
    def _get_streams(self):
        page = self.session.http.get(self.url)
        api_info = self._get_api_info(page)

        if not api_info:
            log.error("Could not find API info in page")
            return

        token_res = self.session.http.post(api_info["token_url"])
        token = self.session.http.json(token_res, schema=self._token_schema)

        log.debug("Got token: {0}".format(token))
        log.debug("Getting stream data: {0}".format(api_info["stream_url"]))
        res = self.session.http.get(api_info["stream_url"],
                                    params={
                                        "vrtPlayerToken": token,
                                        "client": "vrtvideo"
                                    },
                                    raise_for_status=False)
        data = self.session.http.json(res, schema=self._stream_schema)

        if "code" in data:
            log.error("{0} ({1})".format(data['message'], data['code']))
            return

        log.debug(
            "Streams have {0}DRM".format("no " if not data["drm"] else ""))

        for target in data["targetUrls"]:
            if data["drm"]:
                if target["type"] == "hls_aes":
                    yield from HLSStream.parse_variant_playlist(
                        self.session, target["url"]).items()
            elif target["type"] == "hls":
                yield from HLSStream.parse_variant_playlist(
                    self.session, target["url"]).items()
            elif target["type"] == "mpeg_dash":
                yield from DASHStream.parse_manifest(self.session,
                                                     target["url"]).items()
Ejemplo n.º 32
0
    def _watch(self):
        log.debug('_watch ...')
        channel = self.match.group('channel')
        vod_id = self.match.group('vod_id')
        recording_id = self.match.group('recording_id')

        params = {'https_watch_urls': True}
        if channel:
            watch_url = f'{self.base_url}/zapi/watch'
            params_cid = self._get_params_cid(channel)
            if not params_cid:
                return
            params.update(params_cid)
        elif vod_id:
            log.debug('Found vod_id: {0}'.format(vod_id))
            watch_url = f'{self.base_url}/zapi/avod/videos/{vod_id}/watch'
        elif recording_id:
            log.debug('Found recording_id: {0}'.format(recording_id))
            watch_url = f'{self.base_url}/zapi/watch/recording/{recording_id}'
        else:
            log.debug('Missing watch_url')
            return

        zattoo_stream_types = self.get_option('stream-types')
        for stream_type in zattoo_stream_types:
            params_stream_type = {'stream_type': stream_type}
            params.update(params_stream_type)

            data = self.session.http.post(
                watch_url,
                headers=self.headers,
                data=params,
                acceptable_status=(200, 402, 403, 404),
                schema=validate.Schema(validate.parse_json(), validate.any({
                    'success': validate.transform(bool),
                    'stream': {
                        'watch_urls': [{
                            'url': validate.url(),
                            validate.optional('maxrate'): int,
                            validate.optional('audio_channel'): str,
                        }],
                        validate.optional('quality'): str,
                    },
                }, {
                    'success': validate.transform(bool),
                    'internal_code': int,
                    validate.optional('http_status'): int,
                })),
            )

            if not data['success']:
                if data['internal_code'] == 401:
                    log.error(f'invalid stream_type {stream_type}')
                elif data['internal_code'] == 421:
                    log.error('Unfortunately streaming is not permitted in this country or this channel does not exist.')
                elif data['internal_code'] == 422:
                    log.error('Paid subscription required for this channel.')
                    log.info('If paid subscription exist, use --zattoo-purge-credentials to start a new session.')
                else:
                    log.debug(f'unknown error {data!r}')
                    log.debug('Force session reset for watch_url')
                    self.reset_session()
                continue

            log.debug(f'Found data for {stream_type}')
            if stream_type == 'hls7':
                for url in data['stream']['watch_urls']:
                    yield from HLSStream.parse_variant_playlist(self.session, url['url']).items()
            elif stream_type == 'dash':
                for url in data['stream']['watch_urls']:
                    yield from DASHStream.parse_manifest(self.session, url['url']).items()
Ejemplo n.º 33
0
    def _get_streams(self):
        mpdurl = self._url_re.match(self.url).group(2)

        self.logger.debug("Parsing MPD URL: {0}".format(mpdurl))

        return DASHStream.parse_manifest(self.session, mpdurl)