Ejemplo n.º 1
0
class MonitorPublisher(threading.Thread, Publisher):
    publishes = Events().Monitor.keys()

    def __init__(self, dispatcher, settings):
        Publisher.__init__(self, dispatcher)
        threading.Thread.__init__(self, name='MonitorPublisher')
        self.dispatcher = dispatcher
        self._abortevt = threading.Event()
        self._abortevt.clear()
        self.jsoncriteria = settings.getJsonNotifications()

    def run(self):
        publish = super(MonitorPublisher, self).publish
        monitor = _Monitor()
        monitor.jsoncriteria = self.jsoncriteria
        monitor.publish = publish
        while not self._abortevt.is_set():
            xbmc.sleep(500)
        del monitor

    def abort(self, timeout=0):
        self._abortevt.set()
        if timeout > 0:
            self.join(timeout)
            if self.is_alive():
                xbmc.log(msg=_('Could not stop MonitorPublisher T:%i') %
                         self.ident)
class WatchdogPublisherDummy(Publisher):
    publishes = Events().Watchdog.keys()

    def __init__(self, dispatcher, watchdogSettings):
        super(WatchdogPublisherDummy, self).__init__(dispatcher)

    def start(self):
        pass
def test(key):
    global log
    log = KodiLogger.log
    import resources.lib.tests.direct_test as direct_test
    from resources.lib.events import Events
    import traceback
    log(msg=_('Running Test for Event: %s') % key)
    events = Events().AllEvents
    settings = Settings()
    settings.getSettings()
    if settings.general['elevate_loglevel'] is True:
        KodiLogger.setLogLevel(xbmc.LOGNOTICE)
    else:
        KodiLogger.setLogLevel(xbmc.LOGDEBUG)
    log(msg=_('Settings for test read'))
    evtsettings = settings.events[key]
    topic = settings.topicFromSettingsEvent(key)
    task_key = settings.events[key]['task']
    tasksettings = settings.tasks[task_key]
    testlogger = direct_test.TestLogger()
    log(msg=_('Creating subscriber for test'))
    subscriberfactory = SubscriberFactory(settings, testlogger)
    subscriber = subscriberfactory.createSubscriber(key)
    if subscriber is not None:
        log(msg=_('Test subscriber created successfully'))
        try:
            kwargs = events[evtsettings['type']]['expArgs']
        except KeyError:
            kwargs = {}
        testRH = direct_test.TestHandler(
            direct_test.testMsg(subscriber.taskmanagers[0], tasksettings,
                                kwargs))
        subscriber.taskmanagers[0].returnHandler = testRH.testReturnHandler
        # Run test
        log(msg=_('Running test'))
        nMessage = PubSub_Threaded.Message(topic=topic, **kwargs)
        try:
            subscriber.notify(nMessage)
        except Exception:
            msg = _('Unspecified error during testing')
            e = sys.exc_info()[0]
            if hasattr(e, 'message'):
                msg = str(e.message)
            msg = msg + '\n' + traceback.format_exc()
            log(msg=msg)
            msgList = msg.split('\n')
            import resources.lib.dialogtb as dialogtb
            dialogtb.show_textbox('Error', msgList)
    else:
        log(msg=_('Test subscriber creation failed due to errors'))
        msgList = testlogger.retrieveLogAsList()
        import resources.lib.dialogtb as dialogtb
        dialogtb.show_textbox('Error', msgList)

    xbmc.sleep(2000)
Ejemplo n.º 4
0
class WatchdogPublisherDummy(Publisher):
    publishes = Events().Watchdog.keys()

    def __init__(self, dispatcher, _):
        super(WatchdogPublisherDummy, self).__init__(dispatcher)

    def start(self):
        pass

    def abort(self, timeout=None):
        pass

    def join(self, timeout=None):
        pass
Ejemplo n.º 5
0
class SchedulePublisher(threading.Thread, Publisher):
    publishes = Events().Schedule.keys()

    def __init__(self, dispatcher, settings):
        Publisher.__init__(self, dispatcher)
        threading.Thread.__init__(self, name='SchedulePublisher')
        self.dailyAlarms = settings.getEventsByType('onDailyAlarm')
        self.intervalAlarms = settings.getEventsByType('onIntervalAlarm')
        self.abortEvt = threading.Event()
        self.abortEvt.clear()
        self.sleep = xbmc.sleep
        self.sleepinterval = 1000
        self.schedules = []

    def run(self):
        for alarm in self.dailyAlarms:
            hour = str(alarm['hour']).zfill(2)
            minute = str(alarm['minutle']).zfill(2)
            stime = ':'.join([hour, minute])
            schedule.every().day.at(stime).do(self.prePublishDailyAlarm, key=alarm['key'])
        for alarm in self.intervalAlarms:
            interval = alarm['hours'] * 3600 + alarm['minutes'] * 60 + alarm['seconds']
            if interval > 0:
                schedule.every(interval).seconds.do(self.prePublishIntervalAlarm, key=alarm['key'])
            else:
                xbmc.log(msg=_('onIntervalAlarm interval cannot be zero'))

        while not self.abortEvt.is_set():
            schedule.run_pending()
            self.sleep(self.sleepinterval)
        schedule.clear()

    def prePublishDailyAlarm(self, key):
        meseage = Message(Topic('onDailyAlarm', key))
        self.publish(meseage)

    def prePublishIntervalAlarm(self, key):
        meseage = Message(Topic('onIntervalAlarm', key))
        self.publish(meseage)

    def abort(self, timeout=0):
        self.abortEvt.set()
        if timeout > 0:
            self.join(timeout)
            if self.is_alive():
                xbmc.log(msg=_('Could not stop SchedulePublisher T:%i') % self.ident)
