Exemple #1
0
def update_scheme(current, target, force=True):
    # type: (str, str, bool) -> str
    """
    Take the scheme from the current URL and apply it to the target URL if it is missing
    :param current: current URL
    :param target: target URL
    :param force: always apply the current scheme to the target, even if a target scheme exists
    :return: target URL with the current URL's scheme
    """
    target_p = urlparse(target)

    if (
            # target URLs with implicit scheme and netloc including a port: ("http://", "foo.bar:1234") -> "http://foo.bar:1234"
            # urllib.parse.urlparse has incorrect behavior in py<3.9, so we'll have to use a regex here
            # py>=3.9: urlparse("127.0.0.1:1234") == ParseResult(scheme='127.0.0.1', netloc='', path='1234', ...)
            # py<3.9 : urlparse("127.0.0.1:1234") == ParseResult(scheme='', netloc='', path='127.0.0.1:1234', ...)
            not _re_uri_implicit_scheme.search(target)
            and not target.startswith("//")
            # target URLs without scheme and netloc: ("http://", "foo.bar/foo") -> "http://foo.bar/foo"
            or not target_p.scheme and not target_p.netloc):
        return "{0}://{1}".format(
            urlparse(current).scheme, urlunparse(target_p))

    # target URLs without scheme but with netloc: ("http://", "//foo.bar/foo") -> "http://foo.bar/foo"
    if not target_p.scheme and target_p.netloc:
        return "{0}:{1}".format(urlparse(current).scheme, urlunparse(target_p))

    # target URLs with scheme
    # override the target scheme
    if force:
        return urlunparse(target_p._replace(scheme=urlparse(current).scheme))

    # keep the target scheme
    return target
Exemple #2
0
def update_scheme(current, target):
    """
    Take the scheme from the current URL and applies it to the
    target URL if the target URL startswith // or is missing a scheme
    :param current: current URL
    :param target: target URL
    :return: target URL with the current URLs scheme
    """
    target_p = urlparse(target)
    if not target_p.scheme and target_p.netloc:
        return "{0}:{1}".format(urlparse(current).scheme, urlunparse(target_p))
    elif not target_p.scheme and not target_p.netloc:
        return "{0}://{1}".format(urlparse(current).scheme, urlunparse(target_p))
    else:
        return target
Exemple #3
0
    def _get_streams(self):
        zdf_json = self.session.http.get(self.url, schema=_api_schema)
        if zdf_json is None:
            return

        headers = {
            "Accept": "application/vnd.de.zdf.v1.0+json",
            "Api-Auth": "Bearer {0}".format(zdf_json['apiToken']),
            "Referer": self.url
        }

        res = self.session.http.get(zdf_json['content'], headers=headers)
        document = self.session.http.json(res, schema=_documents_schema)

        document_url_p = urlparse(zdf_json['content'])
        api_url = urlunparse(
            (document_url_p.scheme, document_url_p.netloc, "", "", "", ""))

        content = document["mainVideoContent"]
        target = content["http://zdf.de/rels/target"]
        template = target["http://zdf.de/rels/streams/ptmd-template"]
        stream_request_url = url_concat(
            api_url,
            template.format(playerId="ngplayer_2_3").replace(" ", ""))

        res = self.session.http.get(stream_request_url, headers=headers)
        res = self.session.http.json(res, schema=_schema)

        streams = {}
        for format_ in self._extract_streams(res):
            streams.update(format_)

        return streams
    def __init__(self, node, root=None, parent=None, url=None, *args, **kwargs):
        # top level has no parent
        super(MPD, self).__init__(node, root=self, *args, **kwargs)
        # parser attributes
        self.url = url
        self.timelines = defaultdict(lambda: -1)
        self.timelines.update(kwargs.pop("timelines", {}))
        self.id = self.attr(u"id")
        self.profiles = self.attr(u"profiles", required=True)
        self.type = self.attr(u"type", default=u"static", parser=MPDParsers.type)
        self.minimumUpdatePeriod = self.attr(u"minimumUpdatePeriod", parser=MPDParsers.duration, default=Duration())
        self.minBufferTime = self.attr(u"minBufferTime", parser=MPDParsers.duration, required=True)
        self.timeShiftBufferDepth = self.attr(u"timeShiftBufferDepth", parser=MPDParsers.duration)
        self.availabilityStartTime = self.attr(u"availabilityStartTime", parser=MPDParsers.datetime,
                                               default=datetime.datetime.fromtimestamp(0, utc),  # earliest date
                                               required=self.type == "dynamic")
        self.publishTime = self.attr(u"publishTime", parser=MPDParsers.datetime, required=self.type == "dynamic")
        self.availabilityEndTime = self.attr(u"availabilityEndTime", parser=MPDParsers.datetime)
        self.mediaPresentationDuration = self.attr(u"mediaPresentationDuration", parser=MPDParsers.duration)
        self.suggestedPresentationDelay = self.attr(u"suggestedPresentationDelay", parser=MPDParsers.duration)

        # parse children
        location = self.children(Location)
        self.location = location[0] if location else None
        if self.location:
            self.url = self.location.text
            urlp = list(urlparse(self.url))
            if urlp[2]:
                urlp[2], _ = urlp[2].rsplit("/", 1)
            self._base_url = urlunparse(urlp)

        self.baseURLs = self.children(BaseURL)
        self.periods = self.children(Period, minimum=1)
        self.programInformation = self.children(ProgramInformation)
Exemple #5
0
    def _get_vod(self, user_id, video_name):
        res = self.session.http.get(urljoin(self.api_url,
                                            "getVideoByFileName"),
                                    params=dict(userId=user_id,
                                                videoName=video_name,
                                                serverType="web",
                                                callback="x"))

        vod_data = self.session.http.json(res, schema=self.vod_schema)

        if video_name == vod_data['ShowTitle']:
            host, base_path = self.server_addr_re.search(
                vod_data['ServerAddress']).groups()
            if not host or not base_path:
                raise PluginError("Could not split 'ServerAddress' components")

            base_file, file_ext = self.media_file_re.search(
                vod_data['MediaFile']).groups()
            if not base_file or not file_ext:
                raise PluginError("Could not split 'MediaFile' components")

            media_path = "{0}{1}{2}{3}{4}{5}".format(
                base_path, vod_data['MediaRoot'], base_file,
                vod_data['Bitrates'], file_ext, vod_data['StreamingType'])
            log.debug("Media path={0}".format(media_path))

            vod_url = urlunparse((vod_data['ProtocolType'], host, media_path,
                                  '', vod_data['Token'], ''))
            log.debug("URL={0}".format(vod_url))

            return HLSStream.parse_variant_playlist(self.session, vod_url)
