예제 #1
0
    def __init__(self, addon_name, handle, params):
        """

        :param str addon_name:  The name of the add-on
        :param int handle:      The handle for this run
        :param str params:      The parameters used to start the ActionParser

        """

        Logger.debug("Parsing parameters from: %s", params)

        self.handle = int(handle)

        # determine the query parameters
        self._params = params
        self.params = self.__get_parameters(params)
        self.pluginName = addon_name

        # We need a picker for this instance
        self.pickler = Pickler(Config.profileDir)

        # Field for property
        self.__media_item = None

        # For remote debugging and log reading purpose we need the full pickle string.
        if Logger.instance().minLogLevel <= Logger.LVL_DEBUG \
                and self.media_item is not None \
                and self.pickler.is_pickle_store_id(self.params[keyword.PICKLE]):
            Logger.debug("Replacing PickleStore pickle '%s' with full pickle", self.params[keyword.PICKLE])
            self.params[keyword.PICKLE] = self.pickler.pickle_media_item(self.media_item)
    def __init__(self, addon_name, params):
        """

        :param str addon_name:  The name of the add-on
        :param str params:      The parameteters used to start the ParameterParser

        """

        Logger.debug("Parsing parameters from: %s", params)

        # Url Keywords
        self.keywordPickle = "pickle"  # : Used for the pickle item
        self.keywordAction = "action"  # : Used for specifying the action
        self.keywordChannel = "channel"  # : Used for the channel
        self.keywordChannelCode = "channelcode"  # : Used for the channelcode
        self.keywordCategory = "category"  # : Used for the category
        self.keywordRandomLive = "rnd"  # : Used for randomizing live items
        self.keywordSettingId = "settingid"  # : Used for setting an encrypted setting
        self.keywordSettingActionId = "settingactionid"  # : Used for passing the actionid for the encryption
        self.keywordSettingName = "settingname"  # : Used for setting an encrypted settings display name
        self.keywordSettingTabFocus = "tabfocus"  # : Used for setting the tabcontrol to focus after changing a setting
        self.keywordSettingSettingFocus = "settingfocus"  # : Used for setting the setting control to focus after changing a setting
        self.keywordLanguage = "lang"  # : Used for the 2 char language information
        self.keywordProxy = "proxy"  # : Used so set the proxy index
        self.keywordLocalIP = "localip"  # : Used to set the local ip index

        # Url Actions
        self.actionFavourites = "favourites"  # : Used to show favorites for a channel
        self.actionAllFavourites = "allfavourites"  # : Used to show all favorites
        self.actionRemoveFavourite = "removefromfavourites"  # : Used to remove items from favorites
        self.actionAddFavourite = "addtofavourites"  # : Used to add items to favorites
        self.actionDownloadVideo = "downloadVideo"  # : Used to download a video item
        self.actionPlayVideo = "playvideo"  # : Used to play a video item
        self.actionUpdateChannels = "updatechannels"  # : Used to update channels
        self.actionListFolder = "listfolder"  # : Used to list a folder
        self.actionListCategory = "listcategory"  # : Used to show the channels from a category
        self.actionConfigureChannel = "configurechannel"  # : Used to configure a channel
        self.actionSetEncryptionPin = "changepin"  # : Used for setting an application pin
        self.actionSetEncryptedValue = "encryptsetting"  # : Used for setting an application pin
        self.actionResetVault = "resetvault"  # : Used for resetting the vault
        self.actionPostLog = "postlog"  # : Used for sending log files to pastebin.com
        self.actionProxy = "setproxy"  # : Used for setting a proxy

        self.propertyRetrospect = "Retrospect"
        self.propertyRetrospectChannel = "RetrospectChannel"
        self.propertyRetrospectChannelSetting = "RetrospectChannelSettings"
        self.propertyRetrospectFolder = "RetrospectFolder"
        self.propertyRetrospectVideo = "RetrospectVideo"
        self.propertyRetrospectCloaked = "RetrospectCloaked"
        self.propertyRetrospectCategory = "RetrospectCategory"
        self.propertyRetrospectFavorite = "RetrospectFavorite"
        self.propertyRetrospectAdaptive = "RetrospectAdaptive"

        # determine the query parameters
        self.params = self.__get_parameters(params)
        self.pluginName = addon_name

        # We need a picker for this instance
        self._pickler = Pickler()
