Пример #1
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

        """

        from resources.lib.streams.m3u8 import M3u8

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

        meta_data = UriHandler.open(item.url,
                                    proxy=self.proxy,
                                    referer=self.baseUrl)
        meta = JsonHelper(meta_data)
        stream_parts = meta.get_value("feed", "items")
        for stream_part in stream_parts:
            stream_url = stream_part["group"]["content"]
            stream_url = stream_url.replace("&device={device}", "")
            stream_url = "%s&format=json&acceptMethods=hls" % (stream_url, )
            stream_data = UriHandler.open(stream_url, proxy=self.proxy)
            stream = JsonHelper(stream_data)

            # subUrls = stream.get_value("package", "video", "item", 0, "transcript", 0, "typographic")  # NOSONAR
            part = item.create_new_empty_media_part()

            hls_streams = stream.get_value("package", "video", "item", 0,
                                           "rendition")
            for hls_stream in hls_streams:
                hls_url = hls_stream["src"]
                item.complete |= M3u8.update_part_with_m3u8_streams(
                    part, hls_url, proxy=self.proxy)

        item.complete = True
        Logger.trace("Media url: %s", item)
        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("Updating a (Live) video item")
        content, url = UriHandler.header(item.url)

        part = item.create_new_empty_media_part()
        if AddonSettings.use_adaptive_stream_add_on():
            part = item.create_new_empty_media_part()
            stream = part.append_media_stream(url, 0)
            M3u8.set_input_stream_addon_input(stream, item.HttpHeaders)
            item.complete = True
        else:
            for s, b in M3u8.get_streams_from_m3u8(url,
                                                   append_query_string=True):
                item.complete = True
                part.append_media_stream(s, b)
            item.complete = True

        return item
Пример #3
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)

        xml_data = UriHandler.open(item.url, proxy=self.proxy)
        # <ref type='adaptive' device='pc' host='http://manifest.us.rtl.nl' href='/rtlxl/network/pc/adaptive/components/videorecorder/27/278629/278630/d009c025-6e8c-3d11-8aba-dc8579373134.ssm/d009c025-6e8c-3d11-8aba-dc8579373134.m3u8' />
        m3u8_urls = Regexer.do_regex(
            "<ref type='adaptive' device='pc' host='([^']+)' href='/([^']+)' />",
            xml_data)
        if not m3u8_urls:
            Logger.warning("No m3u8 data found for: %s", item)
            return item
        m3u8_url = "%s/%s" % (m3u8_urls[0][0], m3u8_urls[0][1])

        part = item.create_new_empty_media_part()
        # prevent the "418 I'm a teapot" error
        part.HttpHeaders[
            "user-agent"] = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0"

        # Remove the Range header to make all streams start at the beginning.
        # Logger.debug("Setting an empty 'Range' http header to force playback at the start of a stream")
        # part.HttpHeaders["Range"] = ''

        item.complete = M3u8.update_part_with_m3u8_streams(
            part,
            m3u8_url,
            proxy=self.proxy,
            headers=part.HttpHeaders,
            channel=self)
        return item
    def update_live_item(self, item):
        """ Updates an existing MediaItem for a live stream 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_live_item for %s (%s)', item.name, self.channelName)

        item.MediaItemParts = []
        part = item.create_new_empty_media_part()

        spoof_ip = self._get_setting("spoof_ip", "0.0.0.0")
        if spoof_ip:
            for s, b in M3u8.get_streams_from_m3u8(item.url,
                                                   headers={"X-Forwarded-For": spoof_ip}):
                part.append_media_stream(s, b)
        else:
            for s, b in M3u8.get_streams_from_m3u8(item.url):
                part.append_media_stream(s, b)

        item.complete = True
        return item
Пример #5
0
    def __update_embedded(self, item, embedded_data):
        """ Updates a new "embedded" stream based on the json data

        :param MediaItem item:  The item to update
        :param embedded_data:   The json data

        :return: Updated MediaItem
        :rtype: MediaItem

        """

        stream_url = embedded_data["prioritizedStreams"][0]["links"]["stream"]["href"]
        part = item.create_new_empty_media_part()
        stream = part.append_media_stream(stream_url, 0)
        M3u8.set_input_stream_addon_input(stream, self.proxy)
        item.complete = True

        subtitle_urls = embedded_data["subtitles"]
        if subtitle_urls:
            subtitle_url = subtitle_urls[0]["link"]["href"]
            part.Subtitle = SubtitleHelper.download_subtitle(subtitle_url)

        return item
Пример #6
0
    def __update_live_audio(self, item, manifest, headers):
        video_info = manifest.get_value("playable", "assets", 0)
        url = video_info["url"]
        # Is it encrypted? encrypted = video_info["encrypted"]
        part = item.create_new_empty_media_part()

        # Adaptive add-on does not work with audio only
        for s, b in M3u8.get_streams_from_m3u8(url,
                                               self.proxy,
                                               headers=headers):
            item.complete = True
            part.append_media_stream(s, b)

        return item