Ejemplo n.º 6
0
class WatchdogPublisher(Publisher):
    publishes = Events().Watchdog.keys()

    def __init__(self, dispatcher, settings):
        super(WatchdogPublisher, self).__init__(dispatcher)
        self.watchdogSettings = settings.getWatchdogSettings()
        self.event_handlers = []
        self.observersettings = []
        self.observers = []
        self.initialize()

    def initialize(self):
        for setting in self.watchdogSettings:
            patterns = setting['patterns'].split(',')
            ignore_patterns = setting['ignore_patterns'].split(',')
            eh = EventHandler(patterns=patterns,
                              ignore_patterns=ignore_patterns,
                              ignore_directories=setting['ignore_directories'],
                              topic=Topic('onFileSystemChange',
                                          setting['key']),
                              publish=self.publish)
            self.event_handlers.append(eh)
            folder = translatepath(setting['folder'])
            mysetting = [eh, folder, setting['recursive']]
            self.observersettings.append(mysetting)

    def start(self):
        for item in self.observersettings:
            observer = Observer()
            observer.schedule(item[0], item[1], recursive=item[2])
            observer.start()
            self.observers.append(observer)

    def abort(self, timeout=0):
        for item in self.observers:
            assert isinstance(item, Observer)
            item.stop()
        if timeout > 0:
            self.join(timeout)

    def join(self, timeout=0):
        for item in self.observers:
            if timeout > 0:
                item.join(timeout)
            else:
                item.join()
Ejemplo n.º 7
0
#
#    You should have received a copy of the GNU General Public License
#    along with this program. If not, see <http://www.gnu.org/licenses/>.
#

import threading
import queue
import abc
import re
import copy
from resources.lib.kodilogging import KodiLogger
from resources.lib.pubsub import TaskReturn
from resources.lib.events import Events
import xbmcgui

events = Events()


def notify(msg):
    dialog = xbmcgui.Dialog()
    dialog.notification('Kodi Callbacks', msg, xbmcgui.NOTIFICATION_INFO, 5000)


class AbstractTask(threading.Thread):
    """
    Abstract class for command specific workers to follow
    """
    __metaclass__ = abc.ABCMeta
    tasktype = 'abstract'
    lock = threading.RLock()
import time
import re
import traceback
import json
from resources.lib import taskdict
from resources.lib.pubsub import Topic, TaskManager
from resources.lib.events import Events
from resources.lib.kodilogging import KodiLogger
from resources.lib.utils.kodipathtools import translatepath, setPathExecuteRW
import xbmc
from resources.lib.utils.poutil import KodiPo
kodipo = KodiPo()
_ = kodipo.getLocalizedString
kl = KodiLogger()
log = kl.log
events = Events().AllEvents
isAndroid = 'XBMC_ANDROID_SYSTEM_LIBS' in os.environ.keys()
testdir = translatepath('special://addon/resources/lib/tests')
setPathExecuteRW(testdir)


def is_xbmc_debug():
    json_query = xbmc.executeJSONRPC('{ "jsonrpc": "2.0", "id": 0, "method": "Settings.GetSettingValue", "params": {"setting":"debug.showloginfo"} }')
    json_query = str(json_query)
    json_response = json.loads(json_query)
    if json_response.has_key('result'):
        if json_response['result'].has_key('value'):
            return json_response['result']['value']
        else:
            raise SyntaxError('Bad JSON')
    else:
