Exemplo n.º 1
0
    def __update_video_from_mpd(self, item, mpd_info,
                                use_adaptive_with_encryption):
        """ Updates an existing MediaItem with more data based on an MPD stream.

        :param dict[str,str] mpd_info:              Stream info retrieved from the stream json.
        :param bool use_adaptive_with_encryption:   Do we use the Adaptive InputStream add-on?
        :param MediaItem item:                      The original MediaItem that needs updating.

        :return: The original item with more data added to it's properties.
        :rtype: MediaItem

        """

        Logger.debug("Updating streams using BrightCove data.")

        part = item.create_new_empty_media_part()
        mpd_manifest_url = "https:{0}".format(mpd_info["mediaLocator"])
        mpd_data = UriHandler.open(mpd_manifest_url, proxy=self.proxy)
        subtitles = Regexer.do_regex(r'<BaseURL>([^<]+\.vtt)</BaseURL>',
                                     mpd_data)

        if subtitles:
            Logger.debug("Found subtitle: %s", subtitles[0])
            subtitle = SubtitleHelper.download_subtitle(subtitles[0],
                                                        proxy=self.proxy,
                                                        format="webvtt")
            part.Subtitle = subtitle

        if use_adaptive_with_encryption:
            # We can use the adaptive add-on with encryption
            Logger.info("Using MPD InputStreamAddon")
            license_url = Regexer.do_regex('licenseUrl="([^"]+)"', mpd_data)[0]
            token = "Bearer {0}".format(mpd_info["playToken"])
            key_headers = {"Authorization": token}
            license_key = Mpd.get_license_key(license_url,
                                              key_headers=key_headers)

            stream = part.append_media_stream(mpd_manifest_url, 0)
            Mpd.set_input_stream_addon_input(stream,
                                             self.proxy,
                                             license_key=license_key)
            item.complete = True
        else:
            XbmcWrapper.show_dialog(
                LanguageHelper.get_localized_string(LanguageHelper.DrmTitle),
                LanguageHelper.get_localized_string(
                    LanguageHelper.WidevineLeiaRequired))

        return item
Exemplo n.º 2
0
    def update_video_item(self, item):
        """ Updates an existing MediaItem with more data.

        Used to update none complete MediaItems (self.complete = False). This
        could include opening the item's URL to fetch more data and then process that
        data or retrieve it's real media-URL.

        The method should at least:
        * cache the thumbnail to disk (use self.noImage if no thumb is available).
        * set at least one MediaItemPart with a single MediaStream.
        * set self.complete = True.

        if the returned item does not have a MediaItemPart then the self.complete flag
        will automatically be set back to False.

        :param MediaItem item: the original MediaItem that needs updating.

        :return: The original item with more data added to it's properties.
        :rtype: MediaItem

        """

        Logger.debug('Starting update_video_item for %s (%s)', item.name,
                     self.channelName)

        # Get the authentication part right.
        token = self.__authenticator.get_authentication_token()
        headers = {"Authorization": "Bearer {}".format(token)}
        video_data = UriHandler.open(item.url, additional_headers=headers)
        video_json = JsonHelper(video_data)
        license_url = video_json.get_value("licenseUrl")
        video_manifest = video_json.get_value("manifest")
        token = video_json.get_value("token")
        key_headers = {
            "Authorization": "Bearer {0}".format(token),
            "content-type": "application/octet-stream"
        }

        part = item.create_new_empty_media_part()
        stream = part.append_media_stream(video_manifest, 0)

        from resources.lib.streams.mpd import Mpd
        license_key = Mpd.get_license_key(license_url,
                                          key_headers=key_headers,
                                          key_type="A")
        Mpd.set_input_stream_addon_input(stream, license_key=license_key)
        item.complete = True
        return item