Пример #7
0
    def __get_video_streams(self, video_id, part):
        """ Fetches the video stream for a given videoId

        @param video_id: (integer) the videoId
        @param part:    (MediaPart) the mediapart to add the streams to
        @return:        (bool) indicating a successfull retrieval

        """

        # hardcoded for now as it does not seem top matter
        dscgeo = '{"countryCode":"%s","expiry":1446917369986}' % (
            self.language.upper(), )
        dscgeo = HtmlEntityHelper.url_encode(dscgeo)
        headers = {"Cookie": "dsc-geo=%s" % (dscgeo, )}

        # send the data
        http, nothing, host, other = self.baseUrl.split("/", 3)
        subdomain, domain = host.split(".", 1)
        url = "https://secure.%s/secure/api/v2/user/authorization/stream/%s?stream_type=hls" \
              % (domain, video_id,)
        data = UriHandler.open(url,
                               proxy=self.proxy,
                               additional_headers=headers,
                               no_cache=True)
        json = JsonHelper(data)
        url = json.get_value("hls")

        if url is None:
            return False

        streams_found = False
        if "?" in url:
            qs = url.split("?")[-1]
        else:
            qs = None
        for s, b in M3u8.get_streams_from_m3u8(url, self.proxy):
            # and we need to append the original QueryString
            if "X-I-FRAME-STREAM" in s:
                continue

            streams_found = True
            if qs is not None:
                if "?" in s:
                    s = "%s&%s" % (s, qs)
                else:
                    s = "%s?%s" % (s, qs)

            part.append_media_stream(s, b)

        return streams_found
