Esempio n. 1
0
    def get_channel(self, class_name, channel_code, info_only=False):
        """ Fetches a single channel for a given className and channelCode

        If updated channels are found, the those channels are indexed and the
        channel index is rebuild.

        :param str|unicode class_name:      The chn_<name> class name.
        :param str|unicode channel_code:    A possible channel code within the channel set.
        :param bool info_only:              Only return the ChannelInfo.

        :return: a Channel object
        :rtype: Channel

        """

        channel_set = self.__channelIndex[self.__CHANNEL_INDEX_CHANNEL_KEY].get(class_name, None)
        if channel_set is None:
            Logger.error("Could not find info for channelClass '%s'.", class_name)
            return None

        channel_set_info_path = channel_set[self.__CHANNEL_INDEX_CHANNEL_INFO_KEY]
        channel_set_version = channel_set[self.__CHANNEL_INDEX_CHANNEL_VERSION_KEY]
        if not os.path.isfile(channel_set_info_path) and not self.__reindexed:
            Logger.warning("Missing channel_set file: %s.", channel_set_info_path)
            self.__rebuild_index()
            return self.get_channel(class_name, channel_code)

        channel_infos = ChannelInfo.from_json(channel_set_info_path, channel_set_version)
        if channel_code is None:
            channel_infos = [ci for ci in channel_infos if ci.channelCode is None]
        else:
            channel_infos = [ci for ci in channel_infos if ci.channelCode == channel_code]

        if len(channel_infos) != 1:
            Logger.error("Found none or more than 1 matches for '%s' and '%s' in the channel index.",
                         class_name, channel_code or "None")
            return None
        else:
            Logger.debug("Found single channel in the channel index: %s.", channel_infos[0])

        if self.__is_channel_set_updated(channel_infos[0]):
            # let's see if the index has already been updated this section, of not, do it and
            # restart the ChannelRetrieval.
            if not self.__reindexed:
                # rebuild and restart
                Logger.warning("Re-index channel index due to channel_set update: %s.", channel_set_info_path)
                self.__rebuild_index()
            else:
                Logger.warning("Found updated channel_set: %s.", channel_set_info_path)

            # new we should init all channels by loading them all, just to be shure that all is ok
            Logger.debug("Going to fetching all channels to init them all.")
            self.get_channels()
            return self.get_channel(class_name, channel_code)

        if info_only:
            return channel_infos[0]

        return channel_infos[0].get_channel()
Esempio n. 2
0
    def GetChannel(self, className, channelCode):
        """ Fetches a single channel for a given className and channelCode

        If updated channels are found, the those channels are indexed and the
        channel index is rebuild.

        @param className:       the chn_<name> class name
        @param channelCode:     a possible channel code within the channel set
        @return:                a ChannelInfo object

        """

        channelSet = self.__channelIndex[self.__CHANNEL_INDEX_CHANNEL_KEY].get(className, None)
        if channelSet is None:
            Logger.Error("Could not find info for channelClass '%s'.", className)
            return None

        channelSetInfoPath = channelSet[self.__CHANNEL_INDEX_CHANNEL_INFO_KEY]
        channelSetVersion = channelSet[self.__CHANNEL_INDEX_CHANNEL_VERSION_KEY]
        if not os.path.isfile(channelSetInfoPath) and not self.__reindexed:
            Logger.Warning("Missing channelSet file: %s.", channelSetInfoPath)
            self.__RebuildIndex()
            return self.GetChannel(className, channelCode)

        channelInfos = ChannelInfo.FromJson(channelSetInfoPath, channelSetVersion)
        if channelCode is None:
            channelInfos = filter(lambda ci: ci.channelCode is None, channelInfos)
        else:
            channelInfos = filter(lambda ci: ci.channelCode == channelCode, channelInfos)

        if len(channelInfos) != 1:
            Logger.Error("Found none or more than 1 matches for '%s' and '%s' in the channel index.",
                         className, channelCode or "None")
            return None
        else:
            Logger.Debug("Found single channel in the channel index: %s.", channelInfos[0])

        if self.__IsChannelSetUpdated(channelInfos[0]):
            # let's see if the index has already been updated this section, of not, do it and
            # restart the ChannelRetrieval.
            if not self.__reindexed:
                # rebuild and restart
                Logger.Warning("Re-index channel index due to channelSet update: %s.", channelSetInfoPath)
                self.__RebuildIndex()
            else:
                Logger.Warning("Found updated channelSet: %s.", channelSetInfoPath)

            # new we should init all channels by loading them all, just to be shure that all is ok
            Logger.Debug("Going to fetching all channels to init them all.")
            self.GetChannels()
            return self.GetChannel(className, channelCode)

        return channelInfos[0].GetChannel()