Exemplo n.º 3
0
    def __update_dash_video(self, item, stream_info):
        """

        :param MediaItem item:          The item that was updated
        :param JsonHelper stream_info:  The stream info
        """

        if not AddonSettings.use_adaptive_stream_add_on(with_encryption=True):
            XbmcWrapper.show_dialog(
                LanguageHelper.get_localized_string(LanguageHelper.DrmTitle),
                LanguageHelper.get_localized_string(
                    LanguageHelper.WidevineLeiaRequired))
            return item

        playback_item = stream_info.get_value("playbackItem")

        stream_url = playback_item["manifestUrl"]
        part = item.create_new_empty_media_part()
        stream = part.append_media_stream(stream_url, 0)

        license_info = playback_item.get("license", None)
        if license_info is not None:
            license_key_token = license_info["token"]
            auth_token = license_info["castlabsToken"]
            header = {
                "x-dt-auth-token": auth_token,
                "content-type": "application/octstream"
            }
            license_url = license_info["castlabsServer"]
            license_key = Mpd.get_license_key(license_url,
                                              key_value=license_key_token,
                                              key_headers=header)

            Mpd.set_input_stream_addon_input(stream,
                                             proxy=self.proxy,
                                             license_key=license_key)
            item.isDrmProtected = False
        else:
            Mpd.set_input_stream_addon_input(stream, proxy=self.proxy)

        item.complete = True
        return item
Exemplo n.º 4
0
    def update_graphql_item(self, item):
        """ Updates video items that are encrypted. This could be the default for Krypton!

        :param MediaItem item: The item to update.

        :return: An updated item.
        :rtype: MediaItem

        """

        sources = item.metaData["sources"]
        part = item.create_new_empty_media_part()
        hls_over_dash = self._get_setting("hls_over_dash") == "true"

        for src in sources:
            stream_type = src["type"]
            url = src["file"]
            drm = src["drm"]
            if "?filter=" in url:
                url = url[:url.index("?filter=")]

            if stream_type == "dash" and not drm:
                bitrate = 0 if hls_over_dash else 2
                stream = part.append_media_stream(url, bitrate)
                item.complete = Mpd.set_input_stream_addon_input(
                    stream, self.proxy)

            elif stream_type == "dash" and drm and "widevine" in drm:
                bitrate = 0 if hls_over_dash else 1
                stream = part.append_media_stream(url, bitrate)

                # fetch the authentication token:
                # url = self.__get_api_persisted_url("drmToken", "634c83ae7588a877e2bb67d078dda618cfcfc70ac073aef5e134e622686c0bb6", variables={})
                url = self.__get_api_query_url("drmToken",
                                               "{token,expiration}")
                token_data = UriHandler.open(url,
                                             proxy=self.proxy,
                                             no_cache=True)
                token_json = JsonHelper(token_data)
                token = token_json.get_value("data", "drmToken", "token")

                # we need to POST to this url using this wrapper:
                key_url = drm["widevine"]["url"]
                release_pid = drm["widevine"]["releasePid"]
                encryption_json = '{{"getRawWidevineLicense":{{"releasePid":"{}","widevineChallenge":"b{{SSM}}"}}}}'.format(
                    release_pid)
                encryption_key = Mpd.get_license_key(
                    key_url=key_url,
                    key_type="b",
                    key_value=encryption_json,
                    key_headers={
                        "Content-Type": "application/json",
                        "authorization": "Basic {}".format(token)
                    })
                Mpd.set_input_stream_addon_input(stream,
                                                 license_key=encryption_key)
                item.complete = True

            elif stream_type == "m3u8" and not drm:
                bitrate = 2 if hls_over_dash else 0
                item.complete = M3u8.update_part_with_m3u8_streams(
                    part, url, proxy=self.proxy, channel=self, bitrate=bitrate)

            else:
                Logger.debug("Found incompatible stream: %s", src)

        subtitle = None
        for sub in item.metaData.get("subtitles", []):
            subtitle = sub["file"]
        part.Subtitle = subtitle

        # If we are here, we can playback.
        item.isDrmProtected = False
        return item