Пример #8
0
    def update_live_stream(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

        """

        part = item.create_new_empty_media_part()
        if item.url == "#livetv":
            url = "https://d34pj260kw1xmk.cloudfront.net/live/l1/tv/index.m3u8"
            M3u8.update_part_with_m3u8_streams(part,
                                               url,
                                               encrypted=True,
                                               proxy=self.proxy)
        else:
            # the audio won't play with the InputStream Adaptive add-on.
            url = "https://d34pj260kw1xmk.cloudfront.net/live/l1/radio/index.m3u8"
            for s, b in M3u8.get_streams_from_m3u8(url, self.proxy):
                part.append_media_stream(s, b)

        item.complete = True
        return item
Пример #9
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 item.url.endswith("m3u8"):
            data = UriHandler.open(item.url, proxy=self.proxy)
            json_data = Regexer.do_regex(self.mediaUrlRegex, data)
            if not json_data:
                Logger.error("Cannot find JSON stream info.")
                return item

            json = JsonHelper(json_data[0])
            Logger.trace(json.json)
            stream = json.get_value("source", "hls")
            if stream is None:
                stream = json.get_value("mzsource", "hls")
            Logger.debug("Found HLS: %s", stream)
        else:
            stream = item.url

        part = item.create_new_empty_media_part()
        for s, b in M3u8.get_streams_from_m3u8(stream, self.proxy):
            item.complete = True
            part.append_media_stream(s, b)

        # var playerConfig = {"id":"mediaplayer","width":"100%","height":"100%","autostart":"false","image":"http:\/\/www.ketnet.be\/sites\/default\/files\/thumb_5667ea22632bc.jpg","brand":"ketnet","source":{"hls":"http:\/\/vod.stream.vrt.be\/ketnet\/_definst_\/mp4:ketnet\/2015\/12\/Ben_ik_familie_van_R001_A0023_20151208_143112_864.mp4\/playlist.m3u8"},"analytics":{"type_stream":"vod","playlist":"Ben ik familie van?","program":"Ben ik familie van?","episode":"Ben ik familie van?: Warre - Aflevering 3","parts":"1","whatson":"270157835527"},"title":"Ben ik familie van?: Warre - Aflevering 3","description":"Ben ik familie van?: Warre - Aflevering 3"}
        return item
Пример #10
0
    def __update_m3u8(self, url, part, headers, use_kodi_hls):
        """ Update a video that has M3u8 streams.

        :param str url:                 The URL for the stream.
        :param MediaItemPart part:      The new part that needs updating.
        :param dict[str,str] headers:   The URL headers to use.
        :param bool use_kodi_hls:       Should we use the InputStream Adaptive add-on?

        """
        # first see if there are streams in this file, else check the second location.
        for s, b in M3u8.get_streams_from_m3u8(url,
                                               self.proxy,
                                               headers=headers):
            if use_kodi_hls:
                strm = part.append_media_stream(url, 0)
                M3u8.set_input_stream_addon_input(strm, headers=headers)
                # Only the main M3u8 is needed
                break
            else:
                part.append_media_stream(s, b)

        if not part.MediaStreams and "manifest.m3u8" in url:
            Logger.warning(
                "No streams found in %s, trying alternative with 'master.m3u8'",
                url)
            url = url.replace("manifest.m3u8", "master.m3u8")
            for s, b in M3u8.get_streams_from_m3u8(url,
                                                   self.proxy,
                                                   headers=headers):
                if use_kodi_hls:
                    strm = part.append_media_stream(url, 0)
                    M3u8.set_input_stream_addon_input(strm, headers=headers)
                    # Only the main M3u8 is needed
                    break
                else:
                    part.append_media_stream(s, b)

        # check for subs
        # https://mtgxse01-vh.akamaihd.net/i/201703/13/DCjOLN_1489416462884_427ff3d3_,48,260,460,900,1800,2800,.mp4.csmil/master.m3u8?__b__=300&hdnts=st=1489687185~exp=3637170832~acl=/*~hmac=d0e12e62c219d96798e5b5ef31b11fa848724516b255897efe9808c8a499308b&cc1=name=Svenska%20f%C3%B6r%20h%C3%B6rselskadade~default=no~forced=no~lang=sv~uri=https%3A%2F%2Fsubstitch.play.mtgx.tv%2Fsubtitle%2Fconvert%2Fxml%3Fsource%3Dhttps%3A%2F%2Fcdn-subtitles-mtgx-tv.akamaized.net%2Fpitcher%2F20xxxxxx%2F2039xxxx%2F203969xx%2F20396967%2F20396967-swt.xml%26output%3Dm3u8
        # https://cdn-subtitles-mtgx-tv.akamaized.net/pitcher/20xxxxxx/2039xxxx/203969xx/20396967/20396967-swt.xml&output=m3u8
        if "uri=" in url and not part.Subtitle:
            Logger.debug("Extracting subs from M3u8")
            sub_url = url.rsplit("uri=")[-1]
            sub_url = HtmlEntityHelper.url_decode(sub_url)
            sub_data = UriHandler.open(sub_url, proxy=self.proxy)
            subs = [
                line for line in sub_data.split("\n")
                if line.startswith("http")
            ]
            if subs:
                part.Subtitle = SubtitleHelper.download_subtitle(
                    subs[0], format='webvtt', proxy=self.proxy)
        return
Пример #11
0
    def update_live_item(self, item):
        data = UriHandler.open(item.url,
                               proxy=self.proxy,
                               additional_headers=item.HttpHeaders)
        media_regex = 'data-media="([^"]+)"'
        media_info = Regexer.do_regex(media_regex, data)[0]
        media_info = HtmlEntityHelper.convert_html_entities(media_info)
        media_info = JsonHelper(media_info)
        Logger.trace(media_info)
        part = item.create_new_empty_media_part()

        hls_url = media_info.get_value("streamUrl")
        if hls_url is not None and "m3u8" in hls_url:
            Logger.debug("Found HLS url for %s: %s",
                         media_info.json["streamName"], hls_url)

            for s, b in M3u8.get_streams_from_m3u8(hls_url, self.proxy):
                part.append_media_stream(s, b)
                item.complete = True
        else:
            Logger.debug("No HLS url found for %s. Fetching RTMP Token.",
                         media_info.json["streamName"])
            # fetch the token:
            token_url = "%s/api/media/streaming?streamname=%s" \
                        % (self.baseUrl, media_info.json["streamName"])

            token_data = UriHandler.open(token_url,
                                         proxy=self.proxy,
                                         additional_headers=item.HttpHeaders,
                                         no_cache=True)

            token_data = JsonHelper(token_data)
            token = token_data.get_value("token")
            Logger.debug("Found token '%s' for '%s'", token,
                         media_info.json["streamName"])

            rtmp_url = "rtmp://rtmp.rtbf.be/livecast/%s?%s pageUrl=%s tcUrl=rtmp://rtmp.rtbf.be/livecast" \
                       % (media_info.json["streamName"], token, self.baseUrl)
            rtmp_url = self.get_verifiable_video_url(rtmp_url)
            part.append_media_stream(rtmp_url, 0)
            item.complete = True

        item.isGeoLocked = not media_info.get_value(
            "geoLocRestriction", fallback="world") == "world"
        return item
Пример #12
0
    def update_live_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

        """

        # http://services.vrt.be/videoplayer/r/live.json?_1466364209811=
        channel_data = UriHandler.open(
            "http://services.vrt.be/videoplayer/r/live.json", proxy=self.proxy)
        channel_data = JsonHelper(channel_data)
        url = None
        for channel_id in channel_data.json:
            if channel_id not in item.url:
                continue
            else:
                url = channel_data.json[channel_id].get("hls")

        if url is None:
            Logger.error("Could not find stream for live channel: %s",
                         item.url)
            return item

        Logger.debug("Found stream url for %s: %s", item, url)
        part = item.create_new_empty_media_part()
        for s, b in M3u8.get_streams_from_m3u8(url, self.proxy):
            item.complete = True
            part.append_media_stream(s, b)
        return item
Пример #13
0
    def __update_video(self, item, data):
        if not item.url.startswith("https://api.viervijfzes.be/content/"):
            regex = 'data-videoid="([^"]+)'
            m3u8_url = Regexer.do_regex(regex, data)[-1]
            # we either have an URL now or an uuid
        else:
            m3u8_url = item.url.rsplit("/", 1)[-1]

        if ".m3u8" not in m3u8_url:
            Logger.info("Not a direct M3u8 file. Need to log in")
            url = "https://api.viervijfzes.be/content/%s" % (m3u8_url, )

            # We need to log in
            if not self.loggedOn:
                self.log_on()

            # add authorization header
            authentication_header = {
                "authorization": self.__idToken,
                "content-type": "application/json"
            }
            data = UriHandler.open(url,
                                   proxy=self.proxy,
                                   additional_headers=authentication_header)
            json_data = JsonHelper(data)
            m3u8_url = json_data.get_value("video", "S")

        # Geo Locked?
        if "/geo/" in m3u8_url.lower():
            # set it for the error statistics
            item.isGeoLocked = True

        part = item.create_new_empty_media_part()
        item.complete = M3u8.update_part_with_m3u8_streams(part,
                                                           m3u8_url,
                                                           proxy=self.proxy,
                                                           channel=self,
                                                           encrypted=False)

        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("Updating a (Live) video item")

        if item.type == "audio":
            item.append_single_stream(item.url, 0)
            item.complete = True

        elif ".m3u8" in item.url:
            part = item.create_new_empty_media_part()
            item.complete = M3u8.update_part_with_m3u8_streams(part,
                                                               item.url,
                                                               channel=self,
                                                               encrypted=False)

        elif item.url.endswith(".mp4"):
            item.append_single_stream(item.url, self.channelBitrate)
            item.complete = True

        return item
Пример #15
0
    def __update_video(self, item, data):
        regex = 'data-file="([^"]+)'
        m3u8_url = Regexer.do_regex(regex, data)[-1]

        if ".m3u8" not in m3u8_url:
            Logger.info("Not a direct M3u8 file. Need to log in")
            url = "https://api.viervijfzes.be/content/%s" % (m3u8_url, )

            # We need to log in
            if not self.loggedOn:
                self.log_on()

            # add authorization header
            authentication_header = {
                "authorization": self.__idToken,
                "content-type": "application/json"
            }
            data = UriHandler.open(url,
                                   proxy=self.proxy,
                                   additional_headers=authentication_header)
            json_data = JsonHelper(data)
            m3u8_url = json_data.get_value("video", "S")

        # Geo Locked?
        if "geo" in m3u8_url.lower():
            # set it for the error statistics
            item.isGeoLocked = True

        part = item.create_new_empty_media_part()
        for s, b in M3u8.get_streams_from_m3u8(m3u8_url, self.proxy):
            if int(b) < 200:
                Logger.info("Skipping stream of quality '%s' kbps", b)
                continue

            item.complete = True
            part.append_media_stream(s, b)

        item.complete = True
        return item
Пример #16
0
    def update_video_item(self, item):
        """
        Accepts an item. It returns an updated item. Usually retrieves the MediaURL
        and the Thumb! It should return a completed item.
        """
        Logger.debug('Starting update_video_item for %s (%s)', item.name,
                     self.channelName)

        # rtmpt://vrt.flash.streampower.be/een//2011/07/1000_110723_getipt_neefs_wiels_Website_EEN.flv
        # http://www.een.be/sites/een.be/modules/custom/vrt_video/player/player_4.3.swf

        # now the mediaurl is derived. First we try WMV
        data = UriHandler.open(item.url, proxy=self.proxy)

        part = item.create_new_empty_media_part()
        if "mediazone.vrt.be" not in item.url:
            # Extract actual media data
            video_id = Regexer.do_regex('data-video=[\'"]([^"\']+)[\'"]',
                                        data)[0]
            url = "https://mediazone.vrt.be/api/v1/een/assets/%s" % (
                video_id, )
            data = UriHandler.open(url, proxy=self.proxy)

        json = JsonHelper(data)
        urls = json.get_value("targetUrls")

        for url_info in urls:
            Logger.trace(url_info)
            if url_info["type"].lower() != "hls":
                continue

            hls_url = url_info["url"]
            for s, b in M3u8.get_streams_from_m3u8(hls_url, self.proxy):
                part.append_media_stream(s, b)

        item.complete = True
        return item
Пример #17
0
    def __update_live_video(self, item, manifest, headers):
        video_info = manifest.get_value("playable", "assets", 0)
        url = video_info["url"]
        encrypted = video_info["encrypted"]
        part = item.create_new_empty_media_part()

        if encrypted:
            use_adaptive = AddonSettings.use_adaptive_stream_add_on(
                with_encryption=True)
            if not use_adaptive:
                Logger.error(
                    "Cannot playback encrypted item without inputstream.adaptive with encryption support"
                )
                return item
            stream = part.append_media_stream(url, 0)
            key = M3u8.get_license_key("", key_headers=headers, key_type="R")
            M3u8.set_input_stream_addon_input(stream,
                                              proxy=self.proxy,
                                              headers=headers,
                                              license_key=key)
            item.complete = True
        else:
            use_adaptive = AddonSettings.use_adaptive_stream_add_on(
                with_encryption=False)
            if use_adaptive:
                stream = part.append_media_stream(url, 0)
                M3u8.set_input_stream_addon_input(stream,
                                                  self.proxy,
                                                  headers=headers)
                item.complete = True
            else:
                for s, b in M3u8.get_streams_from_m3u8(url,
                                                       self.proxy,
                                                       headers=headers):
                    item.complete = True
                    part.append_media_stream(s, b)

        return item
Пример #18
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)

        # noinspection PyStatementEffect
        """
                C:\temp\rtmpdump-2.3>rtmpdump.exe -z -o test.flv -n "cp70051.edgefcs.net" -a "tv
                4ondemand" -y "mp4:/mp4root/2010-06-02/pid2780626_1019976_T3MP48_.mp4?token=c3Rh
                cnRfdGltZT0yMDEwMDcyNjE2NDYyNiZlbmRfdGltZT0yMDEwMDcyNjE2NDgyNiZkaWdlc3Q9ZjFjN2U1
                NTRiY2U5ODMxMDMwYWQxZWEwNzNhZmUxNjI=" -l 2

                C:\temp\rtmpdump-2.3>rtmpdump.exe -z -o test.flv -r rtmpe://cp70051.edgefcs.net/
                tv4ondemand/mp4root/2010-06-02/pid2780626_1019976_T3MP48_.mp4?token=c3RhcnRfdGlt
                ZT0yMDEwMDcyNjE2NDYyNiZlbmRfdGltZT0yMDEwMDcyNjE2NDgyNiZkaWdlc3Q9ZjFjN2U1NTRiY2U5
                ODMxMDMwYWQxZWEwNzNhZmUxNjI=
                """

        # retrieve the mediaurl
        data = UriHandler.open(item.url,
                               proxy=self.proxy,
                               additional_headers=self.localIP)
        stream_info = JsonHelper(data)
        stream_url = stream_info.get_value("playbackItem", "manifestUrl")
        if stream_url is None:
            return item

        if ".mpd" in stream_url:
            return self.__update_dash_video(item, stream_info)

        part = item.create_new_empty_media_part()

        if AddonSettings.use_adaptive_stream_add_on() and False:
            subtitle = M3u8.get_subtitle(stream_url, proxy=self.proxy)
            stream = part.append_media_stream(stream_url, 0)
            M3u8.set_input_stream_addon_input(stream, self.proxy)
            item.complete = True
        else:
            m3u8_data = UriHandler.open(stream_url,
                                        proxy=self.proxy,
                                        additional_headers=self.localIP)
            subtitle = M3u8.get_subtitle(stream_url,
                                         proxy=self.proxy,
                                         play_list_data=m3u8_data)
            for s, b, a in M3u8.get_streams_from_m3u8(stream_url,
                                                      self.proxy,
                                                      play_list_data=m3u8_data,
                                                      map_audio=True):
                item.complete = True
                if not item.isLive and "-video" not in s:
                    continue

                if a and "-audio" not in s:
                    # remove any query parameters
                    video_part = s.rsplit("?", 1)[0]
                    video_part = video_part.rsplit("-", 1)[-1]
                    video_part = "-%s" % (video_part, )
                    s = a.replace(".m3u8", video_part)
                part.append_media_stream(s, b)

        if subtitle:
            subtitle = subtitle.replace(".m3u8", ".webvtt")
            part.Subtitle = SubtitleHelper.download_subtitle(subtitle,
                                                             format="m3u8srt",
                                                             proxy=self.proxy)
        return item