Esempio n. 3
0
    def get_channels(self, include_disabled=False, **kwargs):  # NOSONAR
        """ Retrieves all enabled channels within Retrospect.

        If updated channels are found, the those channels are indexed and the
        channel index is rebuild.

        :param bool include_disabled:   Boolean to indicate if we should include those channels
                                        that are explicitly disabled from the settings.
        :param dict kwargs:             Here for backward compatibility.

        :return: a list of ChannelInfo objects of enabled channels.
        :rtype: list[ChannelInfo]

        """

        sw = StopWatch("ChannelIndex.get_channels Importer", Logger.instance())
        Logger.info("Fetching all enabled channels.")

        self.__allChannels = []
        valid_channels = []

        # What platform are we
        platform = envcontroller.EnvController.get_platform()

        channels_updated = False
        country_visibility = {}

        for channel_set in self.__channelIndex[self.__CHANNEL_INDEX_CHANNEL_KEY]:
            channel_set = self.__channelIndex[self.__CHANNEL_INDEX_CHANNEL_KEY][channel_set]
            channel_set_info_path = channel_set[self.__CHANNEL_INDEX_CHANNEL_INFO_KEY]
            channel_set_version = channel_set[self.__CHANNEL_INDEX_CHANNEL_VERSION_KEY]

            # Check if file exists. If not, rebuild index
            if not os.path.isfile(channel_set_info_path) and not self.__reindexed:
                Logger.warning("Missing channelSet file: %s.", channel_set_info_path)
                self.__rebuild_index()
                return self.get_channels()

            channel_infos = ChannelInfo.from_json(channel_set_info_path, channel_set_version)

            # Check if the channel was updated
            if self.__is_channel_set_updated(channel_infos[0]):
                # let's see if the index has already been updated this section, of not, do it and
                # restart the ChannelRetrieval.
                if not self.__reindexed:
                    # rebuild and restart
                    Logger.warning("Re-index channel index due to channelSet update: %s.", channel_set_info_path)
                    self.__rebuild_index()
                    return self.get_channels()
                else:
                    Logger.warning("Found updated channelSet: %s.", channel_set_info_path)

                if not channels_updated:
                    # this was the first update found (otherwise channelsUpdated was True) show a message:
                    title = LanguageHelper.get_localized_string(LanguageHelper.InitChannelTitle)
                    text = LanguageHelper.get_localized_string(LanguageHelper.InitChannelText)
                    XbmcWrapper.show_notification(title, text, display_time=15000, logger=Logger.instance())
                channels_updated |= True

                # Initialise the channelset.
                self.__initialise_channel_set(channel_infos[0])

                # And perform all first actions for the included channels in the set
                for channel_info in channel_infos:
                    self.__initialise_channel(channel_info)

            # Check the channel validity
            for channel_info in channel_infos:
                if not self.__channel_is_correct(channel_info):
                    continue
                self.__allChannels.append(channel_info)

                # valid channel for this platform ?
                if not channel_info.compatiblePlatforms & platform == platform:
                    Logger.warning("Not loading: %s -> platform '%s' is not compatible.",
                                   channel_info, Environments.name(platform))
                    continue
                valid_channels.append(channel_info)

                # was the channel hidden based on language settings? We do some caching to speed
                # things up.
                if channel_info.language not in country_visibility:
                    country_visibility[channel_info.language] = AddonSettings.show_channel_with_language(channel_info.language)
                channel_info.visible = country_visibility[channel_info.language]

                # was the channel explicitly disabled from the settings?
                channel_info.enabled = AddonSettings.get_channel_visibility(channel_info)

                Logger.debug("Found channel: %s", channel_info)

        if channels_updated:
            Logger.info("New or updated channels found. Updating add-on configuration for all channels and user agent.")
            AddonSettings.update_add_on_settings_with_channels(valid_channels, Config)
            AddonSettings.update_user_agent()
        else:
            Logger.debug("No channel changes found. Skipping add-on configuration for channels.")
            # TODO: perhaps we should check that the settings.xml is correct and not broken?

        valid_channels.sort(key=lambda c: c.sort_key)
        visible_channels = [ci for ci in valid_channels if ci.visible and ci.enabled]
        Logger.info("Fetch a total of %d channels of which %d are visible.",
                    len(valid_channels),
                    len(visible_channels))

        sw.stop()

        if include_disabled:
            return valid_channels

        return visible_channels