Exemplo n.º 5
0
    def __update_embedded_video(self, item):
        """ Updates video items that are encrypted. This could be the default for Krypton!

        :param MediaItem item: The item to update.

        :return: An updated item.
        :rtype: MediaItem

        """

        data = UriHandler.open(item.url, proxy=self.proxy)
        if UriHandler.instance().status.code == 404:
            title, message = Regexer.do_regex(
                r'<h1>([^<]+)</h1>\W+<p>([^<]+)<', data)[0]
            XbmcWrapper.show_dialog(title, message)
            return item

        start_needle = "var playerConfig ="
        start_data = data.index(start_needle) + len(start_needle)
        end_data = data.index("var talpaPlayer")
        data = data[start_data:end_data].strip().rstrip(";")

        json = JsonHelper(data)
        has_drm_only = True
        adaptive_available = AddonSettings.use_adaptive_stream_add_on(
            with_encryption=False, channel=self)
        adaptive_available_encrypted = AddonSettings.use_adaptive_stream_add_on(
            with_encryption=True, channel=self)

        for play_list_entry in json.get_value("playlist"):
            part = item.create_new_empty_media_part()
            for source in play_list_entry["sources"]:
                stream_type = source["type"]
                stream_url = source["file"]
                stream_drm = source.get("drm")

                if not stream_drm:
                    has_drm_only = False
                    if stream_type == "m3u8":
                        Logger.debug("Found non-encrypted M3u8 stream: %s",
                                     stream_url)
                        M3u8.update_part_with_m3u8_streams(part,
                                                           stream_url,
                                                           proxy=self.proxy,
                                                           channel=self)
                        item.complete = True
                    elif stream_type == "dash" and adaptive_available:
                        Logger.debug("Found non-encrypted Dash stream: %s",
                                     stream_url)
                        stream = part.append_media_stream(stream_url, 1)
                        Mpd.set_input_stream_addon_input(stream,
                                                         proxy=self.proxy)
                        item.complete = True
                    else:
                        Logger.debug("Unknown stream source: %s", source)

                else:
                    compatible_drm = "widevine"
                    if compatible_drm not in stream_drm or stream_type != "dash":
                        Logger.debug("Found encrypted %s stream: %s",
                                     stream_type, stream_url)
                        continue

                    Logger.debug("Found Widevine encrypted Dash stream: %s",
                                 stream_url)
                    license_url = stream_drm[compatible_drm]["url"]
                    pid = stream_drm[compatible_drm]["releasePid"]
                    encryption_json = '{"getRawWidevineLicense":' \
                                      '{"releasePid":"%s", "widevineChallenge":"b{SSM}"}' \
                                      '}' % (pid,)

                    headers = {
                        "Content-Type": "application/json",
                        "Origin": "https://embed.kijk.nl",
                        "Referer": stream_url
                    }

                    encryption_key = Mpd.get_license_key(
                        license_url,
                        key_type=None,
                        key_value=encryption_json,
                        key_headers=headers)

                    stream = part.append_media_stream(stream_url, 0)
                    Mpd.set_input_stream_addon_input(
                        stream, proxy=self.proxy, license_key=encryption_key)
                    item.complete = True

            subs = [
                s['file'] for s in play_list_entry.get("tracks", [])
                if s.get('kind') == "captions"
            ]
            if subs:
                subtitle = SubtitleHelper.download_subtitle(subs[0],
                                                            format="webvtt")
                part.Subtitle = subtitle

        if has_drm_only and not adaptive_available_encrypted:
            XbmcWrapper.show_dialog(
                LanguageHelper.get_localized_string(LanguageHelper.DrmTitle),
                LanguageHelper.get_localized_string(
                    LanguageHelper.WidevineLeiaRequired))
        return item