Ejemplo n.º 9
0
class WatchdogStartup(Publisher):
    publishes = Events().WatchdogStartup.keys()

    def __init__(self, dispatcher, settings):
        super(WatchdogStartup, self).__init__(dispatcher)
        self.settings = settings.getWatchdogStartupSettings()

    def start(self):
        oldsnapshots = WatchdogStartup.getPickle()
        newsnapshots = {}
        for setting in self.settings:
            folder = translatepath(setting['ws_folder'])
            if os.path.exists(folder):
                newsnapshot = DirectorySnapshot(folder, recursive=setting['ws_recursive'])
                newsnapshots[folder] = newsnapshot
                if oldsnapshots is not None:
                    if folder in oldsnapshots.keys():
                        oldsnapshot = oldsnapshots[folder]
                        diff = DirectorySnapshotDiff(oldsnapshot, newsnapshot)
                        changes = self.getChangesFromDiff(diff)
                        if len(changes) > 0:
                            eh = EventHandler(patterns=setting['ws_patterns'].split(u','), ignore_patterns=setting['ws_ignore_patterns'].split(u','),
                                              ignore_directories=setting['ws_ignore_directories'])
                            observer = Observer()
                            try:
                                observer.schedule(eh, folder, recursive=setting['ws_recursive'])
                                time.sleep(0.5)
                                for change in changes:
                                    eh.dispatch(change)
                                    time.sleep(0.25)
                                try:
                                    observer.unschedule_all()
                                except Exception:
                                    pass
                            except Exception:
                                raise
                            if len(eh.data) > 0:
                                message = Message(Topic('onStartupFileChanges', setting['key']), listOfChanges=eh.data)
                                self.publish(message)
            else:
                message = Message(Topic('onStartupFileChanges', setting['key']), listOfChanges=[{'DirsDeleted':folder}])
                log(msg=_(u'Watchdog Startup folder not found: %s') % folder)
                self.publish(message)

    @staticmethod
    def getChangesFromDiff(diff):
        ret = []
        events = {'dirs_created':(EVENT_TYPE_CREATED, True), 'dirs_deleted':(EVENT_TYPE_DELETED, True), 'dirs_modified':(EVENT_TYPE_MODIFIED, True), 'dirs_moved':(EVENT_TYPE_MOVED, True),
                  'files_created':(EVENT_TYPE_CREATED, False), 'files_deleted':(EVENT_TYPE_DELETED, False), 'files_modified':(EVENT_TYPE_MODIFIED, False), 'files_moved':(EVENT_TYPE_MOVED, False)}
        for event in events.keys():
            try:
                mylist = diff.__getattribute__(event)
            except AttributeError:
                mylist = []
            if len(mylist) > 0:
                for item in mylist:
                    evt = FileSystemEvent(item)
                    evt.event_type = events[event][0]
                    evt.is_directory = events[event][1]
                    ret.append(evt)
        return ret

    def abort(self, *args):
        snapshots = {}
        for setting in self.settings:
            folder = xbmc.translatePath(setting['ws_folder'])
            if folder == u'':
                folder = setting['ws_folder']
            folder = translatepath(folder)
            if os.path.exists(folder):
                snapshot = DirectorySnapshot(folder, recursive=setting['ws_recursive'])
                snapshots[folder] = snapshot
        WatchdogStartup.savePickle(snapshots)

    def join(self, timeout=None):
        pass

    @staticmethod
    def savePickle(snapshots):
        picklepath = WatchdogStartup.getPicklePath()
        try:
            with open(picklepath, 'w') as f:
                pickle.dump(snapshots, f)
        except pickle.PicklingError:
            log(msg=_('Watchdog startup pickling error on exit'))
        except OSError:
            log(msg=_('Watchdog startup OSError on pickle attempt'))
        else:
            log(msg=_('Watchdog startup pickle saved'))

    @staticmethod
    def clearPickle():
        path = WatchdogStartup.getPicklePath()
        if os.path.exists(path):
            try:
                os.remove(path)
            except OSError:
                log(msg=_('Watchdog startup could not clear pickle'))

    @staticmethod
    def getPicklePath():
        path = translatepath('special://addondata/watchdog.pkl')
        setPathRW(os.path.split(path)[0])
        return path

    @staticmethod
    def getPickle():
        picklepath = WatchdogStartup.getPicklePath()
        if not os.path.exists(picklepath):
            return
        try:
            with open(picklepath, 'r') as f:
                oldsnapshots = pickle.load(f)
        except OSError:
            log (msg=_('Watchdog Startup could not load pickle'))
        except pickle.UnpicklingError:
            log (msg=_('Watchdog Startup unpickling error'))
        else:
            return oldsnapshots
Ejemplo n.º 10
0
class LoopPublisher(threading.Thread, Publisher):
    publishes = Events().CustomLoop.keys()

    def __init__(self, dispatcher, settings):
        Publisher.__init__(self, dispatcher)
        threading.Thread.__init__(self, name='LoopPublisher')
        self.interval = settings.general['LoopFreq']
        self.abort_evt = threading.Event()
        self.abort_evt.clear()
        self.openwindowids = settings.getOpenwindowids()
        self.closewindowsids = settings.getClosewindowids()
        idleT = settings.getIdleTimes()
        afterIdle = settings.getAfterIdleTimes()
        self.player = xbmc.Player()
        if idleT is not None:
            if len(idleT) > 0:
                self.idleTs = []
                self._startidle = 0
                self._playeridle = False
                for key in idleT.keys():
                    # time, key, executed
                    self.idleTs.append([idleT[key], key, False])
            else:
                self.idleTs = []
        else:
            self.idleTs = []
        if afterIdle is not None:
            if len(afterIdle) > 0:
                self.afterIdles = []
                self._startidle = 0
                self._playeridle = False
                for key in afterIdle.keys():
                    # time, key, triggered
                    self.afterIdles.append([afterIdle[key], key, False])
            else:
                self.afterIdles = []
        else:
            self.afterIdles = []
        if len(self.idleTs) > 0 or len(self.afterIdles) > 0:
            self.doidle = True
        else:
            self.doidle = False

    def run(self):
        lastwindowid = xbmcgui.getCurrentWindowId()
        lastprofile = getProfileString()
        laststereomode = getStereoscopicMode()
        interval = self.interval
        firstloop = True
        starttime = time.time()
        while not self.abort_evt.is_set():

            self._checkIdle()

            newprofile = getProfileString()
            if newprofile != lastprofile:
                self.publish(
                    Message(Topic('onProfileChange'), profilePath=newprofile))
                lastprofile = newprofile

            newstereomode = getStereoscopicMode()
            if newstereomode != laststereomode:
                self.publish(
                    Message(Topic('onStereoModeChange'),
                            stereoMode=newstereomode))
                laststereomode = newstereomode

            newwindowid = xbmcgui.getCurrentWindowId()
            if newwindowid != lastwindowid:
                if lastwindowid in self.closewindowsids.keys():
                    self.publish(
                        Message(
                            Topic('onWindowClose',
                                  self.closewindowsids[lastwindowid])))
                if newwindowid in self.openwindowids:
                    self.publish(
                        Message(
                            Topic('onWindowOpen',
                                  self.openwindowids[newwindowid])))
                lastwindowid = newwindowid

            if firstloop:
                endtime = time.time()
                interval = int(interval - (endtime - starttime) * 1000)
                interval = max(5, interval)
                firstloop = False
            xbmc.sleep(interval)
        del self.player

    def _checkIdle(self):
        if self.doidle is False:
            return
        XBMCit = xbmc.getGlobalIdleTime()
        if self.player.isPlaying():
            self._playeridle = False
            self._startidle = XBMCit
        else:  # player is not playing
            if self._playeridle is False:  # if the first pass with player idle, start timing here
                self._playeridle = True
                self._startidle = XBMCit
        myit = XBMCit - self._startidle  # amount of time idle and not playing
        for it in self.idleTs:
            if myit > it[0]:  # if time exceeded idle timer
                if it[2] is False:  # idle task has NOT been executed
                    msg = Message(Topic('onIdle', it[1]))
                    self.publish(msg)
                    it[2] = True
            else:  # if time has not exceeded timer
                it[2] = False  # reset task executed flag
        for it in self.afterIdles:
            if myit > it[0]:  # time has exceeded timer
                it[2] = True  # set flag that task needs to be executed when exiting idle
            else:  # time has not exceeded idle timer
                if it[2] is True:  # if flag to execute has been set
                    msg = Message(Topic('afterIdle', it[1]))
                    self.publish(msg)
                it[2] = False  # reset flag to execute

    def abort(self, timeout=0):
        self.abort_evt.set()
        if timeout > 0:
            self.join(timeout)
            if self.is_alive():
                xbmc.log(msg=_('Could not stop LoopPublisher T:%i') %
                         self.ident)
