예제 #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

        """

        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)
        m3u8_url = stream_info.get_value("playbackItem", "manifestUrl")
        if m3u8_url is None:
            return item

        part = item.create_new_empty_media_part()

        if AddonSettings.use_adaptive_stream_add_on() and False:
            subtitle = M3u8.get_subtitle(m3u8_url, proxy=self.proxy)
            stream = part.append_media_stream(m3u8_url, 0)
            M3u8.set_input_stream_addon_input(stream, self.proxy)
            item.complete = True
        else:
            m3u8_data = UriHandler.open(m3u8_url,
                                        proxy=self.proxy,
                                        additional_headers=self.localIP)
            subtitle = M3u8.get_subtitle(m3u8_url,
                                         proxy=self.proxy,
                                         play_list_data=m3u8_data)
            for s, b, a in M3u8.get_streams_from_m3u8(m3u8_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
예제 #2
0
    def UpdateVideoItem(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 UpdateVideoItem 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)

        # descriptions = Regexer.DoRegex('<div class="longdesc"><p>([^<]+)</', data)
        # Logger.Trace(descriptions)
        # for desc in descriptions:
        #     item.description = desc

        data = data.replace("\\/", "/")
        urls = Regexer.DoRegex(self.mediaUrlRegex, data)
        part = item.CreateNewEmptyMediaPart()
        for url in urls:
            Logger.Trace(url)
            if url[0] == "src":
                flv = url[1]
                bitrate = 750
            else:
                flvServer = url[1]
                flvPath = url[2]

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

                elif url[0] == "rtmpt-server":
                    continue
                    #flv = "%s//%s" % (flvServer, flvPath)
                    #flv = self.GetVerifiableVideoUrl(flv)
                    #bitrate = 1500

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

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

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

                else:
                    flv = "%s/%s" % (flvServer, flvPath)
                    bitrate = 0

            part.AppendMediaStream(flv, bitrate)

        item.complete = True
        return item
예제 #3
0
    def update_video_for_mzid(self, item, mzid, live=False):  # NOSONAR
        """ Updates a video item based on the MZID

        :param MediaItem item: the parent item
        :param str mzid:       the MZID

        """

        # region New URL retrieval with DRM protection
        # 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=vrtvideo"\
            .format(HtmlEntityHelper.url_encode(mzid), HtmlEntityHelper.url_encode(token))
        asset_data = UriHandler.open(asset_url,
                                     proxy=self.proxy,
                                     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)
        part = item.create_new_empty_media_part()
        srt = None

        # see if we prefer hls over dash
        hls_prio = 2 if self._get_setting("hls_over_dash",
                                          'false') == 'true' 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, self.proxy)

            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, self.proxy)
                else:
                    m3u8_data = UriHandler.open(video_url, self.proxy)
                    for s, b, a in M3u8.get_streams_from_m3u8(
                            video_url,
                            self.proxy,
                            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,
                                            proxy=self.proxy)
                    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, self.proxy)
                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, self.proxy, license_key=encryption_key)

            if video_type.startswith("hls") and srt is None:
                srt = M3u8.get_subtitle(video_url, proxy=self.proxy)
                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
        # endregion
        return item
    def update_video_item(self, item):
        """ Updates an existing MediaItem with more data.

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

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

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

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

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

        """

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

        # 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
예제 #5
0
    def UpdateVideoItem(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 UpdateVideoItem 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.CreateNewEmptyMediaPart()
        if "mediazone.vrt.be" not in item.url:
            # Extract actual media data
            videoId = Regexer.DoRegex('data-video=[\'"]([^"\']+)[\'"]',
                                      data)[0]
            # if videoId.startswith("http"):
            #     Logger.Info("Found direct stream. Not processing any further.")
            #     part.AppendMediaStream(videoId, 0)
            #     item.complete = True
            #     return item

            url = "https://mediazone.vrt.be/api/v1/een/assets/%s" % (videoId, )
            data = UriHandler.Open(url, proxy=self.proxy)

        json = JsonHelper(data)
        urls = json.GetValue("targetUrls")
        for urlInfo in urls:
            Logger.Trace(urlInfo)
            if urlInfo["type"].lower() != "hls":
                continue

            hlsUrl = urlInfo["url"]
            for s, b in M3u8.GetStreamsFromM3u8(hlsUrl, self.proxy):
                part.AppendMediaStream(s, b)

        # urls = Regexer.DoRegex(self.mediaUrlRegex, data)
        # Logger.Trace(urls)
        # part = item.CreateNewEmptyMediaPart()
        # for url in urls:
        #     if not url[1] == "":
        #         mediaurl = "%s//%s" % (url[0], url[1])  # the extra slash in the url causes the application name in the RTMP stream to be "een" instead of "een/2011"
        #     else:
        #         mediaurl = url[0]
        #
        #     mediaurl = mediaurl.replace(" ", "%20")
        #
        #     if "rtmp" in mediaurl:
        #         mediaurl = self.GetVerifiableVideoUrl(mediaurl)
        #         # In some cases the RTMPT does not work. Let's just try the RTMP first and then add the original if the RTMP version fails.
        #         part.AppendMediaStream(mediaurl.replace("rtmpt://", "rtmp://"), 650)
        #     elif "rtsp" in mediaurl:
        #         part.AppendMediaStream(mediaurl, 600)
        #     elif mediaurl.startswith("http") and "m3u8" in mediaurl:
        #         # http://iphone.streampower.be/een_nogeo/_definst_/2013/08/1000_130830_placetobe_marjolein_Website_Een_M4V.m4v/playlist.m3u8
        #         mediaurl = mediaurl.rstrip()
        #         for s, b in M3u8.GetStreamsFromM3u8(mediaurl, self.proxy):
        #             part.AppendMediaStream(s, b)
        #     else:
        #         Logger.Warning("Media url was not recognised: %s", mediaurl)

        item.complete = True
        return item
예제 #6
0
    def add_others(self, data):
        """ Performs pre-process actions for data processing.

        Accepts an data from the process_folder_list method, BEFORE the items are
        processed. Allows setting of parameters (like title etc) for the channel.
        Inside this method the <data> could be changed and additional items can
        be created.

        The return values should always be instantiated in at least ("", []).

        :param str data: The retrieve data that was loaded for the current item and URL.

        :return: A tuple of the data and a list of MediaItems that were generated.
        :rtype: tuple[str|JsonHelper,list[MediaItem]]

        """

        Logger.info("Performing Pre-Processing")
        items = []

        others = MediaItem(
            "\b.: Populair :.",
            "https://api.kijk.nl/v2/default/sections/popular_PopularVODs?offset=0"
        )
        items.append(others)

        days = MediaItem("\b.: Deze week :.", "#lastweek")
        items.append(days)

        search = MediaItem("\b.: Zoeken :.", "searchSite")
        search.complete = True
        search.icon = self.icon
        search.thumb = self.noImage
        search.dontGroup = True
        search.HttpHeaders = {"X-Requested-With": "XMLHttpRequest"}
        items.append(search)

        if self.channelCode == "veronica":
            live = LanguageHelper.get_localized_string(
                LanguageHelper.LiveStreamTitleId)
            live_radio = MediaItem("Radio Veronica {}".format(live), "")
            live_radio.type = "video"
            live_radio.icon = self.icon
            live_radio.thumb = self.noImage
            live_radio.dontGroup = True

            part = live_radio.create_new_empty_media_part()
            live_stream = "https://talparadiohls-i.akamaihd.net/hls/live/585615/VR-Veronica-1/playlist.m3u8"
            if AddonSettings.use_adaptive_stream_add_on(with_encryption=False,
                                                        channel=self):
                stream = part.append_media_stream(live_stream, 0)
                M3u8.set_input_stream_addon_input(stream, self.proxy)
                live_radio.complete = True
            else:
                for s, b in M3u8.get_streams_from_m3u8(live_stream,
                                                       self.proxy):
                    live_radio.complete = True
                    part.append_media_stream(s, b)

            items.append(live_radio)

        Logger.debug("Pre-Processing finished")
        return data, items
예제 #7
0
    def UpdateLiveItem(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 UpdateVideoItem for %s (%s)', item.name,
                     self.channelName)

        data = UriHandler.Open(item.url,
                               proxy=self.proxy,
                               additionalHeaders=item.HttpHeaders)
        json = JsonHelper(data)
        videoPlayLists = json.GetValue("Video", "Playlists", "Playlist")

        part = item.CreateNewEmptyMediaPart()
        for playList in videoPlayLists:
            streams = playList["url"]
            Logger.Trace("Found %s streams", len(streams))
            for stream in streams:
                streamUrl = stream["text"]
                if ".m3u8" in streamUrl:
                    for s, b in M3u8.GetStreamsFromM3u8(streamUrl, self.proxy):
                        item.complete = True
                        # s = self.GetVerifiableVideoUrl(s)
                        part.AppendMediaStream(s, b)
                else:
                    Logger.Debug("Cannot use stream url: %s", streamUrl)

        # videoInfo = json.GetValue("content", "videoInfos")
        #
        # part = item.CreateNewEmptyMediaPart()
        # 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.GetStreamsFromM3u8(videoInfo["HLSurlHD"], self.proxy):
        #         item.complete = True
        #         # s = self.GetVerifiableVideoUrl(s)
        #         part.AppendMediaStream(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.GetStreamsFromM3u8(videoInfo["HLSurl"], self.proxy):
        #         item.complete = True
        #         # s = self.GetVerifiableVideoUrl(s)
        #         part.AppendMediaStream(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.AppendMediaStream(videoInfo["downloadLink"], 1000)

        return item
예제 #8
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)
                # stop when finding one
                break

        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

        """

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

        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)
        return item
