src/streamlink/stream/hds.py
def parse_manifest(cls, session, url, timeout=60, pvswf=None, is_akamai=False,
                       **request_params):
        """Parses a HDS manifest and returns its substreams.

        :param url: The URL to the manifest.
        :param timeout: How long to wait for data to be returned from
                        from the stream before raising an error.
        :param is_akamai: force adding of the akamai parameters
        :param pvswf: URL of player SWF for Akamai HD player verification.
        """
        # private argument, should only be used in recursive calls
        raise_for_drm = request_params.pop("raise_for_drm", False)

        if not request_params:
            request_params = {}

        request_params["headers"] = request_params.get("headers", {})
        request_params["params"] = request_params.get("params", {})

        # These params are reserved for internal use
        request_params.pop("exception", None)
        request_params.pop("stream", None)
        request_params.pop("timeout", None)
        request_params.pop("url", None)

        if "akamaihd" in url or is_akamai:
            request_params["params"]["hdcore"] = HDCORE_VERSION
            request_params["params"]["g"] = cls.cache_buster_string(12)

        res = session.http.get(url, exception=IOError, **request_params)
        manifest = session.http.xml(res, "manifest XML", ignore_ns=True,
                                    exception=IOError)

        if manifest.findtext("drmAdditionalHeader"):
            log.debug("Omitting HDS stream protected by DRM: {}", url)
            if raise_for_drm:
                raise PluginError("{} is protected by DRM".format(url))
            log.warning("Some or all streams are unavailable as they are protected by DRM")
            return {}

        parsed = urlparse(url)
        baseurl = manifest.findtext("baseURL")
        baseheight = manifest.findtext("height")
        bootstraps = {}
        streams = {}

        if not baseurl:
            baseurl = urljoin(url, os.path.dirname(parsed.path))

        if not baseurl.endswith("/"):
            baseurl += "/"

        for bootstrap in manifest.findall("bootstrapInfo"):
            name = bootstrap.attrib.get("id") or "_global"
            url = bootstrap.attrib.get("url")

            if url:
                box = absolute_url(baseurl, url)
            else:
                data = base64.b64decode(bytes(bootstrap.text, "utf8"))
                box = Box.deserialize(BytesIO(data))

            bootstraps[name] = box

        pvtoken = manifest.findtext("pv-2.0")
        if pvtoken:
            if not pvswf:
                raise IOError("This manifest requires the 'pvswf' parameter "
                              "to verify the SWF")

            params = cls._pv_params(session, pvswf, pvtoken, **request_params)
            request_params["params"].update(params)

        child_drm = False

        for media in manifest.findall("media"):
            url = media.attrib.get("url")
            bootstrapid = media.attrib.get("bootstrapInfoId", "_global")
            href = media.attrib.get("href")

            if url and bootstrapid:
                bootstrap = bootstraps.get(bootstrapid)

                if not bootstrap:
                    continue

                bitrate = media.attrib.get("bitrate")
                streamid = media.attrib.get("streamId")
                height = media.attrib.get("height")

                if height:
                    quality = height + "p"
                elif bitrate:
                    quality = bitrate + "k"
                elif streamid:
                    quality = streamid
                elif baseheight:
                    quality = baseheight + "p"
                else:
                    quality = "live"

                metadata = media.findtext("metadata")

                if metadata:
                    metadata = base64.b64decode(bytes(metadata, "utf8"))
                    metadata = ScriptData.deserialize(BytesIO(metadata))
                else:
                    metadata = None

                stream = HDSStream(session, baseurl, url, bootstrap,
                                   metadata=metadata, timeout=timeout,
                                   **request_params)
                streams[quality] = stream

            elif href:
                url = absolute_url(baseurl, href)
                try:
                    child_streams = cls.parse_manifest(session, url,
                                                       timeout=timeout,
                                                       is_akamai=is_akamai,
                                                       raise_for_drm=True,
                                                       **request_params)
                except PluginError:
                    child_drm = True
                    child_streams = {}

                for name, stream in child_streams.items():
                    # Override stream name if bitrate is available in parent
                    # manifest but not the child one.
                    bitrate = media.attrib.get("bitrate")

                    if bitrate and not re.match(r"^(\d+)k$", name):
                        name = bitrate + "k"

                    streams[name] = stream
        if child_drm:
            log.warning("Some or all streams are unavailable as they are protected by DRM")

        return streams