Пример #19
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)

        # noinspection PyStatementEffect
        """
        data-video-id="1613274"
        data-video-type="video"
        data-video-src="http://media.vrtnieuws.net/2013/04/135132051ONL1304255866693.urlFLVLong.flv"
        data-video-title="Het journaal 1 - 25/04/13"
        data-video-rtmp-server="rtmp://vrt.flash.streampower.be/vrtnieuws"
        data-video-rtmp-path="2013/04/135132051ONL1304255866693.urlFLVLong.flv"
        data-video-rtmpt-server="rtmpt://vrt.flash.streampower.be/vrtnieuws"
        data-video-rtmpt-path="2013/04/135132051ONL1304255866693.urlFLVLong.flv"
        data-video-iphone-server="http://iphone.streampower.be/vrtnieuws_nogeo/_definst_"
        data-video-iphone-path="2013/04/135132051ONL1304255866693.urlMP4_H.264.m4v"
        data-video-mobile-server="rtsp://mp4.streampower.be/vrt/vrt_mobile/vrtnieuws_nogeo"
        data-video-mobile-path="2013/04/135132051ONL1304255866693.url3GP_MPEG4.3gp"
        data-video-sitestat-program="het_journaal_1_-_250413_id_1-1613274"
        """

        # now the mediaurl is derived. First we try WMV
        data = UriHandler.open(item.url, proxy=self.proxy)
        data = data.replace("\\/", "/")
        urls = Regexer.do_regex(self.mediaUrlRegex, data)
        part = item.create_new_empty_media_part()
        for url in urls:
            Logger.trace(url)
            if url[0] == "src":
                flv = url[1]
                bitrate = 750
            else:
                flv_server = url[1]
                flv_path = url[2]

                if url[0] == "rtmp-server":
                    flv = "%s//%s" % (flv_server, flv_path)
                    bitrate = 750

                elif url[0] == "rtmpt-server":
                    continue
                    # Not working for now
                    #flv = "%s//%s" % (flv_server, flv_path)
                    #flv = self.get_verifiable_video_url(flv)
                    #bitrate = 1500

                elif url[0] == "iphone-server":
                    flv = "%s/%s" % (flv_server, flv_path)
                    if not flv.endswith("playlist.m3u8"):
                        flv = "%s/playlist.m3u8" % (flv,)

                    for s, b in M3u8.get_streams_from_m3u8(flv, self.proxy):
                        item.complete = True
                        part.append_media_stream(s, b)
                    # no need to continue adding the streams
                    continue

                elif url[0] == "mobile-server":
                    flv = "%s/%s" % (flv_server, flv_path)
                    bitrate = 250

                else:
                    flv = "%s/%s" % (flv_server, flv_path)
                    bitrate = 0

            part.append_media_stream(flv, bitrate)

        item.complete = True
        return item
