1 from enigma import eEPGCache, getBestPlayableServiceReference, \
2 eServiceReference, iRecordableService, quitMainloop
4 from Components.config import config
5 from Components.UsageConfig import defaultMoviePath
6 from Components.TimerSanityCheck import TimerSanityCheck
7 from Components.SystemInfo import SystemInfo
9 from Screens.MessageBox import MessageBox
10 import Screens.Standby
11 from Tools import Directories, Notifications, ASCIItranslit
12 from Tools.XMLTools import stringToXML
15 import xml.etree.cElementTree
16 import NavigationInstance
17 from ServiceReference import ServiceReference
19 from time import localtime, strftime, ctime, time
20 from bisect import insort
24 # ok, for descriptions etc we have:
25 # service reference (to get the service name)
27 # description (description)
28 # event data (ONLY for time adjustments etc.)
31 # parses an event, and gives out a (begin, end, name, duration, eit)-tuple.
32 # begin and end will be corrected
33 def parseEvent(ev, description = True):
35 name = ev.getEventName()
36 description = ev.getShortDescription()
40 begin = ev.getBeginTime()
41 end = begin + ev.getDuration()
43 begin -= config.recording.margin_before.value * 60
44 end += config.recording.margin_after.value * 60
45 return (begin, end, name, description, eit)
53 def findSafeRecordPath(dirname):
57 from Components import Harddisk
58 dirname = os.path.realpath(dirname)
59 mountpoint = Harddisk.findMountPoint(dirname)
60 if mountpoint in ('/', '/media'):
61 print '[RecordTimer] media is not mounted:', dirname
63 if not os.path.isdir(dirname):
67 print '[RecordTimer] Failed to create dir "%s":' % dirname, ex
72 # please do not translate log messages
73 class RecordTimerEntry(timer.TimerEntry, object):
74 ######### the following static methods and members are only in use when the box is in (soft) standby
75 receiveRecordEvents = False
82 def staticGotRecordEvent(recservice, event):
83 if event == iRecordableService.evEnd:
84 print "RecordTimer.staticGotRecordEvent(iRecordableService.evEnd)"
85 recordings = NavigationInstance.instance.getRecordings()
86 if not recordings: # no more recordings exist
87 rec_time = NavigationInstance.instance.RecordTimer.getNextRecordingTime()
88 if rec_time > 0 and (rec_time - time()) < 360:
89 print "another recording starts in", rec_time - time(), "seconds... do not shutdown yet"
91 print "no starting records in the next 360 seconds... immediate shutdown"
92 RecordTimerEntry.shutdown() # immediate shutdown
93 elif event == iRecordableService.evStart:
94 print "RecordTimer.staticGotRecordEvent(iRecordableService.evStart)"
97 def stopTryQuitMainloop():
98 print "RecordTimer.stopTryQuitMainloop"
99 NavigationInstance.instance.record_event.remove(RecordTimerEntry.staticGotRecordEvent)
100 RecordTimerEntry.receiveRecordEvents = False
103 def TryQuitMainloop(default_yes = True):
104 if not RecordTimerEntry.receiveRecordEvents:
105 print "RecordTimer.TryQuitMainloop"
106 NavigationInstance.instance.record_event.append(RecordTimerEntry.staticGotRecordEvent)
107 RecordTimerEntry.receiveRecordEvents = True
108 # send fake event.. to check if another recordings are running or
109 # other timers start in a few seconds
110 RecordTimerEntry.staticGotRecordEvent(None, iRecordableService.evEnd)
111 # send normal notification for the case the user leave the standby now..
112 Notifications.AddNotification(Screens.Standby.TryQuitMainloop, 1, onSessionOpenCallback=RecordTimerEntry.stopTryQuitMainloop, default_yes = default_yes)
113 #################################################################
115 def __init__(self, serviceref, begin, end, name, description, eit, disabled = False, justplay = False, afterEvent = AFTEREVENT.AUTO, checkOldTimers = False, dirname = None, tags = None, descramble = True, record_ecm = False, filename = None):
116 timer.TimerEntry.__init__(self, int(begin), int(end))
118 if checkOldTimers == True:
119 if self.begin < time() - 1209600:
120 self.begin = int(time())
122 if self.end < self.begin:
123 self.end = self.begin
125 assert isinstance(serviceref, ServiceReference)
127 if serviceref.isRecordable():
128 self.service_ref = serviceref
130 self.service_ref = ServiceReference(None)
132 self.dontSave = False
134 self.description = description
135 self.disabled = disabled
137 self.__record_service = None
138 self.start_prepare = 0
139 if SystemInfo["PVRSupport"]:
140 self.justplay = justplay
143 self.afterEvent = afterEvent
144 self.dirname = dirname
145 self.dirnameHadToFallback = False
146 self.autoincrease = False
147 self.autoincreasetime = 3600 * 24 # 1 day
148 self.tags = tags or []
150 self.descramble = descramble
151 self.record_ecm = record_ecm
153 self.log_entries = []
156 self.Filename = filename
157 self.pvrConvert = False
159 def log(self, code, msg):
160 self.log_entries.append((int(time()), code, msg))
163 def calculateFilename(self):
165 self.log(0, "Filename calculated as: '%s'" % self.Filename)
168 service_name = self.service_ref.getServiceName()
169 begin_date = strftime("%Y%m%d %H%M", localtime(self.begin))
170 begin_shortdate = strftime("%Y%m%d", localtime(self.begin))
172 print "begin_date: ", begin_date
173 print "service_name: ", service_name
174 print "name:", self.name
175 print "description: ", self.description
177 filename = begin_date + " - " + service_name
179 if config.usage.setup_level.index >= 2: # expert+
180 if config.recording.filename_composition.value == "short":
181 filename = begin_shortdate + " - " + self.name
182 elif config.recording.filename_composition.value == "long":
183 filename += " - " + self.name + " - " + self.description
185 filename += " - " + self.name # standard
187 filename += " - " + self.name
189 if config.recording.ascii_filenames.value:
190 filename = ASCIItranslit.legacyEncode(filename)
193 dirname = findSafeRecordPath(defaultMoviePath())
195 dirname = findSafeRecordPath(self.dirname)
197 dirname = findSafeRecordPath(defaultMoviePath())
198 self.dirnameHadToFallback = True
203 self.Filename = Directories.getRecordingFilename(filename, dirname)
204 self.log(0, "Filename calculated as: '%s'" % self.Filename)
205 #begin_date + " - " + service_name + description)
208 def tryPrepare(self):
212 if not self.calculateFilename():
214 self.start_prepare = time() + self.backoff
217 rec_ref = self.service_ref and self.service_ref.ref
218 if rec_ref and rec_ref.flags & eServiceReference.isGroup:
219 rec_ref = getBestPlayableServiceReference(rec_ref, eServiceReference())
221 self.log(1, "'get best playable service for group... record' failed")
224 self.record_service = rec_ref and NavigationInstance.instance.recordService(rec_ref)
226 if not self.record_service:
227 self.log(1, "'record service' failed")
231 epgcache = eEPGCache.getInstance()
232 queryTime=self.begin+(self.end-self.begin)/2
233 evt = epgcache.lookupEventTime(rec_ref, queryTime)
235 self.description = evt.getShortDescription()
236 event_id = evt.getEventId()
244 prep_res=self.record_service.prepare(self.Filename + ".ts", self.begin, self.end, event_id, self.name.replace("\n", ""), self.description.replace("\n", ""), ' '.join(self.tags), bool(self.descramble), bool(self.record_ecm))
247 self.log(4, "failed to write meta information")
249 self.log(2, "'prepare' failed: error %d" % prep_res)
251 # we must calc nur start time before stopRecordService call because in Screens/Standby.py TryQuitMainloop tries to get
252 # the next start time in evEnd event handler...
254 self.start_prepare = time() + self.backoff
256 NavigationInstance.instance.stopRecordService(self.record_service)
257 self.record_service = None
261 def do_backoff(self):
262 if self.backoff == 0:
266 if self.backoff > 100:
268 self.log(10, "backoff: retry in %d seconds" % self.backoff)
271 next_state = self.state + 1
272 self.log(5, "activating state %d" % next_state)
274 if next_state == self.StatePrepared:
275 if self.tryPrepare():
276 self.log(6, "prepare ok, waiting for begin")
277 # create file to "reserve" the filename
278 # because another recording at the same time on another service can try to record the same event
279 # i.e. cable / sat.. then the second recording needs an own extension... when we create the file
280 # here than calculateFilename is happy
281 if not self.justplay:
282 open(self.Filename + ".ts", "w").close()
283 # fine. it worked, resources are allocated.
284 self.next_activation = self.begin
288 self.log(7, "prepare failed")
289 if self.first_try_prepare:
290 self.first_try_prepare = False
291 cur_ref = NavigationInstance.instance.getCurrentlyPlayingServiceReference()
292 if cur_ref and not cur_ref.getPath():
293 if not config.recording.asktozap.value:
294 self.log(8, "asking user to zap away")
295 Notifications.AddNotificationWithCallback(self.failureCB, MessageBox, _("A timer failed to record!\nDisable TV and try again?\n"), timeout=20)
296 else: # zap without asking
297 self.log(9, "zap without asking")
298 Notifications.AddNotification(MessageBox, _("In order to record a timer, the TV was switched to the recording service!\n"), type=MessageBox.TYPE_INFO, timeout=20)
301 self.log(8, "currently running service is not a live service.. so stop it makes no sense")
303 self.log(8, "currently no service running... so we dont need to stop it")
305 elif next_state == self.StateRunning:
306 # if this timer has been cancelled, just go to "end" state.
311 if Screens.Standby.inStandby:
312 self.log(11, "wakeup and zap")
313 #set service to zap after standby
314 Screens.Standby.inStandby.prev_running_service = self.service_ref.ref
316 Screens.Standby.inStandby.Power()
318 self.log(11, "zapping")
319 NavigationInstance.instance.playService(self.service_ref.ref)
322 self.log(11, "start recording")
323 record_res = self.record_service.start()
326 self.log(13, "start record returned %d" % record_res)
329 self.begin = time() + self.backoff
333 elif next_state == self.StateEnded:
335 if self.setAutoincreaseEnd():
336 self.log(12, "autoincrase recording %d minute(s)" % int((self.end - old_end)/60))
339 self.log(12, "stop recording")
340 if not self.justplay:
341 NavigationInstance.instance.stopRecordService(self.record_service)
342 self.record_service = None
343 if self.afterEvent == AFTEREVENT.STANDBY:
344 if not Screens.Standby.inStandby: # not already in standby
345 Notifications.AddNotificationWithCallback(self.sendStandbyNotification, MessageBox, _("A finished record timer wants to set your\nSTB to standby. Do that now?"), timeout = 20)
346 elif self.afterEvent == AFTEREVENT.DEEPSTANDBY:
347 if not Screens.Standby.inTryQuitMainloop: # not a shutdown messagebox is open
348 if Screens.Standby.inStandby: # in standby
349 RecordTimerEntry.TryQuitMainloop() # start shutdown handling without screen
351 Notifications.AddNotificationWithCallback(self.sendTryQuitMainloopNotification, MessageBox, _("A finished record timer wants to shut down\nyour STB. Shutdown now?"), timeout = 20)
354 def setAutoincreaseEnd(self, entry = None):
355 if not self.autoincrease:
358 new_end = int(time()) + self.autoincreasetime
360 new_end = entry.begin -30
362 dummyentry = RecordTimerEntry(self.service_ref, self.begin, new_end, self.name, self.description, self.eit, disabled=True, justplay = self.justplay, afterEvent = self.afterEvent, dirname = self.dirname, tags = self.tags)
363 dummyentry.disabled = self.disabled
364 timersanitycheck = TimerSanityCheck(NavigationInstance.instance.RecordTimer.timer_list, dummyentry)
365 if not timersanitycheck.check():
366 simulTimerList = timersanitycheck.getSimulTimerList()
367 if simulTimerList is not None and len(simulTimerList) > 1:
368 new_end = simulTimerList[1].begin
369 new_end -= 30 # 30 Sekunden Prepare-Zeit lassen
370 if new_end <= time():
375 def sendStandbyNotification(self, answer):
377 Notifications.AddNotification(Screens.Standby.Standby)
379 def sendTryQuitMainloopNotification(self, answer):
381 Notifications.AddNotification(Screens.Standby.TryQuitMainloop, 1)
383 def getNextActivation(self):
384 if self.state == self.StateEnded:
387 next_state = self.state + 1
389 return {self.StatePrepared: self.start_prepare,
390 self.StateRunning: self.begin,
391 self.StateEnded: self.end }[next_state]
393 def failureCB(self, answer):
395 self.log(13, "ok, zapped away")
396 #NavigationInstance.instance.stopUserServices()
397 NavigationInstance.instance.playService(self.service_ref.ref)
399 self.log(14, "user didn't want to zap away, record will probably fail")
401 def timeChanged(self):
402 old_prepare = self.start_prepare
403 self.start_prepare = self.begin - self.prepare_time
406 if int(old_prepare) != int(self.start_prepare):
407 self.log(15, "record time changed, start prepare is now: %s" % ctime(self.start_prepare))
409 def gotRecordEvent(self, record, event):
410 # TODO: this is not working (never true), please fix. (comparing two swig wrapped ePtrs)
411 if self.__record_service.__deref__() != record.__deref__():
413 self.log(16, "record event %d" % event)
414 if event == iRecordableService.evRecordWriteError:
415 print "WRITE ERROR on recording, disk full?"
416 # show notification. the 'id' will make sure that it will be
417 # displayed only once, even if more timers are failing at the
418 # same time. (which is very likely in case of disk fullness)
419 Notifications.AddPopup(text = _("Write error while recording. Disk full?\n"), type = MessageBox.TYPE_ERROR, timeout = 0, id = "DiskFullMessage")
420 # ok, the recording has been stopped. we need to properly note
421 # that in our state, with also keeping the possibility to re-try.
422 # TODO: this has to be done.
423 elif event == iRecordableService.evStart:
427 text = _("A record has been started:\n%s") % self.name
428 if self.dirnameHadToFallback:
429 text = '\n'.join((text, _("Please note that the previously selected media could not be accessed and therefore the default directory is being used instead.")))
431 if config.usage.show_message_when_recording_starts.value:
432 Notifications.AddPopup(text = text, type = MessageBox.TYPE_INFO, timeout = 3)
434 # we have record_service as property to automatically subscribe to record service events
435 def setRecordService(self, service):
436 if self.__record_service is not None:
437 print "[remove callback]"
438 NavigationInstance.instance.record_event.remove(self.gotRecordEvent)
440 self.__record_service = service
442 if self.__record_service is not None:
443 print "[add callback]"
444 NavigationInstance.instance.record_event.append(self.gotRecordEvent)
446 record_service = property(lambda self: self.__record_service, setRecordService)
448 def isUsbRecordingPath(self):
452 dirname = findSafeRecordPath(self.dirname)
455 dirname = findSafeRecordPath(defaultMoviePath())
457 from Components import Harddisk
458 return Harddisk.isUsbStorage(dirname)
460 def createTimer(xml):
461 begin = int(xml.get("begin"))
462 end = int(xml.get("end"))
463 serviceref = ServiceReference(xml.get("serviceref").encode("utf-8"))
464 description = xml.get("description").encode("utf-8")
465 repeated = xml.get("repeated").encode("utf-8")
466 disabled = long(xml.get("disabled") or "0")
467 if SystemInfo["PVRSupport"]:
468 justplay = long(xml.get("justplay") or "0")
471 afterevent = str(xml.get("afterevent") or "nothing")
473 "nothing": AFTEREVENT.NONE,
474 "standby": AFTEREVENT.STANDBY,
475 "deepstandby": AFTEREVENT.DEEPSTANDBY,
476 "auto": AFTEREVENT.AUTO
479 if eit and eit != "None":
483 location = xml.get("location")
484 if location and location != "None":
485 location = location.encode("utf-8")
488 tags = xml.get("tags")
489 if tags and tags != "None":
490 tags = tags.encode("utf-8").split(' ')
494 name = xml.get("name").encode("utf-8")
495 #filename = xml.get("filename").encode("utf-8")
496 entry = RecordTimerEntry(serviceref, begin, end, name, description, eit, disabled, justplay, afterevent, dirname = location, tags = tags)
497 entry.repeated = int(repeated)
499 for l in xml.findall("log"):
500 time = int(l.get("time"))
501 code = int(l.get("code"))
502 msg = l.text.strip().encode("utf-8")
503 entry.log_entries.append((time, code, msg))
507 class RecordTimer(timer.Timer):
509 timer.Timer.__init__(self)
511 self.Filename = Directories.resolveFilename(Directories.SCOPE_CONFIG, "timers.xml")
516 print "unable to load timers from file!"
518 def doActivate(self, w):
519 if w.state == RecordTimerEntry.StateWaiting:
520 from Components.SystemInfo import SystemInfo
521 if SystemInfo.get("DisableUsbRecord", True) and w.isUsbRecordingPath():
522 service_name = w.service_ref.getServiceName()
523 self.timer_list.remove(w)
524 if w.dontSave is False:
527 self.addTimerEntry(w)
528 Notifications.AddNotification(MessageBox, _("Can not recording on a USB storage.\nService name : %s"% service_name), MessageBox.TYPE_ERROR)
531 # when activating a timer which has already passed,
532 # simply abort the timer. don't run trough all the stages.
534 w.state = RecordTimerEntry.StateEnded
536 # when active returns true, this means "accepted".
537 # otherwise, the current state is kept.
538 # the timer entry itself will fix up the delay then.
542 self.timer_list.remove(w)
544 # did this timer reached the last state?
545 if w.state < RecordTimerEntry.StateEnded:
546 # no, sort it into active list
547 insort(self.timer_list, w)
549 # yes. Process repeated, and re-add.
552 w.state = RecordTimerEntry.StateWaiting
553 self.addTimerEntry(w)
555 insort(self.processed_timers, w)
559 def isRecording(self):
561 for timer in self.timer_list:
562 if timer.isRunning() and not timer.justplay:
569 doc = xml.etree.cElementTree.parse(self.Filename)
571 from Tools.Notifications import AddPopup
572 from Screens.MessageBox import MessageBox
574 AddPopup(_("The timer file (timers.xml) is corrupt and could not be loaded."), type = MessageBox.TYPE_ERROR, timeout = 0, id = "TimerLoadFailed")
576 print "timers.xml failed to load!"
579 os.rename(self.Filename, self.Filename + "_old")
580 except (IOError, OSError):
581 print "renaming broken timer failed"
584 print "timers.xml not found!"
589 # put out a message when at least one timer overlaps
591 for timer in root.findall("timer"):
592 newTimer = createTimer(timer)
593 if (self.record(newTimer, True, dosave=False) is not None) and (checkit == True):
594 from Tools.Notifications import AddPopup
595 from Screens.MessageBox import MessageBox
596 AddPopup(_("Timer overlap in timers.xml detected!\nPlease recheck it!"), type = MessageBox.TYPE_ERROR, timeout = 0, id = "TimerLoadFailed")
597 checkit = False # at moment it is enough when the message is displayed one time
600 #root_element = xml.etree.cElementTree.Element('timers')
601 #root_element.text = "\n"
603 #for timer in self.timer_list + self.processed_timers:
604 # some timers (instant records) don't want to be saved.
608 #t = xml.etree.cElementTree.SubElement(root_element, 'timers')
609 #t.set("begin", str(int(timer.begin)))
610 #t.set("end", str(int(timer.end)))
611 #t.set("serviceref", str(timer.service_ref))
612 #t.set("repeated", str(timer.repeated))
613 #t.set("name", timer.name)
614 #t.set("description", timer.description)
615 #t.set("afterevent", str({
616 # AFTEREVENT.NONE: "nothing",
617 # AFTEREVENT.STANDBY: "standby",
618 # AFTEREVENT.DEEPSTANDBY: "deepstandby",
619 # AFTEREVENT.AUTO: "auto"}))
620 #if timer.eit is not None:
621 # t.set("eit", str(timer.eit))
622 #if timer.dirname is not None:
623 # t.set("location", str(timer.dirname))
624 #t.set("disabled", str(int(timer.disabled)))
625 #t.set("justplay", str(int(timer.justplay)))
629 #for time, code, msg in timer.log_entries:
630 #l = xml.etree.cElementTree.SubElement(t, 'log')
631 #l.set("time", str(time))
632 #l.set("code", str(code))
636 #doc = xml.etree.cElementTree.ElementTree(root_element)
637 #doc.write(self.Filename)
641 list.append('<?xml version="1.0" ?>\n')
642 list.append('<timers>\n')
644 for timer in self.timer_list + self.processed_timers:
648 list.append('<timer')
649 list.append(' begin="' + str(int(timer.begin)) + '"')
650 list.append(' end="' + str(int(timer.end)) + '"')
651 list.append(' serviceref="' + stringToXML(str(timer.service_ref)) + '"')
652 list.append(' repeated="' + str(int(timer.repeated)) + '"')
653 list.append(' name="' + str(stringToXML(timer.name)) + '"')
654 list.append(' description="' + str(stringToXML(timer.description)) + '"')
655 list.append(' afterevent="' + str(stringToXML({
656 AFTEREVENT.NONE: "nothing",
657 AFTEREVENT.STANDBY: "standby",
658 AFTEREVENT.DEEPSTANDBY: "deepstandby",
659 AFTEREVENT.AUTO: "auto"
660 }[timer.afterEvent])) + '"')
661 if timer.eit is not None:
662 list.append(' eit="' + str(timer.eit) + '"')
663 if timer.dirname is not None:
664 list.append(' location="' + str(stringToXML(timer.dirname)) + '"')
665 if timer.tags is not None:
666 list.append(' tags="' + str(stringToXML(' '.join(timer.tags))) + '"')
667 list.append(' disabled="' + str(int(timer.disabled)) + '"')
668 if SystemInfo["PVRSupport"]:
669 list.append(' justplay="' + str(int(timer.justplay)) + '"')
671 list.append(' justplay="1"')
674 if config.recording.debug.value:
675 for time, code, msg in timer.log_entries:
677 list.append(' code="' + str(code) + '"')
678 list.append(' time="' + str(time) + '"')
680 list.append(str(stringToXML(msg)))
681 list.append('</log>\n')
683 list.append('</timer>\n')
685 list.append('</timers>\n')
687 file = open(self.Filename, "w")
692 def getNextZapTime(self):
694 for timer in self.timer_list:
695 if not timer.justplay or timer.begin < now:
700 def getNextRecordingTime(self):
702 for timer in self.timer_list:
703 next_act = timer.getNextActivation()
704 if timer.justplay or next_act < now:
709 def isNextRecordAfterEventActionAuto(self):
712 for timer in self.timer_list:
713 if timer.justplay or timer.begin < now:
715 if t is None or t.begin == timer.begin:
717 if t.afterEvent == AFTEREVENT.AUTO:
721 def record(self, entry, ignoreTSC=False, dosave=True): #wird von loadTimer mit dosave=False aufgerufen
722 timersanitycheck = TimerSanityCheck(self.timer_list,entry)
723 if not timersanitycheck.check():
724 if ignoreTSC != True:
725 print "timer conflict detected!"
726 print timersanitycheck.getSimulTimerList()
727 return timersanitycheck.getSimulTimerList()
729 print "ignore timer conflict"
730 elif timersanitycheck.doubleCheck():
731 print "ignore double timer"
734 print "[Timer] Record " + str(entry)
736 self.addTimerEntry(entry)
741 def isInTimer(self, eventid, begin, duration, service):
745 chktimecmp_end = None
746 end = begin + duration
747 refstr = str(service)
748 for x in self.timer_list:
749 check = x.service_ref.ref.toString() == refstr
751 sref = x.service_ref.ref
752 parent_sid = sref.getUnsignedData(5)
753 parent_tsid = sref.getUnsignedData(6)
754 if parent_sid and parent_tsid: # check for subservice
755 sid = sref.getUnsignedData(1)
756 tsid = sref.getUnsignedData(2)
757 sref.setUnsignedData(1, parent_sid)
758 sref.setUnsignedData(2, parent_tsid)
759 sref.setUnsignedData(5, 0)
760 sref.setUnsignedData(6, 0)
761 check = sref.toCompareString() == refstr
765 event = eEPGCache.getInstance().lookupEventId(sref, eventid)
766 num = event and event.getNumOfLinkageServices() or 0
767 sref.setUnsignedData(1, sid)
768 sref.setUnsignedData(2, tsid)
769 sref.setUnsignedData(5, parent_sid)
770 sref.setUnsignedData(6, parent_tsid)
771 for cnt in range(num):
772 subservice = event.getLinkageService(sref, cnt)
773 if sref.toCompareString() == subservice.toCompareString():
779 chktime = localtime(begin)
780 chktimecmp = chktime.tm_wday * 1440 + chktime.tm_hour * 60 + chktime.tm_min
781 chktimecmp_end = chktimecmp + (duration / 60)
782 time = localtime(x.begin)
783 for y in (0, 1, 2, 3, 4, 5, 6):
784 if x.repeated & (1 << y) and (x.begin <= begin or begin <= x.begin <= end):
785 timecmp = y * 1440 + time.tm_hour * 60 + time.tm_min
786 if timecmp <= chktimecmp < (timecmp + ((x.end - x.begin) / 60)):
787 time_match = ((timecmp + ((x.end - x.begin) / 60)) - chktimecmp) * 60
788 elif chktimecmp <= timecmp < chktimecmp_end:
789 time_match = (chktimecmp_end - timecmp) * 60
790 else: #if x.eit is None:
791 if begin <= x.begin <= end:
793 if time_match < diff:
795 elif x.begin <= begin <= x.end:
797 if time_match < diff:
803 def removeEntry(self, entry):
804 print "[Timer] Remove " + str(entry)
807 entry.repeated = False
810 # this sets the end time to current time, so timer will be stopped.
811 entry.autoincrease = False
814 if entry.state != entry.StateEnded:
815 self.timeChanged(entry)
817 print "state: ", entry.state
818 print "in processed: ", entry in self.processed_timers
819 print "in running: ", entry in self.timer_list
820 # autoincrease instanttimer if possible
821 if not entry.dontSave:
822 for x in self.timer_list:
823 if x.setAutoincreaseEnd():
825 # now the timer should be in the processed_timers list. remove it from there.
826 self.processed_timers.remove(entry)