def parse_manifest(cls, session, url, timeout=60, pvswf=None, is_akamai=False,
                       **request_params):
        """Parses a HDS manifest and returns its substreams.

        :param url: The URL to the manifest.
        :param timeout: How long to wait for data to be returned from
                        from the stream before raising an error.
        :param is_akamai: force adding of the akamai parameters
        :param pvswf: URL of player SWF for Akamai HD player verification.
        """
        # private argument, should only be used in recursive calls
        raise_for_drm = request_params.pop("raise_for_drm", False)

        if not request_params:
            request_params = {}

        request_params["headers"] = request_params.get("headers", {})
        request_params["params"] = request_params.get("params", {})

        # These params are reserved for internal use
        request_params.pop("exception", None)
        request_params.pop("stream", None)
        request_params.pop("timeout", None)
        request_params.pop("url", None)

        if "akamaihd" in url or is_akamai:
            request_params["params"]["hdcore"] = HDCORE_VERSION
            request_params["params"]["g"] = cls.cache_buster_string(12)

        res = session.http.get(url, exception=IOError, **request_params)
        manifest = session.http.xml(res, "manifest XML", ignore_ns=True,
                                    exception=IOError)

        if manifest.findtext("drmAdditionalHeader"):
            log.debug("Omitting HDS stream protected by DRM: {}", url)
            if raise_for_drm:
                raise PluginError("{} is protected by DRM".format(url))
            log.warning("Some or all streams are unavailable as they are protected by DRM")
            return {}

        parsed = urlparse(url)
        baseurl = manifest.findtext("baseURL")
        baseheight = manifest.findtext("height")
        bootstraps = {}
        streams = {}

        if not baseurl:
            baseurl = urljoin(url, os.path.dirname(parsed.path))

        if not baseurl.endswith("/"):
            baseurl += "/"

        for bootstrap in manifest.findall("bootstrapInfo"):
            name = bootstrap.attrib.get("id") or "_global"
            url = bootstrap.attrib.get("url")

            if url:
                box = absolute_url(baseurl, url)
            else:
                data = base64.b64decode(bytes(bootstrap.text, "utf8"))
                box = Box.deserialize(BytesIO(data))

            bootstraps[name] = box

        pvtoken = manifest.findtext("pv-2.0")
        if pvtoken:
            if not pvswf:
                raise IOError("This manifest requires the 'pvswf' parameter "
                              "to verify the SWF")

            params = cls._pv_params(session, pvswf, pvtoken, **request_params)
            request_params["params"].update(params)

        child_drm = False

        for media in manifest.findall("media"):
            url = media.attrib.get("url")
            bootstrapid = media.attrib.get("bootstrapInfoId", "_global")
            href = media.attrib.get("href")

            if url and bootstrapid:
                bootstrap = bootstraps.get(bootstrapid)

                if not bootstrap:
                    continue

                bitrate = media.attrib.get("bitrate")
                streamid = media.attrib.get("streamId")
                height = media.attrib.get("height")

                if height:
                    quality = height + "p"
                elif bitrate:
                    quality = bitrate + "k"
                elif streamid:
                    quality = streamid
                elif baseheight:
                    quality = baseheight + "p"
                else:
                    quality = "live"

                metadata = media.findtext("metadata")

                if metadata:
                    metadata = base64.b64decode(bytes(metadata, "utf8"))
                    metadata = ScriptData.deserialize(BytesIO(metadata))
                else:
                    metadata = None

                stream = HDSStream(session, baseurl, url, bootstrap,
                                   metadata=metadata, timeout=timeout,
                                   **request_params)
                streams[quality] = stream

            elif href:
                url = absolute_url(baseurl, href)
                try:
                    child_streams = cls.parse_manifest(session, url,
                                                       timeout=timeout,
                                                       is_akamai=is_akamai,
                                                       raise_for_drm=True,
                                                       **request_params)
                except PluginError:
                    child_drm = True
                    child_streams = {}

                for name, stream in child_streams.items():
                    # Override stream name if bitrate is available in parent
                    # manifest but not the child one.
                    bitrate = media.attrib.get("bitrate")

                    if bitrate and not re.match(r"^(\d+)k$", name):
                        name = bitrate + "k"

                    streams[name] = stream
        if child_drm:
            log.warning("Some or all streams are unavailable as they are protected by DRM")

        return streams