예제 #10
0
    def UpdateVideoItem(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 UpdateVideoItem for %s (%s)', item.name, self.channelName)
        url = item.url

        if self.localIP:
            item.HttpHeaders.update(self.localIP)

        if ".m3u8" not in item.url:
            data = UriHandler.Open(url, proxy=self.proxy, additionalHeaders=item.HttpHeaders)
            json = JsonHelper(data)
            url = json.GetValue("mediaUrl")
            if url is None:
                Logger.Warning("Could not find mediaUrl in %s", item.url)
                return
            f4mNeedle = "/manifest.f4m"
            if f4mNeedle in url:
                Logger.Info("Found F4m stream. Converting to M3u8.")
                url = url[:url.index(f4mNeedle)].replace("/z/", "/i/").replace("http:", "https:")
                url = "%s/master.m3u8" % (url, )

        # are there subs? They are added as URL parameter

        part = item.CreateNewEmptyMediaPart()
        subMatches = Regexer.DoRegex('https*%3a%2f%2.+master.m3u8', url)
        if subMatches:
            subUrl = HtmlEntityHelper.UrlDecode(subMatches[0])
            Logger.Info("Item has subtitles: %s", subUrl)
            subTitle = SubtitleHelper.DownloadSubtitle(subUrl, format="m3u8srt", proxy=self.proxy)
            if subTitle:
                part.Subtitle = subTitle

        for s, b in M3u8.GetStreamsFromM3u8(url, self.proxy, headers=item.HttpHeaders):
            item.complete = True
            # s = self.GetVerifiableVideoUrl(s)
            part.AppendMediaStream(s, b)
            if self.localIP:
                part.HttpHeaders.update(self.localIP)

        return item
예제 #11
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)
            strm.add_property("inputstreamaddon", "inputstream.adaptive")
            strm.add_property("inputstream.adaptive.manifest_type", "hls")
            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