Esempio n. 4
0
    def GetChannels(self, includeDisabled=False, **kwargs):
        # type: (object) -> list
        """ Retrieves all enabled channels within Retrospect.

        If updated channels are found, the those channels are indexed and the
        channel index is rebuild.

        @type kwargs: here for backward compatibility

        @return: a list of ChannelInfo objects of enabled channels.

        """

        sw = StopWatch("ChannelIndex.GetChannels Importer", Logger.Instance())
        Logger.Info("Fetching all enabled channels.")

        self.__enabledChannels = []
        self.__allChannels = []
        self.__validChannels = []

        # What platform are we
        platform = envcontroller.EnvController.GetPlatform()

        channelsUpdated = False
        for channelSet in self.__channelIndex[self.__CHANNEL_INDEX_CHANNEL_KEY]:
            channelSet = self.__channelIndex[self.__CHANNEL_INDEX_CHANNEL_KEY][channelSet]
            channelSetInfoPath = channelSet[self.__CHANNEL_INDEX_CHANNEL_INFO_KEY]
            channelSetVersion = channelSet[self.__CHANNEL_INDEX_CHANNEL_VERSION_KEY]

            # Check if file exists. If not, rebuild index
            if not os.path.isfile(channelSetInfoPath) and not self.__reindexed:
                Logger.Warning("Missing channelSet file: %s.", channelSetInfoPath)
                self.__RebuildIndex()
                return self.GetChannels()

            channelInfos = ChannelInfo.FromJson(channelSetInfoPath, channelSetVersion)

            # Check if the channel was updated
            if self.__IsChannelSetUpdated(channelInfos[0]):
                # let's see if the index has already been updated this section, of not, do it and
                # restart the ChannelRetrieval.
                if not self.__reindexed:
                    # rebuild and restart
                    Logger.Warning("Re-index channel index due to channelSet update: %s.", channelSetInfoPath)
                    self.__RebuildIndex()
                    return self.GetChannels()
                else:
                    Logger.Warning("Found updated channelSet: %s.", channelSetInfoPath)

                if not channelsUpdated:
                    # this was the first update found (otherwise channelsUpdated was True) show a message:
                    title = LanguageHelper.GetLocalizedString(LanguageHelper.InitChannelTitle)
                    text = LanguageHelper.GetLocalizedString(LanguageHelper.InitChannelText)
                    XbmcWrapper.ShowNotification(title, text, displayTime=15000, logger=Logger.Instance())
                channelsUpdated |= True

                # Initialise the channelset.
                self.__InitialiseChannelSet(channelInfos[0])

                # And perform all first actions for the included channels in the set
                for channelInfo in channelInfos:
                    self.__InitialiseChannel(channelInfo)

            # Check the channel validity
            for channelInfo in channelInfos:
                if not self.__ChannelIsCorrect(channelInfo):
                    continue
                self.__allChannels.append(channelInfo)

                # valid channel for this platform ?
                if not channelInfo.compatiblePlatforms & platform == platform:
                    Logger.Warning("Not loading: %s -> platform '%s' is not compatible.",
                                   channelInfo, Environments.Name(platform))
                    continue
                self.__validChannels.append(channelInfo)

                # was the channel disabled?
                if not (AddonSettings.ShowChannel(
                        channelInfo) and AddonSettings.ShowChannelWithLanguage(
                        channelInfo.language)):
                    Logger.Warning("Not loading: %s -> Channel was disabled from settings.",
                                   channelInfo)
                    continue
                self.__enabledChannels.append(channelInfo)

                Logger.Debug("Loading: %s", channelInfo)

        if channelsUpdated:
            Logger.Info("New or updated channels found. Updating add-on configuration for all channels and user agent.")
            AddonSettings.UpdateAddOnSettingsWithChannels(self.__validChannels, Config)
            AddonSettings.UpdateUserAgent()
        else:
            Logger.Debug("No channel changes found. Skipping add-on configuration for channels.")
            # TODO: perhaps we should check that the settings.xml is correct and not broken?

        self.__enabledChannels.sort()
        Logger.Info("Fetch a total of %d channels of which %d are enabled.",
                    len(self.__allChannels),
                    len(self.__enabledChannels))

        sw.Stop()
        if includeDisabled:
            return self.__validChannels
        return self.__enabledChannels