class Settings(object):
    allevents = Events().AllEvents
    taskSuffixes = {
        'general': [['maxrunning', 'int'], ['maxruns', 'int'],
                    ['refractory', 'int']],
    }
    eventsReverseLookup = None

    def __init__(self):
        self.tasks = {}
        self.events = {}
        self.general = {}
        rl = {}
        for key in Settings.allevents.keys():
            evt = Settings.allevents[key]
            rl[evt['text']] = key
        Settings.eventsReverseLookup = rl

    def logSettings(self):
        import pprint
        settingspp = {
            'Tasks': self.tasks,
            'Events': self.events,
            'General': self.general
        }
        pp = pprint.PrettyPrinter(indent=2)
        msg = pp.pformat(settingspp)
        kl = KodiLogger()
        kl.log(msg=msg)

    def getSettings(self):
        self.getTaskSettings()
        self.getEventSettings()
        self.getGeneralSettings()

    def getTaskSettings(self):
        for i in xrange(1, 11):
            pid = 'T%s' % str(i)
            tsk = self.getTaskSetting(pid)
            if tsk is not None:
                self.tasks[pid] = tsk

    @staticmethod
    def getTaskSetting(pid):
        tsk = {}
        tasktype = get('%s.type' % pid, 'text')
        if tasktype == 'none':
            return None
        else:
            tsk['type'] = tasktype
            for suff in Settings.taskSuffixes['general']:
                tsk[suff[0]] = get('%s.%s' % (pid, suff[0]), suff[1])
            for var in taskdict[tasktype]['variables']:
                tsk[var['id']] = get('%s.%s' % (pid, var['id']),
                                     var['settings']['type'])
            return tsk

    def getEventSettings(self):
        for i in xrange(1, 11):
            pid = "E%s" % str(i)
            evt = self.getEventSetting(pid)
            if evt is not None:
                self.events[pid] = evt

    @staticmethod
    def getEventSetting(pid):
        evt = {}
        et = get('%s.type' % pid, 'text')
        if et == podict.has_msgid('None')[1]:
            return
        else:
            et = _(et)
            et = Settings.eventsReverseLookup[et]
            evt['type'] = et
        tsk = get('%s.task' % pid, 'text')
        if tsk == '' or tsk.lower() == 'none':
            return None
        evt['task'] = 'T%s' % int(tsk[5:])
        for ri in Settings.allevents[et]['reqInfo']:
            evt[ri[0]] = get('%s.%s' % (pid, ri[0]), ri[1])
        evt['userargs'] = get('%s.userargs' % pid, 'text')
        return evt

    @staticmethod
    def getTestEventSettings(taskId):
        evt = {'type': 'onTest', 'task': taskId}
        for oa in Settings.allevents['onTest']['optArgs']:
            evt[oa] = True
        evt['eventId'] = True
        evt['taskId'] = True
        return evt

    def getGeneralSettings(self):
        polls = ['LoopFreq', 'LogFreq', 'TaskFreq']
        self.general['Notify'] = get('Notify', 'bool')
        for p in polls:
            self.general[p] = get(p, 'int')
        self.general['elevate_loglevel'] = get('loglevel', 'bool')

    def getOpenwindowids(self):
        ret = {}
        for evtkey in self.events.keys():
            evt = self.events[evtkey]
            if evt['type'] == 'onWindowOpen':
                ret[evt['windowIdO']] = evt['key']
        return ret

    def getClosewindowids(self):
        ret = {}
        for evtkey in self.events.keys():
            evt = self.events[evtkey]
            if evt['type'] == 'onWindowClose':
                ret[evt['windowIdC']] = evt['key']
        return ret

    def getEventsByType(self, eventType):
        ret = []
        for key in self.events.keys():
            evt = self.events[key]
            if evt['type'] == eventType:
                evt['key'] = key
                ret.append(evt)
        return ret

    def getIdleTimes(self):
        idleEvts = self.getEventsByType('onIdle')
        ret = {}
        for evt in idleEvts:
            ret[evt['key']] = int(evt['idleTime'])
        return ret

    def getAfterIdleTimes(self):
        idleEvts = self.getEventsByType('afterIdle')
        ret = {}
        for evt in idleEvts:
            ret[evt['key']] = int(evt['afterIdleTime'])
        return ret

    def getJsonNotifications(self):
        jsonEvts = self.getEventsByType('onNotification')
        ret = []
        dic = {}
        for evt in jsonEvts:
            dic['eventId'] = evt['key']
            dic['sender'] = evt['reqInfo']['sender']
            dic['method'] = evt['regInfo']['method']
            dic['data'] = evt['reqInfo']['data']
            ret.append(dic)
        return ret

    def getLogSimples(self):
        evts = self.getEventsByType('onLogSimple')
        ret = []
        for evt in evts:
            ret.append({
                'matchIf': evt['matchIf'],
                'rejectIf': evt['rejectIf'],
                'eventId': evt['key']
            })
        return ret

    def getLogRegexes(self):
        evts = self.getEventsByType('onLogRegex')
        ret = []
        for evt in evts:
            ret.append({
                'matchIf': evt['matchIf'],
                'rejectIf': evt['rejectIf'],
                'eventId': evt['key']
            })
        return ret

    def getWatchdogSettings(self):
        evts = self.getEventsByType('onFileSystemChange')
        return evts

    def getWatchdogStartupSettings(self):
        evts = self.getEventsByType('onStartupFileChanges')
        return evts

    def topicFromSettingsEvent(self, key):
        top = self.events[key]['type']
        if top in requires_subtopic():
            return Topic(top, key)
        else:
            return Topic(top)
