from xml.dom.minidom import parse import datetime from datetime import timedelta import simplejson from xml.etree import ElementTree class NotTextNodeError(BaseException): pass class AuraSchedulerConfig(): def __init__(self, xmlpath): self.jobs = {} self.filename = xmlpath self.playperiods = [] self.recordperiods = [] self.hasinstance = False self.until = None # -----------------------------------------------------------------------# def getPlayPeriods(self): if not self.hasinstance: self.getJobs() return self.playperiods # -----------------------------------------------------------------------# def getRecordPeriods(self): if not self.hasinstance: self.getJobs() return self.recordperiods # -----------------------------------------------------------------------# def getJobs(self): self.hasinstance = True self.loadXml() for job in self.jobs: if 'job' not in job: continue; if 'until' not in job: job['until'] = '' if 'day' not in job: job['day'] = 'all' # self.jobs.sort(cmp=lambda x,y: cmp(x['time'], y['time'])) # self.jobs.sort(cmp=lambda x,y: cmp(x['day'], y['day'])) self.jobs.sort(key=lambda job: job['time']) self.jobs.sort(key=lambda job: job['day']) for index, job in enumerate(self.jobs): if job['job'] == 'play_playlist': job['duration'] = self._calcDuration(job['time'], job['until']) self.playperiods.append({'from': job['time'],'until': job['until'], 'duration': job['duration']}) day = None if 'day' in job: day = job['day'] self.addPlaylistLoadJob(job['time'], job['until'], day) if job['job'] == 'start_recording': job['duration'] = self._calcDuration(job['time'], job['until']) self.recordperiods.append({'from': job['time'],'until': job['until'], 'duration': job['duration']}) return self.jobs # -----------------------------------------------------------------------# def addPlaylistLoadJob(self, playTime, untilTime, day=None): job = {} playStart = datetime.datetime.strptime('1901-01-01T' + playTime,'%Y-%m-%dT%H:%M'); loadTime = playStart - timedelta(minutes=3) loadTime = loadTime.strftime('%H:%M') job['time'] = loadTime job['from'] = playTime job['until'] = untilTime job['job'] = 'load_playlist' if day and not day == 'all' and loadTime > playTime: day = int(day) day = 6 if day == 0 else day - 1 job['day'] = str(day) self.jobs.append(job) # -----------------------------------------------------------------------# def storeJsonToXml(self, json): try: jobs = simplejson.loads(json) except: return False xml = '<?xml version="1.0" encoding="UTF-8"?>'+"\n" xml += '<Config>'+"\n"; xml += ' <Jobs multiple="true">'+"\n"; xmlend = ' </Jobs>'+"\n"; xmlend += '</Config>'; for job in jobs: xml+= ' <job>'+"\n"; for key in job.keys(): xml+= ' <'+key+'>'+str(job[key])+'</'+key+'>'+"\n" if not job.has_key('params'): xml+= ' <params></params>'+"\n" if not job.has_key('day'): xml+= ' <day>all</day>'+"\n" xml+= ' </job>'+"\n" # validate xml try: x = ElementTree.fromstring(xml+xmlend) except: return False else: try: file = open(self.filename, "w") file.write(xml+xmlend) file.close() except: return False else: return True # -----------------------------------------------------------------------# def loadXml(self): dom = parse(self.filename) config = self.nodeToDic(dom) self.jobs = config['Config']['Jobs'] # -----------------------------------------------------------------------# def getTextFromNode(self, node): t = "" for n in node.childNodes: if n.nodeType == n.TEXT_NODE: t += n.nodeValue else: raise NotTextNodeError return t # -----------------------------------------------------------------------# def nodeToDic(self, node): dic = {} for n in node.childNodes: if n.nodeType != n.ELEMENT_NODE: continue if n.getAttribute("multiple") == "true": # node with multiple children: # put them in a list l = [] for c in n.childNodes: if c.nodeType != n.ELEMENT_NODE: continue l.append(self.nodeToDic(c)) dic.update({n.nodeName: l}) continue try: text = self.getTextFromNode(n) except NotTextNodeError: # 'normal' node dic.update({str(n.nodeName): self.nodeToDic(n)}) continue # text node dic.update({str(n.nodeName): str(text)}) continue return dic # -----------------------------------------------------------------------# def in_timeperiod(self, now, job): if 'until' not in job or not job['until']: print("not in timeperiod") return False (hour1, minute1) = job['time'].split(':') (hour2, minute2) = job['until'].split(':') if job['time'] > job['until']: print("in time period. time greater than until") return datetime.time(hour=int(hour1), minute=int(minute1)) \ <= now.time() else: print("in time period. until greater than time") return datetime.time(hour=int(hour1), minute=int(minute1)) \ <= now.time() \ <= datetime.time(hour=int(hour2), minute=int(minute2)) # -----------------------------------------------------------------------# def _calcDuration(self, timestring1, timestring2): """Berechnet Zeit in Sekunden aus zwei Time-Strings """ ftr = [3600, 60, 1] sec1 = sum([a * b for a, b in zip(ftr, map(int, timestring1.split(':')))]) sec2 = sum([a * b for a, b in zip(ftr, map(int, timestring2.split(':')))]) offset = 0 if sec2 > sec1 else 86400 return (sec2 + offset) - sec1 # -----------------------------------------------------------------------# def find_next(self, items, index, key, value): for idx, item in enumerate(items): if idx <= index: continue if item[key] == value: return idx return self.find_next(items,0,key,value)