예제 #3
0
    def __init__(self, path):
        """ Initializes a Favourites class that can be use to show, add and delete favourites.

        :param str path: The path to store the favourites file

        """

        self.__filePattern = "%s-%s.xotfav"
        self.__pickler = Pickler()

        self.FavouriteFolder = path
예제 #4
0
class ActionParser(object):
    # Mapping from old to new
    __lookup = {
        "chn_nos2010": "channel.nos.nos2010",
        "chn_een": "channel.be.een",
        "chn_ketnet": "channel.be.ketnet",
        "chn_rtbf": "channel.be.rtbf",
        "chn_sporza": "channel.be.sporza",
        "chn_vier": "channel.be.vier",
        "chn_vrtnu": "channel.be.vrtnu",
        "chn_vtm": "channel.be.vtm",
        "chn_vtmbe": "channel.be.vtmbe",
        "chn_srf": "channel.de.srf",
        "chn_tvse": "channel.mtg.tvse",
        "chn_viafree": "channel.mtg.viafree",
        "chn_mtvnl": "channel.mtv.mtvnl",
        "chn_southpark": "channel.mtv.southpark",
        "chn_nickelodeon": "channel.nick.nickelodeon",
        "chn_nickjr": "channel.nick.nickjr",
        "chn_nrkno": "channel.no.nrkno",
        "chn_nosnl": "channel.nos.nosnl",
        "chn_schooltv": "channel.nos.schooltv",
        "chn_at5": "channel.regionalnl.at5",
        "chn_flevo": "channel.regionalnl.flevo",
        "chn_gelderland": "channel.regionalnl.gelderland",
        "chn_l1": "channel.regionalnl.l1",
        "chn_lokaal": "channel.regionalnl.lokaal",
        "chn_rpoapp": "channel.regionalnl.rpoapp",
        "chn_rtl": "channel.rtlnl.rtl",
        "chn_kijknl": "channel.sbsnl.kijknl",
        "chn_oppetarkiv": "channel.se.oppetarkiv",
        "chn_sbs": "channel.se.sbs",
        "chn_svt": "channel.se.svt",
        "chn_tv4se": "channel.se.tv4se",
        "chn_urplay": "channel.se.urplay",
        "chn_24classic": "channel.streams.24classic",
        "chn_radio538": "channel.streams.radio538",
        "chn_bbc": "channel.uk.bbc",
        "chn_amt": "channel.videos.amt",
        "chn_channel9": "channel.videos.channel9",
        "chn_dumpert": "channel.videos.dumpert",
        "chn_eredivisie": "channel.videos.eredivisie",
        "chn_extreme": "channel.videos.extreme",
        "chn_hardwareinfo": "channel.videos.hardwareinfo",
        "chn_ons": "channel.videos.ons",
        "chn_pathenl": "channel.videos.pathenl",
        "chn_twit": "channel.videos.twit"
    }

    def __init__(self, addon_name, handle, params):
        """

        :param str addon_name:  The name of the add-on
        :param int handle:      The handle for this run
        :param str params:      The parameters used to start the ActionParser

        """

        Logger.debug("Parsing parameters from: %s", params)

        self.handle = int(handle)

        # determine the query parameters
        self._params = params
        self.params = self.__get_parameters(params)
        self.pluginName = addon_name

        # We need a picker for this instance
        self.pickler = Pickler(Config.profileDir)

        # Field for property
        self.__media_item = None

        # For remote debugging and log reading purpose we need the full pickle string.
        if Logger.instance().minLogLevel <= Logger.LVL_DEBUG \
                and self.media_item is not None \
                and self.pickler.is_pickle_store_id(self.params[keyword.PICKLE]):
            Logger.debug("Replacing PickleStore pickle '%s' with full pickle", self.params[keyword.PICKLE])
            self.params[keyword.PICKLE] = self.pickler.pickle_media_item(self.media_item)

    @property
    def media_item(self):
        """ The current MediaItem

        :returns: The current MediaItem
        :rtype: MediaItem

        """

        if self.__media_item is None and keyword.PICKLE in self.params:
            self.__media_item = self.pickler.de_pickle_media_item(self.params[keyword.PICKLE])

        return self.__media_item

    def create_action_url(self, channel, action, item=None, store_id=None, category=None):
        """ Creates an URL that includes an action.

        Arguments:
        channel : Channel -
        action  : string  -

        Keyword Arguments:
        item : MediaItem -

        :param ChannelInfo|Channel channel:     The channel object to use for the URL
        :param str action:                      Action to create an url for
        :param MediaItem item:                  The media item to add
        :param str store_id:                    The ID of the pickle store
        :param str category:                    The category to use

        :return: a complete action url with all keywords and values
        :rtype: str|unicode

        """

        if action is None:
            raise Exception("action is required")

        # catch the plugin:// url's for items and channels.
        if item is not None and item.url and item.url.startswith("plugin://"):
            return item.url

        if item is None and channel is not None and channel.uses_external_addon:
            return channel.addonUrl

        params = dict()
        if channel:
            params[keyword.CHANNEL] = channel.url_id

        params[keyword.ACTION] = action

        # it might have an item or not
        if item is not None:
            params[keyword.PICKLE] = "{}--{}".format(store_id, item.guid)

            if action == PLAY_VIDEO and item.isLive:
                params[keyword.RANDOM_LIVE] = random.randint(10000, 99999)

        if category:
            params[keyword.CATEGORY] = category

        url = "%s?" % (self.pluginName, )
        for k in params.keys():
            url = "%s%s=%s&" % (url, k, params[k])

        url = url.strip('&')
        # Logger.Trace("Created url: '%s'", url)
        return url

    def get_parent_guid(self, channel, parent_item):
        """ Returns the parent guid of an item

        :param channel:         The parent channel object
        :param parent_item:     The parent items

        :return: a guid of either the parent channel or item
        :rtype: str

        """

        if channel is None and parent_item is None:
            # we should not use the store
            return None

        return channel.guid if parent_item is None else parent_item.guid

    def __get_parameters(self, query_string):
        """ Extracts the actual parameters as a dictionary from the passed in querystring.
        This method takes the self.quotedPlus into account.

        :param str query_string:    The querystring

        :return: dict() of keywords and values.
        :rtype: dict[str,str|None]

        """
        result = dict()
        query_string = query_string.strip('?')
        if query_string == '':
            return result

        try:
            for pair in query_string.split("&"):
                (k, v) = pair.split("=")
                result[k] = v

            # if the channelcode was empty, it was stripped, add it again.
            if keyword.CHANNEL in result and "-" in result[keyword.CHANNEL]:
                id_parts = result[keyword.CHANNEL].split("-")
                result[keyword.CHANNEL] = id_parts[0]
                result[keyword.CHANNEL_CODE] = id_parts[1]
            elif keyword.CHANNEL in result and "." not in result[keyword.CHANNEL]:
                result[keyword.CHANNEL] = ActionParser.__lookup[result[keyword.CHANNEL]]

            if keyword.CHANNEL_CODE not in result:
                Logger.debug("Adding ChannelCode=None as it was missing from the dict: %s", result)
                result[keyword.CHANNEL_CODE] = None
        except:
            Logger.critical("Cannot determine query strings from %s", query_string, exc_info=True)
            raise

        return result

    def __str__(self):
        return "Plugin Params: {} ({})\n" \
               "Handle:      {}\n" \
               "Name:        {}\n" \
               "Query:       {}".format(self.params, len(self.params), self.handle, self.pluginName, self._params)