Ejemplo n.º 12
0
def createEvents(tasks):
    podirty = False
    allevts = Events().AllEvents
    evts = []
    for evtkey in allevts.keys():
        evts.append(allevts[evtkey]['text'])
    evts.sort()
    evts.insert(0, 'None')
    levts = []
    for evt in evts:
        levts.append(glsid(evt))
    levts = "|".join(levts)
    eventcontrols = []

    last_id = None
    for i in xrange(1, 11):
        prefix = 'E%s' % str(i)
        curEvtType = '%s.type' % prefix
        action_evt = 'RunScript(script.service.kodi.callbacks, lselector, id=%s.type, heading=%s, lvalues=%s)' % (
            prefix, glsid('Choose event type'), levts)
        if i == 1:
            eventcontrols.append(
                struct.Lsep('%s.lsep' % prefix, 'Event %i' % i))
            eventcontrols.append(
                struct.Action('%s.action' % prefix,
                              'Choose event type (click here)',
                              action=action_evt))
            eventcontrols.append(
                struct.Select('%s.type-v' % prefix,
                              'Event:',
                              default='None',
                              enable=False,
                              lvalues=evts))
        else:
            conditionals = struct.Conditional(struct.Conditional.OP_NOT_EQUAL,
                                              glsid('None'), last_id)
            eventcontrols.append(
                struct.Lsep('%s.lsep' % prefix,
                            'Event %i' % i,
                            visible=conditionals))
            eventcontrols.append(
                struct.Action('%s.action' % prefix,
                              'Choose event type (click here)',
                              action=action_evt,
                              visible=conditionals))
            eventcontrols.append(
                struct.Select('%s.type-v' % prefix,
                              'Event:',
                              default=glsid('None'),
                              enable=False,
                              lvalues=evts,
                              visible=conditionals))
        conditionals = struct.Conditional(struct.Conditional.OP_NOT_EQUAL,
                                          glsid('None'), curEvtType)
        eventcontrols.append(
            struct.Text(curEvtType, '', default=glsid('None'), visible=False))

        eventcontrols.append(
            struct.LabelEnum('%s.task' % prefix,
                             'Task',
                             default='Task 1',
                             lvalues=tasks,
                             visible=conditionals))

        for evtkey in allevts.keys():
            evt = allevts[evtkey]
            conditionals = struct.Conditional(struct.Conditional.OP_EQUAL,
                                              glsid(evt['text']), curEvtType)
            for req in evt['reqInfo']:
                r1 = req[1]
                if r1 in ['float', 'int']:
                    r1 = 'number'
                if r1 == 'sfolder':
                    mytype = 'browse'
                else:
                    mytype = r1

                if r1 == 'sfolder':
                    labelbrowse = '%s - browse' % req[0]
                    labeledit = '%s - edit' % req[0]
                    eventcontrols.append(
                        struct.FileBrowser('%s.%s' % (prefix, req[0]),
                                           labelbrowse,
                                           struct.FileBrowser.TYPE_FOLDER,
                                           default=req[2],
                                           visible=conditionals))
                    eventcontrols.append(
                        struct.Text('%s.%s' % (prefix, req[0]),
                                    labeledit,
                                    default=req[2],
                                    visible=conditionals))
                else:
                    Control = struct.getControlClass[mytype]
                    eventcontrols.append(
                        Control(sid='%s.%s' % (prefix, req[0]),
                                label=req[0],
                                default=req[2],
                                visible=conditionals))
            eventcontrols.append(
                struct.Lsep(
                    label=
                    'Note: variables can be subbed (%%=%, _%=space, __%=,):',
                    visible=conditionals))
            try:
                vargs = evt['varArgs']
            except KeyError:
                vargs = {}
            vs = []
            for key in vargs.keys():
                vs.append('%s=%s' % (key, vargs[key]))
            vs = ','.join(vs)
            brk = 60
            if len(vs) > 0:
                if len(vs) < brk:
                    found, strid = podict.has_msgid(vs)
                    if found is False:
                        podict.addentry(strid, vs)
                        podirty = True
                    eventcontrols.append(
                        struct.Lsep(label=vs, visible=conditionals))
                else:
                    startindex = 0
                    x = 0
                    lines = []
                    while startindex + brk < len(vs):
                        x = vs.rfind(',', startindex, startindex + brk)
                        found, strid = podict.has_msgid(vs[startindex:x])
                        if found is False:
                            podict.addentry(strid, vs[startindex:x])
                            podirty = True
                        lines.append(vs[startindex:x])
                        startindex = x + 1
                    found, strid = podict.has_msgid(vs[x + 1:])
                    if found is False:
                        podict.addentry(strid, vs[x + 1:])
                        podirty = True
                    lines.append(vs[x + 1:])
                    for line in lines:
                        eventcontrols.append(
                            struct.Lsep(label=line, visible=conditionals))
        conditionals = struct.Conditional(struct.Conditional.OP_NOT_EQUAL,
                                          unicode(glsid('None')), curEvtType)
        eventcontrols.append(
            struct.Text('%s.userargs' % prefix,
                        'Var subbed arg string',
                        default='',
                        visible=conditionals))
        eventcontrols.append(
            struct.Action(
                '%s.test' % prefix,
                'Test Command (click OK to save changes first)',
                action='RunScript(script.service.kodi.callbacks, %s)' % prefix,
                visible=conditionals))
        last_id = curEvtType
    return eventcontrols, podirty