예제 #12
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)
        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
예제 #13
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 paramter 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)
예제 #14
0
    def UpdateVideoItem(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 UpdateVideoItem for %s (%s)', item.name,
                     self.channelName)

        data = UriHandler.Open(item.url, proxy=self.proxy)
        json = JsonHelper(data, Logger.Instance())
        videoData = json.GetValue("video")
        if videoData:
            part = item.CreateNewEmptyMediaPart()
            spoofIp = self._GetSetting("spoof_ip", valueForNone="0.0.0.0")
            if spoofIp:
                part.HttpHeaders["X-Forwarded-For"] = spoofIp

            # get the videos
            videoUrls = videoData.get("videoReferences")
            for videoUrl in videoUrls:
                # Logger.Trace(videoUrl)
                streamInfo = videoUrl['url']
                if "manifest.f4m" in streamInfo:
                    continue
                elif "master.m3u8" in streamInfo:
                    for s, b in M3u8.GetStreamsFromM3u8(
                            streamInfo, self.proxy, headers=part.HttpHeaders):
                        item.complete = True
                        part.AppendMediaStream(s, b)

                    #m3u8Data = UriHandler.Open(streamInfo, proxy=self.proxy)

                    #urls = Regexer.DoRegex(self.mediaUrlRegex, m3u8Data)
                    #Logger.Trace(urls)
                    #for url in urls:
                    #part.AppendMediaStream(url[1].strip(), url[0])

            # subtitles
            subtitles = videoData.get("subtitleReferences")
            if subtitles:
                Logger.Trace(subtitles)
                subUrl = subtitles[0]["url"]
                fileName = "%s.srt" % (EncodingHelper.EncodeMD5(subUrl), )
                subData = UriHandler.Open(subUrl, proxy=self.proxy)

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

                localCompletePath = os.path.join(Config.cacheDir, fileName)
                Logger.Debug("Saving subtitle to: %s", localCompletePath)
                f = open(localCompletePath, 'w')
                f.write(subData)
                f.close()
                part.Subtitle = localCompletePath

            item.complete = True

        return item
