3 #from time import datetime
4 from Tools import Directories, Notifications
6 from Components.config import config
10 from Screens.MessageBox import MessageBox
11 from Screens.SubserviceSelection import SubserviceSelection
12 import NavigationInstance
13 from time import localtime
15 from Tools.XMLTools import elementsWithTag, mergeText, stringToXML
16 from ServiceReference import ServiceReference
18 # ok, for descriptions etc we have:
19 # service reference (to get the service name)
21 # description (description)
22 # event data (ONLY for time adjustments etc.)
25 # parses an event, and gives out a (begin, end, name, duration, eit)-tuple.
26 # begin and end will be corrected
28 name = ev.getEventName()
29 description = ev.getShortDescription()
30 begin = ev.getBeginTime()
31 end = begin + ev.getDuration()
33 begin -= config.recording.margin_before.value[0] * 60
34 end += config.recording.margin_after.value[0] * 60
35 return (begin, end, name, description, eit)
37 # please do not translate log messages
38 class RecordTimerEntry(timer.TimerEntry):
39 def __init__(self, serviceref, begin, end, name, description, eit, disabled = False):
40 timer.TimerEntry.__init__(self, int(begin), int(end))
42 assert isinstance(serviceref, ServiceReference)
44 self.service_ref = serviceref
48 self.description = description
49 self.disabled = disabled
51 self.record_service = None
52 self.start_prepare = 0
57 def log(self, code, msg):
58 self.log_entries.append((int(time.time()), code, msg))
62 self.state = self.StateWaiting
63 self.first_try_prepare = True
66 def calculateFilename(self):
67 service_name = self.service_ref.getServiceName()
68 begin_date = time.strftime("%Y%m%d %H%M", time.localtime(self.begin))
70 print "begin_date: ", begin_date
71 print "service_name: ", service_name
72 print "name:", self.name
73 print "description: ", self.description
75 filename = begin_date + " - " + service_name
77 filename += " - " + self.name
79 self.Filename = Directories.getRecordingFilename(filename)
80 self.log(0, "Filename calculated as: '%s'" % self.Filename)
81 #begin_date + " - " + service_name + description)
84 self.calculateFilename()
85 self.record_service = NavigationInstance.instance.recordService(self.service_ref)
86 if self.record_service == None:
87 self.log(1, "'record service' failed")
93 prep_res = self.record_service.prepare(self.Filename + ".ts", self.begin, self.end, event_id )
95 self.log(2, "'prepare' failed: error %d" % prep_res)
96 self.record_service = None
99 self.log(3, "prepare ok, writing meta information to %s" % self.Filename)
101 f = open(self.Filename + ".ts.meta", "w")
102 f.write(str(self.service_ref) + "\n")
103 f.write(self.name + "\n")
104 f.write(self.description + "\n")
105 f.write(str(self.begin) + "\n")
108 self.log(4, "failed to write meta information")
111 def do_backoff(self):
112 if self.backoff == 0:
116 if self.backoff > 100:
118 self.log(10, "backoff: retry in %d seconds" % self.backoff)
121 next_state = self.state + 1
122 self.log(5, "activating state %d" % next_state)
124 if next_state == self.StatePrepared:
125 if self.tryPrepare():
126 self.log(6, "prepare ok, waiting for begin")
127 # fine. it worked, resources are allocated.
128 self.next_activation = self.begin
132 self.log(7, "prepare failed")
133 if self.first_try_prepare:
134 self.first_try_prepare = False
135 if config.recording.asktozap.value == 0:
136 self.log(8, "asking user to zap away")
137 Notifications.AddNotificationWithCallback(self.failureCB, MessageBox, _("A timer failed to record!\nDisable TV and try again?\n"))
138 else: # zap without asking
139 self.log(9, "zap without asking")
144 self.start_prepare = time.time() + self.backoff
146 elif next_state == self.StateRunning:
147 self.log(11, "start recording")
148 record_res = self.record_service.start()
151 self.log(13, "start record returned %d" % record_res)
154 self.begin = time.time() + self.backoff
158 elif next_state == self.StateEnded:
159 self.log(12, "stop recording")
160 self.record_service.stop()
161 self.record_service = None
164 def getNextActivation(self):
165 if self.state == self.StateEnded:
168 next_state = self.state + 1
170 return {self.StatePrepared: self.start_prepare,
171 self.StateRunning: self.begin,
172 self.StateEnded: self.end }[next_state]
174 def failureCB(self, answer):
176 self.log(13, "ok, zapped away")
177 #NavigationInstance.instance.stopUserServices()
178 NavigationInstance.instance.playService(self.service_ref.ref)
180 self.log(14, "user didn't want to zap away, record will probably fail")
182 def timeChanged(self):
183 old_prepare = self.start_prepare
184 self.start_prepare = self.begin - self.prepare_time
187 if old_prepare != self.start_prepare:
188 self.log(15, "record time changed, start prepare is now: %s" % time.ctime(self.start_prepare))
190 def createTimer(xml):
191 begin = int(xml.getAttribute("begin"))
192 end = int(xml.getAttribute("end"))
193 serviceref = ServiceReference(str(xml.getAttribute("serviceref")))
194 description = xml.getAttribute("description").encode("utf-8")
195 repeated = xml.getAttribute("repeated").encode("utf-8")
196 disabled = long(xml.getAttribute("disabled") or "0")
197 if xml.hasAttribute("eit") and xml.getAttribute("eit") != "None":
198 eit = long(xml.getAttribute("eit"))
202 name = xml.getAttribute("name").encode("utf-8")
203 #filename = xml.getAttribute("filename").encode("utf-8")
204 entry = RecordTimerEntry(serviceref, begin, end, name, description, eit, disabled)
205 entry.repeated = int(repeated)
207 for l in elementsWithTag(xml.childNodes, "log"):
208 time = int(l.getAttribute("time"))
209 code = int(l.getAttribute("code"))
210 msg = mergeText(l.childNodes).strip().encode("utf-8")
211 entry.log_entries.append((time, code, msg))
215 class RecordTimer(timer.Timer):
217 timer.Timer.__init__(self)
219 self.Filename = Directories.resolveFilename(Directories.SCOPE_CONFIG, "timers.xml")
224 print "unable to load timers from file!"
226 def isRecording(self):
228 for timer in self.timer_list:
229 if timer.isRunning():
235 doc = xml.dom.minidom.parse(self.Filename)
237 root = doc.childNodes[0]
238 for timer in elementsWithTag(root.childNodes, "timer"):
239 self.record(createTimer(timer))
242 #doc = xml.dom.minidom.Document()
243 #root_element = doc.createElement('timers')
244 #doc.appendChild(root_element)
245 #root_element.appendChild(doc.createTextNode("\n"))
247 #for timer in self.timer_list + self.processed_timers:
248 # some timers (instant records) don't want to be saved.
252 #t = doc.createTextNode("\t")
253 #root_element.appendChild(t)
254 #t = doc.createElement('timer')
255 #t.setAttribute("begin", str(int(timer.begin)))
256 #t.setAttribute("end", str(int(timer.end)))
257 #t.setAttribute("serviceref", str(timer.service_ref))
258 #t.setAttribute("repeated", str(timer.repeated))
259 #t.setAttribute("name", timer.name)
260 #t.setAttribute("description", timer.description)
261 #t.setAttribute("eit", str(timer.eit))
263 #for time, code, msg in timer.log_entries:
264 #t.appendChild(doc.createTextNode("\t\t"))
265 #l = doc.createElement('log')
266 #l.setAttribute("time", str(time))
267 #l.setAttribute("code", str(code))
268 #l.appendChild(doc.createTextNode(msg))
270 #t.appendChild(doc.createTextNode("\n"))
272 #root_element.appendChild(t)
273 #t = doc.createTextNode("\n")
274 #root_element.appendChild(t)
277 #file = open(self.Filename, "w")
284 list.append('<?xml version="1.0" ?>\n')
285 list.append('<timers>\n')
287 for timer in self.timer_list + self.processed_timers:
291 list.append('<timer')
292 list.append(' begin="' + str(int(timer.begin)) + '"')
293 list.append(' end="' + str(int(timer.end)) + '"')
294 list.append(' serviceref="' + str(timer.service_ref) + '"')
295 list.append(' repeated="' + str(int(timer.repeated)) + '"')
296 list.append(' name="' + str(stringToXML(timer.name)) + '"')
297 list.append(' description="' + str(stringToXML(timer.description)) + '"')
298 if timer.eit is not None:
299 list.append(' eit="' + str(timer.eit) + '"')
300 list.append(' disabled="' + str(int(timer.disabled)) + '"')
303 #for time, code, msg in timer.log_entries:
305 #list.append(' code="' + str(code) + '"')
306 #list.append(' time="' + str(time) + '"')
308 #list.append(str(msg))
309 #list.append('</log>\n')
312 list.append('</timer>\n')
314 list.append('</timers>\n')
316 file = open(self.Filename, "w")
321 def record(self, entry):
323 print "[Timer] Record " + str(entry)
325 self.addTimerEntry(entry)
327 def isInTimer(self, eventid, begin, duration, service):
329 for x in self.timer_list:
330 if str(x.service_ref) == str(service):
331 #if x.eit is not None and x.repeated == 0:
332 # if x.eit == eventid:
335 chktime = localtime(begin)
336 time = localtime(x.begin)
337 chktimecmp = chktime.tm_wday * 1440 + chktime.tm_hour * 60 + chktime.tm_min
339 if x.repeated & (2 ** y):
340 timecmp = y * 1440 + time.tm_hour * 60 + time.tm_min
341 if timecmp <= chktimecmp < (timecmp + ((x.end - x.begin) / 60)):
342 time_match = ((timecmp + ((x.end - x.begin) / 60)) - chktimecmp) * 60
343 elif chktimecmp <= timecmp < (chktimecmp + (duration / 60)):
344 time_match = ((chktimecmp + (duration / 60)) - timecmp) * 60
345 else: #if x.eit is None:
346 end = begin + duration
347 if begin <= x.begin <= end:
349 if time_match < diff:
351 elif x.begin <= begin <= x.end:
353 if time_match < diff:
361 def removeEntry(self, entry):
362 print "[Timer] Remove " + str(entry)
365 entry.repeated = False
368 # this sets the end time to current time, so timer will be stopped.
371 if entry.state != entry.StateEnded:
372 self.timeChanged(entry)
374 print "state: ", entry.state
375 print "in processed: ", entry in self.processed_timers
376 print "in running: ", entry in self.timer_list
377 # now the timer should be in the processed_timers list. remove it from there.
378 self.processed_timers.remove(entry)