Exemple #6
0
    def __init__(self, node, root=None, parent=None, url=None, *args, **kwargs):
        # top level has no parent
        super(MPD, self).__init__(node, root=self, *args, **kwargs)
        # parser attributes
        self.url = url
        self.timelines = defaultdict(lambda: -1)
        self.timelines.update(kwargs.pop("timelines", {}))
        self.id = self.attr(u"id")
        self.profiles = self.attr(u"profiles", required=True)
        self.type = self.attr(u"type", default=u"static", parser=MPDParsers.type)
        self.minimumUpdatePeriod = self.attr(u"minimumUpdatePeriod", parser=MPDParsers.duration, default=Duration())
        self.minBufferTime = self.attr(u"minBufferTime", parser=MPDParsers.duration, required=True)
        self.timeShiftBufferDepth = self.attr(u"timeShiftBufferDepth", parser=MPDParsers.duration)
        self.availabilityStartTime = self.attr(u"availabilityStartTime", parser=MPDParsers.datetime,
                                               default=datetime.datetime.fromtimestamp(0, utc),  # earliest date
                                               required=self.type == "dynamic")
        self.publishTime = self.attr(u"publishTime", parser=MPDParsers.datetime, required=self.type == "dynamic")
        self.mediaPresentationDuration = self.attr(u"mediaPresentationDuration", parser=MPDParsers.duration)
        self.suggestedPresentationDelay = self.attr(u"suggestedPresentationDelay", parser=MPDParsers.duration)

        # parse children
        location = self.children(Location)
        self.location = location[0] if location else None
        if self.location:
            self.url = self.location.text
            urlp = list(urlparse(self.url))
            if urlp[2]:
                urlp[2], _ = urlp[2].rsplit("/", 1)
            self._base_url = urlunparse(urlp)

        self.baseURLs = self.children(BaseURL)
        self.periods = self.children(Period, minimum=1)
        self.programInformation = self.children(ProgramInformation)
Exemple #7
0
    def _get_streams(self):
        streams = self.session.http.get(self.url, schema=self._stream_schema)
        if streams is None:
            return

        if streams['type'] != 'STATION':
            return

        stream_urls = set()
        for stream in streams['streams']:
            log.trace('{0!r}'.format(stream))
            url = stream['url']

            url_no_scheme = urlunparse(urlparse(url)._replace(scheme=''))
            if url_no_scheme in stream_urls:
                continue
            stream_urls.add(url_no_scheme)

            if stream['contentFormat'] in ('audio/mpeg', 'audio/aac'):
                yield 'live', HTTPStream(self.session, url, allow_redirects=True)
            elif stream['contentFormat'] == 'video/MP2T':
                streams = HLSStream.parse_variant_playlist(self.session, stream["url"])
                if not streams:
                    yield stream["quality"], HLSStream(self.session, stream["url"])
                else:
                    for s in streams.items():
                        yield s
Exemple #8
0
    def __init__(self,
                 session,
                 baseurl,
                 url,
                 bootstrap,
                 metadata=None,
                 timeout=60,
                 **request_params):
        Stream.__init__(self, session)

        self.baseurl = baseurl
        self.url = url
        self.bootstrap = bootstrap
        self.metadata = metadata
        self.timeout = timeout

        # Deep copy request params to make it mutable
        self.request_params = deepcopy(request_params)

        parsed = urlparse(self.url)
        if parsed.query:
            params = parse_qsl(parsed.query)
            if params:
                if not self.request_params.get("params"):
                    self.request_params["params"] = {}

                self.request_params["params"].update(params)

        self.url = urlunparse(
            (parsed.scheme, parsed.netloc, parsed.path, None, None, None))
Exemple #9
0
def update_scheme(current, target):
    """
    Take the scheme from the current URL and applies it to the
    target URL if the target URL startswith // or is missing a scheme
    :param current: current URL
    :param target: target URL
    :return: target URL with the current URLs scheme
    """
    target_p = urlparse(target)
    if not target_p.scheme and target_p.netloc:
        return "{0}:{1}".format(urlparse(current).scheme,
                                urlunparse(target_p))
    elif not target_p.scheme and not target_p.netloc:
        return "{0}://{1}".format(urlparse(current).scheme,
                                  urlunparse(target_p))
    else:
        return target
    def __init__(self, url):
        super(YouTube, self).__init__(url)
        parsed = urlparse(self.url)
        if parsed.netloc == 'gaming.youtube.com':
            self.url = urlunparse(parsed._replace(netloc='www.youtube.com'))

        self.author = None
        self.title = None
        self.video_id = None
        self.session.http.headers.update({'User-Agent': useragents.CHROME})
Exemple #11
0
    def auth_url(self, url):
        parsed = urlparse(url)
        path, _ = parsed.path.rsplit("/", 1)
        token_res = http.get(self.token_url, params=dict(acl=path + "/*"))
        authparams = http.json(token_res, schema=self.token_schema)

        existing = dict(parse_qsl(parsed.query))
        existing.update(dict(parse_qsl(authparams)))

        return urlunparse(parsed._replace(query=urlencode(existing)))
Exemple #12
0
    def get_stream_url(self, event_id):
        site = self.match.group(1) or self.match.group(2)
        api_url = self.api_url.format(id=event_id, site=site.upper())
        log.debug("Calling API: {0}".format(api_url))

        stream_url = self.session.http.get(api_url).text.strip("\"'")

        parsed = urlparse(stream_url)
        query = dict(parse_qsl(parsed.query))
        return urlunparse(parsed._replace(query="")), query
Exemple #13
0
    def auth_url(self, url):
        parsed = urlparse(url)
        path, _ = parsed.path.rsplit("/", 1)
        token_res = self.session.http.get(self.token_url, params=dict(acl=path + "/*"))
        authparams = self.session.http.json(token_res, schema=self.token_schema)

        existing = dict(parse_qsl(parsed.query))
        existing.update(dict(parse_qsl(authparams)))

        return urlunparse(parsed._replace(query=urlencode(existing)))
    def handle_module_info(self, args):
        res = {}
        for arg in args:
            if "cdnConfig" in arg:
                parts = [
                    # scheme
                    arg["cdnConfig"]["protocol"],
                    # netloc
                    arg["cdnConfig"]["data"][0]["data"][0]["sites"][0]["host"],
                    # path
                    arg["cdnConfig"]["data"][0]["data"][0]["sites"][0]["path"],
                    "",
                    "",
                    "",  # params, query, fragment
                ]
                # Example:
                # LIVE: http://uhs-akamai.ustream.tv/
                # VOD:  http://vod-cdn.ustream.tv/
                res["cdn_url"] = urlunparse(parts)
            if "stream" in arg and bool(arg["stream"].get("streamFormats")):
                data = arg["stream"]
                if data["streamFormats"].get("flv/segmented"):
                    flv_segmented = data["streamFormats"]["flv/segmented"]
                    path = flv_segmented["contentAccess"]["accessList"][0][
                        "data"]["path"]

                    res["streams"] = []
                    for stream in flv_segmented["streams"]:
                        res["streams"] += [
                            dict(
                                stream_name="{0}p".format(
                                    stream["videoCodec"]["height"]),
                                path=urljoin(
                                    path,
                                    stream["segmentUrl"].replace("%", "%s")),
                                hashes=flv_segmented["hashes"],
                                first_chunk=flv_segmented["chunkId"],
                                chunk_time=flv_segmented["chunkTime"],
                            )
                        ]
                elif bool(data["streamFormats"]):
                    # supported formats:
                    # - flv/segmented
                    # unsupported formats:
                    # - flv
                    # - mp4
                    # - mp4/segmented
                    raise PluginError(
                        "Stream format is not supported: {0}".format(", ".join(
                            data["streamFormats"].keys())))
            elif "stream" in arg and arg["stream"]["contentAvailable"] is False:
                log.error("This stream is currently offline")
                raise ModuleInfoNoStreams

        return res