Esempio n. 5
0
    def __ImportChannels(self):  # , className = None):
        """Import the available channels

        This method will:
         - iterate through the Addons folder and find all the folders name
           <basename>.channel.<channelname>.
         - then adds all the subfolders into a list (with paths).
         - then all paths are added to the system path, so they can be imported.
         - then read all the chn_<name>.xml metadata files and add the ChannelInfo
           objects to the self.__channelsToImport
         - then the channels in the self.__channelsToImport list are instantiated
           into the self.channels list.

        """

        Logger.Debug("Importing available channels")
        # import each channelPath. On import, the channelPath will call the RegisterChannel Method
        try:
            # clear a possible previous import
            self.__enabledChannels = []
            self.__allChannels = []
            self.__validChannels = []
            self.__channelVersions = []

            # first find all folders with channels that we might need to import
            channelImport = []
            importTimer = StopWatch("ChannelImporter :: importing channels", Logger.Instance())

            addonPath = self.__GetAddonPath()

            channelPathStart = "%s.channel" % (Config.addonDir,)
            for directory in os.listdir(addonPath):
                if channelPathStart in directory and "BUILD" not in directory:
                    path = os.path.join(addonPath, directory)

                    channelVersion = self.__ParseChannelVersionInfo(path)
                    if channelVersion:
                        self.__channelVersions.append(channelVersion)
                    else:
                        # no info was returned, so we will not include the channel
                        continue

                    # get all nested channels
                    subDirs = os.listdir(path)
                    channelImport.extend(
                        [os.path.abspath(os.path.join(path, weapon)) for weapon in subDirs])

            channelImport.sort()
            importTimer.Lap("Directories scanned for .channel")

            # we need to make sure we don't load multiple channel classes and track if we found updates
            channelsUpdated = False
            loadedChannels = []
            channelsToImport = []

            # now import the channels
            for channelPath in channelImport:
                if not os.path.isdir(channelPath):
                    continue

                # determine channelname
                channelName = os.path.split(channelPath)[-1]
                if channelName == self.__updateChannelPath:
                    Logger.Trace("Update path found and skipping: %s", channelName)
                    continue

                # if loadedChannels.count(channelName) > 0:
                if channelName in loadedChannels:
                    Logger.Warning(
                        "Not loading: chn_%s.xml in %s because there is already a path with "
                        "name '%s' that name loaded", channelName, channelPath, channelName)
                    continue

                if channelName.startswith("."):
                    continue

                # now we can continue
                loadedChannels.append(channelName)

                fileName = os.path.join(channelPath, "chn_" + channelName + ".json")
                Logger.Trace("Loading info for chn_%s @ %s", channelName, fileName)
                if os.path.isfile(fileName):
                    try:
                        ci = ChannelInfo.FromJson(fileName)
                        if len(ci) <= 0:
                            Logger.Warning("No channels found in '%s'", fileName)
                            continue

                        # Add them to the list to import
                        channelsToImport += ci

                        if self.__IsChannelSetUpdated(ci[0]):
                            if not channelsUpdated:
                                # this was the first update found (otherwise channelsUpdated was True) show a message:
                                title = LanguageHelper.GetLocalizedString(
                                    LanguageHelper.InitChannelTitle)
                                text = LanguageHelper.GetLocalizedString(
                                    LanguageHelper.InitChannelText)
                                XbmcWrapper.ShowNotification(title, text, displayTime=15000)

                            # set the updates found bit
                            channelsUpdated |= True

                            # Initialise the channelset.
                            self.__InitialiseChannelSet(ci[0])

                            # And perform all first actions for the included channels in the set
                            for channelInfo in ci:
                                self.__FirstTimeChannelActions(channelInfo)
                    except:
                        Logger.Error("Error import chn_%s.json", channelName, exc_info=True)

            importTimer.Lap()

            # What platform are we
            platform = envcontroller.EnvController.GetPlatform()

            # instantiate the registered channels
            for channelInfo in channelsToImport:
                # noinspection PyUnusedLocal
                isValid = self.__ValidateChannelInfo(channelInfo, platform)

            # sort the channels
            self.__enabledChannels.sort()

            if channelsUpdated:
                Logger.Info("New or updated channels found. Updating add-on configuration for all "
                            "channels and user agent")
                AddonSettings.UpdateAddOnSettingsWithChannels(self.__validChannels, Config)
                AddonSettings.UpdateUserAgent()
            else:
                Logger.Debug("No channel changes found. Skipping add-on configuration for channels")

            # Should we update the channel index?
            if channelsUpdated or not os.path.isfile(self.__CHANNEL_INDEX):
                self.__CreateChannelIndex()

            Logger.Info("Imported %s channels from which %s are enabled",
                        len(self.__allChannels), len(self.__enabledChannels))
            importTimer.Stop()
        except:
            Logger.Critical("Error loading channel modules", exc_info=True)