class ParameterParser(object):
    def __init__(self, addon_name, handle, params):
        """

        :param str addon_name:  The name of the add-on
        :param int handle:      The handle for this run
        :param str params:      The parameteters used to start the ParameterParser

        """

        Logger.debug("Parsing parameters from: %s", params)

        # Url Keywords
        self.keywordPickle = "pickle"  # : Used for the pickle item
        self.keywordAction = "action"  # : Used for specifying the action
        self.keywordChannel = "channel"  # : Used for the channel
        self.keywordChannelCode = "channelcode"  # : Used for the channelcode
        self.keywordCategory = "category"  # : Used for the category
        self.keywordRandomLive = "rnd"  # : Used for randomizing live items
        self.keywordSettingId = "settingid"  # : Used for setting an encrypted setting
        self.keywordSettingActionId = "settingactionid"  # : Used for passing the actionid for the encryption
        self.keywordSettingName = "settingname"  # : Used for setting an encrypted settings display name
        self.keywordSettingTabFocus = "tabfocus"  # : Used for setting the tabcontrol to focus after changing a setting
        self.keywordSettingSettingFocus = "settingfocus"  # : Used for setting the setting control to focus after changing a setting
        self.keywordLanguage = "lang"  # : Used for the 2 char language information
        self.keywordProxy = "proxy"  # : Used so set the proxy index
        self.keywordLocalIP = "localip"  # : Used to set the local ip index

        # Url Actions
        self.actionFavourites = "favourites"  # : Used to show favorites for a channel
        self.actionAllFavourites = "allfavourites"  # : Used to show all favorites
        self.actionRemoveFavourite = "removefromfavourites"  # : Used to remove items from favorites
        self.actionAddFavourite = "addtofavourites"  # : Used to add items to favorites
        self.actionDownloadVideo = "downloadVideo"  # : Used to download a video item
        self.actionPlayVideo = "playvideo"  # : Used to play a video item
        self.actionUpdateChannels = "updatechannels"  # : Used to update channels
        self.actionListFolder = "listfolder"  # : Used to list a folder
        self.actionListCategory = "listcategory"  # : Used to show the channels from a category
        self.actionConfigureChannel = "configurechannel"  # : Used to configure a channel
        self.actionSetEncryptionPin = "changepin"  # : Used for setting an application pin
        self.actionSetEncryptedValue = "encryptsetting"  # : Used for setting an application pin
        self.actionResetVault = "resetvault"  # : Used for resetting the vault
        self.actionPostLog = "postlog"  # : Used for sending log files to pastebin.com
        self.actionProxy = "setproxy"  # : Used for setting a proxy

        self.handle = int(handle)

        # determine the query parameters
        self._params = params
        self.params = self.__get_parameters(params)
        self.pluginName = addon_name

        # We need a picker for this instance
        self._pickler = Pickler(Config.profileDir)

        # Field for property
        self.__media_item = None

        # For remote debugging and log reading purpose we need the full pickle string.
        if Logger.instance().minLogLevel <= Logger.LVL_DEBUG \
                and self.media_item is not None \
                and self._pickler.is_pickle_store_id(self.params[self.keywordPickle]):
            Logger.debug("Replacing PickleStore pickle '%s' with full pickle",
                         self.params[self.keywordPickle])
            self.params[self.keywordPickle] = self._pickler.pickle_media_item(
                self.media_item)

    @property
    def media_item(self):

        if self.__media_item is None and self.keywordPickle in self.params:
            self.__media_item = self._pickler.de_pickle_media_item(
                self.params[self.keywordPickle])

        return self.__media_item

    def _create_action_url(self,
                           channel,
                           action,
                           item=None,
                           store_id=None,
                           category=None):
        """ Creates an URL that includes an action.

        Arguments:
        channel : Channel -
        action  : string  -

        Keyword Arguments:
        item : MediaItem -

        :param ChannelInfo|Channel channel:     The channel object to use for the URL
        :param str action:                      Action to create an url for
        :param MediaItem item:                  The media item to add
        :param str store_id:                    The ID of the pickle store
        :param str category:                    The category to use

        :return: a complete action url with all keywords and values
        :rtype: str|unicode

        """

        if action is None:
            raise Exception("action is required")

        # catch the plugin:// url's for items and channels.
        if item is not None and item.url and item.url.startswith("plugin://"):
            return item.url

        if item is None and channel is not None and channel.uses_external_addon:
            return channel.addonUrl

        params = dict()
        if channel:
            params[self.keywordChannel] = channel.moduleName
            if channel.channelCode:
                params[self.keywordChannelCode] = channel.channelCode

        params[self.keywordAction] = action

        # it might have an item or not
        if item is not None:
            params[self.keywordPickle] = "{}--{}".format(store_id, item.guid)

            if action == self.actionPlayVideo and item.isLive:
                params[self.keywordRandomLive] = random.randint(10000, 99999)

        if category:
            params[self.keywordCategory] = category

        url = "%s?" % (self.pluginName, )
        for k in params.keys():
            url = "%s%s=%s&" % (url, k, params[k])

        url = url.strip('&')
        # Logger.Trace("Created url: '%s'", url)
        return url

    def _get_parent_guid(self, channel, parent_item):
        """ Returns the parent guid of an item

        :param channel:         The parent channel object
        :param parent_item:     The parent items

        :return: a guid of either the parent channel or item
        :rtype: str

        """

        if channel is None and parent_item is None:
            # we should not use the store
            return None

        return channel.guid if parent_item is None else parent_item.guid

    def __get_parameters(self, query_string):
        """ Extracts the actual parameters as a dictionary from the passed in querystring.
        This method takes the self.quotedPlus into account.

        :param str query_string:    The querystring

        :return: dict() of keywords and values.
        :rtype: dict[str,str|None]

        """
        result = dict()
        query_string = query_string.strip('?')
        if query_string == '':
            return result

        try:
            for pair in query_string.split("&"):
                (k, v) = pair.split("=")
                result[k] = v

            # if the channelcode was empty, it was stripped, add it again.
            if self.keywordChannelCode not in result:
                Logger.debug(
                    "Adding ChannelCode=None as it was missing from the dict: %s",
                    result)
                result[self.keywordChannelCode] = None
        except:
            Logger.critical("Cannot determine query strings from %s",
                            query_string,
                            exc_info=True)
            raise

        return result

    def __str__(self):
        return "Plugin Params: {} ({})\n" \
               "Handle:      {}\n" \
               "Name:        {}\n" \
               "Query:       {}".format(self.params, len(self.params), self.handle, self.pluginName, self._params)
    def __init__(self, addon_name, handle, params):
        """

        :param str addon_name:  The name of the add-on
        :param int handle:      The handle for this run
        :param str params:      The parameteters used to start the ParameterParser

        """

        Logger.debug("Parsing parameters from: %s", params)

        # Url Keywords
        self.keywordPickle = "pickle"  # : Used for the pickle item
        self.keywordAction = "action"  # : Used for specifying the action
        self.keywordChannel = "channel"  # : Used for the channel
        self.keywordChannelCode = "channelcode"  # : Used for the channelcode
        self.keywordCategory = "category"  # : Used for the category
        self.keywordRandomLive = "rnd"  # : Used for randomizing live items
        self.keywordSettingId = "settingid"  # : Used for setting an encrypted setting
        self.keywordSettingActionId = "settingactionid"  # : Used for passing the actionid for the encryption
        self.keywordSettingName = "settingname"  # : Used for setting an encrypted settings display name
        self.keywordSettingTabFocus = "tabfocus"  # : Used for setting the tabcontrol to focus after changing a setting
        self.keywordSettingSettingFocus = "settingfocus"  # : Used for setting the setting control to focus after changing a setting
        self.keywordLanguage = "lang"  # : Used for the 2 char language information
        self.keywordProxy = "proxy"  # : Used so set the proxy index
        self.keywordLocalIP = "localip"  # : Used to set the local ip index

        # Url Actions
        self.actionFavourites = "favourites"  # : Used to show favorites for a channel
        self.actionAllFavourites = "allfavourites"  # : Used to show all favorites
        self.actionRemoveFavourite = "removefromfavourites"  # : Used to remove items from favorites
        self.actionAddFavourite = "addtofavourites"  # : Used to add items to favorites
        self.actionDownloadVideo = "downloadVideo"  # : Used to download a video item
        self.actionPlayVideo = "playvideo"  # : Used to play a video item
        self.actionUpdateChannels = "updatechannels"  # : Used to update channels
        self.actionListFolder = "listfolder"  # : Used to list a folder
        self.actionListCategory = "listcategory"  # : Used to show the channels from a category
        self.actionConfigureChannel = "configurechannel"  # : Used to configure a channel
        self.actionSetEncryptionPin = "changepin"  # : Used for setting an application pin
        self.actionSetEncryptedValue = "encryptsetting"  # : Used for setting an application pin
        self.actionResetVault = "resetvault"  # : Used for resetting the vault
        self.actionPostLog = "postlog"  # : Used for sending log files to pastebin.com
        self.actionProxy = "setproxy"  # : Used for setting a proxy

        self.handle = int(handle)

        # determine the query parameters
        self._params = params
        self.params = self.__get_parameters(params)
        self.pluginName = addon_name

        # We need a picker for this instance
        self._pickler = Pickler(Config.profileDir)

        # Field for property
        self.__media_item = None

        # For remote debugging and log reading purpose we need the full pickle string.
        if Logger.instance().minLogLevel <= Logger.LVL_DEBUG \
                and self.media_item is not None \
                and self._pickler.is_pickle_store_id(self.params[self.keywordPickle]):
            Logger.debug("Replacing PickleStore pickle '%s' with full pickle",
                         self.params[self.keywordPickle])
            self.params[self.keywordPickle] = self._pickler.pickle_media_item(
                self.media_item)
