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)
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
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)
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()
# # 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:
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
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)
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