Esempio n. 6
0
    def GetSingleChannel(self, className, channelCode):
        """Imports a single channel

        Arguments:
        className : string - class name of the channel to import.

        Returns:
        The channels in the requested class. So that could be more, but they
        can be distinguished using the channelcode.

        Returns an empty list if no channels were found.

        """

        if not className:
            raise ValueError("className should be specified.")

        Logger.Info("Loading channels for class '%s' and channelCode '%s'", className, channelCode)

        self.__enabledChannels = []
        self.__allChannels = []
        self.__validChannels = []
        self.__channelVersions = []

        # noinspection PyUnusedLocal
        classPath = None
        channelPath = None
        classBaseName = className[4:]
        if os.path.isfile(self.__CHANNEL_INDEX):
            Logger.Debug("Using ChannelIndex for channel lookup: %s", self.__CHANNEL_INDEX)
            fd = None
            try:
                fd = open(self.__CHANNEL_INDEX)
                data = fd.read()
            finally:
                if fd is not None and not fd.closed:
                    fd.close()
            channelIndex = JsonHelper(data)
            classPath = channelIndex.GetValue(className, channelCode or "null")
            if classPath is not None:
                if not os.path.isdir(classPath):
                    Logger.Warning("Missing channel class path '%s' found. Rebuilding the ChannelIndex.", classPath)
                    # remove the old one
                    os.remove(self.__CHANNEL_INDEX)
                    # return self.GetSingleChannel(className, channelCode)
                    return self.__ImportChannel(className, channelCode)
                channelPath = os.path.join(classPath, "..")
        else:
            Logger.Warning("Missing ChannelIndex. Rebuilding the ChannelIndex.")
            return self.__ImportChannel(className, channelCode)

            # Logger.Warning("Falling back to classic find pattern")
            #
            # # walk the channel dirs to find the one that has the channel
            # addonPath = self.__GetAddonPath()
            # channelPathStart = "%s.channel" % (Config.addonDir,)
            #
            # # list all add-ons
            # for directory in os.listdir(addonPath):
            #     # find the xot ones
            #     if channelPathStart in directory and "BUILD" not in directory:
            #         channelPath = os.path.join(addonPath, directory)
            #
            #         # list the subfolders for the requested folder to find the one we need
            #         if classBaseName not in os.listdir(channelPath):
            #             continue
            #
            #         # we perhaps found it.
            #         classPath = os.path.join(channelPath, classBaseName)

        if classPath is None:
            Logger.Error("No Channel found for class '%s' and channelCode '%s'",
                         className, channelCode)
            return None

        Logger.Debug("Found possible channel folder in %s", classPath)

        # check the addon.xml with self.__ParseChannelVersionInfo(path)
        channelVersion = self.__ParseChannelVersionInfo(channelPath)
        if channelVersion:
            self.__channelVersions.append(channelVersion)
        else:
            # no info was returned, so we will not include the channel
            Logger.Error("Match in %s has incorrect version", classPath)
            return None

        # create ChannelInfo objects from the xml file and get the correct ChannelInfo object. It coulde that none
        # is found and we might need to continue (in case there were duplicate channel names
        fileName = os.path.join(classPath, "chn_" + classBaseName + ".json")

        Logger.Debug("Loading info for chn_%s @ %s", classBaseName, fileName)
        if not os.path.isfile(fileName):
            Logger.Error("Could not load %s", fileName)
            return None

        cis = ChannelInfo.FromJson(fileName)
        ci = filter(lambda c: c.moduleName == className and (c.channelCode == channelCode or
                                                             c.channelCode is channelCode), cis)
        if not ci or len(ci) > 1:
            Logger.Error("Could not load channel with className=%s and channelCode=%s from %s",
                         className, channelCode, fileName)
            return None

        ci = ci[0]
        if self.__IsChannelSetUpdated(ci):
            # apparently a new channel was found, so we need to do it all
            Logger.Info("Found a new channel, we need to reload all channels")
            return self.__ImportChannel(className, channelCode)

        # What platform are we
        platform = envcontroller.EnvController.GetPlatform()

        # check if it is enabled or not
        if self.__ValidateChannelInfo(ci, platform):
            return ci.GetChannel()
        else:
            Logger.Error("Invalid Channel found for class '%s' and channelCode '%s'",
                         className, channelCode)
            return None