Exemplo n.º 6
0
    def update_video_item(self, item):
        """ Updates an existing MediaItem with more data.

        Used to update none complete MediaItems (self.complete = False). This
        could include opening the item's URL to fetch more data and then process that
        data or retrieve it's real media-URL.

        The method should at least:
        * cache the thumbnail to disk (use self.noImage if no thumb is available).
        * set at least one MediaItemPart with a single MediaStream.
        * set self.complete = True.

        if the returned item does not have a MediaItemPart then the self.complete flag
        will automatically be set back to False.

        :param MediaItem item: the original MediaItem that needs updating.

        :return: The original item with more data added to it's properties.
        :rtype: MediaItem

        """

        Logger.debug('Starting update_video_item for %s (%s)', item.name, self.channelName)

        data = UriHandler.open(item.url, proxy=self.proxy)
        json_data, _ = self.extract_json(data)
        video_id = json_data.get_value("versions", 0, "id")
        stream_data_url = "http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/mediaset/iptv-all/vpid/{}".format(video_id)

        # this URL is one from the webbrowser but requires a security part. So NOT:
        # streamDataUrl = "http://open.live.bbc.co.uk/mediaselector/5/select/version
        # /2.0/mediaset/pc/vpid/%s" % (vid,)
        #
        # but:
        # streamDataUrl = "http://open.live.bbc.co.uk/mediaselector/5/select/version
        # /2.0/mediaset/pc/vpid/%s/atk/2214e42b5729dcdd012dfb61a3054d39309ccd31/asn/1/
        # And I don't know where that one comes from

        part = item.create_new_empty_media_part()

        stream_data = UriHandler.open(stream_data_url, proxy=self.proxy)
        # Reroute for debugging
        # from debug.router import Router
        # streamData = Router.get_via("uk", streamDataUrl, self.proxy)

        connection_datas = Regexer.do_regex(
            r'<media bitrate="(\d+)"[^>]+>\W*'
            r'(<connection[^>]+>\W*)'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?'
            r'(<connection[^>]+>\W*)?</media>', stream_data)

        for connection_data in connection_datas:
            # first the bitrate
            bitrate = int(connection_data[0])
            Logger.trace("Found Media: %s", connection_data)

            # go through the available connections
            for connection in connection_data[1:]:
                if not connection:
                    continue

                connection_xml = XmlHelper(connection)
                stream_bitrate = bitrate
                Logger.trace("Analyzing Connection: %s", connection)
                supplier = connection_xml.get_tag_attribute("connection", {"supplier": None})
                protocol = connection_xml.get_tag_attribute("connection", {"protocol": None})
                transfer_format = connection_xml.get_tag_attribute("connection", {"transferFormat": None})
                Logger.debug("Found connection information:\n"
                             "Protocol:       %s\n"
                             "TransferFormat: %s\n"
                             "Supplier:       %s\n"
                             "Bitrate:        %s",
                             protocol, transfer_format, supplier, bitrate)

                if protocol.startswith("http"):
                    if transfer_format != "hls":  # and transfer_format != "dash":
                        Logger.debug("Ignoring TransferFormat: %s", transfer_format)
                        continue
                    if "lime" in supplier or "mf_akamai_uk" in supplier:
                        # Prefer others
                        stream_bitrate -= 1
                        # Logger.debug("Ignoring Supplier: %s", supplier)
                        # continue
                    url = connection_xml.get_tag_attribute("connection", {"href": None})

                elif protocol.startswith("rtmp"):
                    Logger.warning("Ignoring RTMP for now")
                    continue
                else:
                    Logger.warning("Unknown protocol: %s", protocol)
                    continue

                if transfer_format == "hls":
                    item.complete = M3u8.update_part_with_m3u8_streams(part, url, proxy=self.proxy, bitrate=stream_bitrate)
                elif transfer_format == "dash":
                    strm = part.append_media_stream(url, bitrate)
                    Mpd.set_input_stream_addon_input(strm, self.proxy)

        # get the subtitle
        subtitles = Regexer.do_regex(
            '<connection href="(http://www.bbc.co.uk/iplayer/subtitles/[^"]+/)([^/]+.xml)"',
            stream_data)
        if len(subtitles) > 0:
            subtitle = subtitles[0]
            subtitle_url = "%s%s" % (subtitle[0], subtitle[1])
            part.Subtitle = subtitlehelper.SubtitleHelper.download_subtitle(
                subtitle_url, subtitle[1], "ttml", proxy=self.proxy)

        item.complete = True
        Logger.trace('finishing update_video_item: %s.', item)
        return item