예제 #15
0
    def GetLiveStreamsFromNpo(url, cacheDir, proxy=None, headers=None):
        """ Retrieve NPO Player Live streams from a different number of stream urls.

        @param url:               (String) The url to download
        @param cacheDir:          (String) The cache dir where to find the 'uzg-i.js' file.
        @param headers:           (dict) Possible HTTP Headers
        @param proxy:             (Proxy) The proxy to use for opening

        Can be used like this:

            part = item.CreateNewEmptyMediaPart()
            for s, b in NpoStream.GetStreamsFromNpo(m3u8Url, self.proxy):
                item.complete = True
                # s = self.GetVerifiableVideoUrl(s)
                part.AppendMediaStream(s, b)

        """

        if url.startswith("http://ida.omroep.nl/aapi/"):
            Logger.Debug(
                "Already found an IDA data url '%s'. Using it to fetch the streams.",
                url)
            # we already have the m3u8
            actualStreamData = UriHandler.Open(url,
                                               proxy=proxy,
                                               additionalHeaders=headers)

            url = NpoStream.__FetchActualStream(actualStreamData, proxy)

        elif url.endswith("m3u8"):
            Logger.Debug(
                "Found a stream url '%s'. Using a call to IDA to determine the actual streams.",
                url)
            hashCode = NpoStream.GetNpoToken(proxy, cacheDir)
            actualStreamData = UriHandler.Open(
                "http://ida.omroep.nl/aapi/?stream=%s&token=%s" %
                (url, hashCode),
                proxy=proxy,
                additionalHeaders=headers)
            url = NpoStream.__FetchActualStream(actualStreamData, proxy)

        elif url.startswith("http://e.omroep.nl/metadata/"):
            Logger.Debug(
                "Found a metadata url '%s'. Determining the actual stream url's",
                url)
            jsonData = UriHandler.Open(url, proxy=proxy)
            json = JsonHelper(jsonData, Logger.Instance())
            streams = []
            for stream in json.GetValue("streams"):
                if stream['type'] != "hls":
                    continue
                url = stream['url']
                for k, v in NpoStream.GetLiveStreamsFromNpo(url,
                                                            cacheDir,
                                                            proxy=proxy,
                                                            headers=headers):
                    streams.append((k, v))
            return streams
        else:
            Logger.Warning("None-stream url found: %s", url)
            return []

        return M3u8.GetStreamsFromM3u8(url, proxy=proxy)