Exemple #15
0
    def get_stream_url(self, event_id):
        url_m = self.url_re.match(self.url)
        site = url_m.group(1) or url_m.group(2)
        api_url = self.api_url.format(id=event_id, site=site.upper())
        self.logger.debug("Calling API: {0}", api_url)

        stream_url = http.get(api_url).text.strip("\"'")

        parsed = urlparse(stream_url)
        query = dict(parse_qsl(parsed.query))
        return urlunparse(parsed._replace(query="")), query
    def get_stream_url(self, event_id):
        url_m = self.url_re.match(self.url)
        site = url_m.group(1) or url_m.group(2)
        api_url = self.api_url.format(id=event_id, site=site.upper())
        self.logger.debug("Calling API: {0}", api_url)

        stream_url = http.get(api_url).text.strip("\"'")

        parsed = urlparse(stream_url)
        query = dict(parse_qsl(parsed.query))
        return urlunparse(parsed._replace(query="")), query
Exemple #17
0
    def _get_streams(self):
        url_match = self.url_re.match(self.url)
        url_type, show_name, episode_name = url_match.groups()

        if url_type == 'streams' and not show_name:
            url_type = 'live-stream'
        elif not show_name:
            raise PluginError("Missing show_name for url_type: {0}".format(
                url_type, ))

        log.debug("URL type={0}".format(url_type))

        if url_type == 'live-stream':
            video_id = self._get_stream_data(url_type)
        elif url_type == 'streams':
            video_id = self._get_stream_data(show_name)
        elif url_type == 'videos':
            if show_name is None or episode_name is None:
                raise PluginError(
                    "Missing show_name or episode_name for url_type: {0}".
                    format(url_type, ))
            video_id = self._get_video_data(episode_name)
        else:
            raise PluginError("Unrecognised url_type: {0}".format(url_type))

        if video_id is None:
            raise PluginError("Could not find video_id")
        log.debug("Video ID={0}".format(video_id))

        res = self.session.http.get(self.video_data_url.format(video_id))

        url_data = self.session.http.json(res, schema=self._api_schema)
        if 'unprotected' in url_data:
            url = url_data['unprotected']['url']
        elif 'bulkaes' in url_data:
            url_parsed = urlparse(url_data['bulkaes']['url'])
            token = self._get_token(url_parsed.path)
            url = urlunparse((
                url_parsed.scheme,
                url_parsed.netloc,
                url_parsed.path,
                url_parsed.params,
                "{0}={1}".format('hdnts', token),
                url_parsed.fragment,
            ))
        else:
            raise PluginError("Could not find a usable URL in url_data")

        log.debug("URL={0}".format(url))

        return HLSStream.parse_variant_playlist(self.session, url)
Exemple #18
0
    def __init__(self, url):
        super(YouTube, self).__init__(url)
        parsed = urlparse(url)

        # translate input URLs to be able to find embedded data and to avoid unnecessary HTTP redirects
        if parsed.netloc == "gaming.youtube.com":
            self.url = urlunparse(
                parsed._replace(scheme="https", netloc="www.youtube.com"))
        elif self.match.group("video_id_short") is not None:
            self.url = self._url_canonical.format(
                video_id=self.match.group("video_id_short"))
        elif self.match.group("embed") is not None:
            self.url = self._url_canonical.format(
                video_id=self.match.group("video_id"))
        elif self.match.group("embed_live") is not None:
            self.url = self._url_channelid_live.format(
                channel_id=self.match.group("embed_live"))
        elif parsed.scheme != "https":
            self.url = urlunparse(parsed._replace(scheme="https"))

        self.session.http.headers.update({'User-Agent': useragents.CHROME})
        consent = self.cache.get("consent_ck")
        if consent is not None:
            self.set_consent_ck(consent)
Exemple #19
0
    def parse_manifest(cls, session, url, **args):
        """
        Attempt to parse a DASH manifest file and return its streams

        :param session: Streamlink session instance
        :param url: URL of the manifest file
        :return: a dict of name -> DASHStream instances
        """
        ret = {}
        res = session.http.get(url, **args)
        url = res.url

        urlp = list(urlparse(url))
        urlp[2], _ = urlp[2].rsplit("/", 1)

        mpd = MPD(session.http.xml(res, ignore_ns=True),
                  base_url=urlunparse(urlp),
                  url=url)

        video, audio = [], []

        # Search for suitable video and audio representations
        for aset in mpd.periods[0].adaptationSets:
            if aset.contentProtection:
                raise PluginError("{} is protected by DRM".format(url))
            for rep in aset.representations:
                if rep.mimeType.startswith("video"):
                    video.append(rep)
                elif rep.mimeType.startswith("audio"):
                    audio.append(rep)

        if not video:
            video = [None]

        if not audio:
            audio = [None]

        for vid, aud in itertools.product(video, audio):
            stream = DASHStream(session, mpd, vid, aud, **args)
            stream_name = []

            if vid:
                stream_name.append("{:0.0f}{}".format(
                    vid.height or vid.bandwidth, "p" if vid.height else "k"))
            if audio and len(audio) > 1:
                stream_name.append("a{:0.0f}k".format(aud.bandwidth))
            ret['+'.join(stream_name)] = stream
        return ret