class ActionParser(object):
    def __init__(self, addon_name, handle, params):
        """

        :param str addon_name:  The name of the add-on
        :param int handle:      The handle for this run
        :param str params:      The parameters used to start the ActionParser

        """

        Logger.debug("Parsing parameters from: %s", params)

        self.handle = int(handle)

        # determine the query parameters
        self._params = params
        self.params = self.__get_parameters(params)
        self.pluginName = addon_name

        # We need a picker for this instance
        self.pickler = Pickler(Config.profileDir)

        # Field for property
        self.__media_item = None

        # For remote debugging and log reading purpose we need the full pickle string.
        if Logger.instance().minLogLevel <= Logger.LVL_DEBUG \
                and self.media_item is not None \
                and self.pickler.is_pickle_store_id(self.params[keyword.PICKLE]):
            Logger.debug("Replacing PickleStore pickle '%s' with full pickle",
                         self.params[keyword.PICKLE])
            self.params[keyword.PICKLE] = self.pickler.pickle_media_item(
                self.media_item)

    @property
    def media_item(self):
        """ The current MediaItem

        :returns: The current MediaItem
        :rtype: MediaItem

        """

        if self.__media_item is None and keyword.PICKLE in self.params:
            self.__media_item = self.pickler.de_pickle_media_item(
                self.params[keyword.PICKLE])

        return self.__media_item

    def create_action_url(self,
                          channel,
                          action,
                          item=None,
                          store_id=None,
                          category=None):
        """ Creates an URL that includes an action.

        Arguments:
        channel : Channel -
        action  : string  -

        Keyword Arguments:
        item : MediaItem -

        :param ChannelInfo|Channel channel:     The channel object to use for the URL
        :param str action:                      Action to create an url for
        :param MediaItem item:                  The media item to add
        :param str store_id:                    The ID of the pickle store
        :param str category:                    The category to use

        :return: a complete action url with all keywords and values
        :rtype: str|unicode

        """

        if action is None:
            raise Exception("action is required")

        # catch the plugin:// url's for items and channels.
        if item is not None and item.url and item.url.startswith("plugin://"):
            return item.url

        if item is None and channel is not None and channel.uses_external_addon:
            return channel.addonUrl

        params = dict()
        if channel:
            params[keyword.CHANNEL] = channel.moduleName
            if channel.channelCode:
                params[keyword.CHANNEL_CODE] = channel.channelCode

        params[keyword.ACTION] = action

        # it might have an item or not
        if item is not None:
            params[keyword.PICKLE] = "{}--{}".format(store_id, item.guid)

            if action == PLAY_VIDEO and item.isLive:
                params[keyword.RANDOM_LIVE] = random.randint(10000, 99999)

        if category:
            params[keyword.CATEGORY] = category

        url = "%s?" % (self.pluginName, )
        for k in params.keys():
            url = "%s%s=%s&" % (url, k, params[k])

        url = url.strip('&')
        # Logger.Trace("Created url: '%s'", url)
        return url

    def get_parent_guid(self, channel, parent_item):
        """ Returns the parent guid of an item

        :param channel:         The parent channel object
        :param parent_item:     The parent items

        :return: a guid of either the parent channel or item
        :rtype: str

        """

        if channel is None and parent_item is None:
            # we should not use the store
            return None

        return channel.guid if parent_item is None else parent_item.guid

    def __get_parameters(self, query_string):
        """ Extracts the actual parameters as a dictionary from the passed in querystring.
        This method takes the self.quotedPlus into account.

        :param str query_string:    The querystring

        :return: dict() of keywords and values.
        :rtype: dict[str,str|None]

        """
        result = dict()
        query_string = query_string.strip('?')
        if query_string == '':
            return result

        try:
            for pair in query_string.split("&"):
                (k, v) = pair.split("=")
                result[k] = v

            # if the channelcode was empty, it was stripped, add it again.
            if keyword.CHANNEL_CODE not in result:
                Logger.debug(
                    "Adding ChannelCode=None as it was missing from the dict: %s",
                    result)
                result[keyword.CHANNEL_CODE] = None
        except:
            Logger.critical("Cannot determine query strings from %s",
                            query_string,
                            exc_info=True)
            raise

        return result

    def __str__(self):
        return "Plugin Params: {} ({})\n" \
               "Handle:      {}\n" \
               "Name:        {}\n" \
               "Query:       {}".format(self.params, len(self.params), self.handle, self.pluginName, self._params)