예제 #16
0
    def UpdateVideoItem(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 UpdateVideoItem 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)
        spoofIp = self._GetSetting("spoof_ip", "0.0.0.0")
        if spoofIp:
            data = UriHandler.Open(
                item.url,
                proxy=self.proxy,
                additionalHeaders={"X-Forwarded-For": spoofIp})
        else:
            data = UriHandler.Open(item.url, proxy=self.proxy)

        urlRegex = "<bitrate>(\d+)</bitrate>\W+<mediaFormat>([^<]+)</mediaFormat>\W+(?:<scheme>([^<]+)</scheme>\W+<server>([^<]+)</server>\W+){0,1}<base>([^<]+)</base>\W+<url>([^<]+)</url>"
        # urlRegex = "<bitrate>(\d+)</bitrate>\W+<mediaFormat>([^<]+)</mediaFormat>\W+<scheme>([^<]+)</scheme>\W+<server>([^<]+)</server>\W+<base>([^<]+)</base>\W+<url>([^<]+)</url>"

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

        for result in Regexer.DoRegex(urlRegex, data):
            Logger.Trace(result)

            if "smi" in result[1]:
                subTitleUrl = result[5]
                part.Subtitle = subtitlehelper.SubtitleHelper.DownloadSubtitle(
                    subTitleUrl, proxy=self.proxy)
            else:
                if "rtmp" in result[-1]:
                    Logger.Trace("RTMP Stream found")
                    bitrate = result[0]
                    # get the actual path
                    pos = string.find(result[5], '/')
                    path = result[5][pos:]

                    url = "%s%s" % (result[4], path)
                    url = self.GetVerifiableVideoUrl(url)
                    part.AppendMediaStream(url, bitrate)

                elif result[-1].endswith("master.m3u8"):
                    Logger.Trace("M3U8 Stream found")
                    for s, b in M3u8.GetStreamsFromM3u8(
                            result[-1], self.proxy):
                        part.AppendMediaStream(s, b)

                else:
                    Logger.Trace("Other Stream found")
                    bitrate = result[0]
                    url = result[5]
                    part.AppendMediaStream(url, bitrate)

                item.complete = True

        return item
예제 #17
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
예제 #18
0
    def UpdateVideoItem(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 UpdateVideoItem for %s (%s)', item.name,
                     self.channelName)

        data = UriHandler.Open(item.url,
                               proxy=self.proxy,
                               additionalHeaders=item.HttpHeaders)
        videoId = Regexer.DoRegex('data-video="([^"]+)"', data)[-1]
        url = "https://mediazone.vrt.be/api/v1/canvas/assets/%s" % (videoId, )
        data = UriHandler.Open(url,
                               proxy=self.proxy,
                               additionalHeaders=item.HttpHeaders)
        json = JsonHelper(data)

        geoLocked = str(json.GetValue("metaInfo", "allowedRegion").lower())
        hideGeoLocked = AddonSettings.HideGeoLockedItemsForLocation(geoLocked)
        if hideGeoLocked:
            geoRegion = AddonSettings.HideGeoLockedItemsForLocation(
                geoLocked, True)
            Logger.Warning(
                "Found GEO Locked item for region '%s'. Current region is '%s'",
                geoLocked, geoRegion)
            return item

        part = item.CreateNewEmptyMediaPart()
        for video in json.GetValue("targetUrls"):
            videoType = video["type"].lower()
            url = video["url"]
            if videoType == "progressive_download":
                bitrate = 1000
            elif videoType == "hls":
                for s, b in M3u8.GetStreamsFromM3u8(url, self.proxy):
                    # s = self.GetVerifiableVideoUrl(s)
                    part.AppendMediaStream(s, b)
                continue
            elif videoType == "rtmp":
                # url=rtmp://vod.stream.vrt.be/mediazone_canvas/_definst_/mp4:2015/11/mz-ast-79a551d6-2621-4a0f-9af0-a272fb0954db-1/video_1296.mp4
                url = url.replace("_definst_/mp4:", "?slist=")
                bitrate = 1100
            else:
                Logger.Debug("Found unhandled stream type '%s':%s", videoType,
                             url)
                continue
            part.AppendMediaStream(url, bitrate)

        item.complete = True
        return item