Пример #20
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
Пример #21
0
    def update_live_item(self, item):
        """ Updates an existing Live stream 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,
                               additional_headers=item.HttpHeaders)
        json = JsonHelper(data)
        video_play_lists = json.get_value("Video", "Playlists", "Playlist")

        part = item.create_new_empty_media_part()
        for play_list in video_play_lists:
            streams = play_list["url"]
            Logger.trace("Found %s streams", len(streams))
            for stream in streams:
                stream_url = stream["text"]
                if ".m3u8" in stream_url:
                    for s, b in M3u8.get_streams_from_m3u8(
                            stream_url, self.proxy):
                        item.complete = True
                        part.append_media_stream(s, b)
                else:
                    Logger.debug("Cannot use stream url: %s", stream_url)

        # Unused at the moment
        # videoInfo = json.get_value("content", "videoInfos")
        #
        # part = item.create_new_empty_media_part()
        # if "HLSurlHD" in videoInfo:
        #     # HLSurlHD=http://srfvodhd-vh.akamaihd.net/i/vod/potzmusig/2015/03/potzmusig_20150307_184438_v_webcast_h264_,q10,q20,q30,q40,q50,q60,.mp4.csmil/master.m3u8
        #     for s, b in M3u8.get_streams_from_m3u8(videoInfo["HLSurlHD"], self.proxy):
        #         item.complete = True
        #         # s = self.get_verifiable_video_url(s)
        #         part.append_media_stream(s, b)
        # elif "HLSurl" in videoInfo:
        #     # HLSurl=http://srfvodhd-vh.akamaihd.net/i/vod/potzmusig/2015/03/potzmusig_20150307_184438_v_webcast_h264_,q10,q20,q30,q40,.mp4.csmil/master.m3u8
        #     for s, b in M3u8.get_streams_from_m3u8(videoInfo["HLSurl"], self.proxy):
        #         item.complete = True
        #         # s = self.get_verifiable_video_url(s)
        #         part.append_media_stream(s, b)
        #
        # if "downloadLink" in videoInfo:
        #     # downloadLink=http://podcastsource.sf.tv/nps/podcast/10vor10/2015/03/10vor10_20150304_215030_v_podcast_h264_q10.mp4
        #     part.append_media_stream(videoInfo["downloadLink"], 1000)

        return item
Пример #22
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
Пример #23
0
    def __update_video_from_brightcove(self, item, data,
                                       use_adaptive_with_encryption):
        """ Updates an existing MediaItem with more data based on an MPD stream.

        :param str data:                            Stream info retrieved from BrightCove.
        :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

        """

        part = item.create_new_empty_media_part()
        # Then try the new BrightCove JSON
        bright_cove_regex = '<video[^>]+data-video-id="(?<videoId>[^"]+)[^>]+data-account="(?<videoAccount>[^"]+)'
        bright_cove_data = Regexer.do_regex(
            Regexer.from_expresso(bright_cove_regex), data)
        if not bright_cove_data:
            Logger.warning("Error updating using BrightCove data: %s", item)
            return item

        Logger.info("Found new BrightCove JSON data")
        bright_cove_url = 'https://edge.api.brightcove.com/playback/v1/accounts/' \
                          '%(videoAccount)s/videos/%(videoId)s' % bright_cove_data[0]
        headers = {
            "Accept":
            "application/json;pk=BCpkADawqM3ve1c3k3HcmzaxBvD8lXCl89K7XEHiKutxZArg2c5RhwJHJANOwPwS_4o7UsC4RhIzXG8Y69mrwKCPlRkIxNgPQVY9qG78SJ1TJop4JoDDcgdsNrg"
        }

        bright_cove_data = UriHandler.open(bright_cove_url,
                                           proxy=self.proxy,
                                           additional_headers=headers)
        bright_cove_json = JsonHelper(bright_cove_data)
        streams = [
            d for d in bright_cove_json.get_value("sources")
            if d["container"] == "M2TS"
        ]
        # Old filter
        # streams = filter(lambda d: d["container"] == "M2TS", bright_cove_json.get_value("sources"))
        if not streams:
            Logger.warning("Error extracting streams from BrightCove data: %s",
                           item)
            return item

        # noinspection PyTypeChecker
        stream_url = streams[0]["src"]

        # these streams work better with the the InputStreamAddon because it removes the
        # "range" http header
        if use_adaptive_with_encryption:
            Logger.info("Using InputStreamAddon for playback of HLS stream")
            strm = part.append_media_stream(stream_url, 0)
            M3u8.set_input_stream_addon_input(strm, proxy=self.proxy)
            item.complete = True
            return item

        for s, b in M3u8.get_streams_from_m3u8(stream_url, self.proxy):
            item.complete = True
            part.append_media_stream(s, b)
        return item
Пример #24
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
Пример #25
0
    def update_json_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

        """

        headers = {"accept": "application/vnd.sbs.ovp+json; version=2.0"}
        data = UriHandler.open(item.url,
                               proxy=self.proxy,
                               additional_headers=headers)

        if UriHandler.instance().status.code == 404:
            Logger.warning("No normal stream found. Trying newer method")
            new_url = item.url.replace("https://embed.kijk.nl/api/",
                                       "https://embed.kijk.nl/")
            item.url = new_url[:new_url.index("?")]
            return self.__update_embedded_video(item)

        json = JsonHelper(data)
        embed_url = json.get_value("metadata", "embedURL")
        if embed_url:
            Logger.warning(
                "Embed URL found. Using that to determine the streams.")
            item.url = embed_url
            try:
                return self.__update_embedded_video(item)
            except:
                Logger.warning("Failed to update embedded item:",
                               exc_info=True)

        use_adaptive_with_encryption = AddonSettings.use_adaptive_stream_add_on(
            with_encryption=True, channel=self)
        mpd_info = json.get_value("entitlements", "play")

        # is there MPD information in the API response?
        if mpd_info is not None:
            return self.__update_video_from_mpd(item, mpd_info,
                                                use_adaptive_with_encryption)

        # Try the plain M3u8 streams
        part = item.create_new_empty_media_part()
        m3u8_url = json.get_value("playlist")
        use_adaptive = AddonSettings.use_adaptive_stream_add_on(channel=self)

        # with the Accept: application/vnd.sbs.ovp+json; version=2.0 header, the m3u8 streams that
        # are brightcove based have an url parameter instead of an empty m3u8 file
        Logger.debug("Trying standard M3u8 streams.")
        if m3u8_url != "https://embed.kijk.nl/api/playlist/.m3u8" \
                and "hostingervice=brightcove" not in m3u8_url:
            for s, b in M3u8.get_streams_from_m3u8(m3u8_url,
                                                   self.proxy,
                                                   append_query_string=True):
                if "_enc_" in s:
                    continue

                if use_adaptive:
                    # we have at least 1 none encrypted streams
                    Logger.info("Using HLS InputStreamAddon")
                    strm = part.append_media_stream(m3u8_url, 0)
                    M3u8.set_input_stream_addon_input(strm, proxy=self.proxy)
                    item.complete = True
                    return item

                part.append_media_stream(s, b)
                item.complete = True
            return item

        Logger.warning("No M3u8 data found. Falling back to BrightCove")
        video_id = json.get_value("vpakey")
        # videoId = json.get_value("videoId") -> Not all items have a videoId
        mpd_manifest_url = "https://embed.kijk.nl/video/%s?width=868&height=491" % (
            video_id, )
        referer = "https://embed.kijk.nl/video/%s" % (video_id, )

        data = UriHandler.open(mpd_manifest_url,
                               proxy=self.proxy,
                               referer=referer)
        # First try to find an M3u8
        m3u8_urls = Regexer.do_regex('https:[^"]+.m3u8', data)
        for m3u8_url in m3u8_urls:
            m3u8_url = m3u8_url.replace("\\", "")

            # We need the actual URI to make this work, so fetch it.
            m3u8_url = UriHandler.header(m3u8_url, proxy=self.proxy)[-1]
            Logger.debug("Found direct M3u8 in brightcove data.")
            if use_adaptive:
                # we have at least 1 none encrypted streams
                Logger.info("Using HLS InputStreamAddon")
                strm = part.append_media_stream(m3u8_url, 0)
                M3u8.set_input_stream_addon_input(strm, proxy=self.proxy)
                item.complete = True
                return item

            for s, b in M3u8.get_streams_from_m3u8(m3u8_url,
                                                   self.proxy,
                                                   append_query_string=True):
                item.complete = True
                part.append_media_stream(s, b)

            return item

        return self.__update_video_from_brightcove(
            item, data, use_adaptive_with_encryption)