예제 #8
0
class Favourites:
    def __init__(self, path):
        """ Initializes a Favourites class that can be use to show, add and delete favourites.

        :param str path: The path to store the favourites file

        """

        self.__filePattern = "%s-%s.xotfav"
        self.__pickler = Pickler()

        self.FavouriteFolder = path

    def add(self, channel, item, action_url):
        """ Adds a favourite for a specific channel.

        :param channel:       The channel
        :param item:          The mediaitem
        :param str action_url:     The mediaitem's actionUrl

        """

        Logger.debug("Adding item %s\nfor channel %s\n%s", item, channel,
                     action_url)
        file_name = self.__filePattern % (channel.guid, item.guid)
        file_path = os.path.join(self.FavouriteFolder, file_name)
        pickle = self.__pickler.pickle_media_item(item)

        # Just double check for folder existence
        if not os.path.isdir(self.FavouriteFolder):
            os.makedirs(self.FavouriteFolder)

        # replacing to pickle in the actionUrl to save space
        action_url = self.__remove_pickle(action_url)

        try:
            with io.open(file_path, mode='w', encoding='utf-8') as file_handle:
                file_handle.write(
                    "%s\n%s\n%s\n%s" %
                    (channel.channelName, item.name, action_url, pickle))
        except:
            Logger.error("Error saving favourite", exc_info=True)
            raise
        return

    # noinspection PyUnusedLocal
    def remove(self, item):
        """ Adds a favourite for a specific channel

        :param item:          The mediaitem

        """

        path_mask = os.path.join(self.FavouriteFolder,
                                 "*-%s.xotfav" % (item.guid, ))

        Logger.debug("Removing favourites for mask: %s", path_mask)
        for fav in glob.glob(path_mask):
            Logger.trace("Removing item %s\nFileName: %s", item, fav)
            os.remove(fav)
        return

    def list(self, channel=None):
        """ Lists favourites. If a channel was specified it will limit them to that.

        :param channel: The channel to limit the favourites to.

        :return: A list of tupples (action_url, pickle)
        :rtype: list

        """

        favs = []

        if channel:
            path_mask = os.path.join(self.FavouriteFolder,
                                     "%s-*.xotfav" % (channel.guid, ))
        else:
            path_mask = os.path.join(self.FavouriteFolder, "*.xotfav")

        Logger.debug("Fetching favourites for mask: %s", path_mask)
        for fav in glob.glob(path_mask):
            Logger.trace("Fetching %s", fav)

            try:
                with io.open(fav, mode='r', encoding='utf-8') as file_handle:
                    channel_name = file_handle.readline().rstrip()
                    name = file_handle.readline().rstrip()
                    action_url = file_handle.readline().rstrip()
                    if "pickle=" in action_url and "pickle=%s" not in action_url:
                        # see issue https://github.com/retrospect-addon/plugin.video.retrospect/issues/1037
                        Logger.debug(
                            "Found favourite with full pickle, removing the pickle as we should use the one from the file."
                        )
                        action_url = self.__remove_pickle(action_url)

                    pickle = file_handle.readline()
            except:
                Logger.error("Error fetching favourite", exc_info=True)
                raise

            if channel_name == "" or name == "" or action_url == "" or pickle == "":
                Logger.error(
                    "Apparently the file had too few lines, corrupt Favourite, removing it:\n"
                    "Pickle: %s\n"
                    "Channel: %s\n"
                    "Item: %s\n"
                    "ActionUrl: %s\n"
                    "Pickle: %s", fav, channel_name, name, action_url, pickle)

                # Remove the invalid favourite
                os.remove(fav)
                continue

            Logger.debug("Found favourite: %s", name)
            try:
                item = self.__pickler.de_pickle_media_item(pickle)
            except Exception:
                Logger.error("Cannot depickle item.", exc_info=True)
                # Let's not remove them for now. Just ignore.
                # os.remove(fav)
                continue

            validation_error = self.__pickler.validate(
                item, logger=Logger.instance())
            if validation_error:
                Logger.error(
                    "Invalid Pickled Item: %s\nRemoving favourite: %s",
                    validation_error, fav)

                # Remove the invalid favourite
                os.remove(fav)
                continue

            # clean up the .: from titles
            if ".:" in item.name and ":." in item.name:
                item.name = item.name.strip(".:\0\b ")

            # add the channel name
            if channel is None:
                item.name = "%s [%s]" % (item.name, channel_name)

            item.clear_date()

            item.actionUrl = action_url % (pickle, )
            favs.append(item)
        return favs

    def __remove_pickle(self, action_url):
        pickle = Regexer.do_regex("pickle=([^&]+)", action_url)
        if not pickle:
            return action_url

        return action_url.replace(pickle[0], "%s")