def generate_settingsxml(fn=None):
    podirty = False
    allevts = Events().AllEvents
    output = []
    ssp = '    <setting '
    evts = ['None']
    for evtkey in allevts.keys():
        evts.append(allevts[evtkey]['text'])
    evts.sort()
    evts = "|".join(evts)

    def getoffset(idx, lst):
        return str(idx-len(lst))

    output.append('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n')
    output.append('<settings>\n')
    output.append('  <category label="%s">\n' % _('Tasks'))

    startnum = int(kodipo.getLocalizedStringId('Task 1')) - 1
    tasks = []
    for i in xrange(1,11):
        prefix = "T%s" % str(i)
        output.append('    <setting label="%s" type="lsep"/>\n'% str(startnum + i))
        tasks.append(str(startnum + i))
        idx = len(output)
        taskchoices = ['none']
        for key in sorted(taskdict.keys()):
            taskchoices.append(key)
        ltaskchoices = []
        for taskchoice in taskchoices:
            found, strid = podict.has_msgid(taskchoice)
            if found is False:
                podict.addentry(strid, taskchoice)
                podirty = True
            ltaskchoices.append(strid)
        ltaskchoices = "|".join(ltaskchoices)
        output.append('    <setting default="none" id="%s.type" label="%s" type="labelenum" lvalues="%s" />\n' % (prefix, _('Task'), ltaskchoices))
        output.append('    <setting default="-1" id="%s.maxrunning" label="%s" type="number" visible="!eq(-1,0)" />\n' % (prefix, _('Max num of this task running simultaneously (-1=no limit)')))
        output.append('    <setting default="-1" id="%s.maxruns" label="%s" type="number" visible="!eq(-2,0)" />\n' % (prefix, _('Max num of times this task runs (-1=no limit)')))
        output.append('    <setting default="-1" id="%s.refractory" label="%s" type="number" visible="!eq(-3,0)" />\n' % (prefix, _('Refractory period in secs (-1=none)')))
        for i1, key in enumerate(sorted(taskdict.keys())):
            for var in taskdict[key]['variables']:
                varset = var['settings']
                if varset['type'] == 'sfile':
                    mytype = 'file'
                else:
                    mytype = varset['type']
                try:
                    option = varset['option']
                except KeyError:
                    output.append('    <setting default="%s" id="%s.%s" label="%s" type="%s" visible="eq(%s,%s)" />\n' %
                                  (varset['default'], prefix, var['id'], varset['label'], mytype, getoffset(idx,output), i1+1))
                else:
                    output.append('    <setting default="%s" id="%s.%s" label="%s" type="%s" option="%s" visible="eq(%s,%s)" />\n' %
                                  (varset['default'], prefix, var['id'], varset['label'], mytype, option, getoffset(idx,output), i1+1))
                if varset['type'] == 'sfile':
                    output.append('    <setting default="%s" id="%s.%s" label="%s" type="%s" visible="eq(%s,%s)" />\n' %
                                  (varset['default'], prefix, var['id'], varset['label'], 'text', getoffset(idx,output), i1+1))

    output.append('  </category>\n\n')
    output.append('  <category label="%s">\n' % _('Events'))
    tasks = '|'.join(tasks)

    startnum = int(kodipo.getLocalizedStringId('Event 1')) - 1
    for i in xrange(1,11):
        prefix = 'E%s' % str(i)
        output.append(ssp + 'label="%s" type="lsep" />\n' % str(startnum + i))
        idx = len(output)
        output.append(ssp + 'default="None" id="%s.type" label="%s" type="select" values="%s" />\n' % (prefix, _('Type'), evts))
        output.append(ssp + 'default="Task 1" id="%s.task" label="%s" type="labelenum" visible="!eq(%s,None)" lvalues="%s" />\n' %(prefix, _('Task'), getoffset(idx,output),tasks))
        for evtkey in allevts.keys():
            evt = allevts[evtkey]
            for req in evt['reqInfo']:
                r1 = req[1]
                if r1 in ['float', 'int']:
                    r1 = 'number'
                if r1 == 'sfolder':
                    mytype = 'folder'
                else:
                    mytype = r1
                output.append(ssp + 'default="%s" id="%s.%s" label="%s" type="%s" visible="eq(%s,%s)" />\n' % (req[2], prefix, req[0], kodipo.getLocalizedStringId(req[0]), mytype, getoffset(idx,output), evt['text'] ))
                if r1 == 'sfolder':
                    output.append(ssp + 'default="%s" id="%s.%s" label="%s" type="%s" visible="eq(%s,%s)" />\n' % (req[2], prefix, req[0], kodipo.getLocalizedStringId(req[0]), 'text', getoffset(idx,output), evt['text'] ))
            output.append(ssp + 'label="%s" type="lsep" visible="eq(%s,%s)" />\n' % (_('Hint - variables can be subbed (%%=%, _%=space, _%%=,): '), getoffset(idx,output), evt['text']))
            try:
                vargs = evt['varArgs']
            except KeyError:
                vargs = {}
            vs = ''
            for key in vargs.keys():
                vs += '%s=%s,' % (key, vargs[key])
            vs = vs[:-1]
            brk = 60
            if len(vs) > 0:
                if len(vs) < brk:
                    found, strid =  podict.has_msgid(vs)
                    if found is False:
                        podict.addentry(strid, vs)
                        podirty = True
                    output.append(ssp + 'label="%s" type="lsep" visible="eq(%s,%s)" />\n' % (strid, getoffset(idx,output), evt['text']))
                else:
                    x = vs.rfind(',', 0, brk)
                    found, strid =  podict.has_msgid(vs[:x])
                    if found is False:
                        podict.addentry(strid, vs[:x])
                        podirty = True
                    output.append(ssp + 'label="%s" type="lsep" visible="eq(%s,%s)" />\n' % (strid, getoffset(idx,output), evt['text']))
                    found, strid =  podict.has_msgid(vs[x+1:])
                    if found is False:
                        podict.addentry(strid, vs[x+1:])
                        podirty = True
                    output.append(ssp + 'label="%s" type="lsep" visible="eq(%s,%s)" />\n' % (strid, getoffset(idx,output), evt['text']))
        output.append(ssp + 'default="" id="%s.userargs" label="%s" type="text" visible="!eq(%s,None)" />\n' % (prefix, _('Var subbed arg string'), getoffset(idx, output)))
        output.append(ssp + 'default="" id="%s.test" label="%s" type="action" action="RunScript(script.service.kodi.callbacks, %s)" visible="!eq(%s,0)" />\n' % (prefix, _('Test Command (click OK to save changes first)'), prefix,getoffset(idx, output)))

    output.append('  </category>\n')
    output.append('  <category label="%s">\n' % _('General'))
    output.append('    <setting default="false" id="Notify" label="%s" type="bool" />\n' % _('Display Notifications when Tasks Run?'))
    output.append('    <setting default="500" id="LoopFreq" label="%s" type="number" />\n'% _('Loop Pooling Frequency (ms)'))
    output.append('    <setting default="500" id="LogFreq" label="%s" type="number" />\n' % _('Log Polling Frequency (ms)'))
    output.append('    <setting default="100" id="TaskFreq" label="%s" type="number" />\n' % _('Task Polling Frequency (ms)'))
    output.append('    <setting default="false" id="loglevel" label="%s" type="bool" />\n' % _('Show debugging info in normal log?'))
    output.append('    <setting id="regen" label="%s" type="action" action="RunScript(script.service.kodi.callbacks, regen)" />\n' % _('Regenerate settings.xml'))
    output.append('    <setting id="test" label="%s" type="action" action="RunScript(script.service.kodi.callbacks, test)" />\n' % _('Test addon native tasks (see log for output)'))
    output.append('  </category>\n')
    output.append('  <category label="%s">\n' % _('Update'))
    output.append('    <setting id="updatefromzip" label="%s" type="action" action="RunScript(script.service.kodi.callbacks, updatefromzip)" />\n' % _('Update from downloaded zip'))
    output.append('    <setting id="restorebackup" label="%s" type="action" action="RunScript(script.service.kodi.callbacks, restorebackup)" />\n' % _('Restore from previous back up'))
    output.append('  </category>\n')
    output.append('</settings>')
    output = "".join(output)
    if fn is None:
        fn = os.path.join(xbmcaddon.Addon('script.service.kodi.callbacks').getAddonInfo('path'), 'resources', 'lib', 'tests')
    with open(fn, mode='w') as f:
        f.writelines(output)

    if podirty is True:
        podict.write_to_file(pofile)
    log(_('Settings.xml rewritten'))