Exemple #20
0
    def handle_module_info(self, args):
        res = {}
        for arg in args:
            if "cdnConfig" in arg:
                parts = [
                    # scheme
                    arg["cdnConfig"]["protocol"],
                    # netloc
                    arg["cdnConfig"]["data"][0]["data"][0]["sites"][0]["host"],
                    # path
                    arg["cdnConfig"]["data"][0]["data"][0]["sites"][0]["path"],
                    "", "", "",  # params, query, fragment
                ]
                # Example:
                # LIVE: http://uhs-akamai.ustream.tv/
                # VOD:  http://vod-cdn.ustream.tv/
                res["cdn_url"] = urlunparse(parts)
            if "stream" in arg and bool(arg["stream"].get("streamFormats")):
                data = arg["stream"]
                if data["streamFormats"].get("flv/segmented"):
                    flv_segmented = data["streamFormats"]["flv/segmented"]
                    path = flv_segmented["contentAccess"]["accessList"][0]["data"]["path"]

                    res["streams"] = []
                    for stream in flv_segmented["streams"]:
                        res["streams"] += [dict(
                            stream_name=stream["preset"],
                            path=urljoin(path,
                                         stream["segmentUrl"].replace("%", "%s")),
                            hashes=flv_segmented["hashes"],
                            first_chunk=flv_segmented["chunkId"],
                            chunk_time=flv_segmented["chunkTime"],
                        )]
                elif bool(data["streamFormats"]):
                    # supported formats:
                    # - flv/segmented
                    # unsupported formats:
                    # - flv
                    # - mp4
                    # - mp4/segmented
                    raise PluginError("Stream format is not supported: {0}".format(
                        ", ".join(data["streamFormats"].keys())))
            elif "stream" in arg and arg["stream"]["contentAvailable"] is False:
                    log.error("This stream is currently offline")
                    raise ModuleInfoNoStreams

        return res
Exemple #21
0
    def _get_streams(self):
        json_url = self.session.http.get(self.url, schema=self._schema_data)
        if not json_url:
            return

        json_url = urlunparse(urlparse(self.url)._replace(path=json_url))
        log.debug("Found JSON URL: {0}".format(json_url))

        stream_url = self.session.http.get(json_url, schema=self._schema_json)
        log.debug("Found stream URL: {0}".format(stream_url))

        res = self.session.http.request("HEAD", stream_url)
        # status code will be 200 even if geo-blocked, so check the returned content-type
        if not res or not res.headers or res.headers["Content-Type"] == "video/mp4":
            log.error("Geo-restricted content")
            return

        for stream in HLSStream.parse_variant_playlist(self.session, stream_url).items():
            yield stream
    def parse_manifest(cls, session, url, **args):
        """
        Attempt to parse a DASH manifest file and return its streams

        :param session: Streamlink session instance
        :param url: URL of the manifest file
        :return: a dict of name -> DASHStream instances
        """
        ret = {}
        res = session.http.get(url, **args)
        url = res.url

        urlp = list(urlparse(url))
        urlp[2], _ = urlp[2].rsplit("/", 1)

        mpd = MPD(session.http.xml(res, ignore_ns=True),
                  base_url=urlunparse(urlp),
                  url=url)

        video, audio = [], []

        # Search for suitable video and audio representations
        for aset in mpd.periods[0].adaptationSets:
            if aset.contentProtection:
                raise PluginError("{} is protected by DRM".format(url))
            for rep in aset.representations:
                if rep.mimeType.startswith("video"):
                    video.append(rep)
                elif rep.mimeType.startswith("audio"):
                    audio.append(rep)

        if not video:
            video = [None]

        if not audio:
            audio = [None]

        locale = session.localization
        locale_lang = locale.language
        lang = None
        available_languages = set()

        # if the locale is explicitly set, prefer that language over others
        for aud in audio:
            if aud and aud.lang:
                available_languages.add(aud.lang)
                try:
                    if locale.explicit and aud.lang and Language.get(
                            aud.lang) == locale_lang:
                        lang = aud.lang
                except LookupError:
                    continue

        if not lang:
            # filter by the first language that appears
            lang = audio[0] and audio[0].lang

        log.debug(
            "Available languages for DASH audio streams: {0} (using: {1})".
            format(", ".join(available_languages) or "NONE", lang or "n/a"))

        # if the language is given by the stream, filter out other languages that do not match
        if len(available_languages) > 1:
            audio = list(
                filter(lambda a: a.lang is None or a.lang == lang, audio))

        for vid, aud in itertools.product(video, audio):
            stream = DASHStream(session, mpd, vid, aud, **args)
            stream_name = []

            if vid:
                stream_name.append("{:0.0f}{}".format(
                    vid.height or vid.bandwidth_rounded,
                    "p" if vid.height else "k"))
            if audio and len(audio) > 1:
                stream_name.append("a{:0.0f}k".format(aud.bandwidth))
            ret['+'.join(stream_name)] = stream
        return ret
Exemple #23
0
 def _handle_module_info_cdn_config(self, data):
     # type: (Dict)
     self.stream_cdn = urlunparse(
         (data["protocol"], data["data"][0]["data"][0]["sites"][0]["host"],
          data["data"][0]["data"][0]["sites"][0]["path"], "", "", ""))
     self._set_ready()
Exemple #24
0
    def parse_manifest(cls, session, url_or_manifest, **args):
        """
        Attempt to parse a DASH manifest file and return its streams

        :param session: Streamlink session instance
        :param url_or_manifest: URL of the manifest file or an XML manifest string
        :return: a dict of name -> DASHStream instances
        """

        if url_or_manifest.startswith('<?xml'):
            mpd = MPD(parse_xml(url_or_manifest, ignore_ns=True))
        else:
            res = session.http.get(url_or_manifest, **session.http.valid_request_args(**args))
            url = res.url

            urlp = list(urlparse(url))
            urlp[2], _ = urlp[2].rsplit("/", 1)

            mpd = MPD(session.http.xml(res, ignore_ns=True), base_url=urlunparse(urlp), url=url)

        video, audio = [], []

        # Search for suitable video and audio representations
        for aset in mpd.periods[0].adaptationSets:
            if aset.contentProtection:
                raise PluginError("{} is protected by DRM".format(url))
            for rep in aset.representations:
                if rep.mimeType.startswith("video"):
                    video.append(rep)
                elif rep.mimeType.startswith("audio"):
                    audio.append(rep)

        if not video:
            video = [None]

        if not audio:
            audio = [None]

        locale = session.localization
        locale_lang = locale.language
        lang = None
        available_languages = set()

        # if the locale is explicitly set, prefer that language over others
        for aud in audio:
            if aud and aud.lang:
                available_languages.add(aud.lang)
                try:
                    if locale.explicit and aud.lang and Language.get(aud.lang) == locale_lang:
                        lang = aud.lang
                except LookupError:
                    continue

        if not lang:
            # filter by the first language that appears
            lang = audio[0] and audio[0].lang

        log.debug("Available languages for DASH audio streams: {0} (using: {1})".format(
            ", ".join(available_languages) or "NONE",
            lang or "n/a"
        ))

        # if the language is given by the stream, filter out other languages that do not match
        if len(available_languages) > 1:
            audio = list(filter(lambda a: a.lang is None or a.lang == lang, audio))

        ret = []
        for vid, aud in itertools.product(video, audio):
            stream = DASHStream(session, mpd, vid, aud, **args)
            stream_name = []

            if vid:
                stream_name.append("{:0.0f}{}".format(vid.height or vid.bandwidth_rounded, "p" if vid.height else "k"))
            if audio and len(audio) > 1:
                stream_name.append("a{:0.0f}k".format(aud.bandwidth))
            ret.append(('+'.join(stream_name), stream))

        # rename duplicate streams
        dict_value_list = defaultdict(list)
        for k, v in ret:
            dict_value_list[k].append(v)

        ret_new = {}
        for q in dict_value_list:
            items = dict_value_list[q]

            try:
                items = sorted(items, key=lambda k: k.video_representation.bandwidth, reverse=True)
            except AttributeError:
                pass

            for n in range(len(items)):
                if n == 0:
                    ret_new[q] = items[n]
                elif n == 1:
                    ret_new['{0}_alt'.format(q)] = items[n]
                else:
                    ret_new['{0}_alt{1}'.format(q, n)] = items[n]
        return ret_new
