Esempio n. 1
0
    def run(self):
        okno = None
        try:
            okno = Window(xbmcgui.getCurrentWindowId())
            okno.setProperty('RSS.count', '0')
        except:
            pass
        unread_c = 0
        for set in self.sets:
            self.reader.ReadSet(set, True)
            for src in set.sources:
                for channel in src.channels:
                    unread_c += channel.unread_count
                    for item in channel.items:
                        if already_read.count(item.link) > 0:
                            item.read = True
                        else:
                            channel.unread_count += 1
                            channel.read = False

        log('All sets read from cache')

        if ui != None and ui.isReady: ui.updateChannelList()

        changes = False

        next_update = -1

        for set in self.sets:
            for source in set.sources:
                last_checking = time.time() - source.lastupdate
                interval = int(source.updateinterval) * 60
                if last_checking > interval:
                    for src in set.sources:
                        for channel in src.channels:
                            unread_c -= channel.unread_count

                    self.reader.ReadSource(source, False)
                    changes = True
                    for src in set.sources:
                        for channel in src.channels:
                            unread_c += channel.unread_count
                            for item in channel.items:
                                if already_read.count(item.link) > 0:
                                    item.read = True
                                else:
                                    channel.unread_count += 1
                                    channel.read = False

                    if next_update == -1 or interval < next_update:
                        next_update = interval
                elif next_update == -1 or interval - last_checking < next_update:
                    next_update = interval - last_checking

        if changes:
            log('Sets updated from URL')
            if ui != None and ui.isReady: ui.updateChannelList()
    def run(self):
        okno = None
        try:
            okno = Window(xbmcgui.getCurrentWindowId())
            okno.setProperty('RSS.count', '0');
        except:
            pass
        unread_c = 0
        for set in self.sets:
            self.reader.ReadSet(set, True)
            for src in set.sources:
                for channel in src.channels:
                    unread_c += channel.unread_count
                    for item in channel.items:
                        if already_read.count(item.link) > 0:
                            item.read = True
                        else:
                            channel.unread_count += 1
                            channel.read = False

        log('All sets read from cache')  
          
        if ui != None and ui.isReady: ui.updateChannelList()
        
        changes = False
        
        next_update = -1
        
        for set in self.sets:
            for source in set.sources:
                last_checking = time.time() - source.lastupdate
                interval = int(source.updateinterval) * 60
                if last_checking > interval:
                    for src in set.sources:
                        for channel in src.channels:
                            unread_c -= channel.unread_count
                            
                    self.reader.ReadSource(source, False)
                    changes = True
                    for src in set.sources:
                        for channel in src.channels:
                            unread_c += channel.unread_count
                            for item in channel.items:
                                if already_read.count(item.link) > 0:
                                    item.read = True
                                else:
                                    channel.unread_count += 1
                                    channel.read = False
                    
                    if next_update == -1 or interval < next_update:
                        next_update = interval
                elif next_update == -1 or interval - last_checking < next_update:
                    next_update = interval - last_checking
        
        if changes:
            log('Sets updated from URL')    
            if ui != None and ui.isReady: ui.updateChannelList()
 def shutdown(self):
     """
     Stop the background services
     """
     from xbmcgui import Window
     window_cls = Window(10000)
     window_cls.setProperty('nf_service_status', 'stopped')
     for server in self.SERVERS:
         server['instance'].server_close()
         server['instance'].shutdown()
         server['instance'] = None
         server['thread'].join()
         server['thread'] = None
     info('Stopped MSL Service')
Esempio n. 4
0
def main():
    """
    Grabs kodi_id and kodi_type and sends a request to our main python instance
    that context menu needs to be displayed
    """
    window = Window(10000)
    kodi_id = listitem.getVideoInfoTag().getDbId()
    if kodi_id == -1:
        # There is no getDbId() method for getMusicInfoTag
        # YET TO BE IMPLEMENTED - lookup ID using path
        kodi_id = listitem.getMusicInfoTag().getURL()
    kodi_type = _get_kodi_type()
    args = {'kodi_id': kodi_id, 'kodi_type': kodi_type}
    while window.getProperty('plex_command'):
        sleep(20)
    window.setProperty('plex_command', 'CONTEXT_menu?%s' % urlencode(args))
    def run(self):
        """Main loop. Runs until xbmc.Monitor requests abort"""
        # pylint: disable=broad-except
        try:
            self.start_services()
        except Exception as exc:
            from xbmcgui import Window
            window_cls = Window(10000)
            window_cls.setProperty('nf_service_status', 'stopped')
            import traceback
            from resources.lib.kodi.ui import show_addon_error_info
            error(traceback.format_exc())
            show_addon_error_info(exc)
            return

        while not self.controller.abortRequested():
            if self._tick_and_wait_for_abort():
                break
        self.shutdown()
 def start_services(self):
     """
     Start the background services
     """
     from resources.lib.services.playback.controller import PlaybackController
     from resources.lib.services.library_updater import LibraryUpdateService
     from resources.lib.services.settings_monitor import SettingsMonitor
     for server in self.SERVERS:
         server['instance'].server_activate()
         server['instance'].timeout = 1
         server['thread'].start()
         info('[{}] Thread started'.format(server['name']))
     self.controller = PlaybackController()
     self.library_updater = LibraryUpdateService()
     self.settings_monitor = SettingsMonitor()
     # Mark the service as active
     from xbmcgui import Window
     window_cls = Window(10000)
     window_cls.setProperty('nf_service_status', 'running')
     if not g.ADDON.getSettingBool('disable_startup_notification'):
         from resources.lib.kodi.ui import show_notification
         show_notification(get_local_string(30110))