Esempio n. 7
0
    def GetSingleChannel_old(self, className, channelCode):
        """Imports a single channel

        Arguments:
        className : string - class name of the channel to import.

        Returns:
        The channels in the requested class. So that could be more, but they
        can be distinguished using the channelcode.

        Returns an empty list if no channels were found.

        """

        if not className:
            raise ValueError("className should be specified.")

        Logger.Info("Loading channels for class '%s' and channelCode '%s'", className, channelCode)

        self.__enabledChannels = []
        self.__allChannels = []
        self.__validChannels = []
        self.__channelVersions = []

        channel = None

        # walk the channel dirs to find the one that has the channel
        addonPath = self.__GetAddonPath()
        channelPathStart = "%s.channel" % (Config.addonDir, )
        folderToFind = className[4:]

        # list all add-ons
        for directory in os.listdir(addonPath):
            # find the xot ones
            if channelPathStart in directory and "BUILD" not in directory:
                channelPath = os.path.join(addonPath, directory)

                # list the subfolders for the requested folder to find the one we need
                if folderToFind not in os.listdir(channelPath):
                    continue

                # we perhaps found it.
                classPath = os.path.join(channelPath, folderToFind)
                Logger.Debug("Found possible channel folder in %s", classPath)

                # check the addon.xml with self.__ParseChannelVersionInfo(path)
                channelVersion = self.__ParseChannelVersionInfo(channelPath)
                if channelVersion:
                    self.__channelVersions.append(channelVersion)
                else:
                    # no info was returned, so we will not include the channel
                    Logger.Warning("Match in %s has incorrect version", classPath)
                    continue

                # create ChannelInfo objects from the xml file and get the correct ChannelInfo object. It coulde that none
                # is found and we might need to continue (in case there were duplicate channel names
                fileName = os.path.join(classPath, "chn_" + folderToFind + ".json")

                Logger.Debug("Loading info for chn_%s @ %s", folderToFind, fileName)
                if not os.path.isfile(fileName):
                    Logger.Warning("Could not load %s", fileName)
                    continue

                cis = ChannelInfo.FromJson(fileName)
                ci = filter(lambda c: c.moduleName == className and (c.channelCode == channelCode or c.channelCode is channelCode), cis)
                if not ci or len(ci) > 1:
                    Logger.Warning("Could not load channel with className=%s and channelCode=%s from %s", className, channelCode, fileName)
                    continue

                ci = ci[0]
                if self.__IsChannelSetUpdated(ci):
                    # apparently a new channel was found, so we need to do it all
                    Logger.Info("Found a new channel, we need to reload all channels")
                    return self.__ImportChannel(className, channelCode)

                # What platform are we
                platform = envcontroller.EnvController.GetPlatform()

                # check if it is enabled or not
                if self.__ValidateChannelInfo(ci, platform):
                    return ci.GetChannel()
                else:
                    continue

        Logger.Error("No Channel found for class '%s' and channelCode '%s'", className, channelCode)
        return channel