Exemple #25
0
 def __init__(self, url):
     super(BBCiPlayer, self).__init__(url)
     self.url = urlunparse(urlparse(self.url)._replace(scheme="https"))
Exemple #26
0
    def _get_streams(self):
        match = url_re.match(self.url)

        stream_page_scheme = 'https'
        stream_page_domain = match.group(4)
        stream_page_path = match.group(5)
        country_code = CONST_DEFAULT_COUNTRY_CODE
        is_paid_show = False

        # create http session and set headers
        http_session = http
        http_session.headers.update(CONST_HEADERS)

        # get swf url and cookies
        r = http_session.get(
            urlunparse((stream_page_scheme, stream_page_domain,
                        stream_page_path, '', '', '')))

        # redirect to profile page means stream is offline
        if '/profile/' in r.url:
            raise NoStreamsError(self.url)
        if not r.ok:
            self.logger.debug("Status code for {}: {}", r.url, r.status_code)
            raise NoStreamsError(self.url)
        if len(http_session.cookies) == 0:
            raise PluginError("Can't get a cookies")

        if urlparse(r.url).netloc != stream_page_domain:
            # then redirected to regional subdomain
            country_code = urlparse(r.url).netloc.split('.')[0].lower()

        # time to set variables
        baseurl = urlunparse(
            (stream_page_scheme, urlparse(r.url).netloc, '', '', '', ''))
        amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION)
        stream_page_url = urljoin(baseurl, stream_page_path)

        match = swf_re.search(r.text)
        if match:
            swf_url = urljoin(baseurl, match.group())
            self.logger.debug("swf url found: {}", swf_url)
        else:
            # most likely it means that country/region banned
            # can try use default swf-url
            swf_url = urljoin(baseurl, CONST_DEFAULT_SWF_LOCATION)
            self.logger.debug("swf url not found. Will try {}", swf_url)

        # create amf query
        amf_message = AMFMessage("svDirectAmf.getRoomData", "/1",
                                 [stream_page_path, is_paid_show])
        amf_packet = AMFPacket(version=0)
        amf_packet.messages.append(amf_message)

        # send request and close http-session
        r = http_session.post(url=amf_gateway_url,
                              params={CONST_AMF_GATEWAY_PARAM: country_code},
                              data=bytes(amf_packet.serialize()))
        http_session.close()

        if r.status_code != 200:
            raise PluginError("unexpected status code for {}: {}", r.url,
                              r.status_code)

        amf_response = AMFPacket.deserialize(BytesIO(r.content))

        if len(amf_response.messages
               ) != 1 or amf_response.messages[0].target_uri != "/1/onResult":
            raise PluginError("unexpected response from amf gate")

        stream_source_info = amf_msg_schema.validate(
            amf_response.messages[0].value)
        self.logger.debug("source stream info:\n{}", stream_source_info)

        stream_params = {
            "live":
            True,
            "realtime":
            True,
            "flashVer":
            CONST_FLASH_VER,
            "swfUrl":
            swf_url,
            "tcUrl":
            stream_source_info['localData']['NC_ConnUrl'],
            "rtmp":
            stream_source_info['localData']['NC_ConnUrl'],
            "pageUrl":
            stream_page_url,
            "playpath":
            "%s?uid=%s" %
            (''.join(('stream_', stream_page_path)),
             self._get_stream_uid(stream_source_info['userData']['username'])),
            "conn": [
                "S:{0}".format(stream_source_info['userData']['username']),
                "S:{0}".format(
                    stream_source_info['localData']['NC_AccessKey']), "B:0",
                "S:{0}".format(stream_source_info['localData']['dataKey'])
            ]
        }

        self.logger.debug("Stream params:\n{}", stream_params)
        stream = RTMPStream(self.session, stream_params)

        return {'live': stream}
