X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=blobdiff_plain;f=RecordTimer.py;h=8449a2d25f306fb57284acf7be4babb5fae436cd;hp=de4f6cc1c1075c672b5d83ddd6169739596b40aa;hb=c2bbed774d6e5c51b4af23a60a95aca74aa5d4e9;hpb=162684da1ab0762f27043cd38a66a81c90916338 diff --git a/RecordTimer.py b/RecordTimer.py index de4f6cc..8449a2d 100644 --- a/RecordTimer.py +++ b/RecordTimer.py @@ -4,20 +4,20 @@ from Tools import Directories, Notifications from Components.config import config import timer -import xml.dom.minidom +import xml.etree.cElementTree from enigma import eEPGCache, getBestPlayableServiceReference, \ eServiceReference, iRecordableService, quitMainloop from Screens.MessageBox import MessageBox - +from Components.TimerSanityCheck import TimerSanityCheck import NavigationInstance import Screens.Standby from time import localtime -from Tools.XMLTools import elementsWithTag, mergeText, stringToXML +from Tools.XMLTools import stringToXML from ServiceReference import ServiceReference # ok, for descriptions etc we have: @@ -47,6 +47,7 @@ class AFTEREVENT: NONE = 0 STANDBY = 1 DEEPSTANDBY = 2 + AUTO = 3 # please do not translate log messages class RecordTimerEntry(timer.TimerEntry, object): @@ -79,7 +80,7 @@ class RecordTimerEntry(timer.TimerEntry, object): RecordTimerEntry.receiveRecordEvents = False @staticmethod - def TryQuitMainloop(): + def TryQuitMainloop(default_yes = True): if not RecordTimerEntry.receiveRecordEvents: print "RecordTimer.TryQuitMainloop" NavigationInstance.instance.record_event.append(RecordTimerEntry.staticGotRecordEvent) @@ -88,10 +89,10 @@ class RecordTimerEntry(timer.TimerEntry, object): # other timers start in a few seconds RecordTimerEntry.staticGotRecordEvent(None, iRecordableService.evEnd) # send normal notification for the case the user leave the standby now.. - Notifications.AddNotification(Screens.Standby.TryQuitMainloop, 1, onSessionOpenCallback=RecordTimerEntry.stopTryQuitMainloop) + Notifications.AddNotification(Screens.Standby.TryQuitMainloop, 1, onSessionOpenCallback=RecordTimerEntry.stopTryQuitMainloop, default_yes = default_yes) ################################################################# - def __init__(self, serviceref, begin, end, name, description, eit, disabled = False, justplay = False, afterEvent = AFTEREVENT.NONE, checkOldTimers = False): + def __init__(self, serviceref, begin, end, name, description, eit, disabled = False, justplay = False, afterEvent = AFTEREVENT.AUTO, checkOldTimers = False, dirname = None, tags = None): timer.TimerEntry.__init__(self, int(begin), int(end)) if checkOldTimers == True: @@ -114,20 +115,18 @@ class RecordTimerEntry(timer.TimerEntry, object): self.start_prepare = 0 self.justplay = justplay self.afterEvent = afterEvent - + self.dirname = dirname + self.dirnameHadToFallback = False + self.autoincrease = False + self.tags = tags or [] + self.log_entries = [] self.resetState() def log(self, code, msg): self.log_entries.append((int(time.time()), code, msg)) print "[TIMER]", msg - - def resetState(self): - self.state = self.StateWaiting - self.cancelled = False - self.first_try_prepare = True - self.timeChanged() - + def calculateFilename(self): service_name = self.service_ref.getServiceName() begin_date = time.strftime("%Y%m%d %H%M", time.localtime(self.begin)) @@ -141,7 +140,11 @@ class RecordTimerEntry(timer.TimerEntry, object): if self.name: filename += " - " + self.name - self.Filename = Directories.getRecordingFilename(filename) + if self.dirname and not Directories.pathExists(self.dirname): + self.dirnameHadToFallback = True + self.Filename = Directories.getRecordingFilename(filename, None) + else: + self.Filename = Directories.getRecordingFilename(filename, self.dirname) self.log(0, "Filename calculated as: '%s'" % self.Filename) #begin_date + " - " + service_name + description) @@ -191,6 +194,7 @@ class RecordTimerEntry(timer.TimerEntry, object): f.write(self.name + "\n") f.write(self.description + "\n") f.write(str(self.begin) + "\n") + f.write(' '.join(self.tags)) f.close() except IOError: self.log(4, "failed to write meta information") @@ -271,9 +275,9 @@ class RecordTimerEntry(timer.TimerEntry, object): if self.afterEvent == AFTEREVENT.STANDBY: if not Screens.Standby.inStandby: # not already in standby Notifications.AddNotificationWithCallback(self.sendStandbyNotification, MessageBox, _("A finished record timer wants to set your\nDreambox to standby. Do that now?"), timeout = 20) - if self.afterEvent == AFTEREVENT.DEEPSTANDBY: + elif self.afterEvent == AFTEREVENT.DEEPSTANDBY: if not Screens.Standby.inTryQuitMainloop: # not a shutdown messagebox is open - if Screens.Standby.inStandby: # not in standby + if Screens.Standby.inStandby: # in standby RecordTimerEntry.TryQuitMainloop() # start shutdown handling without screen else: Notifications.AddNotificationWithCallback(self.sendTryQuitMainloopNotification, MessageBox, _("A finished record timer wants to shut down\nyour Dreambox. Shutdown now?"), timeout = 20) @@ -328,8 +332,12 @@ class RecordTimerEntry(timer.TimerEntry, object): # that in our state, with also keeping the possibility to re-try. # TODO: this has to be done. elif event == iRecordableService.evStart: + text = _("A record has been started:\n%s") % self.name + if self.dirnameHadToFallback: + text = '\n'.join([text, _("Please note that the previously selected media could not be accessed and therefore the default directory is being used instead.")]) + # maybe this should be configurable? - Notifications.AddPopup(text = _("A record has been started:\n%s") % self.name, type = MessageBox.TYPE_INFO, timeout = 3) + Notifications.AddPopup(text = text, type = MessageBox.TYPE_INFO, timeout = 3) # we have record_service as property to automatically subscribe to record service events def setRecordService(self, service): @@ -346,29 +354,45 @@ class RecordTimerEntry(timer.TimerEntry, object): record_service = property(lambda self: self.__record_service, setRecordService) def createTimer(xml): - begin = int(xml.getAttribute("begin")) - end = int(xml.getAttribute("end")) - serviceref = ServiceReference(xml.getAttribute("serviceref").encode("utf-8")) - description = xml.getAttribute("description").encode("utf-8") - repeated = xml.getAttribute("repeated").encode("utf-8") - disabled = long(xml.getAttribute("disabled") or "0") - justplay = long(xml.getAttribute("justplay") or "0") - afterevent = str(xml.getAttribute("afterevent") or "nothing") - afterevent = { "nothing": AFTEREVENT.NONE, "standby": AFTEREVENT.STANDBY, "deepstandby": AFTEREVENT.DEEPSTANDBY }[afterevent] - if xml.hasAttribute("eit") and xml.getAttribute("eit") != "None": - eit = long(xml.getAttribute("eit")) + begin = int(xml.get("begin")) + end = int(xml.get("end")) + serviceref = ServiceReference(xml.get("serviceref").encode("utf-8")) + description = xml.get("description").encode("utf-8") + repeated = xml.get("repeated").encode("utf-8") + disabled = long(xml.get("disabled") or "0") + justplay = long(xml.get("justplay") or "0") + afterevent = str(xml.get("afterevent") or "nothing") + afterevent = { + "nothing": AFTEREVENT.NONE, + "standby": AFTEREVENT.STANDBY, + "deepstandby": AFTEREVENT.DEEPSTANDBY, + "auto": AFTEREVENT.AUTO + }[afterevent] + eit = xml.get("eit") + if eit and eit != "None": + eit = long(eit); else: eit = None - - name = xml.getAttribute("name").encode("utf-8") - #filename = xml.getAttribute("filename").encode("utf-8") - entry = RecordTimerEntry(serviceref, begin, end, name, description, eit, disabled, justplay, afterevent) + location = xml.get("location") + if location and location != "None": + location = location.encode("utf-8") + else: + location = None + tags = xml.get("tags") + if tags and tags != "None": + tags = tags.encode("utf-8").split(' ') + else: + tags = None + + name = xml.get("name").encode("utf-8") + #filename = xml.get("filename").encode("utf-8") + entry = RecordTimerEntry(serviceref, begin, end, name, description, eit, disabled, justplay, afterevent, dirname = location, tags = tags) entry.repeated = int(repeated) - for l in elementsWithTag(xml.childNodes, "log"): - time = int(l.getAttribute("time")) - code = int(l.getAttribute("code")) - msg = mergeText(l.childNodes).strip().encode("utf-8") + for l in xml.findall("log"): + time = int(l.get("time")) + code = int(l.get("code")) + msg = l.text.strip().encode("utf-8") entry.log_entries.append((time, code, msg)) return entry @@ -393,52 +417,76 @@ class RecordTimer(timer.Timer): def loadTimer(self): # TODO: PATH! - doc = xml.dom.minidom.parse(self.Filename) - - root = doc.childNodes[0] - for timer in elementsWithTag(root.childNodes, "timer"): - self.record(createTimer(timer)) + try: + doc = xml.etree.cElementTree.parse(self.Filename) + except SyntaxError: + from Tools.Notifications import AddPopup + from Screens.MessageBox import MessageBox + + AddPopup(_("The timer file (timers.xml) is corrupt and could not be loaded."), type = MessageBox.TYPE_ERROR, timeout = 0, id = "TimerLoadFailed") + + print "timers.xml failed to load!" + try: + import os + os.rename(self.Filename, self.Filename + "_old") + except (IOError, OSError): + print "renaming broken timer failed" + return + except IOError: + print "timers.xml not found!" + return + + root = doc.getroot() + + # put out a message when at least one timer overlaps + checkit = True + for timer in root.findall("timer"): + newTimer = createTimer(timer) + if (self.record(newTimer, True, True) is not None) and (checkit == True): + from Tools.Notifications import AddPopup + from Screens.MessageBox import MessageBox + AddPopup(_("Timer overlap in timers.xml detected!\nPlease recheck it!"), type = MessageBox.TYPE_ERROR, timeout = 0, id = "TimerLoadFailed") + checkit = False # at moment it is enough when the message is displayed one time def saveTimer(self): - #doc = xml.dom.minidom.Document() - #root_element = doc.createElement('timers') - #doc.appendChild(root_element) - #root_element.appendChild(doc.createTextNode("\n")) - + #root_element = xml.etree.cElementTree.Element('timers') + #root_element.text = "\n" + #for timer in self.timer_list + self.processed_timers: # some timers (instant records) don't want to be saved. # skip them #if timer.dontSave: #continue - #t = doc.createTextNode("\t") - #root_element.appendChild(t) - #t = doc.createElement('timer') - #t.setAttribute("begin", str(int(timer.begin))) - #t.setAttribute("end", str(int(timer.end))) - #t.setAttribute("serviceref", str(timer.service_ref)) - #t.setAttribute("repeated", str(timer.repeated)) - #t.setAttribute("name", timer.name) - #t.setAttribute("description", timer.description) - #t.setAttribute("eit", str(timer.eit)) - - #for time, code, msg in timer.log_entries: - #t.appendChild(doc.createTextNode("\t\t")) - #l = doc.createElement('log') - #l.setAttribute("time", str(time)) - #l.setAttribute("code", str(code)) - #l.appendChild(doc.createTextNode(msg)) - #t.appendChild(l) - #t.appendChild(doc.createTextNode("\n")) - - #root_element.appendChild(t) - #t = doc.createTextNode("\n") - #root_element.appendChild(t) + #t = xml.etree.cElementTree.SubElement(root_element, 'timers') + #t.set("begin", str(int(timer.begin))) + #t.set("end", str(int(timer.end))) + #t.set("serviceref", str(timer.service_ref)) + #t.set("repeated", str(timer.repeated)) + #t.set("name", timer.name) + #t.set("description", timer.description) + #t.set("afterevent", str({ + # AFTEREVENT.NONE: "nothing", + # AFTEREVENT.STANDBY: "standby", + # AFTEREVENT.DEEPSTANDBY: "deepstandby", + # AFTEREVENT.AUTO: "auto"})) + #if timer.eit is not None: + # t.set("eit", str(timer.eit)) + #if timer.dirname is not None: + # t.set("location", str(timer.dirname)) + #t.set("disabled", str(int(timer.disabled))) + #t.set("justplay", str(int(timer.justplay))) + #t.text = "\n" + #t.tail = "\n" + #for time, code, msg in timer.log_entries: + #l = xml.etree.cElementTree.SubElement(t, 'log') + #l.set("time", str(time)) + #l.set("code", str(code)) + #l.text = str(msg) + #l.tail = "\n" - #file = open(self.Filename, "w") - #doc.writexml(file) - #file.write("\n") - #file.close() + #doc = xml.etree.cElementTree.ElementTree(root_element) + #doc.write(self.Filename) list = [] @@ -456,9 +504,18 @@ class RecordTimer(timer.Timer): list.append(' repeated="' + str(int(timer.repeated)) + '"') list.append(' name="' + str(stringToXML(timer.name)) + '"') list.append(' description="' + str(stringToXML(timer.description)) + '"') - list.append(' afterevent="' + str(stringToXML({ AFTEREVENT.NONE: "nothing", AFTEREVENT.STANDBY: "standby", AFTEREVENT.DEEPSTANDBY: "deepstandby" }[timer.afterEvent])) + '"') + list.append(' afterevent="' + str(stringToXML({ + AFTEREVENT.NONE: "nothing", + AFTEREVENT.STANDBY: "standby", + AFTEREVENT.DEEPSTANDBY: "deepstandby", + AFTEREVENT.AUTO: "auto" + }[timer.afterEvent])) + '"') if timer.eit is not None: list.append(' eit="' + str(timer.eit) + '"') + if timer.dirname is not None: + list.append(' location="' + str(stringToXML(timer.dirname)) + '"') + if timer.tags is not None: + list.append(' tags="' + str(stringToXML(' '.join(timer.tags))) + '"') list.append(' disabled="' + str(int(timer.disabled)) + '"') list.append(' justplay="' + str(int(timer.justplay)) + '"') list.append('>\n') @@ -497,12 +554,36 @@ class RecordTimer(timer.Timer): return timer.begin return -1 - def record(self, entry): + def isNextRecordAfterEventActionAuto(self): + now = time.time() + t = None + for timer in self.timer_list: + if timer.justplay or timer.begin < now: + continue + if t is None or t.begin == timer.begin: + t = timer + if t.afterEvent == AFTEREVENT.AUTO: + return True + return False + + def record(self, entry, ignoreTSC=False, dosave=True): #wird von loadTimer mit dosave=False aufgerufen + timersanitycheck = TimerSanityCheck(self.timer_list,entry) + if not timersanitycheck.check(): + if ignoreTSC != True: + print "timer conflict detected!" + print timersanitycheck.getSimulTimerList() + return timersanitycheck.getSimulTimerList() + else: + print "ignore timer conflict" + elif timersanitycheck.doubleCheck(): + print "ignore double timer" entry.timeChanged() print "[Timer] Record " + str(entry) entry.Timer = self self.addTimerEntry(entry) - self.saveTimer() + if dosave: + self.saveTimer() + return None def isInTimer(self, eventid, begin, duration, service): time_match = 0