コード例 #1
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)
        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):
                part.append_media_stream(s, b)

        item.complete = True
        return item
コード例 #2
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

        """

        Logger.debug("Updating the live stream")
        url = "https://rrr.sz.xlcdn.com/?account=atvijf" \
              "&file=live&type=live&service=wowza&protocol=https&output=playlist.m3u8"

        part = item.create_new_empty_media_part()
        item.complete = \
            M3u8.update_part_with_m3u8_streams(part, url, proxy=self.proxy, channel=self)

        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)

        part = item.create_new_empty_media_part()
        item.complete = M3u8.update_part_with_m3u8_streams(part,
                                                           item.url,
                                                           channel=self)
        return item
コード例 #4
0
    def __update_video(self, item, data):
        if not item.url.startswith("https://api.viervijfzes.be/content/"):
            regex = 'data-video-*id="([^"]+)'
            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, 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, channel=self, encrypted=False)

        return item
コード例 #5
0
    def create_video_item_json(self, result_set):
        """ Creates a MediaItem of type 'video' using the result_set from the regex.

        This method creates a new MediaItem from the Regular Expression or Json
        results <result_set>. The method should be implemented by derived classes
        and are specific to the channel.

        If the item is completely processed an no further data needs to be fetched
        the self.complete property should be set to True. If not set to True, the
        self.update_video_item method is called if the item is focussed or selected
        for playback.

        :param dict result_set: The result_set of the self.episodeItemRegex

        :return: A new MediaItem of type 'video' or 'audio' (despite the method's name).
        :rtype: MediaItem|None

        """

        Logger.trace(result_set)

        image_data = result_set.get("media", [])
        thumb = None
        url = None
        for image in image_data:
            thumb = image.get("imageHigh", image["image"])
            url = image.get("url")

        item = MediaItem(result_set["title"], url)
        item.type = "video"
        item.icon = self.icon
        item.thumb = thumb or self.noImage
        item.complete = True
        item.description = result_set.get("text")
        part = item.create_new_empty_media_part()
        M3u8.update_part_with_m3u8_streams(part,
                                           url,
                                           proxy=self.proxy,
                                           channel=self)

        # Let's not do the time now
        time_stamp = result_set["created"]
        date_time = DateHelper.get_date_from_posix(time_stamp)
        item.set_date(date_time.year, date_time.month, date_time.day,
                      date_time.hour, date_time.minute, date_time.second)
        return item
コード例 #6
0
    def update_video_item(self, item):
        """Updates an existing MediaItem with more data.

        Arguments:
        item : MediaItem - the MediaItem that needs to be updated

        Returns:
        The original item with more data added to it's properties.

        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.

        """

        Logger.debug('Starting update_video_item for %s (%s)', item.name,
                     self.channelName)
        from resources.lib.streams.m3u8 import M3u8

        data = UriHandler.open(item.url, proxy=self.proxy)
        video_id = Regexer.do_regex(r'{"video":{"config":{"uri":"([^"]+)',
                                    data)[0]
        url = "http://media.mtvnservices.com/pmt/e1/access/index.html?uri={}&configtype=edge".format(
            video_id)
        meta_data = UriHandler.open(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
コード例 #7
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

        """

        data = UriHandler.open(item.url)
        video_data = JsonHelper(data)
        stream_data = video_data.get_value("playable")
        if not stream_data:
            return item

        part = item.create_new_empty_media_part()
        for stream_info in stream_data["assets"]:
            url = stream_info["url"]
            stream_type = stream_info["format"]
            if stream_type == "HLS":
                item.complete = M3u8.update_part_with_m3u8_streams(part, url)
            else:
                Logger.warning("Found unknow stream type: %s", stream_type)

        if "subtitles" not in stream_data or not stream_data["subtitles"]:
            return item

        for sub in stream_data["subtitles"]:
            sub_url = None
            sub_type = sub["type"]
            default_sub = sub["defaultOn"]
            if default_sub:
                sub_url = sub["webVtt"]
                sub_type = "webvtt"  # set Retrospect type

            if sub_url:
                part.Subtitle = SubtitleHelper.download_subtitle(
                    sub_url, format=sub_type)
                break

        return item
コード例 #8
0
    def update_video_item(self, item):
        """Updates an existing MediaItem with more data.

        Arguments:
        item : MediaItem - the MediaItem that needs to be updated

        Returns:
        The original item with more data added to it's properties.

        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.

        """

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

        data = UriHandler.open(item.url, proxy=self.proxy)

        # get the playlist GUID
        playlist_guids = Regexer.do_regex(
            "<div[^>]+data-playlist-id='([^']+)'[^>]+></div>", data)
        if not playlist_guids:
            # let's try the alternative then (for the new channels)
            playlist_guids = Regexer.do_regex(
                'local_playlist[", -]+([a-f0-9]{20})"', data)
        playlist_guid = playlist_guids[0]
        play_list_url = "http://api.mtvnn.com/v2/nl/NL/local_playlists/{}.json?video_format=m3u8".format(
            playlist_guid)

        data = UriHandler.open(play_list_url, proxy=self.proxy)

        from resources.lib.helpers.jsonhelper import JsonHelper
        from resources.lib.streams.m3u8 import M3u8

        json_data = JsonHelper(data)
        m3u8_url = json_data.get_value("local_playlist_videos", 0, "url")
        part = item.create_new_empty_media_part()
        item.complete = M3u8.update_part_with_m3u8_streams(part,
                                                           m3u8_url,
                                                           proxy=self.proxy,
                                                           channel=self,
                                                           encrypted=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)

        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
コード例 #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

        """

        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, 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)
            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)

        item.complete = True
        Logger.trace("Media url: %s", item)
        return item
コード例 #11
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("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
コード例 #12
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
コード例 #13
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
コード例 #14
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 = 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
コード例 #15
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
コード例 #16
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
コード例 #17
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