Exemple #27
0
    def _get_streams(self):
        match = url_re.match(self.url)

        stream_page_scheme = 'https'
        stream_page_domain = match.group(4)
        stream_page_path = match.group(5)
        country_code = CONST_DEFAULT_COUNTRY_CODE

        # create http session and set headers
        http_session = http
        http_session.headers.update(CONST_HEADERS)

        # get cookies
        r = http_session.get(
            urlunparse((stream_page_scheme, stream_page_domain,
                        stream_page_path, '', '', '')))

        # redirect to profile page means stream is offline
        if '/profile/' in r.url:
            print(colored('\n => Performer is OFFLINE <=', 'yellow', 'on_red'))
            print(colored('\n => END <= ', 'yellow', 'on_blue'))
            time.sleep(6)
            sys.exit()

        if not r.ok:
            self.logger.debug('Status code for {0}: {1}', r.url, r.status_code)
            raise NoStreamsError(self.url)
        if len(http_session.cookies) == 0:
            raise PluginError("Can't get a cookies")

        if urlparse(r.url).netloc != stream_page_domain:
            # then redirected to regional subdomain
            country_code = urlparse(r.url).netloc.split('.')[0].lower()

        # time to set variables
        baseurl = urlunparse(
            (stream_page_scheme, urlparse(r.url).netloc, '', '', '', ''))
        amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION)
        stream_page_url = urljoin(baseurl, stream_page_path)

        headers = {
            'User-Agent': useragents.CHROME,
            'Referer': stream_page_url,
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With': 'XMLHttpRequest'
        }

        data = 'method=getRoomData&args%5B%5D={0}&args%5B%5D=false'.format(
            stream_page_path)
        self.logger.debug('DATA: {0}'.format(str(data)))
        # send request and close http-session
        r = http_session.post(url=amf_gateway_url,
                              headers=headers,
                              params={CONST_AMF_GATEWAY_PARAM: country_code},
                              data=data)
        http_session.close()

        if r.status_code != 200:
            raise PluginError('unexpected status code for {0}: {1}', r.url,
                              r.status_code)

        stream_source_info = amf_msg_schema.validate(json.loads(r.text))
        self.logger.debug('source stream info:\n{0}', stream_source_info)

        if not stream_source_info:
            return

        performer = stream_source_info['performerData']['username']
        real_name = stream_source_info['performerData']['displayName']
        performer_id = stream_source_info['performerData']['userId']
        print(colored('\n => Performer => {} <=', 'yellow',
                      'on_blue')).format(real_name)
        print(colored('\n => Performer ID => {} <=', 'yellow',
                      'on_blue')).format(performer_id)
        urlnoproto = stream_source_info['localData']['videoServerUrl']
        urlnoproto = update_scheme('https://', urlnoproto)
        hls_url = '{0}/hls/stream_{1}/playlist.m3u8'.format(
            urlnoproto, performer)
        server = re.sub('https://', '', urlnoproto)
        print(colored('\n => Server => {} <=', 'yellow',
                      'on_blue')).format(server)

        if hls_url:
            try:
                for s in HLSStream.parse_variant_playlist(
                        self.session, hls_url, headers=headers).items():
                    timestamp = str(time.strftime('%d%m%Y-%H%M%S'))
                    path = config.get('folders', 'output_folder_BC')
                    fn = real_name + '_BC_' + timestamp + '.flv'
                    pf = (path + fn)
                    ffmpeg = config.get('files', 'ffmpeg')
                    print(
                        colored('\n => FFMPEG-24/7-REC => {} <=', 'yellow',
                                'on_red')).format(fn)
                    print
                    command = (
                        '{} -hide_banner -loglevel panic -i {} -c:v copy -c:a aac -b:a 160k {}'
                        .format(ffmpeg, hls_url, pf))
                    os.system(command)
                    print(colored(' => END <= ', 'yellow', 'on_blue'))
                    sys.exit()

            except Exception as e:
                if '404' in str(e):
                    print(
                        colored('\n => Performer is AWAY or PRIVATE <=',
                                'yellow', 'on_red'))
                    print(colored('\n => END <= ', 'yellow', 'on_blue'))
                    time.sleep(6)
                    sys.exit()
    def _get_streams(self):
        match = url_re.match(self.url)

        stream_page_scheme = 'https'
        stream_page_domain = match.group(4)
        stream_page_path = match.group(5)
        country_code = CONST_DEFAULT_COUNTRY_CODE

        # create http session and set headers
        http_session = http
        http_session.headers.update(CONST_HEADERS)

        # get cookies
        r = http_session.get(
            urlunparse((stream_page_scheme, stream_page_domain,
                        stream_page_path, '', '', '')))

        # redirect to profile page means stream is offline
        if '/profile/' in r.url:
            print(colored('\n => Performer is OFFLINE <=', 'yellow', 'on_red'))
            print(colored('\n => END <= ', 'yellow', 'on_blue'))
            time.sleep(6)
            sys.exit()

        if not r.ok:
            self.logger.debug('Status code for {0}: {1}', r.url, r.status_code)
            raise NoStreamsError(self.url)
        if len(http_session.cookies) == 0:
            raise PluginError("Can't get a cookies")

        if urlparse(r.url).netloc != stream_page_domain:
            # then redirected to regional subdomain
            country_code = urlparse(r.url).netloc.split('.')[0].lower()

        # time to set variables
        baseurl = urlunparse(
            (stream_page_scheme, urlparse(r.url).netloc, '', '', '', ''))
        amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION)
        stream_page_url = urljoin(baseurl, stream_page_path)

        headers = {
            'User-Agent': useragents.CHROME,
            'Referer': stream_page_url,
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With': 'XMLHttpRequest'
        }

        data = 'method=getRoomData&args%5B%5D={0}&args%5B%5D=false'.format(
            stream_page_path)
        self.logger.debug('DATA: {0}'.format(str(data)))
        # send request and close http-session
        r = http_session.post(url=amf_gateway_url,
                              headers=headers,
                              params={CONST_AMF_GATEWAY_PARAM: country_code},
                              data=data)
        http_session.close()

        if r.status_code != 200:
            raise PluginError('unexpected status code for {0}: {1}', r.url,
                              r.status_code)

        stream_source_info = amf_msg_schema.validate(json.loads(r.text))
        self.logger.debug('source stream info:\n{0}', stream_source_info)

        if not stream_source_info:
            return

        performer = stream_source_info['performerData']['username']
        real_name = stream_source_info['performerData']['displayName']
        performer_id = stream_source_info['performerData']['userId']
        print(colored('\n => Performer => {} <=', 'yellow',
                      'on_blue')).format(real_name)
        print(colored('\n => Performer ID => {} <=', 'yellow',
                      'on_blue')).format(performer_id)
        urlnoproto = stream_source_info['localData']['videoServerUrl']
        urlnoproto = update_scheme('https://', urlnoproto)
        hls_url = '{0}/hls/stream_{1}/playlist.m3u8'.format(
            urlnoproto, performer)
        server = re.sub('https://', '', urlnoproto)
        print(colored('\n => Server => {} <=', 'yellow',
                      'on_blue')).format(server)

        if hls_url:
            try:
                for s in HLSStream.parse_variant_playlist(
                        self.session, hls_url, headers=headers).items():
                    while True:
                        try:
                            print
                            mode = int(
                                raw_input(
                                    colored(
                                        ' => Mode => EXIT(5)  YTDL-TS(4)  SL(3)  LS(2)  FFMPEG(1)  FFPLAY(0) => ',
                                        'yellow', 'on_blue')))
                            break
                        except ValueError:
                            print(
                                colored('\n => Input must be a number <=',
                                        'yellow', 'on_red'))
                    if mode == 0:
                        mod = 'FFPLAY'
                    if mode == 1:
                        mod = 'FFMPEG'
                    if mode == 2:
                        mod = 'LS'
                    if mode == 3:
                        mod = 'SL'
                    if mode == 4:
                        mod = 'YTDL-TS'
                    if mode == 5:
                        mod = 'EXIT'

                    timestamp = str(time.strftime('%d%m%Y-%H%M%S'))
                    stime = str(time.strftime('%H:%M:%S'))
                    path = config.get('folders', 'output_folder_BC')
                    fn = real_name + '_BC_' + timestamp
                    fn1 = real_name + '_BC_' + timestamp + '.flv'
                    fn2 = real_name + '_BC_' + timestamp + '.mp4'
                    fn3 = real_name + '_BC_' + timestamp + '.ts'
                    pf1 = (path + fn1)
                    pf2 = (path + fn2)
                    pf3 = (path + fn3)
                    ffmpeg = config.get('files', 'ffmpeg')
                    ffplay = config.get('files', 'ffplay')
                    livestreamer = config.get('files', 'livestreamer')
                    streamlink = config.get('files', 'streamlink')
                    youtube = config.get('files', 'youtube')

                    if mod == 'FFPLAY':
                        print(
                            colored('\n => HLS URL => {} <=', 'yellow',
                                    'on_blue')).format(hls_url)
                        print(
                            colored('\n => FFPLAY => {} <=', 'yellow',
                                    'on_magenta')).format(fn)
                        print
                        command = (
                            '{} -hide_banner -loglevel panic -i {} -infbuf -autoexit -window_title "{} * {} * {}"'
                            .format(ffplay, hls_url, real_name, stime,
                                    urlnoproto))
                        os.system(command)
                        print(colored(' => END <= ', 'yellow', 'on_blue'))

                    if mod == 'FFMPEG':
                        print(
                            colored('\n => HLS URL => {} <=', 'yellow',
                                    'on_blue')).format(hls_url)
                        print(
                            colored('\n => FFMPEG-REC => {} <=', 'yellow',
                                    'on_red')).format(fn1)
                        print
                        command = (
                            '{} -hide_banner -loglevel panic -i {} -c:v copy -c:a aac -b:a 160k {}'
                            .format(ffmpeg, hls_url, pf1))
                        os.system(command)
                        print(colored(' => END <= ', 'yellow', 'on_blue'))

                    if mod == 'LS':
                        print(
                            colored('\n => LS-REC >>> {} <<<', 'yellow',
                                    'on_red')).format(fn2)
                        print
                        command = (
                            '{} hlsvariant://"{}" best -Q -o "{}"'.format(
                                livestreamer, hls_url, pf2))
                        os.system(command)
                        print(colored(' => END <= ', 'yellow', 'on_blue'))

                    if mod == 'SL':
                        print(
                            colored('\n => SL-REC >>> {} <<<', 'yellow',
                                    'on_red')).format(fn2)
                        print
                        command = ('{} hls://"{}" best -Q -o "{}"'.format(
                            streamlink, hls_url, pf2))
                        os.system(command)
                        print(colored(' => END <= ', 'yellow', 'on_blue'))

                    if mod == 'YTDL-TS':
                        print(
                            colored('\n => HLS URL => {} <=', 'yellow',
                                    'on_blue')).format(hls_url)
                        print(
                            colored('\n => YTDL-TS-REC => {} <=', 'yellow',
                                    'on_red')).format(fn3)
                        command = (
                            '{} --hls-use-mpegts --no-part {} -q -o {}'.format(
                                youtube, hls_url, pf3))
                        os.system(command)
                        print(colored('\n => END <= ', 'yellow', 'on_blue'))
                        sys.exit()

                    if mod == 'EXIT':
                        print(colored('\n => END <= ', 'yellow', 'on_blue'))
                        time.sleep(3)
                        sys.exit()

            except Exception as e:
                if '404' in str(e):
                    print(
                        colored('\n => Performer is AWAY or PRIVATE <=',
                                'yellow', 'on_red'))
                    print(colored('\n => END <= ', 'yellow', 'on_blue'))
                    time.sleep(6)
                    sys.exit()