예제 #19
0
    def __UpdateVideoItem(self, item, episodeId):
        """Updates an existing MediaItem with more data.

        Arguments:
        item      : MediaItem - the MediaItem that needs to be updated
        episodeId : String    - The episodeId, e.g.: VARA_xxxxxx

        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.Trace("Using Generic UpdateVideoItem method")

        # get the subtitle
        subTitleUrl = "http://e.omroep.nl/tt888/%s" % (episodeId,)
        subTitlePath = subtitlehelper.SubtitleHelper.DownloadSubtitle(subTitleUrl, episodeId + ".srt", format='srt',
                                                                      proxy=self.proxy)

        # we need an hash code
        hashCode = NpoStream.GetNpoToken(self.proxy, Config.cacheDir)

        item.MediaItemParts = []
        part = item.CreateNewEmptyMediaPart()
        part.Subtitle = subTitlePath

        # then we fetch alternative streams locations and start with the non-adapative ones
        streamsUrls = []
        directStreamVideos = AddonSettings.GetUzgCacheDuration() == 0
        streamSource = [
            "http://ida.omroep.nl/odi/?prid=%s&puboptions=h264_bb,h264_sb,h264_std&adaptive=no&part=1&token=%s" % (
                episodeId, hashCode,)]
        if directStreamVideos:
            # if we stream, then we first look for adaptive streams
            Logger.Debug("UZG is configured to streams, so also check for the adaptive streams")
            streamSource.insert(0,
                                "http://ida.omroep.nl/odi/?prid=%s&puboptions=adaptive&adaptive=yes&part=1&token=%s" % (
                                    episodeId, hashCode,))
        else:
            Logger.Debug("UZG is configured to download. Not going to fetch the adaptive streams")

        # get the actual stream locations streams:
        for streamSourceUrl in streamSource:
            streamUrlData = UriHandler.Open(streamSourceUrl, proxy=self.proxy, noCache=True)
            streamJson = JsonHelper(streamUrlData, logger=Logger.Instance())
            for url in streamJson.GetValue('streams'):
                Logger.Trace("Going to look for streams in: %s", url)
                streamsUrls.append(url)

        # should we cache before playback
        if not directStreamVideos:
            part.CanStream = False

        # now we should now actually go and fetch urls
        for url in streamsUrls:
            data = UriHandler.Open(url, proxy=self.proxy)
            jsonData = JsonHelper(data, logger=Logger.Instance())

            # check for errors
            streamData = jsonData.GetValue()
            if "errorstring" in streamData:
                Logger.Warning("Found error response: %s", streamData["errorstring"])
                continue

            # either do m3u8 or hls
            if "m3u8" in url.lower():
                Logger.Trace("Processing M3U8 Json: %s", url)
                m3u8url = jsonData.GetValue("url")
                if m3u8url is None:
                    Logger.Warning("Could not find stream in: %s", m3u8url)
                    continue
                Logger.Trace("Processing M3U8 Streams: %s", m3u8url)

                for s, b in M3u8.GetStreamsFromM3u8(m3u8url, self.proxy):
                    item.complete = True
                    part.AppendMediaStream(s, b)

                # if we found an adaptive m3u8, we take that one as it's better
                Logger.Info("Found M3u8 streams and using those. Stop looking further for non-adaptive ones.")
                break
            else:
                Logger.Trace("Processing HLS: %s", url)
                if "h264_bb" in url:
                    bitrate = 500
                elif "h264_sb" in url:
                    bitrate = 220
                elif "h264_std" in url:
                    bitrate = 1000
                else:
                    bitrate = None

                protocol = jsonData.GetValue('protocol')
                if protocol:
                    url = "%s://%s%s" % (protocol, jsonData.GetValue('server'), jsonData.GetValue('path'))
                    part.AppendMediaStream(url, bitrate=bitrate)
                else:
                    Logger.Warning("Found UZG Stream without a protocol. Probably a expired page.")

        if not item.HasMediaItemParts():
            Logger.Warning("Apparently no streams were present in the normal places. Trying streams in metadata")

            # fetch the meta data to get more streams
            metaUrl = "http://e.omroep.nl/metadata/%s" % (episodeId,)
            metaData = UriHandler.Open(metaUrl, proxy=self.proxy)
            metaJson = JsonHelper(metaData, logger=Logger.Instance())

            # sometimes there are streams direct in the meta data file
            directStreams = metaJson.GetValue("streams", fallback=[])
            for stream in directStreams:
                quality = stream.get("kwaliteit", 0)
                if quality == 1:
                    bitrate = 180
                elif quality == 2:
                    bitrate = 1000
                elif quality == 3:
                    bitrate = 1500
                else:
                    bitrate = 0

                if "formaat" in stream and stream["formaat"] == "h264":
                    bitrate += 1
                part.AppendMediaStream(stream["url"], bitrate)

            # now we can get extra info from the data
            item.description = metaJson.GetValue("info")
            item.title = metaJson.GetValue('aflevering_titel')
            station = metaJson.GetValue('streamSense', 'station')

            if station is None:
                item.icon = self.icon
            elif station.startswith('nederland_1'):
                item.icon = self.GetImageLocation("1large.png")
            elif station.startswith('nederland_2'):
                item.icon = self.GetImageLocation("2large.png")
            elif station.startswith('nederland_3'):
                item.icon = self.GetImageLocation("3large.png")
            Logger.Trace("Icon for station %s = %s", station, item.icon)

            # <image size="380x285" ratio="4:3">http://u.omroep.nl/n/a/2010-12/380x285_boerzoektvrouw_yvon.png</image>
            thumbUrls = metaJson.GetValue('images')  # , {"size": "380x285"}, {"ratio":"4:3"})
            Logger.Trace(thumbUrls)
            if thumbUrls:
                thumbUrl = thumbUrls[-1]['url']
                if "http" not in thumbUrl:
                    thumbUrl = "http://u.omroep.nl/n/a/%s" % (thumbUrl,)
            else:
                thumbUrl = self.noImage

            item.thumb = thumbUrl

        item.complete = True
        return item
예제 #20
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
예제 #21
0
    def __UpdateVideoItem(self, item, videoId):
        # we need a token:
        token = self.__GetToken()

        # deviceId = AddonSettings.GetClientId()
        mediaUrl = "https://vod.medialaan.io/vod/v2/videos/" \
                   "%s" \
                   "/watch?deviceId=%s" % (
                       videoId,
                       uuid.uuid4()
                   )

        auth = "apikey=%s&access_token=%s" % (self.__apiKey, token)
        headers = {"Authorization": auth}
        data = UriHandler.Open(mediaUrl,
                               proxy=self.proxy,
                               additionalHeaders=headers)

        jsonData = JsonHelper(data)
        dashInfo = jsonData.GetValue("response", "dash-cenc")
        if self.__dashStreamsSupported and dashInfo:
            Logger.Debug("Using Dash streams to playback")
            dashInfo = jsonData.GetValue("response", "dash-cenc")
            licenseUrl = dashInfo["widevineLicenseServerURL"]
            streamUrl = dashInfo["url"]
            sessionId = jsonData.GetValue("request", "access_token")

            licenseHeader = {
                "merchant": "medialaan",
                "userId": self.__userId,
                "sessionId": sessionId
            }
            licenseHeader = JsonHelper.Dump(licenseHeader, False)
            licenseHeaders = "x-dt-custom-data={0}&Content-Type=application/octstream".format(
                base64.b64encode(licenseHeader))

            kodiProps = {
                "inputstreamaddon":
                "inputstream.adaptive",
                "inputstream.adaptive.manifest_type":
                "mpd",
                "inputstream.adaptive.license_type":
                "com.widevine.alpha",
                "inputstream.adaptive.license_key":
                "{0}?specConform=true|{1}|R{{SSM}}|".format(
                    licenseUrl, licenseHeaders or "")
            }

            part = item.CreateNewEmptyMediaPart()
            stream = part.AppendMediaStream(streamUrl, 0)
            # noinspection PyTypeChecker
            for k, v in kodiProps.iteritems():
                stream.AddProperty(k, v)
        else:
            Logger.Debug(
                "No Dash streams supported or no Dash streams available. Using M3u8 streams"
            )

            m3u8Url = jsonData.GetValue("response", "hls-encrypted", "url")
            if not m3u8Url:
                m3u8Url = jsonData.GetValue("response", "uri")
                # m3u8Url = jsonData.GetValue("response", "hls-drm-uri")  # not supported by Kodi

            part = item.CreateNewEmptyMediaPart()
            # Set the Range header to a proper value to make all streams start at the beginning. Make
            # sure that a complete TS part comes in a single call otherwise we get stuttering.
            byteRange = 10 * 1024 * 1024
            Logger.Debug(
                "Setting an 'Range' http header of bytes=0-%d to force playback at the start "
                "of a stream and to include a full .ts part.", byteRange)
            part.HttpHeaders["Range"] = 'bytes=0-%d' % (byteRange, )

            for s, b in M3u8.GetStreamsFromM3u8(m3u8Url, self.proxy):
                item.complete = True
                # s = self.GetVerifiableVideoUrl(s)
                part.AppendMediaStream(s, b)

        return item