import time import codecs #from time import datetime from Tools import Directories, Notifications from Components.config import config import timer import xml.dom.minidom from Screens.MessageBox import MessageBox from Screens.SubserviceSelection import SubserviceSelection import NavigationInstance from Tools.XMLTools import elementsWithTag, mergeText from ServiceReference import ServiceReference # ok, for descriptions etc we have: # service reference (to get the service name) # name (title) # description (description) # event data (ONLY for time adjustments etc.) # parses an event, and gives out a (begin, end, name, duration, eit)-tuple. def parseEvent(ev): name = ev.getEventName() description = ev.getShortDescription() begin = ev.getBeginTime() end = begin + ev.getDuration() eit = ev.getEventId() return (begin, end, name, description, eit) # please do not translate log messages class RecordTimerEntry(timer.TimerEntry): def __init__(self, serviceref, begin, end, name, description, eit): timer.TimerEntry.__init__(self, int(begin), int(end)) assert isinstance(serviceref, ServiceReference) self.service_ref = serviceref self.eit = eit self.dontSave = False self.name = name self.description = description self.timer = None self.record_service = None self.start_prepare = 0 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.first_try_prepare = True self.timeChanged() def calculateFilename(self): service_name = self.service_ref.getServiceName() # begin_date = datetime.fromtimestamp(begin).strf... begin_date = "" print "begin_date: ", begin_date print "service_name: ", service_name print "name:", self.name print "description: ", self.description self.Filename = Directories.getRecordingFilename(service_name) self.log(0, "Filename calculated as: '%s'" % self.Filename) #begin_date + " - " + service_name + description) def tryPrepare(self): self.calculateFilename() self.record_service = NavigationInstance.instance.recordService(self.service_ref) if self.record_service == None: self.log(1, "'record service' failed") return False else: prep_res = self.record_service.prepare(self.Filename + ".ts") if prep_res: self.log(2, "'prepare' failed: error %d" % prep_res) self.record_service = None return False self.log(3, "prepare ok, writing meta information to %s" % self.Filename) try: f = open(self.Filename + ".ts.meta", "w") f.write(str(self.service_ref) + "\n") f.write(self.name + "\n") f.write(self.description + "\n") f.write(str(self.begin) + "\n") f.close() except: self.log(4, "failed to write meta information") return True def do_backoff(self): if self.backoff == 0: self.backoff = 5 else: self.backoff *= 2 if self.backoff > 100: self.backoff = 100 self.log(10, "backoff: retry in %d seconds" % self.backoff) def activate(self): next_state = self.state + 1 self.log(5, "activating state %d" % next_state) if next_state == self.StatePrepared: if self.tryPrepare(): self.log(6, "prepare ok, waiting for begin") # fine. it worked, resources are allocated. self.next_activation = self.begin self.backoff = 0 return True self.log(7, "prepare failed") if self.first_try_prepare: self.first_try_prepare = False if config.recording.asktozap.value == 0: self.log(8, "asking user to zap away") Notifications.AddNotificationWithCallback(self.failureCB, MessageBox, _("A timer failed to record!\nDisable TV and try again?\n")) else: # zap without asking self.log(9, "zap without asking") self.failureCB(True) self.do_backoff() # retry self.start_prepare = time.time() + self.backoff return False elif next_state == self.StateRunning: self.log(11, "start recording") record_res = self.record_service.start() if record_res: self.log(13, "start record returned %d" % record_res) self.do_backoff() # retry self.begin = time.time() + self.backoff return False return True elif next_state == self.StateEnded: self.log(12, "stop recording") self.record_service.stop() self.record_service = None return True def getNextActivation(self): if self.state == self.StateEnded: return self.end next_state = self.state + 1 return {self.StatePrepared: self.start_prepare, self.StateRunning: self.begin, self.StateEnded: self.end }[next_state] def failureCB(self, answer): if answer == True: self.log(13, "ok, zapped away") #NavigationInstance.instance.stopUserServices() NavigationInstance.instance.playService(self.service_ref.ref) else: self.log(14, "user didn't want to zap away, record will probably fail") def timeChanged(self): old_prepare = self.start_prepare self.start_prepare = self.begin - self.prepare_time self.backoff = 0 if old_prepare != self.start_prepare: self.log(15, "record time changed, start prepare is now: %s" % time.ctime(self.start_prepare)) def createTimer(xml): begin = int(xml.getAttribute("begin")) end = int(xml.getAttribute("end")) serviceref = ServiceReference(str(xml.getAttribute("serviceref"))) description = xml.getAttribute("description").encode("utf-8") repeated = xml.getAttribute("repeated").encode("utf-8") try: eit = long(xml.getAttribute("eit").encode("utf-8")) except: eit = None name = xml.getAttribute("name").encode("utf-8") #filename = xml.getAttribute("filename").encode("utf-8") entry = RecordTimerEntry(serviceref, begin, end, name, description, eit) 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() entry.log_entries.append((time, code, msg)) return entry class RecordTimer(timer.Timer): def __init__(self): timer.Timer.__init__(self) self.Filename = Directories.resolveFilename(Directories.SCOPE_CONFIG, "timers.xml") try: self.loadTimer() except IOError: print "unable to load timers from file!" def isRecording(self): isRunning = False for timer in self.timer_list: if timer.isRunning(): isRunning = True return isRunning 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)) def saveTimer(self): #doc = xml.dom.minidom.Document() #root_element = doc.createElement('timers') #doc.appendChild(root_element) #root_element.appendChild(doc.createTextNode("\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) #file = open(self.Filename, "w") #doc.writexml(file) #file.write("\n") #file.close() list = [] list.append('\n') list.append('\n') for timer in self.timer_list + self.processed_timers: list.append('\n') for time, code, msg in timer.log_entries: list.append('') list.append(str(msg)) list.append('\n') list.append('\n') list.append('\n') file = open(self.Filename, "w") for x in list: file.write(x) file.close() def record(self, entry): entry.timeChanged() print "[Timer] Record " + str(entry) entry.Timer = self self.addTimerEntry(entry) def removeEntry(self, entry): print "[Timer] Remove " + str(entry) # avoid re-enqueuing entry.repeated = False # abort timer. # this sets the end time to current time, so timer will be stopped. entry.abort() if entry.state != entry.StateEnded: self.timeChanged(entry) print "state: ", entry.state print "in processed: ", entry in self.processed_timers print "in running: ", entry in self.timer_list # now the timer should be in the processed_timers list. remove it from there. self.processed_timers.remove(entry) def shutdown(self): self.saveTimer()