Пример #26
0
    def update_json_video(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: %s', item.name)

        data = UriHandler.open(item.url,
                               proxy=self.proxy,
                               additional_headers=self.httpHeaders)
        json_data = JsonHelper(data)
        streams = json_data.get_value("formats")
        if not streams:
            return item

        qualities = {
            "720p": 1600,
            "480p": 1200,
            "360p": 500,
            "other": 0
        }  # , "http-hls": 1500, "3gp-mob01": 300, "flv-web01": 500}
        part = item.create_new_empty_media_part()
        urls = []
        for stream in streams:
            url = stream["url"].values()[-1]
            if url in urls:
                # duplicate url, ignore
                continue

            urls.append(url)

            # actually process the url
            if ".m3u8" not in url:
                part.append_media_stream(url=url,
                                         bitrate=qualities.get(
                                             stream.get("name", "other"), 0))
                item.complete = True
            # elif AddonSettings.use_adaptive_stream_add_on():
            #     content_type, url = UriHandler.header(url, self.proxy)
            #     stream = part.append_media_stream(url, 0)
            #     M3u8.SetInputStreamAddonInput(stream, self.proxy)
            #     item.complete = True
            else:
                M3u8.update_part_with_m3u8_streams(part,
                                                   url,
                                                   proxy=self.proxy,
                                                   channel=self)
        return item
Пример #27
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
Пример #28
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

        """

        if item.metaData.get(self.__REQUIRES_LOGIN, False):
            logged_in = self.log_on()
            if not logged_in:
                XbmcWrapper.show_dialog(LanguageHelper.LoginErrorTitle,
                                        LanguageHelper.LoginErrorText)
                return item

        video_data = UriHandler.open(item.url,
                                     proxy=self.proxy,
                                     additional_headers=self.localIP)
        if not video_data:
            return item

        video_data = JsonHelper(video_data)
        video_info = video_data.get_value("data", "attributes")
        errors = video_data.get_value("errors")
        Logger.error("Error updating items: %s", errors)
        if errors:
            return item

        part = item.create_new_empty_media_part()

        m3u8url = video_info["streaming"]["hls"]["url"]

        m3u8data = UriHandler.open(m3u8url, self.proxy)
        if AddonSettings.use_adaptive_stream_add_on():
            stream = part.append_media_stream(m3u8url, 0)
            item.complete = True
            M3u8.set_input_stream_addon_input(stream, self.proxy)
        else:
            # user agent for all sub m3u8 and ts requests needs to be the same
            part.HttpHeaders[
                "user-agent"] = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 (.NET CLR 3.5.30729)"
            for s, b, a in M3u8.get_streams_from_m3u8(
                    m3u8url,
                    self.proxy,
                    append_query_string=False,
                    map_audio=True,
                    play_list_data=m3u8data):
                item.complete = True
                if a:
                    audio_part = a.split("-prog_index.m3u8", 1)[0]
                    audio_id = audio_part.rsplit("/", 1)[-1]
                    s = s.replace("-prog_index.m3u8",
                                  "-{0}-prog_index.m3u8".format(audio_id))
                part.append_media_stream(s, b)

        if self.language == "se":
            vtt_url = M3u8.get_subtitle(m3u8url,
                                        self.proxy,
                                        m3u8data,
                                        language="sv")
        elif self.language == "dk":
            vtt_url = M3u8.get_subtitle(m3u8url,
                                        self.proxy,
                                        m3u8data,
                                        language="da")
        else:
            vtt_url = M3u8.get_subtitle(m3u8url, self.proxy, m3u8data)

        # https://dplaynordics-vod-80.akamaized.net/dplaydni/259/0/hls/243241001/1112635959-prog_index.m3u8?version_hash=bb753129&hdnts=st=1518218118~exp=1518304518~acl=/*~hmac=bdeefe0ec880f8614e14af4d4a5ca4d3260bf2eaa8559e1eb8ba788645f2087a
        vtt_url = vtt_url.replace("-prog_index.m3u8", "-0.vtt")
        part.Subtitle = SubtitleHelper.download_subtitle(vtt_url,
                                                         format='srt',
                                                         proxy=self.proxy)

        # if the user has premium, don't show any warnings
        if self.__has_premium:
            item.isPaid = False
        return item
Пример #29
0
    def get_streams_from_npo(url, episode_id, proxy=None, headers=None):
        """ Retrieve NPO Player Live streams from a different number of stream urls.

        @param url:               (String) The url to download
        @param episode_id:         (String) The NPO episode ID
        @param headers:           (dict) Possible HTTP Headers
        @param proxy:             (Proxy) The proxy to use for opening

        Can be used like this:

            part = item.create_new_empty_media_part()
            for s, b in NpoStream.get_streams_from_npo(m3u8Url, self.proxy):
                item.complete = True
                # s = self.get_verifiable_video_url(s)
                part.append_media_stream(s, b)

        """

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

        # we need an hash code
        token_json_data = UriHandler.open("http://ida.omroep.nl/app.php/auth",
                                          no_cache=True,
                                          proxy=proxy,
                                          additional_headers=headers)
        token_json = JsonHelper(token_json_data)
        token = token_json.get_value("token")

        url = "http://ida.omroep.nl/app.php/%s?adaptive=yes&token=%s" % (
            episode_id, token)
        stream_data = UriHandler.open(url,
                                      proxy=proxy,
                                      additional_headers=headers)
        if not stream_data:
            return []

        stream_json = JsonHelper(stream_data, logger=Logger.instance())
        stream_infos = stream_json.get_value("items")[0]
        Logger.trace(stream_infos)
        streams = []
        for stream_info in stream_infos:
            Logger.debug("Found stream info: %s", stream_info)
            if stream_info["format"] == "mp3":
                streams.append((stream_info["url"], 0))
                continue

            elif stream_info["contentType"] == "live":
                Logger.debug("Found live stream")
                url = stream_info["url"]
                url = url.replace("jsonp", "json")
                live_url_data = UriHandler.open(url,
                                                proxy=proxy,
                                                additional_headers=headers)
                live_url = live_url_data.strip("\"").replace("\\", "")
                Logger.trace(live_url)
                streams += M3u8.get_streams_from_m3u8(live_url,
                                                      proxy,
                                                      headers=headers)

            elif stream_info["format"] == "hls":
                m3u8_info_url = stream_info["url"]
                m3u8_info_data = UriHandler.open(m3u8_info_url,
                                                 proxy=proxy,
                                                 additional_headers=headers)
                m3u8_info_json = JsonHelper(m3u8_info_data,
                                            logger=Logger.instance())
                m3u8_url = m3u8_info_json.get_value("url")
                streams += M3u8.get_streams_from_m3u8(m3u8_url,
                                                      proxy,
                                                      headers=headers)

            elif stream_info["format"] == "mp4":
                bitrates = {"hoog": 1000, "normaal": 500}
                url = stream_info["url"]
                if "contentType" in stream_info and stream_info[
                        "contentType"] == "url":
                    mp4_url = url
                else:
                    url = url.replace("jsonp", "json")
                    mp4_url_data = UriHandler.open(url,
                                                   proxy=proxy,
                                                   additional_headers=headers)
                    mp4_info_json = JsonHelper(mp4_url_data,
                                               logger=Logger.instance())
                    mp4_url = mp4_info_json.get_value("url")
                bitrate = bitrates.get(stream_info["label"].lower(), 0)
                if bitrate == 0 and "/ipod/" in mp4_url:
                    bitrate = 200
                elif bitrate == 0 and "/mp4/" in mp4_url:
                    bitrate = 500
                streams.append((mp4_url, bitrate))

        return streams
    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_urls = video_data.get("videoReferences")
            for video_url in video_urls:
                # Logger.Trace(videoUrl)
                stream_info = video_url['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