コード例 #1
0
    def pre_process_folder_list(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 = []

        end = data.find('<li class="divider playlist-item">')
        if end < 0:
            end = data.find("<p>Liknande videos</p>")
        if end < 0:
            end = data.find("<p>Lignende videoer</p>")
        if end < 0:
            end = data.find("<p>Andere leuke video’s</p>")

        Logger.debug("Pre-Processing finished")
        if end > 0:
            return data[:end], items

        return data, items
コード例 #2
0
    def add_live_channel_and_extract_data(self, data):
        """ Add the live channel and extract the correct data to process further.

        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 = []

        title = LanguageHelper.get_localized_string(
            LanguageHelper.LiveStreamTitleId)
        item = MediaItem("\a.: {} :.".format(title), self.liveUrl)
        item.type = "folder"
        items.append(item)

        if not data:
            return "[]", items

        json_data = Regexer.do_regex(
            r"setupBroadcastArchive\('Tv',\s*([^;]+)\);", data)
        if isinstance(json_data, (tuple, list)) and len(json_data) > 0:
            Logger.debug("Pre-Processing finished")
            return json_data[0], items

        Logger.info("Cannot extract JSON data from HTML.")
        return data, items
コード例 #3
0
    def get_live_items(self, data):
        """ Adds live stream items.

        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("Fetching episode items")
        items = []

        live_items = MediaItem("\a.: Live TV :.", "")
        items.append(live_items)

        live_base = "http://il.srgssr.ch/integrationlayer/1.0/ue/srf/video/play/%s.json"
        live_channels = {
            "SRF 1 live": ("c4927fcf-e1a0-0001-7edd-1ef01d441651", "srf1.png"),
            "SRF zwei live":
            ("c49c1d64-9f60-0001-1c36-43c288c01a10", "srf2.png"),
            "SRF info live":
            ("c49c1d73-2f70-0001-138a-15e0c4ccd3d0", "srfinfo.png")
        }
        for live_item in live_channels.keys():
            item = MediaItem(live_item,
                             live_base % (live_channels[live_item][0], ))
            item.thumb = self.get_image_location(live_channels[live_item][1])
            item.isGeoLocked = True
            item.type = "video"
            live_items.items.append(item)

        return data, items
コード例 #4
0
    def __init__(self, action):
        Logger.info(
            "**** Starting menu '%s' for %s add-on version %s/repo ****",
            action, Config.appName, Config.version)

        # noinspection PyUnresolvedReferences
        self.kodiItem = sys.listitem

        params = self.kodiItem.getPath()
        if not params:
            self.channelObject = None
            return

        name, params = params.split("?", 1)
        params = "?{0}".format(params)

        # Main constructor parses
        super(Menu, self).__init__(name, params)

        self.channelObject = self.__get_channel()
        Logger.debug(
            "Plugin Params: %s (%s)\n"
            "Name:        %s\n"
            "Query:       %s", self.params, len(self.params), self.pluginName,
            params)

        if self.keywordPickle in self.params:
            self.mediaItem = self._pickler.de_pickle_media_item(
                self.params[self.keywordPickle])
        else:
            self.mediaItem = None
コード例 #5
0
    def pre_process_folder_list(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 = []

        if "episode.json" in self.parentItem.url:
            Logger.debug("Fetching Carousel data")
            json = JsonHelper(data)
            data = json.get_value("carousel")

        Logger.debug("Pre-Processing finished")
        return data, items
コード例 #6
0
    def log_on(self):
        """ Logs on to a website, using an url.

        First checks if the channel requires log on. If so and it's not already
        logged on, it should handle the log on. That part should be implemented
        by the specific channel.

        More arguments can be passed on, but must be handled by custom code.

        After a successful log on the self.loggedOn property is set to True and
        True is returned.

        :return: indication if the login was successful.
        :rtype: bool

        """

        if not self.requiresLogon:
            Logger.debug("No login required of %s", self.channelName)
            return True

        if self.loggedOn:
            Logger.info("Already logged in")
            return True

        return False
コード例 #7
0
    def toggle_cloak(self):
        """ Toggles the cloaking (showing/hiding) of the selected folder. """

        item = self._pickler.de_pickle_media_item(
            self.params[self.keywordPickle])
        Logger.info("Cloaking current item: %s", item)
        c = Cloaker(self.channelObject,
                    AddonSettings.store(LOCAL),
                    logger=Logger.instance())

        if c.is_cloaked(item.url):
            c.un_cloak(item.url)
            self.refresh()
            return

        first_time = c.cloak(item.url)
        if first_time:
            XbmcWrapper.show_dialog(
                LanguageHelper.get_localized_string(
                    LanguageHelper.CloakFirstTime),
                LanguageHelper.get_localized_string(
                    LanguageHelper.CloakMessage))

        del c
        self.refresh()
コード例 #8
0
    def add_search(self, data):
        """ Adds a search item.

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

        :param JsonHelper 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 = []

        title = "\a.: %s :." % (self.searchInfo.get(
            self.language, self.searchInfo["se"])[1], )
        Logger.trace("Adding search item: %s", title)
        search_item = MediaItem(title, "searchSite")
        search_item.thumb = self.noImage
        search_item.fanart = self.fanart
        search_item.dontGroup = True
        items.append(search_item)

        Logger.debug("Pre-Processing finished")
        return data, items
コード例 #9
0
    def get_user_agent():
        """ Retrieves a user agent string for this Kodi instance.

        :return: a user-agent string
        :rtype: str

        """

        if not AddonSettings.__user_agent:
            # load and cache
            user_agent = AddonSettings.store(LOCAL).get_setting(AddonSettings.__USER_AGENT_SETTING)
            AddonSettings.__user_agent = user_agent

            # double check if the version of Kodi is still OK
            if AddonSettings.__user_agent:
                # noinspection PyNoneFunctionAssignment
                version = AddonSettings.get_kodi_version()

                if version not in AddonSettings.__user_agent:
                    old = AddonSettings.__user_agent
                    # a new XBMC version was installed, update the User-agent
                    AddonSettings.update_user_agent()
                    Logger.info("User agent updated due to Kodi version change from\n%s to\n%s",
                                old, AddonSettings.__user_agent)
            else:
                AddonSettings.update_user_agent()
                Logger.info("Set initial User agent version because it was missing.")

        Logger.debug("User agent retrieved from cache: %s", AddonSettings.__user_agent)
        return AddonSettings.__user_agent
コード例 #10
0
    def set_input_stream_addon_input(strm,
                                     proxy=None,
                                     headers=None,
                                     license_key=None,
                                     license_type="com.widevine.alpha",
                                     max_bit_rate=None,
                                     persist_storage=False,
                                     service_certificate=None,
                                     manifest_update=None):
        """ Updates an existing stream with parameters for the inputstream adaptive add-on.

        :param strm:                    (MediaStream) the MediaStream to update
        :param proxy:                   (Proxy) The proxy to use for opening
        :param dict headers:            Possible HTTP Headers
        :param str license_key:         The value of the license key request
        :param str license_type:        The type of license key request used (see below)
        :param int max_bit_rate:        The maximum bitrate to use (optional)
        :param bool persist_storage:    Should we store certificates? And request server certificates?
        :param str service_certificate: Use the specified server certificate

        :returns: The updated stream
        :rtype: MediaStream

        Can be used like this:

            part = item.create_new_empty_media_part()
            stream = part.append_media_stream(m3u8url, 0)
            M3u8.set_input_stream_addon_input(stream, self.proxy, self.headers)
            item.complete = True

        if maxBitRate is not set, the bitrate will be configured via the normal generic Retrospect
        or channel settings.

        """

        if license_key is not None:
            # Local import to make sure the overhead is low
            import inputstreamhelper
            from resources.lib.logger import Logger

            is_helper = inputstreamhelper.Helper('mpd', drm=license_type)
            if is_helper.check_inputstream():
                Logger.info(
                    "Widevine library was already installed or installed successfully."
                )
            else:
                Logger.error(
                    "Widevine was not installed or failed to install.")

        return Adaptive.set_input_stream_addon_input(
            strm,
            proxy,
            headers,
            manifest_type="mpd",
            license_key=license_key,
            license_type=license_type,
            max_bit_rate=max_bit_rate,
            persist_storage=persist_storage,
            service_certificate=service_certificate,
            manifest_update=manifest_update)
コード例 #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,
                                           additional_headers=headers)
        bright_cove_json = JsonHelper(bright_cove_data)
        streams = [
            d for d in bright_cove_json.get_value("sources")
            if d["container"] == "M2TS"
        ]
        # Old filter
        # streams = filter(lambda d: d["container"] == "M2TS", bright_cove_json.get_value("sources"))
        if not streams:
            Logger.warning("Error extracting streams from BrightCove data: %s",
                           item)
            return item

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

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

        for s, b in M3u8.get_streams_from_m3u8(stream_url):
            item.complete = True
            part.append_media_stream(s, b)
        return item
コード例 #12
0
    def add_category_and_live_items(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 = []

        sub_items = {
            "\a.: Direct :.": "%s/auvio/direct/" % (self.baseUrl, ),
            "\a.: Cat&eacute;gories :.": "http://www.rtbf.be/news/api/menu?site=media"
        }

        for k, v in sub_items.items():
            item = MediaItem(k, v)
            item.complete = True
            item.dontGroup = True
            items.append(item)
            item.isLive = v.endswith('/direct/')

        Logger.debug("Pre-Processing finished")
        return data, items
コード例 #13
0
    def log_on(self):
        """ Logs on to a website, using an url.

        First checks if the channel requires log on. If so and it's not already
        logged on, it should handle the log on. That part should be implemented
        by the specific channel.

        More arguments can be passed on, but must be handled by custom code.

        After a successful log on the self.loggedOn property is set to True and
        True is returned.

        :return: indication if the login was successful.
        :rtype: bool

        """

        from resources.lib.authentication.rtlxlhandler import RtlXlHandler
        from resources.lib.authentication.authenticator import Authenticator
        handler = RtlXlHandler("rtlxl.nl", "3_R0XjstXd4MpkuqdK3kKxX20icLSE3FB27yQKl4zQVjVpqmgSyRCPKKLGdn5kjoKq")
        self.__authenticator = Authenticator(handler)

        # Always try to log on. If the username was changed to empty, we should clear the current
        # log in.
        username = self._get_setting("rtlxl_username", value_for_none=None)
        result = self.__authenticator.log_on(username=username, channel_guid=self.guid, setting_id="rtlxl_password")

        if not username:
            Logger.info("No username for RTL specified. Not logging in.")
            # Return True to prevent unwanted messages
            return True

        return result.logged_on
コード例 #14
0
    def no_nick_jr(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 = []

        end = data.find("<h2 class='row-title'>Nick Jr")

        Logger.debug("Pre-Processing finished")
        if end > 0:
            Logger.debug("Nick Jr content found starting at %d", end)
            return data[:end], items
        return data, items
コード例 #15
0
    def get_movie_id(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 = []

        movie_id = Regexer.do_regex(r"movietrailers://movie/detail/(\d+)", data)[-1]
        Logger.debug("Found Movie ID: %s", movie_id)
        url = "%s/trailers/feeds/data/%s.json" % (self.baseUrl, movie_id)
        data = UriHandler.open(url)

        # set it for logging purposes
        self.parentItem.url = url

        Logger.debug("Pre-Processing finished")
        return data, items
コード例 #16
0
    def show_settings(tab_id=None, setting_id=None):
        """ Shows the settings dialog

        :param int|str tab_id:   what tab should have focus in the settings?
        :param str setting_id:   what control should have focus in the settings tab?

        """

        if tab_id is None:
            # shows the settings and blocks:
            AddonSettings.store(KODI).open_settings()  # this will open settings window
            # reload the cache because stuff might have changed

            Logger.info("Clearing Settings cache because settings dialog was shown.")
            AddonSettings.__refresh(KODI)
        else:
            # show settings and focus on a tab
            xbmc.executebuiltin('Addon.OpenSettings(%s)' % (Config.addonId,))

            if tab_id:
                # the 100 range are the tabs
                # the 200 range are the controls in a tab
                xbmc.executebuiltin('SetFocus(%i)' % int(tab_id))
                if setting_id:
                    xbmc.executebuiltin('SetFocus(%s)' % int(setting_id))

            Logger.info("Settings shown with focus on %s-%s", tab_id, setting_id or "<none>")
        return
コード例 #17
0
    def make_episode_dictionary_array(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 = []
        json_data = JsonHelper(data)
        dict_items = json_data.get_value("items", fallback=[])
        for item in dict_items:
            if item == "banners" or item == "curators":
                continue
            items.append(self.create_episode_item(dict_items[item]))

        Logger.debug("Pre-Processing finished")
        data = ""
        return data, items
コード例 #18
0
    def add_live_channel(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 = []

        title = LanguageHelper.get_localized_string(
            LanguageHelper.LiveStreamTitleId)
        item = MediaItem("\a.: {} :.".format(title), "")
        item.type = "folder"
        items.append(item)

        live_item = MediaItem(title, "#livestream")
        live_item.type = "video"
        live_item.isLive = True
        item.items.append(live_item)

        Logger.debug("Pre-Processing finished")
        return data, items
コード例 #19
0
    def __initialise_channel_set(self, channel_info):
        # type: (ChannelInfo) -> None
        """ Initialises a channelset (.py file)

        WARNING: these actions are done ONCE per python file, not per channel.

        Arguments:
        channelInfo : ChannelInfo - The channelinfo

        Keyword Arguments:
        abortOnNew  : Boolean - If set to true, channel initialisation will not continue if a new channel was found.
                                This will have to be done later.

        Returns True if any operations where executed

        """

        Logger.info("Initialising channel set at: %s.", channel_info.path)

        # now import (required for the PerformFirstTimeActions
        sys.path.append(channel_info.path)

        # make sure a pyo or pyc exists
        # __import__(channelInfo.moduleName)
        # The debugger won't compile if __import__ is used. So let's use this one.
        import py_compile
        py_compile.compile(os.path.join(channel_info.path, "%s.py" % (channel_info.moduleName,)))

        # purge the texture cache.
        if TextureHandler.instance():
            TextureHandler.instance().purge_texture_cache(channel_info)
        else:
            Logger.warning("Could not purge_texture_cache: no TextureHandler available")
        return
コード例 #20
0
    def get_setting(self, setting_id):
        """ Retrieves an encrypted setting from the Kodi Add-on Settings.

        :param str setting_id: the ID for the setting to retrieve.

        :return: the decrypted value for the setting.
        :rtype: str
        """

        Logger.info("Decrypting value for setting '%s'", setting_id)
        encrypted_value = AddonSettings.get_setting(setting_id)
        if not encrypted_value:
            Logger.warning("Found empty string as encrypted data")
            return encrypted_value

        try:
            decrypted_value = self.__decrypt(encrypted_value, Vault.__Key)
            if not decrypted_value.startswith(setting_id):
                Logger.error("Invalid decrypted value for setting '%s'",
                             setting_id)
                return None

            decrypted_value = decrypted_value[len(setting_id) + 1:]
            Logger.info("Successfully decrypted value for setting '%s'",
                        setting_id)
        except UnicodeDecodeError:
            Logger.error(
                "Invalid Unicode data returned from decryption. Must be wrong data"
            )
            return None

        return decrypted_value
コード例 #21
0
    def set_bitrate(self):
        """ Sets the bitrate for the selected channel via a specific dialog. """

        if self.channelObject is None:
            raise ValueError("Missing channel")

        # taken from the settings.xml
        bitrate_options = "Retrospect|100|250|500|750|1000|1500|2000|2500|4000|8000|20000"\
            .split("|")

        current_bitrate = AddonSettings.get_max_channel_bitrate(
            self.channelObject)
        Logger.debug("Found bitrate for %s: %s", self.channelObject,
                     current_bitrate)
        current_bitrate_index = 0 if current_bitrate not in bitrate_options \
            else bitrate_options.index(current_bitrate)

        dialog = xbmcgui.Dialog()
        heading = LanguageHelper.get_localized_string(
            LanguageHelper.BitrateSelection)
        selected_bitrate = dialog.select(heading,
                                         bitrate_options,
                                         preselect=current_bitrate_index)
        if selected_bitrate < 0:
            return

        Logger.info("Changing bitrate for %s from %s to %s",
                    self.channelObject, bitrate_options[current_bitrate_index],
                    bitrate_options[selected_bitrate])

        AddonSettings.set_max_channel_bitrate(
            self.channelObject, bitrate_options[selected_bitrate])
        return
コード例 #22
0
    def __init__(self):
        """ Creates a new instance of the Vault class """

        self.__newKeyGeneratedInConstructor = False  # : This was the very first time a key was generated

        # ask for PIN of no key is present
        if Vault.__Key is None:
            howto_shown = self.__show_howto()
            key = self.__get_application_key()  # type: bytes

            # was there a key? No, let's initialize it.
            if key is None:
                Logger.warning(
                    "No Application Key present. Initializing a new one.")

                # Show the how to if it was not already shown during this __init__()
                if not howto_shown:
                    self.__show_howto(force=True)

                key = self.__get_new_key()
                if not self.change_pin(key):
                    raise RuntimeError("Error creating Application Key.")
                Logger.info(
                    "Created a new Application Key with MD5: %s (length=%s)",
                    EncodingHelper.encode_md5(key), len(key))
                self.__newKeyGeneratedInConstructor = True

            Vault.__Key = key
            Logger.trace("Using Application Key with MD5: %s (length=%s)",
                         EncodingHelper.encode_md5(key), len(key))
コード例 #23
0
    def create_uri_handler(cache_dir=None,
                           web_time_out=30,
                           cookie_jar=None,
                           ignore_ssl_errors=False):
        """ Initialises the UriHandler class

        Keyword Arguments:
        :param str cache_dir:           A path for http caching. If specified, caching will be used.
        :param int web_time_out:        Timeout for requests in seconds.
        :param str|unicode cookie_jar:  The path to the cookie jar (in case of file storage).
        :param bool ignore_ssl_errors:  Ignore any SSL certificate errors.

        :return: A new UriHandler object
        :rtype: _RequestsHandler

        """

        # Only create a new handler if we did not have, or if the user options changed
        if UriHandler.__handler is None or \
                UriHandler.instance().ignoreSslErrors != ignore_ssl_errors:

            handler = _RequestsHandler(cache_dir=cache_dir,
                                       web_time_out=web_time_out,
                                       cookie_jar=cookie_jar,
                                       ignore_ssl_errors=ignore_ssl_errors)

            UriHandler.__handler = handler
            Logger.info("Initialised: %s", handler)
        else:
            Logger.info("Re-using existing UriHandler: %s",
                        UriHandler.__handler)
        return UriHandler.__handler
コード例 #24
0
    def add_clips(self, data):
        """ Adds a clip folder to items.

        :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 = []
        if not self.parentItem or "guid" not in self.parentItem.metaData:
            return data, items

        clip_title = LanguageHelper.get_localized_string(LanguageHelper.Clips)
        item_id = self.parentItem.metaData["guid"]
        url = "{}/feeds/intl_m300/V8_0_0/{}/{}"\
            .format(self.baseUrl, self.__clip_list_id, item_id)

        clips = MediaItem("\a.: %s :." % (clip_title,), url)
        items.append(clips)

        Logger.debug("Pre-Processing finished")
        return data, items
コード例 #25
0
    def alpha_listing(self, data):
        """ Creates a alpha listing with items pointing to the alpha listing on line.

        :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("Generating an Alpha list for BBC")

        items = []
        # https://www.bbc.co.uk/iplayer/a-z/a

        title_format = LanguageHelper.get_localized_string(LanguageHelper.StartWith)
        url_format = "https://www.bbc.co.uk/iplayer/a-z/%s"
        for char in "abcdefghijklmnopqrstuvwxyz0":
            if char == "0":
                char = "0-9"
            sub_item = MediaItem(title_format % (char.upper(),), url_format % (char,))
            sub_item.complete = True
            sub_item.dontGroup = True
            sub_item.HttpHeaders = {"X-Requested-With": "XMLHttpRequest"}
            items.append(sub_item)
        return data, items
コード例 #26
0
    def pre_process_folder_list(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 = []
        data = data.replace("&#160;", " ")

        page_nav = data.find('<div class="pageNav">')
        if page_nav > 0:
            data = data[0:page_nav]

        Logger.debug("Pre-Processing finished")
        return data, items
コード例 #27
0
    def extract_json_episodes(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 = []

        data = Regexer.do_regex(
            r'window.__DATA__ = ([\w\W]+?});\s*window.__PUSH_STATE__', data)[0]
        json_data = JsonHelper(data)
        main_container = [
            m for m in json_data.get_value("children")
            if m["type"] == "MainContainer"
        ]
        line_list = [
            item for item in main_container[0]["children"]
            if item["type"] == "LineList"
        ]
        line_list = line_list[0]["props"]
        json_data.json = line_list
        return json_data, items
コード例 #28
0
    def extract_json(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 = []

        json_data = Regexer.do_regex('type="application/json">([^<]+)<', data)
        if not json_data:
            Logger.warning("No JSON data found.")
            return data, items

        json = JsonHelper(json_data[0])
        result = []
        for key, value in json.json.items():
            result.append(value)
            value["title"] = key

        # set new json and return JsonHelper object
        json.json = result
        return json, items
コード例 #29
0
    def purge_store(self, addon_id, age=30):
        """ Purges all files older than xx days.

        :param str addon_id: The ID of this add-on
        :param int age:      The age (in days) for pickles to be purged

        """

        if self.__pickle_store_path is None:
            return

        Logger.info("PickleStore: Purging store items older than %d days", age)

        # Retrieve the store_id's for the favourites
        favourite_pickle_stores = self.__get_kodi_favourites(addon_id)

        # Local imports to increase speed
        import glob
        import time

        pickles_path = os.path.join(self.__pickle_store_path, "pickles", "*",
                                    "*", "*.{}".format(self.__ext))

        cache_time = age * 30 * 24 * 60 * 60
        for filename in glob.glob(pickles_path):
            create_time = os.path.getctime(filename)
            pickle_store_id = os.path.split(filename)[1].split(".", 1)[0]
            if create_time + cache_time < time.time():
                if pickle_store_id in favourite_pickle_stores:
                    Logger.debug(
                        "PickleStore: Skipping purge of favourite '%s'",
                        filename)
                    continue
                os.remove(filename)
                Logger.debug("PickleStore: Removed file '%s'", filename)
コード例 #30
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