Esempio n. 7
0
class SimpleCache():

    '''
    Cache version log:
    1: Toonmania2 0.4.0

    2: Toonmania2 0.4.1
        I realized '/GetNew(...)' and '/GetPopular(...)' routes just need the IDs, not the whole JSON data.
        If something is in a '/GetPopular(...)' it will definitely be in the corresponding '/GetAll(...)'.
        So we keep only the IDs and retrieve the full entry from the 'All' routes.
        This change helps use less disk-space and memory.

    3: Toonmania2 0.4.2
        In this cache version we're using separate cache files for each route the user visited.
        This way uses we less memory because we only need to load the routes the user wants to
        go to, not one huge file that has everything, with what the user wants or doesn't want.
    '''
    # Cache version, for future extension. Used with properties saved to disk.
    CACHE_VERSION = 3

    LIFETIME_THREE_DAYS = 72 # 3 days, in hours.
    LIFETIME_FIVE_DAYS = 120 # 5 days.
    LIFETIME_ONE_WEEK = 168 # 7 days.
    LIFETIME_FOREVER = 0 # Never expires.

    # Path to .../kodi/userdata/addons_data/plugin.video.toonmania2/cache/ -> where the JSON cache files will be.
    CACHE_PATH_DIR = xbmc.translatePath(xbmcaddon.Addon().getAddonInfo('profile')).decode('utf-8') + 'cache' + osSeparator

    # Property name pointing to a Python 'set()' of property names.
    # This is used to quickly tell if a property exists or not by checking its name in the set,
    # rather than retrieving a property that could be a huge JSON blob just to see that it exists.
    PROPERTY_DISK_NAMES_SET = 'scache.prop.names'


    # Property name pointing to a comma-separated list of dirty disk-enabled properties that need saving.
    # This list is converted to a set when read and used for quick testing.
    PROPERTY_DIRTY_NAMES_SET = 'scache.prop.dirty'


    def __init__(self):
        '''
        Initialised at every directory change in Kodi <= 17.6.
        '''
        self.window = Window(getCurrentWindowId())
        self.diskNamesSet = None
        self.dirtyNamesSet = None


    def setCacheProperty(self, propName, data, saveToDisk, lifetime=72):
        '''
        Creates a persistent XBMC window memory property.
        :param propName: Name/Identifier the property should have, used to retrieve it later.
        Needs to be file-system friendly, and cannot have commas in the name.
        :param data: Data to store in the property, needs to be JSON-serializable.
        :param saveToDisk: Boolean if this property should be saved to a JSON cache file on
        disk to be loaded on later sessions. Best used for big collections of web-requested data.
        :param lifetime: When saving to disk, 'lifetime' specifies how many hours since its
        creation that the property should have on disk, before being erased. Defaults to 72
        hours (3 days). Setting it as '0' (zero) will make it last forever.
        '''
        if saveToDisk:
            # Create the window memory property.
            self._storeCacheProperty(propName, data, lifetime, self._getEpochHours())

            # Store the name of this disk-enabled property in a set to quickly tell
            # that it's already in memory and doesn't need to be loaded from disk.
            self._ensureDiskNamesSet()
            self.diskNamesSet.add(propName)
            self._storeMemorySet(self.PROPERTY_DISK_NAMES_SET, self.diskNamesSet)

            # Add the name of this new property to a set used by saveCacheIfDirty()
            # to tell which disk-enabled properties need saving to disk.
            self._ensureDirtyNamesSet()
            self.dirtyNamesSet.add(propName)
            self._storeMemorySet(self.PROPERTY_DIRTY_NAMES_SET, self.dirtyNamesSet)
        else:
            # A memory-only property. Other fields (lifetime, epoch etc.) are not needed.
            self.window.setProperty(propName, json.dumps(data))


    def setCacheProperties(self, properties, saveToDisk):
        '''
        Convenience function to create several properties at once.
        :param properties: For disk-enabled properties (saveToDisk=True), it's an iterable where
        each entry should be a tuple, list or other indexable object of this format:
        ((str)PROPERTY_NAME, (anything)PROPERTY_DATA, (int)LIFETIME_HOURS)
        Otherwise (with saveToDisk=False), 'properties' is an iterable of (name, data) pairs.

        The 'PROPERTY_DATA' or 'data' fields should be JSON-serializable.
        '''
        if saveToDisk:
            self._ensureDiskNamesSet()
            self._ensureDirtyNamesSet()

            for pEntry in properties:
                propName, data, lifetime = pEntry
                self._storeCacheProperty(propName, data, lifetime, self._getEpochHours())
                self.diskNamesSet.add(propName)
                self.dirtyNamesSet.add(propName) # These properties are being created \ updated and need saving.

            self._storeMemorySet(self.PROPERTY_DISK_NAMES_SET, self.diskNamesSet)
            self._storeMemorySet(self.PROPERTY_DIRTY_NAMES_SET, self.dirtyNamesSet)
        else:
            for propName, data in properties:
                self.window.setProperty(propName, json.dumps(data)) # Memory-only properties.


    def getCacheProperty(self, propName, readFromDisk):
        '''
        Tries to return the data from a window memory property.
        For the pure property string use the setRaw(...)\getRaw(...) functions instead.
        :param propName: Name of the property to retrieve.
        :param readFromDisk: Used with properties that might be saved on disk. It tries to load
        from memory first though, then if it's not in memory we load from its file, if it exists.
        :returns: The property data, if it exists, or None.
        '''
        if readFromDisk:
            # A disk-enabled property.
            # If it's already in the disk names set then it was either added manually or
            # already loaded from disk into memory.
            self._ensureDiskNamesSet()
            if propName in self.diskNamesSet:
                propRaw = self.window.getProperty(propName)
                return json.loads(propRaw)[0] if propRaw else None # Data is always the first JSON field.
            else:
                # Disk-enabled property isn't in memory yet, try to read it from its file.
                fileProp = self._tryLoadCacheProperty(propName)
                if fileProp:
                    propName, data, lifetime, epoch = fileProp
                    self._storeCacheProperty(propName, data, lifetime, epoch)
                    self.diskNamesSet.add(propName)
                    self._storeMemorySet(self.PROPERTY_DISK_NAMES_SET, self.diskNamesSet)
                    return data
                else:
                    return None
        else:
            # A memory-only property, points directly to data.
            propRaw = self.window.getProperty(propName)
            return json.loads(propRaw) if propRaw else None


    def getCacheProperties(self, propNames, readFromDisk):
        '''
        Retrieves a **generator** to more than one property data at once.
        The data is guaranteed to come in the same order as the provided names.
        '''
        if readFromDisk:
            self._ensureDiskNamesSet()
            anyLoadedFromFile = False

            for propName in propNames:
                if propName in self.diskNamesSet:
                    propRaw = self.window.getProperty(propName)
                    yield json.loads(propRaw)[0] if propRaw else None
                else:
                    fileProp = self._tryLoadCacheProperty(propName)
                    if fileProp:
                        propName, data, lifetime, epoch = fileProp
                        self._storeCacheProperty(propName, data, lifetime, epoch)
                        self.diskNamesSet.add(propName)
                        anyLoadedFromFile = True
                        yield data

            if anyLoadedFromFile:
                self._storeMemorySet(self.PROPERTY_DISK_NAMES_SET, self.diskNamesSet)
        else:
            for propName in propNames:
                propRaw = self.window.getProperty(propName)
                yield json.loads(propRaw) if propRaw else None # Memory-only property, points directly to data.


    def clearCacheProperty(self, propName, readFromDisk):
        '''
        Removes a property from memory. The next time the cache is saved, this property
        won't be included and therefore forgotten.
        '''
        self.window.clearProperty(propName)
        if readFromDisk:
            # Direct way to remove the property name from the comma-separated property name list.
            diskNamesRaw = self.window.getProperty(self.PROPERTY_DISK_NAMES_SET)
            self.window.setProperty(
                self.PROPERTY_DISK_NAMES_SET, diskNamesRaw.replace(propName, '').replace(',,', ',').strip(', ')
            )
            dirtyNamesRaw = self.window.getProperty(self.PROPERTY_DIRTY_NAMES_SET)
            self.window.setProperty(
                self.PROPERTY_DIRTY_NAMES_SET, dirtyNamesRaw.replace(propName, '').replace(',,', ',').strip(', ')
            )


    def setRawProperty(self, propName, data):
        '''
        Convenience function to set a window memory property that doesn't
        need JSON serialization or saving to disk.
        Used for unimportant memory-only properties that should persist between add-on
        directories.
        :param propName: The name of the property used to identify the data, later used
        to retrieve it.
        :param rawData: String data, stored as it is.
        '''
        self.window.setProperty(propName, data)


    def getRawProperty(self, propName):
        '''
        Retrieves a direct window property by name.
        '''
        return self.window.getProperty(propName)


    def clearRawProperty(self, propName):
        '''
        Clears a direct window property by name.
        To clear a property that was created with setCacheProperty()
        use clearCacheProperty() instead.
        '''
        return self.window.clearProperty(propName)


    def saveCacheIfDirty(self):
        # Optimised way to check if anything needs saving. Most of the time
        # 'dirtyNamesRaw' will be an empty string, easy to check for truthness.
        dirtyNamesRaw = self.window.getProperty(self.PROPERTY_DIRTY_NAMES_SET)
        if dirtyNamesRaw:
            for propName in dirtyNamesRaw.split(','):
                self._saveCacheProperty(propName)
            # Reset the dirty names set (and its window property).
            self.dirtyNamesSet = set()
            self.window.setProperty(self.PROPERTY_DIRTY_NAMES_SET, '')            


    def clearCacheFiles(self):
        dirPaths, filePaths = xbmcvfs.listdir(self.CACHE_PATH_DIR)
        for filePath in filePaths:
            self._writeBlankCacheFile(self.CACHE_PATH_DIR + filePath)
        # Clear the disk names set. All disk-enabled properties will be forgotten.
        self.window.setProperty(self.PROPERTY_DISK_NAMES_SET, '')
        self.diskNamesSet = set()
        # 'True' if one or more cache files were cleared / reset.
        return len(filePaths) > 0


    def _writeBlankCacheFile(self, fullPath):
        '''Assumes the directory to the file exists.'''
        file = xbmcvfs.File(fullPath, 'w')
        file.write('null') # JSON equivalent to None.
        file.close()


    def _ensureDiskNamesSet(self):
        '''
        For Kodi <= 17.6, used to initialise this class member in case it's invalid.
        But this function is only called when this member is needed.
        '''
        if self.diskNamesSet == None:
            self.diskNamesSet = self._stringToSet(self.window.getProperty(self.PROPERTY_DISK_NAMES_SET))


    def _ensureDirtyNamesSet(self):
        if self.dirtyNamesSet == None:
            self.dirtyNamesSet = self._stringToSet(self.window.getProperty(self.PROPERTY_DIRTY_NAMES_SET))


    def _storeMemorySet(self, setPropName, setObject):
        self.window.setProperty(setPropName, self._setToString(setObject))


    def _tryLoadCacheProperty(self, propName):
        '''
        Tries to load the cache file for the named property.
        If a cache file doesn't exist for a property, a blank cache file is created.
        :returns: A tuple of property entries, each entry is a tuple of fields
        (propName, data, lifetime, epoch).
        '''
        currentEpoch = self._getEpochHours()
        fullPath = self.CACHE_PATH_DIR + propName + '.json'
        try:
            if xbmcvfs.exists(fullPath):
                file = xbmcvfs.File(fullPath)
                data = file.read()
                file.close()

                if data and data != 'null':
                    fileProp = json.loads(data)

                    # Version restriction.
                    version = fileProp['version']
                    if version >= self.CACHE_VERSION:
                        lifetime = fileProp['lifetime']
                        epoch = fileProp['epoch']
                        # Lifetime restriction. See if the property lasts forever or if
                        # the elapsed time since its creation epoch is bigger than its lifetime.
                        if lifetime == 0 or lifetime >= abs(currentEpoch - epoch):
                           return (fileProp['propName'], fileProp['data'], lifetime, epoch)
            else:
                # Initialize a blank cache file.
                xbmcvfs.mkdir(self.CACHE_PATH_DIR)
                self._writeBlankCacheFile(fullPath)
        except:
            pass
        return None # Fall-through.


    def _storeCacheProperty(self, propName, data, lifetime, epoch):
        '''
        Internal.
        Stores data in a persistent XBMC window memory property.
        '''
        self.window.setProperty(propName, json.dumps((data, lifetime, epoch)))


    def _saveCacheProperty(self, propName):
        '''
        Internal.
        Saves a specific dirty, disk-enabled property to disk.
        Assumes the destination folder already exists.
        '''
        propRaw = self.window.getProperty(propName)
        if propRaw:
            # Base structure as in _storeCacheProperty(), with the cache version added.
            data, lifetime, epoch = json.loads(propRaw)
            file = xbmcvfs.File(self.CACHE_PATH_DIR + propName + '.json', 'w')
            file.write(
                json.dumps(
                    {
                        'version': self.CACHE_VERSION,
                        'propName': propName,
                        'lifetime': lifetime,
                        'epoch': epoch,
                        'data': data
                    }
                )
            )
            file.close()


    def _setToString(self, setObject):
        return ','.join(element for element in setObject)


    def _stringToSet(self, text):
        return set(text.split(',')) if text else set() # The IF is to get a truly empty set, else it'd hold an empty string.


    def _getEpochHours(self):
        '''
        Internal. Gets the current UNIX epoch time in hours.
        '''
        return int(time() // 3600.0)
Esempio n. 8
0
class NetflixService(object):
    """
    Netflix addon service
    """
    SERVERS = []
    HOST_ADDRESS = '127.0.0.1'

    def __init__(self):
        self.window_cls = Window(10000)  # Kodi home window
        # If you use multiple Kodi profiles you need to distinguish the property of current profile
        self.prop_nf_service_status = g.py2_encode(
            'nf_service_status_' + get_current_kodi_profile_name())
        self.controller = None
        self.library_updater = None
        self.settings_monitor = None

    def init_servers(self):
        """Initialize the http servers"""
        try:
            # Import modules here to intercept possible missing libraries on linux systems
            from resources.lib.services.msl.http_server import MSLTCPServer
            from resources.lib.services.nfsession.http_server import NetflixTCPServer
            from resources.lib.services.cache.http_server import CacheTCPServer
            # Do not change the init order of the servers,
            # MSLTCPServer must always be initialized first to get the DRM info
            self.SERVERS = [{
                'name': 'MSL',
                'class': MSLTCPServer,
                'instance': None,
                'thread': None
            }, {
                'name': 'NS',
                'class': NetflixTCPServer,
                'instance': None,
                'thread': None
            }, {
                'name': 'CACHE',
                'class': CacheTCPServer,
                'instance': None,
                'thread': None
            }]

            for server in self.SERVERS:
                self._init_server(server)
            return True
        except Exception as exc:  # pylint: disable=broad-except
            error(
                'Background services do not start due to the following error')
            import traceback
            error(g.py2_decode(traceback.format_exc(), 'latin-1'))
            if isinstance(exc, gaierror):
                message = (
                    'Something is wrong in your network localhost configuration.\r\n'
                    'It is possible that the hostname {} can not be resolved.'
                ).format(self.HOST_ADDRESS)
            elif ImportError(exc, ImportError):
                message = (
                    'In your system is missing some required library to run Netflix.\r\n'
                    'Read how to install the add-on in the GitHub Readme.\r\n'
                    'Error details: {}'.format(exc))
            else:
                message = unicode(exc)
            self._set_service_status('error', message)
        return False

    def _init_server(self, server):
        server['class'].allow_reuse_address = True
        server['instance'] = server['class'](
            (self.HOST_ADDRESS, select_port(server['name'])))
        server['thread'] = threading.Thread(
            target=server['instance'].serve_forever)

    def start_services(self):
        """
        Start the background services
        """
        from resources.lib.services.playback.action_controller import ActionController
        from resources.lib.services.library_updater import LibraryUpdateService
        from resources.lib.services.settings_monitor import SettingsMonitor
        for server in self.SERVERS:
            server['instance'].server_activate()
            server['instance'].timeout = 1
            server['thread'].start()
            info('[{}] Thread started'.format(server['name']))
        self.controller = ActionController()
        self.library_updater = LibraryUpdateService()
        self.settings_monitor = SettingsMonitor()
        # Mark the service as active
        self._set_service_status('running')
        if not g.ADDON.getSettingBool('disable_startup_notification'):
            from resources.lib.kodi.ui import show_notification
            show_notification(get_local_string(30110))

    def shutdown(self):
        """
        Stop the background services
        """
        self._set_service_status('stopped')
        for server in self.SERVERS:
            server['instance'].shutdown()
            server['instance'].server_close()
            server['instance'] = None
            server['thread'].join()
            server['thread'] = None
        info('Stopped MSL Service')

    def run(self):
        """Main loop. Runs until xbmc.Monitor requests abort"""
        try:
            self.start_services()
        except Exception as exc:  # pylint: disable=broad-except
            self._set_service_status('stopped')
            import traceback
            from resources.lib.kodi.ui import show_addon_error_info
            error(g.py2_decode(traceback.format_exc(), 'latin-1'))
            show_addon_error_info(exc)
            return

        while not self.controller.abortRequested():
            if self._tick_and_wait_for_abort():
                break
        self.shutdown()

    def _tick_and_wait_for_abort(self):
        try:
            self.controller.on_service_tick()
            self.library_updater.on_service_tick()
            g.CACHE_MANAGEMENT.on_service_tick()
        except Exception as exc:  # pylint: disable=broad-except
            import traceback
            from resources.lib.kodi.ui import show_notification
            error(g.py2_decode(traceback.format_exc(), 'latin-1'))
            show_notification(': '.join(
                (exc.__class__.__name__, unicode(exc))))
        return self.controller.waitForAbort(1)

    def _set_service_status(self, status, message=None):
        """Save the service status to a Kodi property"""
        from json import dumps
        status = {'status': status, 'message': message}
        self.window_cls.setProperty(self.prop_nf_service_status, dumps(status))
Esempio n. 9
0
ImgBoxDisk = None
ImgBoxDisk = None
filename = xbmc.translatePath("special://profile/addon_data/service.diskfree/diskfree.png")
#filename = 'special://home/henri/.xbmc/scripts/test.png'
ImgBoxDiskId = None
ImgBoxDiskId = None
#start_time = time.time() 
start_time = 0 
re_added_control = False

#Recupère les arguments envoyés par le skin qui a lancé le script
for arg in sys.argv:

    param = str(arg).lower()
    debug("param = %s " % param)
    if 'disk=' in param:
        disk = param.replace('disk=', '')
#On récupère l'ID de la fenêtre de skin qui à lancer le script
okno = Window(xbmcgui.getCurrentWindowId())

#On recupere les parametres des disques
#time = time.time()
freespace = freespace_disk('/home/')
totalspace = totalspace_disk('/home')
diskfree = ('%iGB') % (((freespace / 1024) / 1024) / 1024)
freespace = (((freespace / 1024) / 1024) / 1024)
totalspace = (((totalspace / 1024) / 1024) / 1024)
percent = totalspace and (totalspace - freespace) * 1.0 / totalspace or 0.0
debug( "f = %s, t = %s Pou = %s " % (freespace,totalspace,percent))
okno.setProperty('DISK' , '%s Go' % freespace )
Esempio n. 10
0
class NetflixService(object):
    """
    Netflix addon service
    """
    from resources.lib.services.msl.http_server import MSLTCPServer
    from resources.lib.services.nfsession.http_server import NetflixTCPServer
    SERVERS = [
        {
            'name': 'MSL',
            'class': MSLTCPServer,
            'instance': None,
            'thread': None
        },
        {
            'name': 'NS',
            'class': NetflixTCPServer,
            'instance': None,
            'thread': None
        },
    ]

    def __init__(self):
        self.window_cls = Window(10000)  # Kodi home window
        # If you use multiple Kodi profiles you need to distinguish the property of current profile
        self.prop_nf_service_status = g.py2_encode(
            'nf_service_status_' + get_current_kodi_profile_name())
        for server in self.SERVERS:
            self.init_server(server)
        self.controller = None
        self.library_updater = None
        self.settings_monitor = None

    def init_server(self, server):
        server['class'].allow_reuse_address = True
        server['instance'] = server['class'](
            ('127.0.0.1', select_port(server['name'])))
        server['thread'] = threading.Thread(
            target=server['instance'].serve_forever)

    def start_services(self):
        """
        Start the background services
        """
        from resources.lib.services.playback.controller import PlaybackController
        from resources.lib.services.library_updater import LibraryUpdateService
        from resources.lib.services.settings_monitor import SettingsMonitor
        for server in self.SERVERS:
            server['instance'].server_activate()
            server['instance'].timeout = 1
            server['thread'].start()
            info('[{}] Thread started'.format(server['name']))
        self.controller = PlaybackController()
        self.library_updater = LibraryUpdateService()
        self.settings_monitor = SettingsMonitor()
        # Mark the service as active
        self.window_cls.setProperty(self.prop_nf_service_status, 'running')
        if not g.ADDON.getSettingBool('disable_startup_notification'):
            from resources.lib.kodi.ui import show_notification
            show_notification(get_local_string(30110))

    def shutdown(self):
        """
        Stop the background services
        """
        self.window_cls.setProperty(self.prop_nf_service_status, 'stopped')
        for server in self.SERVERS:
            server['instance'].shutdown()
            server['instance'].server_close()
            server['instance'] = None
            server['thread'].join()
            server['thread'] = None
        info('Stopped MSL Service')

    def run(self):
        """Main loop. Runs until xbmc.Monitor requests abort"""
        # pylint: disable=broad-except
        try:
            self.start_services()
        except Exception as exc:
            self.window_cls.setProperty(self.prop_nf_service_status, 'stopped')
            import traceback
            from resources.lib.kodi.ui import show_addon_error_info
            error(traceback.format_exc())
            show_addon_error_info(exc)
            return

        while not self.controller.abortRequested():
            if self._tick_and_wait_for_abort():
                break
        self.shutdown()

    def _tick_and_wait_for_abort(self):
        try:
            self.controller.on_playback_tick()
            self.library_updater.on_tick()
        except Exception as exc:  # pylint: disable=broad-except
            import traceback
            from resources.lib.kodi.ui import show_notification
            error(traceback.format_exc())
            show_notification(': '.join(
                (exc.__class__.__name__, unicode(exc))))
        return self.controller.waitForAbort(1)
Esempio n. 11
0
#sql_tvshowlinkepisode = "select idshow from tvshowlinkepisode where idEpisode=%u" % ( fields[ 13 ], )
# format our records start and end
xbmc.executehttpapi( "SetResponseFormat(OpenRecord,%s)" % ( "<record>", ) )
xbmc.executehttpapi( "SetResponseFormat(CloseRecord,%s)" % ( "</record>", ) )
# query the database
movies_xml = xbmc.executehttpapi( "QueryVideoDatabase(%s)" % quote_plus( sql_movies ), )
episodes_xml = xbmc.executehttpapi( "QueryVideoDatabase(%s)" % quote_plus( sql_episodes ), )
# separate the records
movies = re.findall( "<record>(.+?)</record>", movies_xml, re.DOTALL )
episodes = re.findall( "<record>(.+?)</record>", episodes_xml, re.DOTALL )
# enumerate thru our records and set our properties
for count, movie in enumerate( movies ):
    # separate individual fields
    fields = re.findall( "<field>(.*?)</field>", movie, re.DOTALL )
    # set title
    WINDOW.setProperty( "LatestMovie.%d.Label" % ( count + 1, ), fields[ 1 ] )
    # set year
    WINDOW.setProperty( "LatestMovie.%d.Label2" % ( count + 1, ), fields[ 8 ] )
    # set running time (uncomment below if you want running time for label2)
    #WINDOW.setProperty( "LatestMovie.%d.Label2" % ( count + 1, ), fields[ 12 ] )
    # set path
    WINDOW.setProperty( "LatestMovie.%d.OnClick" % ( count + 1, ), fields[ 24 ] + fields[ 23 ] )
    # set thumbnail
    thumbnail = xbmc.getCacheThumbName( fields[ 24 ] + fields[ 23 ] )
    WINDOW.setProperty( "LatestMovie.%d.Thumb" % ( count + 1, ), "U:/userdata/Thumbnails/Video/%s/%s" % ( thumbnail[ 0 ], thumbnail, ) )
# enumerate thru our records and set our properties
for count, episode in enumerate( episodes ):
    # separate individual fields
    fields = re.findall( "<field>(.*?)</field>", episode, re.DOTALL )
    # set title
    WINDOW.setProperty( "LatestEpisode.%d.Label" % ( count + 1, ), fields[ 1 ] )
Esempio n. 12
0
from xbmc import translatePath, sleep, log, LOGERROR
from xbmcgui import Window

_ADDON = Addon(id='plugin.video.plexkodiconnect')
try:
    _ADDON_PATH = _ADDON.getAddonInfo('path').decode('utf-8')
except TypeError:
    _ADDON_PATH = _ADDON.getAddonInfo('path').decode()
try:
    _BASE_RESOURCE = translatePath(
        os_path.join(_ADDON_PATH, 'resources', 'lib')).decode('utf-8')
except TypeError:
    _BASE_RESOURCE = translatePath(
        os_path.join(_ADDON_PATH, 'resources', 'lib')).decode()
sys_path.append(_BASE_RESOURCE)

from pickler import unpickle_me, pickl_window

###############################################################################

if __name__ == "__main__":
    WINDOW = Window(10000)
    while WINDOW.getProperty('plex_command'):
        sleep(20)
    WINDOW.setProperty('plex_command', 'CONTEXT_menu')
    while not pickl_window('plex_result'):
        sleep(50)
    RESULT = unpickle_me()
    if RESULT is None:
        log('PLEX.%s: Error encountered, aborting' % __name__, level=LOGERROR)
Esempio n. 13
0
try:
    _addon_path = _addon.getAddonInfo('path').decode('utf-8')
except TypeError:
    _addon_path = _addon.getAddonInfo('path').decode()
try:
    _base_resource = translatePath(os_path.join(
        _addon_path,
        'resources',
        'lib')).decode('utf-8')
except TypeError:
    _base_resource = translatePath(os_path.join(
        _addon_path,
        'resources',
        'lib')).decode()
sys_path.append(_base_resource)

from pickler import unpickle_me, pickl_window

###############################################################################

if __name__ == "__main__":
    win = Window(10000)
    while win.getProperty('plex_command'):
        sleep(20)
    win.setProperty('plex_command', 'CONTEXT_menu')
    while not pickl_window('plex_result'):
        sleep(50)
    result = unpickle_me()
    if result is None:
        log('PLEX.%s: Error encountered, aborting' % __name__, level=LOGERROR)
#On récupère l'ID de la fenêtre de skin qui à lancer le script
okno = Window(xbmcgui.getCurrentWindowId())
#Nb de news dans le flux
NbNews = len(headlines)
#Si il est > à la limite demandée, on ne récupére que limit
if limit > NbNews: limit = NbNews

for i in range(0, limit):
    #On défini les Properties d'apres headlines
    #0 => title, 1 => date, 2=> description, 
    #3 => content_type, 4 =>img_name,
    #5 => link_video, 6 => NoNews
    #7 => ImageCount, 8 => SlideShowable

    debug('%sRSS.%s.Title' % (prefix,i))
    okno.setProperty('%sRSS.%s.Title' % (prefix,i) , headlines[i][0] )
    okno.setProperty('%sRSS.%s.Date' % (prefix,i) , headlines[i][1])
    description = re.sub('(<[bB][rR][ /]>)|(<[/ ]*[pP]>)', '[CR]',
                                 headlines[i][2], re.DOTALL)
    #On nettoie le code HTML
    html = cleanText(description)
    okno.setProperty('%sRSS.%s.Desc' % (prefix, i) , html)
    okno.setProperty('%sRSS.%s.Image' % (prefix, i) , headlines[i][4])
    ##Traitement des liens YT
    link_video = headlines[i][5]
    if 'youtube.com/v' in link_video:
        vid_ids =  re.findall('http://www.youtube.com/v/(.{11})\??',
                                       link_video, re.DOTALL )
        for id in vid_ids:
            link_video = 'plugin://plugin.video.youtube/?action=play_video&videoid=%s' % id
        debug("VIDEO YT = %s " % link_video)
Esempio n. 15
0
#On récupère l'ID de la fenêtre de skin qui à lancer le script
okno = Window(xbmcgui.getCurrentWindowId())
#Nb de news dans le flux
NbNews = len(headlines)
#Si il est > à la limite demandée, on ne récupére que limit
if limit > NbNews: limit = NbNews

for i in range(0, limit):
    #On défini les Properties d'apres headlines
    #0 => title, 1 => date, 2=> description,
    #3 => content_type, 4 =>img_name,
    #5 => link_video, 6 => NoNews
    #7 => ImageCount, 8 => SlideShowable

    debug('%sRSS.%s.Title' % (prefix, i))
    okno.setProperty('%sRSS.%s.Title' % (prefix, i), headlines[i][0])
    okno.setProperty('%sRSS.%s.Date' % (prefix, i), headlines[i][1])
    description = re.sub('(<[bB][rR][ /]>)|(<[/ ]*[pP]>)', '[CR]',
                         headlines[i][2], re.DOTALL)
    #On nettoie le code HTML
    html = cleanText(description)
    okno.setProperty('%sRSS.%s.Desc' % (prefix, i), html)
    okno.setProperty('%sRSS.%s.Image' % (prefix, i), headlines[i][4])
    ##Traitement des liens YT
    link_video = headlines[i][5]
    if 'youtube.com/v' in link_video:
        vid_ids = re.findall('http://www.youtube.com/v/(.{11})\??', link_video,
                             re.DOTALL)
        for id in vid_ids:
            link_video = 'plugin://plugin.video.youtube/?action=play_video&videoid=%s' % id
        debug("VIDEO YT = %s " % link_video)
Esempio n. 16
0
class ProgressManager(PlaybackActionManager):
    """Detect the progress of the played video and send the data to the netflix service"""
    def __init__(self):  # pylint: disable=super-on-old-class
        super(ProgressManager, self).__init__()
        self.event_data = {}
        self.is_event_start_sent = False
        self.last_tick_count = 0
        self.tick_elapsed = 0
        self.last_player_state = {}
        self.is_player_in_pause = False
        self.lock_events = False
        self.window_cls = Window(10000)  # Kodi home window

    def _initialize(self, data):
        if not data['event_data']:
            common.warn('ProgressManager: disabled due to no event data')
            self.enabled = False
            return
        self.event_data = data['event_data']

    def _on_tick(self, player_state):
        if self.lock_events:
            return
        if self.is_player_in_pause and (self.tick_elapsed -
                                        self.last_tick_count) >= 1800:
            # When the player is paused for more than 30 minutes we interrupt the sending of events (1800secs=30m)
            _send_event(EVENT_ENGAGE, self.event_data, self.last_player_state)
            _send_event(EVENT_STOP, self.event_data, self.last_player_state)
            self.is_event_start_sent = False
            self.lock_events = True
        else:
            if not self.is_event_start_sent:
                # We do not use _on_playback_started() to send EVENT_START, because StreamContinuityManager
                # and ResumeManager may cause inconsistencies with the content of player_state data

                # When the playback starts for the first time, for correctness should send elapsed_seconds value to 0
                if self.tick_elapsed < 5 and self.event_data[
                        'resume_position'] is None:
                    player_state['elapsed_seconds'] = 0
                _send_event(EVENT_START, self.event_data, player_state)
                self.is_event_start_sent = True
                self.tick_elapsed = 0
            else:
                # Generate events to send to Netflix service every 1 minute (60secs=1m)
                if (self.tick_elapsed - self.last_tick_count) >= 60:
                    _send_event(EVENT_KEEP_ALIVE, self.event_data,
                                player_state)
                    self.last_tick_count = self.tick_elapsed
                # On Kodi we can save every second instead every minute, but only after the first minute
                if self.last_tick_count:
                    self._save_resume_time(player_state['elapsed_seconds'])
        self.last_player_state = player_state
        self.tick_elapsed += 1  # One tick almost always represents one second

    def on_playback_pause(self, player_state):
        if not self.is_event_start_sent:
            return
        self.tick_elapsed = 0
        self.is_player_in_pause = True
        _send_event(EVENT_ENGAGE, self.event_data, player_state)

    def on_playback_resume(self, player_state):
        self.is_player_in_pause = False
        self.lock_events = False

    def on_playback_seek(self, player_state):
        if not self.is_event_start_sent or self.lock_events:
            # This might happen when ResumeManager skip is performed
            return
        self.tick_elapsed = 0
        _send_event(EVENT_ENGAGE, self.event_data, player_state)

    def _on_playback_stopped(self):
        if not self.is_event_start_sent or self.lock_events:
            return
        self.tick_elapsed = 0
        _send_event(EVENT_ENGAGE, self.event_data, self.last_player_state)
        _send_event(EVENT_STOP, self.event_data, self.last_player_state)

    def _save_resume_time(self, resume_time):
        """Save resume time in order to modify the frontend cache"""
        # Why this, the video lists are requests to the web service only once and then will be cached in order to
        # quickly get the data and speed up a lot the GUI response.
        # Watched status of a (video) list item is based on resume time, and the resume time is saved in the cache data.
        # To avoid slowing down the GUI by invalidating the cache to get new data from website service, one solution is
        # modify the cache data.
        # Altering here the cache on the fly is not possible because it is currently not shared between service-frontend
        # therefore we save the value in a Kodi property and we will modify the cache from addon frontend.
        # The choice to save the value in a Kodi property is to not continuously lock with mutex the database.
        # The callback _on_playback_stopped can not be used, because the loading of frontend happen before.
        self.window_cls.setProperty('nf_playback_resume_time',
                                    str(resume_time))
Esempio n. 17
0
def Read(sets, reader):
    okno = None
    try:
        if isWindow:
            if ID == -1:
                okno = Window(xbmcgui.getCurrentWindowId())
                print ' >> WINDOW ID = %i' % xbmcgui.getCurrentWindowId()
            else:
                okno = Window(ID)
        else:
            if ID == -1:
                okno = WindowDialog(xbmcgui.getCurrentWindowDialogId())
            else:
                okno = WindowDialog(ID)
            
        okno.setProperty('RSS.count', '0');
    except:
        pass
    unread_c = 0
    for set in sets:
        reader.ReadSet(set, True)
        for src in set.sources:
            for channel in src.channels:
                unread_c += channel.unread_count
                for item in channel.items:
                    if already_read.count(item.link) > 0:
                        item.read = True
                    else:
                        channel.unread_count += 1
                        channel.read = False

    log('All sets read from cache')  
      
    changes = False
    
    next_update = -1
    
    for set in sets:
        for source in set.sources:
            last_checking = time.time() - source.lastupdate
            interval = int(source.updateinterval) * 60
            if last_checking > interval:
                for src in set.sources:
                    for channel in src.channels:
                        unread_c -= channel.unread_count
                        
                reader.ReadSource(source, False)
                changes = True
                for src in set.sources:
                    for channel in src.channels:
                        unread_c += channel.unread_count
                        for item in channel.items:
                            if already_read.count(item.link) > 0:
                                item.read = True
                            else:
                                channel.unread_count += 1
                                channel.read = False
                
                if next_update == -1 or interval < next_update:
                    next_update = interval
            elif next_update == -1 or interval - last_checking < next_update:
                next_update = interval - last_checking
    
    if changes:
        log('Sets updated from URL')    

#items = sorted(self.items, cmp=DateCompare, reverse = self.sortdesc )
    try:
        
        okno.setProperty( "unread_rss", str(unread_c) )
        setting_script = xbmc.translatePath('special://home/addons/script.rssclient/set_properties.py')
        okno.setProperty('SettingScript', setting_script)
        itemList = []
        
        
        for set in sets:
            for source in set.sources:
                for channel in source.channels:
                    for item in channel.items:
                        itemList.append(item)
        
        c = 1
        items = sorted(itemList, cmp=DateCompare, reverse = False )
        
        for item in items:
            if c <= limit:
                okno.setProperty('%sRSS.%d.Title' % (prefix, c), item.title)
                
                okno.setProperty('%sRSS.%d.Desc' % (prefix, c), cleanText(item.description))
                
                if len(item.image) > 0:
                    okno.setProperty('%sRSS.%d.Image' % (prefix, c), item.image[0])
                else:
                    okno.setProperty('%sRSS.%d.Image' % (prefix, c), '')
                
                okno.setProperty('%sRSS.%d.ImageCount' % (prefix, c), str(len(item.image)) )
                
                
                okno.setProperty('%sRSS.%d.SlideShowable' % (prefix, c), (( (imageCachingEnabled and len(item.image) > 1) and ['true'] or ['false'])[0]))
                okno.setProperty('%sRSS.%d.MultiImagePath' % (prefix, c), item.multiimagepath)
                
                i = 1
                sep_images = ''
                for image in item.image:
                    okno.setProperty('%sRSS.%d.Image.%d' % (prefix, c,i), image)
                    
                    if len(sep_images) > 0:
                        sep_images = sep_images + ';'
                    sep_images = sep_images + image
                    
                    i = i + 1
                
                okno.setProperty('%sRSS.%d.MultiImages' % (prefix, c), sep_images)
                
                if len(item.video) > 1:
                    okno.setProperty('%sRSS.%d.Media' % (prefix, c), item.video)
                else:
                    okno.setProperty('%sRSS.%d.Media' % (prefix, c), '')
                
                
                okno.setProperty('%sRSS.%d.Date' % (prefix, c), item.date.replace(',', '.'))
                
                if item.channel != None:
                    okno.setProperty('%sRSS.%d.Channel' % (prefix, c), item.channel.title)

                c = c + 1;
                
                okno.setProperty('%sRSS.count' % prefix, str(c));
    except:
        pass

    if alarmEnabled and next_update > -1:
        alarmhash = xbmc.getCacheThumbName(args + str(time.localtime())).replace('.tbn', '')
        napis = 'AlarmClock(RSS_CHECK_%s,XBMC.RunScript(script.rssclient%s),%d,True)' % (alarmhash, args, ((next_update+60)  / 60.0))  
        log('Refresh in %d minutes' % ((next_update+60)  / 60.0))
        xbmc.executebuiltin(napis)
Esempio n. 18
0
from urllib import urlencode

from xbmc import getCondVisibility, sleep
from xbmcgui import Window

###############################################################################


def _get_kodi_type():
    kodi_type = listitem.getVideoInfoTag().getMediaType().decode('utf-8')
    if not kodi_type:
        if getCondVisibility('Container.Content(albums)'):
            kodi_type = "album"
        elif getCondVisibility('Container.Content(artists)'):
            kodi_type = "artist"
        elif getCondVisibility('Container.Content(songs)'):
            kodi_type = "song"
        elif getCondVisibility('Container.Content(pictures)'):
            kodi_type = "picture"
    return kodi_type


if __name__ == "__main__":
    WINDOW = Window(10000)
    KODI_ID = listitem.getVideoInfoTag().getDbId()
    KODI_TYPE = _get_kodi_type()
    ARGS = {'kodi_id': KODI_ID, 'kodi_type': KODI_TYPE}
    while WINDOW.getProperty('plex_command'):
        sleep(20)
    WINDOW.setProperty('plex_command', 'CONTEXT_menu?%s' % urlencode(ARGS))
Esempio n. 19
0
prefix = ''

for arg in sys.argv:
    param = arg.lower()
    if 'prefix=' in param:
        prefix = param.replace('prefix=', '')
        if not prefix.endswith('.'):
            prefix = prefix + '.'
    elif 'id=' in param:
        RSSid = param.replace('id=', '') 
        

if RSSid > -1:
    okno = Window(xbmcgui.getCurrentWindowId())
    
    okno.setProperty('RSS.Title', okno.getProperty('%sRSS.%s.Title' % (prefix, RSSid)  ))
    okno.setProperty('RSS.Desc', okno.getProperty('%sRSS.%s.Desc' % (prefix, RSSid)  ))
    okno.setProperty('RSS.Image', okno.getProperty('%sRSS.%s.Image' % (prefix, RSSid)  ))
    
    okno.setProperty('RSS.Date', okno.getProperty('%sRSS.%s.Date' % (prefix, RSSid)  ))
    okno.setProperty('RSS.Channel', okno.getProperty('%sRSS.%s.Channel' % (prefix, RSSid)))
    okno.setProperty('RSS.Media', okno.getProperty('%sRSS.%s.Media' % (prefix, RSSid)))
    okno.setProperty('RSS.MultiImagePath', okno.getProperty('%sRSS.%s.MultiImagePath' % (prefix, RSSid)))
    okno.setProperty('RSS.SlideShowable', okno.getProperty('%sRSS.%s.SlideShowable' % (prefix, RSSid)))
    okno.setProperty('RSS.ID',  RSSid)
    
    i_count = okno.getProperty('%sRSS.%s.ImageCount' % (prefix, RSSid))
    
    okno.setProperty('RSS.ImageCount', i_count)
    for i in range(1, int(i_count)+1):
        okno.setProperty('RSS.Image.%d' % i, okno.getProperty('%sRSS.%s.Image.%d' % (prefix, RSSid, i)))
Esempio n. 20
0
def Read(sets, reader):
    okno = None
    try:
        if isWindow:
            if ID == -1:
                okno = Window(xbmcgui.getCurrentWindowId())
                print ' >> WINDOW ID = %i' % xbmcgui.getCurrentWindowId()
            else:
                okno = Window(ID)
        else:
            if ID == -1:
                okno = WindowDialog(xbmcgui.getCurrentWindowDialogId())
            else:
                okno = WindowDialog(ID)

        okno.setProperty('RSS.count', '0')
    except:
        pass
    unread_c = 0
    for set in sets:
        reader.ReadSet(set, True)
        for src in set.sources:
            for channel in src.channels:
                unread_c += channel.unread_count
                for item in channel.items:
                    if already_read.count(item.link) > 0:
                        item.read = True
                    else:
                        channel.unread_count += 1
                        channel.read = False

    log('All sets read from cache')

    changes = False

    next_update = -1

    for set in sets:
        for source in set.sources:
            last_checking = time.time() - source.lastupdate
            interval = int(source.updateinterval) * 60
            if last_checking > interval:
                for src in set.sources:
                    for channel in src.channels:
                        unread_c -= channel.unread_count

                reader.ReadSource(source, False)
                changes = True
                for src in set.sources:
                    for channel in src.channels:
                        unread_c += channel.unread_count
                        for item in channel.items:
                            if already_read.count(item.link) > 0:
                                item.read = True
                            else:
                                channel.unread_count += 1
                                channel.read = False

                if next_update == -1 or interval < next_update:
                    next_update = interval
            elif next_update == -1 or interval - last_checking < next_update:
                next_update = interval - last_checking

    if changes:
        log('Sets updated from URL')


#items = sorted(self.items, cmp=DateCompare, reverse = self.sortdesc )
    try:

        okno.setProperty("unread_rss", str(unread_c))
        setting_script = xbmc.translatePath(
            'special://home/addons/script.rssclient/set_properties.py')
        okno.setProperty('SettingScript', setting_script)
        itemList = []

        for set in sets:
            for source in set.sources:
                for channel in source.channels:
                    for item in channel.items:
                        itemList.append(item)

        c = 1
        items = sorted(itemList, cmp=DateCompare, reverse=False)

        for item in items:
            if c <= limit:
                okno.setProperty('%sRSS.%d.Title' % (prefix, c), item.title)

                okno.setProperty('%sRSS.%d.Desc' % (prefix, c),
                                 cleanText(item.description))

                if len(item.image) > 0:
                    okno.setProperty('%sRSS.%d.Image' % (prefix, c),
                                     item.image[0])
                else:
                    okno.setProperty('%sRSS.%d.Image' % (prefix, c), '')

                okno.setProperty('%sRSS.%d.ImageCount' % (prefix, c),
                                 str(len(item.image)))

                okno.setProperty(
                    '%sRSS.%d.SlideShowable' % (prefix, c),
                    (((imageCachingEnabled and len(item.image) > 1)
                      and ['true'] or ['false'])[0]))
                okno.setProperty('%sRSS.%d.MultiImagePath' % (prefix, c),
                                 item.multiimagepath)

                i = 1
                sep_images = ''
                for image in item.image:
                    okno.setProperty('%sRSS.%d.Image.%d' % (prefix, c, i),
                                     image)

                    if len(sep_images) > 0:
                        sep_images = sep_images + ';'
                    sep_images = sep_images + image

                    i = i + 1

                okno.setProperty('%sRSS.%d.MultiImages' % (prefix, c),
                                 sep_images)

                if len(item.video) > 1:
                    okno.setProperty('%sRSS.%d.Media' % (prefix, c),
                                     item.video)
                else:
                    okno.setProperty('%sRSS.%d.Media' % (prefix, c), '')

                okno.setProperty('%sRSS.%d.Date' % (prefix, c),
                                 item.date.replace(',', '.'))

                if item.channel != None:
                    okno.setProperty('%sRSS.%d.Channel' % (prefix, c),
                                     item.channel.title)

                c = c + 1

                okno.setProperty('%sRSS.count' % prefix, str(c))
    except:
        pass

    if alarmEnabled and next_update > -1:
        alarmhash = xbmc.getCacheThumbName(args +
                                           str(time.localtime())).replace(
                                               '.tbn', '')
        napis = 'AlarmClock(RSS_CHECK_%s,XBMC.RunScript(script.rssclient%s),%d,True)' % (
            alarmhash, args, ((next_update + 60) / 60.0))
        log('Refresh in %d minutes' % ((next_update + 60) / 60.0))
        xbmc.executebuiltin(napis)