Exemplo n.º 7
0
    def add_mpd_stream_from_npo(url,
                                episode_id,
                                part,
                                proxy=None,
                                headers=None,
                                live=False):
        """ Extracts the Dash streams for the given url or episode id

        :param str|None url:        The url to download
        :param str episode_id:      The NPO episode ID
        :param dict headers:        Possible HTTP Headers
        :param ProxyInfo proxy:     The proxy to use for opening
        :param bool live:           Is this a live stream?

        :rtype: str|None
        :return: An error message if an error occurred.

        for s, b, p in NpoStream.GetMpdStreamFromNpo(None, episodeId, proxy=self.proxy):
            item.complete = True
            stream = part.append_media_stream(s, b)
            for k, v in p.iteritems():
                stream.add_property(k, v)

        """

        if url:
            Logger.info("Determining MPD streams for url: %s", url)
            episode_id = url.split("/")[-1]
        elif episode_id:
            Logger.info("Determining MPD streams for VideoId: %s", episode_id)
        else:
            Logger.error("No url or streamId specified!")
            return None

        token_headers = {"x-requested-with": "XMLHttpRequest"}
        token_headers.update(headers or {})
        data = UriHandler.open("https://www.npostart.nl/api/token",
                               proxy=proxy,
                               additional_headers=token_headers)
        token = JsonHelper(data).get_value("token")

        post_data = {"_token": token}
        data = UriHandler.open(
            "https://www.npostart.nl/player/{0}".format(episode_id),
            proxy=proxy,
            additional_headers=headers,
            data=post_data)
        Logger.trace("Episode Data: %s", data)

        token = JsonHelper(data).get_value("token")
        Logger.debug("Found token %s", token)

        stream_data_url = "https://start-player.npo.nl/video/{0}/streams?" \
                          "profile=dash-widevine" \
                          "&quality=npo" \
                          "&tokenId={1}" \
                          "&streamType=broadcast" \
                          "&mobile=0" \
                          "&isChromecast=0".format(episode_id, token)

        data = UriHandler.open(stream_data_url,
                               proxy=proxy,
                               additional_headers=headers)
        Logger.trace("Stream Data: %s", data)
        stream_data = JsonHelper(data)
        error = stream_data.get_value("html")
        if error:
            error = Regexer.do_regex(r'message">\s*<p>([^<]+)', error)
            if bool(error):
                return error[0]
            return "Unspecified error retrieving streams"

        stream_url = stream_data.get_value("stream", "src")
        if stream_url is None:
            return None

        # Encryption?
        license_url = stream_data.get_value("stream", "keySystemOptions", 0,
                                            "options", "licenseUrl")
        if license_url:
            Logger.info("Using encrypted Dash for NPO")
            license_headers = stream_data.get_value("stream",
                                                    "keySystemOptions", 0,
                                                    "options",
                                                    "httpRequestHeaders")
            if license_headers:
                license_headers = '&'.join(
                    ["{}={}".format(k, v) for k, v in license_headers.items()])
            license_type = stream_data.get_value("stream", "keySystemOptions",
                                                 0, "name")
            license_key = "{0}|{1}|R{{SSM}}|".format(license_url,
                                                     license_headers or "")
        else:
            Logger.info("Using non-encrypted Dash for NPO")
            license_type = None
            license_key = None

        # Actually set the stream
        stream = part.append_media_stream(stream_url, 0)
        # M3u8.set_input_stream_addon_input(stream, proxy, headers)
        Mpd.set_input_stream_addon_input(
            stream,
            proxy,
            headers,
            license_key=license_key,
            license_type=license_type,
            manifest_update=None if not live else "full")

        return None