def parse_manifest ( cls , session , url , timeout = 60 , pvswf = None , is_akamai = False , * * request_params ) : # private argument, should only be used in recursive calls raise_for_drm = request_params . pop ( "raise_for_drm" , False ) if not request_params : request_params = { } request_params [ "headers" ] = request_params . get ( "headers" , { } ) request_params [ "params" ] = request_params . get ( "params" , { } ) # These params are reserved for internal use request_params . pop ( "exception" , None ) request_params . pop ( "stream" , None ) request_params . pop ( "timeout" , None ) request_params . pop ( "url" , None ) if "akamaihd" in url or is_akamai : request_params [ "params" ] [ "hdcore" ] = HDCORE_VERSION request_params [ "params" ] [ "g" ] = cls . cache_buster_string ( 12 ) res = session . http . get ( url , exception = IOError , * * request_params ) manifest = session . http . xml ( res , "manifest XML" , ignore_ns = True , exception = IOError ) if manifest . findtext ( "drmAdditionalHeader" ) : log . debug ( "Omitting HDS stream protected by DRM: {}" , url ) if raise_for_drm : raise PluginError ( "{} is protected by DRM" . format ( url ) ) log . warning ( "Some or all streams are unavailable as they are protected by DRM" ) return { } parsed = urlparse ( url ) baseurl = manifest . findtext ( "baseURL" ) baseheight = manifest . findtext ( "height" ) bootstraps = { } streams = { } if not baseurl : baseurl = urljoin ( url , os . path . dirname ( parsed . path ) ) if not baseurl . endswith ( "/" ) : baseurl += "/" for bootstrap in manifest . findall ( "bootstrapInfo" ) : name = bootstrap . attrib . get ( "id" ) or "_global" url = bootstrap . attrib . get ( "url" ) if url : box = absolute_url ( baseurl , url ) else : data = base64 . b64decode ( bytes ( bootstrap . text , "utf8" ) ) box = Box . deserialize ( BytesIO ( data ) ) bootstraps [ name ] = box pvtoken = manifest . findtext ( "pv-2.0" ) if pvtoken : if not pvswf : raise IOError ( "This manifest requires the 'pvswf' parameter " "to verify the SWF" ) params = cls . _pv_params ( session , pvswf , pvtoken , * * request_params ) request_params [ "params" ] . update ( params ) child_drm = False for media in manifest . findall ( "media" ) : url = media . attrib . get ( "url" ) bootstrapid = media . attrib . get ( "bootstrapInfoId" , "_global" ) href = media . attrib . get ( "href" ) if url and bootstrapid : bootstrap = bootstraps . get ( bootstrapid ) if not bootstrap : continue bitrate = media . attrib . get ( "bitrate" ) streamid = media . attrib . get ( "streamId" ) height = media . attrib . get ( "height" ) if height : quality = height + "p" elif bitrate : quality = bitrate + "k" elif streamid : quality = streamid elif baseheight : quality = baseheight + "p" else : quality = "live" metadata = media . findtext ( "metadata" ) if metadata : metadata = base64 . b64decode ( bytes ( metadata , "utf8" ) ) metadata = ScriptData . deserialize ( BytesIO ( metadata ) ) else : metadata = None stream = HDSStream ( session , baseurl , url , bootstrap , metadata = metadata , timeout = timeout , * * request_params ) streams [ quality ] = stream elif href : url = absolute_url ( baseurl , href ) try : child_streams = cls . parse_manifest ( session , url , timeout = timeout , is_akamai = is_akamai , raise_for_drm = True , * * request_params ) except PluginError : child_drm = True child_streams = { } for name , stream in child_streams . items ( ) : # Override stream name if bitrate is available in parent # manifest but not the child one. bitrate = media . attrib . get ( "bitrate" ) if bitrate and not re . match ( r"^(\d+)k$" , name ) : name = bitrate + "k" streams [ name ] = stream if child_drm : log . warning ( "Some or all streams are unavailable as they are protected by DRM" ) return streams
Parses a HDS manifest and returns its substreams.

        :param url: The URL to the manifest.
        :param timeout: How long to wait for data to be returned from
                        from the stream before raising an error.
        :param is_akamai: force adding of the akamai parameters
        :param pvswf: URL of player SWF for Akamai HD player verification.
Parses a HDS manifest and returns its substreams .