def createEvents(tasks):
    podirty = False
    allevts = Events().AllEvents
    evts = []
    for evtkey in allevts.keys():
        evts.append(allevts[evtkey]['text'])
    evts.sort()
    evts.insert(0, 'None')
    levts = []
    for evt in evts:
        levts.append(glsid(evt))
    levts = "|".join(levts)
    eventcontrols = []

    last_id = None
    for i in xrange(1, 11):
        prefix = 'E%s' % str(i)
        curEvtType = '%s.type' % prefix
        action_evt = 'RunScript(script.service.kodi.callbacks, lselector, id=%s.type, heading=%s, lvalues=%s)' % (
            prefix, glsid('Choose event type'), levts)
        if i == 1:
            eventcontrols.append(struct.Lsep('%s.lsep' % prefix, 'Event %i' % i))
            eventcontrols.append(
                struct.Action('%s.action' % prefix, 'Choose event type (click here)', action=action_evt))
            eventcontrols.append(
                struct.Select('%s.type-v' % prefix, 'Event:', default='None', enable=False, lvalues=evts))
        else:
            conditionals = struct.Conditional(struct.Conditional.OP_NOT_EQUAL, glsid('None'), last_id)
            eventcontrols.append(struct.Lsep('%s.lsep' % prefix, 'Event %i' % i, visible=conditionals))
            eventcontrols.append(
                struct.Action('%s.action' % prefix, 'Choose event type (click here)', action=action_evt,
                              visible=conditionals))
            eventcontrols.append(
                struct.Select('%s.type-v' % prefix, 'Event:', default=glsid('None'), enable=False, lvalues=evts,
                              visible=conditionals))
        conditionals = struct.Conditional(struct.Conditional.OP_NOT_EQUAL, glsid('None'), curEvtType)
        eventcontrols.append(struct.Text(curEvtType, '', default=glsid('None'), visible=False))

        eventcontrols.append(
            struct.LabelEnum('%s.task' % prefix, 'Task', default='Task 1', lvalues=tasks, visible=conditionals))

        for evtkey in allevts.keys():
            evt = allevts[evtkey]
            conditionals = struct.Conditional(struct.Conditional.OP_EQUAL, glsid(evt['text']), curEvtType)
            for req in evt['reqInfo']:
                r1 = req[1]
                if r1 in ['float', 'int']:
                    r1 = 'number'
                if r1 == 'sfolder':
                    mytype = 'browse'
                else:
                    mytype = r1

                if r1 == 'sfolder':
                    labelbrowse = '%s - browse' % req[0]
                    labeledit = '%s - edit' % req[0]
                    eventcontrols.append(
                        struct.FileBrowser('%s.%s' % (prefix, req[0]), labelbrowse, struct.FileBrowser.TYPE_FOLDER,
                                           default=req[2], visible=conditionals))
                    eventcontrols.append(
                        struct.Text('%s.%s' % (prefix, req[0]), labeledit, default=req[2], visible=conditionals))
                else:
                    Control = struct.getControlClass[mytype]
                    eventcontrols.append(
                        Control(sid='%s.%s' % (prefix, req[0]), label=req[0], default=req[2], visible=conditionals))
            eventcontrols.append(
                struct.Lsep(label='Note: variables can be subbed (%%=%, _%=space, __%=,):', visible=conditionals))
            try:
                vargs = evt['varArgs']
            except KeyError:
                vargs = {}
            vs = []
            for key in vargs.keys():
                vs.append('%s=%s' % (key, vargs[key]))
            vs = ','.join(vs)
            brk = 60
            if len(vs) > 0:
                if len(vs) < brk:
                    found, strid = podict.has_msgid(vs)
                    if found is False:
                        podict.addentry(strid, vs)
                        podirty = True
                    eventcontrols.append(struct.Lsep(label=vs, visible=conditionals))
                else:
                    startindex = 0
                    x = 0
                    lines = []
                    while startindex + brk < len(vs):
                        x = vs.rfind(',', startindex, startindex+brk)
                        found, strid = podict.has_msgid(vs[startindex:x])
                        if found is False:
                            podict.addentry(strid, vs[startindex:x])
                            podirty = True
                        lines.append(vs[startindex:x])
                        startindex = x + 1
                    found, strid = podict.has_msgid(vs[x + 1:])
                    if found is False:
                        podict.addentry(strid, vs[x + 1:])
                        podirty = True
                    lines.append(vs[x+1:])
                    for line in lines:
                        eventcontrols.append(struct.Lsep(label=line, visible=conditionals))
        conditionals = struct.Conditional(struct.Conditional.OP_NOT_EQUAL, unicode(glsid('None')), curEvtType)
        eventcontrols.append(
            struct.Text('%s.userargs' % prefix, 'Var subbed arg string', default='', visible=conditionals))
        eventcontrols.append(struct.Action('%s.test' % prefix, 'Test Command (click OK to save changes first)',
                                           action='RunScript(script.service.kodi.callbacks, %s)' % prefix,
                                           visible=conditionals))
        last_id = curEvtType
    return eventcontrols, podirty