Exemplo n.º 8
0
    def get_stream_info(self, item, mzid, live=False, hls_over_dash=False):  # NOSONAR
        """ Updates an item with Vualto stream data.

        :param MediaItem item:      The Mediaitem to update
        :param str mzid:            The MZ ID of the stream
        :param bool live:           Indicator if the stream is live or not
        :param bool hls_over_dash:  Should we prefer HLS over Dash?

        :return: An updated MediaItem
        :rtype: MediaItem

        """

        # We need a player token
        token_data = UriHandler.open("https://media-services-public.vrt.be/"
                                     "vualto-video-aggregator-web/rest/external/v1/tokens", data="",
                                     additional_headers={"Content-Type": "application/json"})

        token = JsonHelper(token_data).get_value("vrtPlayerToken")

        asset_url = "https://media-services-public.vrt.be/vualto-video-aggregator-web/rest/" \
                    "external/v1/videos/{0}?vrtPlayerToken={1}&client={2}" \
            .format(mzid, HtmlEntityHelper.url_encode(token), self.client_id)
        asset_data = UriHandler.open(asset_url, no_cache=True)
        asset_data = JsonHelper(asset_data)

        drm_key = asset_data.get_value("drm")
        drm_protected = drm_key is not None
        adaptive_available = AddonSettings.use_adaptive_stream_add_on(
            with_encryption=drm_protected, channel=self.channel)
        part = item.create_new_empty_media_part()
        srt = None

        # see if we prefer hls over dash
        hls_prio = 2 if hls_over_dash else 0

        for target_url in asset_data.get_value("targetUrls"):
            video_type = target_url["type"]
            video_url = target_url["url"]

            if video_type == "hls_aes" and drm_protected and adaptive_available:
                # no difference in encrypted or not.
                Logger.debug("Found HLS AES encrypted stream and a DRM key")
                stream = part.append_media_stream(video_url, hls_prio)
                M3u8.set_input_stream_addon_input(stream)

            elif video_type == "hls" and not drm_protected:
                # no difference in encrypted or not.
                if adaptive_available:
                    Logger.debug("Found standard HLS stream and without DRM protection")
                    stream = part.append_media_stream(video_url, hls_prio)
                    M3u8.set_input_stream_addon_input(stream)
                else:
                    m3u8_data = UriHandler.open(video_url)
                    for s, b, a in M3u8.get_streams_from_m3u8(video_url,
                                                              play_list_data=m3u8_data,
                                                              map_audio=True):
                        item.complete = True
                        if a:
                            audio_part = a.rsplit("-", 1)[-1]
                            audio_part = "-%s" % (audio_part,)
                            s = s.replace(".m3u8", audio_part)
                        part.append_media_stream(s, b)

                    srt = M3u8.get_subtitle(video_url, play_list_data=m3u8_data)
                    if not srt or live:
                        # If there is not SRT don't download it. If it a live stream with subs,
                        # don't use it as it is not supported by Kodi
                        continue

                    srt = srt.replace(".m3u8", ".vtt")
                    part.Subtitle = SubtitleHelper.download_subtitle(srt, format="webvtt")

            elif video_type == "mpeg_dash" and adaptive_available:
                if not drm_protected:
                    Logger.debug("Found standard MPD stream and without DRM protection")
                    stream = part.append_media_stream(video_url, 1)
                    Mpd.set_input_stream_addon_input(stream)
                else:
                    stream = part.append_media_stream(video_url, 1)
                    encryption_json = '{{"token":"{0}","drm_info":[D{{SSM}}],"kid":"{{KID}}"}}' \
                        .format(drm_key)
                    encryption_key = Mpd.get_license_key(
                        key_url="https://widevine-proxy.drm.technology/proxy",
                        key_type="D",
                        key_value=encryption_json,
                        key_headers={"Content-Type": "text/plain;charset=UTF-8"}
                    )
                    Mpd.set_input_stream_addon_input(stream, license_key=encryption_key)

            if video_type.startswith("hls") and srt is None:
                srt = M3u8.get_subtitle(video_url)
                if not srt or live:
                    # If there is not SRT don't download it. If it a live stream with subs,
                    # don't use it as it is not supported by Kodi
                    continue

                srt = srt.replace(".m3u8", ".vtt")
                part.Subtitle = SubtitleHelper.download_subtitle(srt, format="webvtt")

            item.complete = True
        return item