Exemple #29
0
    def _get_streams(self):
        match = url_re.match(self.url)

        stream_page_scheme = 'https'
        stream_page_domain = match.group(4)
        stream_page_path = match.group(5)
        country_code = CONST_DEFAULT_COUNTRY_CODE

        # create http session and set headers
        http_session = http
        http_session.headers.update(CONST_HEADERS)

        # get cookies
        r = http_session.get(
            urlunparse((stream_page_scheme, stream_page_domain,
                        stream_page_path, '', '', '')))

        # redirect to profile page means stream is offline
        if '/profile/' in r.url:
            raise NoStreamsError(self.url)
        if not r.ok:
            self.logger.debug("Status code for {0}: {1}", r.url, r.status_code)
            raise NoStreamsError(self.url)
        if len(http_session.cookies) == 0:
            raise PluginError("Can't get a cookies")

        if urlparse(r.url).netloc != stream_page_domain:
            # then redirected to regional subdomain
            country_code = urlparse(r.url).netloc.split('.')[0].lower()

        # time to set variables
        baseurl = urlunparse(
            (stream_page_scheme, urlparse(r.url).netloc, '', '', '', ''))
        amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION)
        stream_page_url = urljoin(baseurl, stream_page_path)

        headers = {
            'User-Agent': useragents.CHROME,
            'Referer': stream_page_url,
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With': 'XMLHttpRequest'
        }

        data = 'method=getRoomData&args%5B%5D={0}&args%5B%5D=false'.format(
            stream_page_path)
        self.logger.debug('DATA: {0}'.format(str(data)))
        # send request and close http-session
        r = http_session.post(url=amf_gateway_url,
                              headers=headers,
                              params={CONST_AMF_GATEWAY_PARAM: country_code},
                              data=data)
        http_session.close()

        if r.status_code != 200:
            raise PluginError("unexpected status code for {0}: {1}", r.url,
                              r.status_code)

        stream_source_info = amf_msg_schema.validate(json.loads(r.text))
        self.logger.debug("source stream info:\n{0}", stream_source_info)

        if not stream_source_info:
            return

        urlnoproto = stream_source_info['localData']['videoServerUrl']
        urlnoproto = update_scheme('https://', urlnoproto)
        performer = stream_source_info['performerData']['username']

        hls_url = '{0}/hls/stream_{1}/playlist.m3u8'.format(
            urlnoproto, performer)

        if hls_url:
            self.logger.debug('HLS URL: {0}'.format(hls_url))
            try:
                for s in HLSStream.parse_variant_playlist(
                        self.session, hls_url, headers=headers).items():
                    yield s
            except Exception as e:
                if '404' in str(e):
                    self.logger.error('Stream is currently offline or private')
                else:
                    self.logger.error(str(e))
                return