Exemplo n.º 9
0
    def __update_item_from_video_references(self,
                                            item,
                                            videos,
                                            subtitles=None):  # NOSONAR
        """

        :param MediaItem item:      The original MediaItem that needs updating.
        :param list[any] videos:    Videos to add.
        :param dict subtitles:      Subtitle information.

        :return: Updated MediaItem
        :rtype: MediaItem

        """

        item.MediaItemParts = []
        part = item.create_new_empty_media_part()
        if self.localIP:
            part.HttpHeaders.update(self.localIP)

        use_input_stream = AddonSettings.use_adaptive_stream_add_on(
            channel=self)

        for video in videos:
            video_format = video.get("format", "")
            if not video_format:
                video_format = video.get("playerType", "")
            video_format = video_format.lower()

            if ("dash" in video_format
                    and not video_format == "dash") or "hds" in video_format:
                Logger.debug("Skipping video format: %s", video_format)
                continue
            Logger.debug("Found video item for format: %s", video_format)

            url = video['url']
            if any(filter(lambda s: s.Url == url, part.MediaStreams)):
                Logger.debug("Skippping duplicate Stream url: %s", url)
                continue

            if video_format == "dash" and use_input_stream:
                stream = part.append_media_stream(video['url'], 1)
                Mpd.set_input_stream_addon_input(stream, self.proxy)

            elif "m3u8" in url:
                alt_index = url.find("m3u8?")
                if alt_index > 0:
                    url = url[0:alt_index + 4]

                if "-fmp4.m3u8" in url or "-lowbw.m3u8" in url:
                    Logger.trace("Ignoring: %s", url)
                    continue

                M3u8.update_part_with_m3u8_streams(part,
                                                   url,
                                                   encrypted=False,
                                                   proxy=self.proxy,
                                                   headers=part.HttpHeaders,
                                                   channel=self)

            elif video["url"].startswith("rtmp"):
                # just replace some data in the URL
                part.append_media_stream(
                    self.get_verifiable_video_url(video["url"]).replace(
                        "_definst_", "?slist="), video[1])
            else:
                part.append_media_stream(url, 0)

        if subtitles:
            Logger.info("Found subtitles to play")
            for sub in subtitles:
                sub_format = sub["format"].lower()
                url = sub["url"]
                if sub_format == "websrt":
                    sub_url = url
                # elif subFormat == "webvtt":
                #     Logger.Info("Found M3u8 subtitle, replacing with WSRT")
                #     start, name, index = sub[-1].rsplit("/", 2)
                #     subUrl = "%s/%s/%s.wsrt" % (start, name, name)
                else:
                    # look for more
                    continue

                part.Subtitle = subtitlehelper.SubtitleHelper.download_subtitle(
                    sub_url,
                    format="srt",
                    proxy=self.proxy,
                    replace={"&amp;": "&"})
                # stop when finding one
                break

        item.complete = True
        return item
Exemplo n.º 10
0
    def update_video_item(self, item):
        """ Updates an existing MediaItem with more data.

        Used to update none complete MediaItems (self.complete = False). This
        could include opening the item's URL to fetch more data and then process that
        data or retrieve it's real media-URL.

        The method should at least:
        * cache the thumbnail to disk (use self.noImage if no thumb is available).
        * set at least one MediaItemPart with a single MediaStream.
        * set self.complete = True.

        if the returned item does not have a MediaItemPart then the self.complete flag
        will automatically be set back to False.

        :param MediaItem item: the original MediaItem that needs updating.

        :return: The original item with more data added to it's properties.
        :rtype: MediaItem

        """

        Logger.debug('Starting update_video_item for %s (%s)', item.name,
                     self.channelName)

        if not AddonSettings.use_adaptive_stream_add_on(with_encryption=False):
            Logger.error("Cannot playback video without adaptive stream addon")
            return item

        # https://www.foxsports.nl/api/video/videodata/2945190
        data = UriHandler.open(item.url,
                               proxy=self.proxy,
                               additional_headers=item.HttpHeaders)
        video_id = Regexer.do_regex(r'data-videoid="(\d+)" ', data)[-1]
        data = UriHandler.open(
            "https://www.foxsports.nl/api/video/videodata/%s" % (video_id, ),
            proxy=self.proxy,
            additional_headers=item.HttpHeaders,
            no_cache=True)
        stream_id = Regexer.do_regex('<uri>([^>]+)</uri>', data)[-1]

        # POST https://d3api.foxsports.nl/api/V2/entitlement/tokenize
        post_data = {
            "Type":
            1,
            "User":
            "",
            "VideoId":
            "{0}".format(video_id),
            "VideoSource":
            "{0}".format(stream_id),
            "VideoKind":
            "vod",
            "AssetState":
            "3",
            "PlayerType":
            "HTML5",
            "VideoSourceFormat":
            "DASH",
            "VideoSourceName":
            "DASH",
            # "VideoSourceFormat": "HLS",
            # "VideoSourceName": "HLS",
            "DRMType":
            "widevine",
            "AuthType":
            "Token",
            "ContentKeyData":
            "",
            "Other__":
            "playerName=HTML5-Web-vod|ae755267-8482-455b-9055-529b643ece1d|"
            "undefined|undefined|undefined|2945541|HTML5|web|diva.MajorVersion=4|"
            "diva.MinorVersion=2|diva.PatchVersion=13"
        }

        data = UriHandler.open(
            "https://d3api.foxsports.nl/api/V2/entitlement/tokenize",
            json=post_data,
            no_cache=True,
            proxy=self.proxy)
        stream_info = JsonHelper(data)
        stream_url = stream_info.get_value("ContentUrl")
        if not stream_url:
            message = "Protected stream: {0}".format(
                stream_info.get_value("Message"))
            XbmcWrapper.show_notification(None,
                                          message,
                                          notification_type=XbmcWrapper.Error,
                                          display_time=5000)

        license_url = stream_info.get_value("LicenseURL")
        part = item.create_new_empty_media_part()
        stream = part.append_media_stream(stream_url, 0)
        license_key = Mpd.get_license_key(license_url)
        Mpd.set_input_stream_addon_input(stream,
                                         proxy=self.proxy,
                                         license_key=license_key)
        return item
    def update_video_item(self, item):
        """ Updates an existing MediaItem with more data.

        Used to update none complete MediaItems (self.complete = False). This
        could include opening the item's URL to fetch more data and then process that
        data or retrieve it's real media-URL.

        The method should at least:
        * cache the thumbnail to disk (use self.noImage if no thumb is available).
        * set at least one MediaItemPart with a single MediaStream.
        * set self.complete = True.

        if the returned item does not have a MediaItemPart then the self.complete flag
        will automatically be set back to False.

        :param MediaItem item: the original MediaItem that needs updating.

        :return: The original item with more data added to it's properties.
        :rtype: MediaItem

        """

        Logger.debug('Starting update_video_item for %s (%s)', item.name, self.channelName)

        data = UriHandler.open(item.url, proxy=self.proxy)
        json = JsonHelper(data, Logger.instance())
        video_data = json.get_value("video")
        if video_data:
            part = item.create_new_empty_media_part()
            if self.localIP:
                part.HttpHeaders.update(self.localIP)

            # Get the videos
            video_infos = video_data.get("videoReferences")
            # Similar to SVT
            supported_formats = {
                "dash": 2,
                "dash-avc-51": 3,
                "hls": 0,
                "hls-ts-avc-51": 1,
                "ios": 0
            }
            for video_info in video_infos:

                video_type = video_info["playerType"]
                video_url = video_info['url']
                if video_type not in supported_formats:
                    Logger.debug("Ignoring %s: %s", video_type, video_url)
                    continue

                if "hls" in video_type or "ios" in video_type:
                    M3u8.update_part_with_m3u8_streams(part, video_url)

                elif "dash" in video_type:
                    stream = part.append_media_stream(video_url, supported_formats[video_type])
                    Mpd.set_input_stream_addon_input(stream, self.proxy)

                else:
                    continue

                # stream_info = video_info['url']
                # if "manifest.f4m" in stream_info:
                #     continue
                # elif "master.m3u8" in stream_info:
                #     for s, b in M3u8.get_streams_from_m3u8(stream_info, self.proxy, headers=part.HttpHeaders):
                #         item.complete = True
                #         part.append_media_stream(s, b)

            # subtitles
            subtitles = video_data.get("subtitleReferences")
            if subtitles and subtitles[0]["url"]:
                Logger.trace(subtitles)
                sub_url = subtitles[0]["url"]
                file_name = "%s.srt" % (EncodingHelper.encode_md5(sub_url),)
                sub_data = UriHandler.open(sub_url, proxy=self.proxy)

                # correct the subs
                regex = re.compile(r"^1(\d:)", re.MULTILINE)
                sub_data = re.sub(regex, r"0\g<1>", sub_data)
                sub_data = re.sub(r"--> 1(\d):", r"--> 0\g<1>:", sub_data)

                local_complete_path = os.path.join(Config.cacheDir, file_name)
                Logger.debug("Saving subtitle to: %s", local_complete_path)
                with open(local_complete_path, 'w') as f:
                    f.write(sub_data)

                part.Subtitle = local_complete_path

            item.complete = True

        return item