Exemple #30
0
    def _get_streams(self):
        match = url_re.match(self.url)

        stream_page_scheme = 'https'
        stream_page_domain = match.group(4)
        stream_page_path = match.group(5)
        country_code = CONST_DEFAULT_COUNTRY_CODE

        # create http session and set headers
        http_session = http
        http_session.headers.update(CONST_HEADERS)

        # get cookies
        r = http_session.get(urlunparse((stream_page_scheme, stream_page_domain, stream_page_path, '', '', '')))

        # redirect to profile page means stream is offline
        if '/profile/' in r.url:
            raise NoStreamsError(self.url)
        if not r.ok:
            self.logger.debug("Status code for {0}: {1}", r.url, r.status_code)
            raise NoStreamsError(self.url)
        if len(http_session.cookies) == 0:
            raise PluginError("Can't get a cookies")

        if urlparse(r.url).netloc != stream_page_domain:
            # then redirected to regional subdomain
            country_code = urlparse(r.url).netloc.split('.')[0].lower()

        # time to set variables
        baseurl = urlunparse((stream_page_scheme, urlparse(r.url).netloc, '', '', '', ''))
        amf_gateway_url = urljoin(baseurl, CONST_AMF_GATEWAY_LOCATION)
        stream_page_url = urljoin(baseurl, stream_page_path)

        headers = {
            'User-Agent': useragents.CHROME,
            'Referer': stream_page_url,
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With': 'XMLHttpRequest'
        }

        data = 'method=getRoomData&args%5B%5D={0}&args%5B%5D=false'.format(stream_page_path)
        self.logger.debug('DATA: {0}'.format(str(data)))
        # send request and close http-session
        r = http_session.post(url=amf_gateway_url,
                              headers=headers,
                              params={CONST_AMF_GATEWAY_PARAM: country_code},
                              data=data)
        http_session.close()

        if r.status_code != 200:
            raise PluginError("unexpected status code for {0}: {1}", r.url, r.status_code)

        stream_source_info = amf_msg_schema.validate(json.loads(r.text))
        self.logger.debug("source stream info:\n{0}", stream_source_info)

        if not stream_source_info:
            return

        urlnoproto = stream_source_info['localData']['videoServerUrl']
        urlnoproto = update_scheme('https://', urlnoproto)
        performer = stream_source_info['performerData']['username']

        hls_url = '{0}/hls/stream_{1}/playlist.m3u8'.format(urlnoproto, performer)

        if hls_url:
            self.logger.debug('HLS URL: {0}'.format(hls_url))
            try:
                for s in HLSStream.parse_variant_playlist(self.session, hls_url, headers=headers).items():
                    yield s
            except Exception as e:
                if '404' in str(e):
                    self.logger.error('Stream is currently offline or private')
                else:
                    self.logger.error(str(e))
                return
Exemple #31
0
    def parse_manifest(cls, session, url, **args):
        """
        Attempt to parse a DASH manifest file and return its streams

        :param session: Streamlink session instance
        :param url: URL of the manifest file
        :return: a dict of name -> DASHStream instances
        """
        ret = {}
        res = session.http.get(url, **args)
        url = res.url

        urlp = list(urlparse(url))
        urlp[2], _ = urlp[2].rsplit("/", 1)

        mpd = MPD(session.http.xml(res, ignore_ns=True), base_url=urlunparse(urlp), url=url)

        video, audio = [], []

        # Search for suitable video and audio representations
        for aset in mpd.periods[0].adaptationSets:
            if aset.contentProtection:
                raise PluginError("{} is protected by DRM".format(url))
            for rep in aset.representations:
                if rep.mimeType.startswith("video"):
                    video.append(rep)
                elif rep.mimeType.startswith("audio"):
                    audio.append(rep)

        if not video:
            video = [None]

        if not audio:
            audio = [None]

        locale = session.localization
        locale_lang = locale.language
        lang = None
        available_languages = set()

        # if the locale is explicitly set, prefer that language over others
        for aud in audio:
            if aud and aud.lang:
                available_languages.add(aud.lang)
                try:
                    if locale.explicit and aud.lang and Language.get(aud.lang) == locale_lang:
                        lang = aud.lang
                except LookupError:
                    continue

        if not lang:
            # filter by the first language that appears
            lang = audio[0] and audio[0].lang

        log.debug("Available languages for DASH audio streams: {0} (using: {1})".format(", ".join(available_languages) or "NONE", lang or "n/a"))

        # if the language is given by the stream, filter out other languages that do not match
        if len(available_languages) > 1:
            audio = list(filter(lambda a: a.lang is None or a.lang == lang, audio))

        for vid, aud in itertools.product(video, audio):
            stream = DASHStream(session, mpd, vid, aud, **args)
            stream_name = []

            if vid:
                stream_name.append("{:0.0f}{}".format(vid.height or vid.bandwidth_rounded, "p" if vid.height else "k"))
            if audio and len(audio) > 1:
                stream_name.append("a{:0.0f}k".format(aud.bandwidth))
            ret['+'.join(stream_name)] = stream
        return ret
Exemple #32
0
 def __init__(self, url):
     super(Filmon, self).__init__(url)
     parsed = urlparse(self.url)
     if parsed.path.startswith("/channel/"):
         self.url = urlunparse(parsed._replace(path=parsed.path.replace("/channel/", "/tv/")))
     self.api = FilmOnAPI(self.session)
    def _get_streams(self):
        zdf_json = self.session.http.get(
            self.url,
            schema=validate.Schema(
                validate.transform(self._re_api_json.search),
                validate.any(
                    None,
                    validate.all(validate.get("json"), validate.parse_json(), {
                        "apiToken": validate.text,
                        "content": validate.url()
                    }, validate.union_get("apiToken", "content")))))
        if zdf_json is None:
            return

        apiToken, apiUrl = zdf_json

        headers = {
            "Accept": "application/vnd.de.zdf.v1.0+json;charset=UTF-8",
            "Api-Auth": "Bearer {0}".format(apiToken),
            "Referer": self.url
        }

        pApiUrl = urlparse(apiUrl)
        apiUrlBase = urlunparse(
            (pApiUrl.scheme, pApiUrl.netloc, "", "", "", ""))
        apiUrlPath = self.session.http.get(
            apiUrl,
            headers=headers,
            schema=validate.Schema(
                validate.parse_json(), {
                    "mainVideoContent": {
                        "http://zdf.de/rels/target": {
                            "http://zdf.de/rels/streams/ptmd-template":
                            validate.text
                        }
                    }
                },
                validate.get(("mainVideoContent", "http://zdf.de/rels/target",
                              "http://zdf.de/rels/streams/ptmd-template")),
                validate.transform(lambda template: template.format(
                    playerId=self.PLAYER_ID).replace(" ", ""))))

        stream_request_url = url_concat(apiUrlBase, apiUrlPath)
        data = self.session.http.get(
            stream_request_url,
            headers=headers,
            schema=validate.Schema(
                validate.parse_json(), {
                    "priorityList": [{
                        "formitaeten":
                        validate.all(
                            [{
                                "type":
                                validate.text,
                                "qualities":
                                validate.all([{
                                    "quality": validate.text,
                                    "audio": {
                                        "tracks": [{
                                            "uri": validate.url()
                                        }]
                                    }
                                }],
                                             validate.filter(lambda obj: obj[
                                                 "quality"] == "auto"))
                            }],
                            validate.filter(lambda obj: obj["type"] ==
                                            "h264_aac_ts_http_m3u8_http"))
                    }]
                }, validate.get("priorityList")))

        for priority in data:
            for formitaeten in priority["formitaeten"]:
                for quality in formitaeten["qualities"]:
                    for audio in quality["audio"]["tracks"]:
                        for s in HLSStream.parse_variant_playlist(
                                self.session, audio["uri"],
                                headers=headers).items():
                            yield s