2 from time import strftime
5 from re import compile as re_compile
7 class AutoTimerComponent(object):
8 """AutoTimer Component which also handles validity checks"""
13 def __init__(self, id, name, match, enabled, *args, **kwargs):
16 self.setValues(name, match, enabled, *args, **kwargs)
21 def clear(self, id = -1, enabled = False):
23 self.setValues('', '', enabled)
26 Create a deep copy of this instance
29 return self.__deepcopy__({})
38 Keeps init small and helps setting many values at once
40 def setValues(self, name, match, enabled, timespan = None, services = None, offset = None, \
41 afterevent = [], exclude = None, maxduration = None, destination = None, \
42 include = None, matchCount = 0, matchLeft = 0, matchLimit = '', matchFormatString = '', \
43 lastBegin = 0, justplay = False, avoidDuplicateDescription = 0, bouquets = None, \
47 self.enabled = enabled
48 self.timespan = timespan
49 self.services = services
51 self.afterevent = afterevent
52 self.exclude = exclude
53 self.maxduration = maxduration
54 self.destination = destination
55 self.include = include
56 self.matchCount = matchCount
57 self.matchLeft = matchLeft
58 self.matchLimit = matchLimit
59 self.matchFormatString = matchFormatString
60 self.lastBegin = lastBegin
61 self.justplay = justplay
62 self.avoidDuplicateDescription = avoidDuplicateDescription
63 self.bouquets = bouquets
64 self.tags = tags or []
66 ### Attributes / Properties
68 def setAfterEvent(self, afterevent):
69 del self._afterevent[:]
71 for definition in afterevent:
72 action, timespan = definition
74 self._afterevent.append((action, (None,)))
76 self._afterevent.append((action, self.calculateDayspan(*timespan)))
78 afterevent = property(lambda self: self._afterevent, setAfterEvent)
80 def setBouquets(self, bouquets):
82 self._bouquets = bouquets
86 bouquets = property(lambda self: self._bouquets , setBouquets)
88 def setExclude(self, exclude):
91 [re_compile(x) for x in exclude[0]],
92 [re_compile(x) for x in exclude[1]],
93 [re_compile(x) for x in exclude[2]],
97 self._exclude = ([], [], [], [])
99 exclude = property(lambda self: self._exclude, setExclude)
101 def setInclude(self, include):
104 [re_compile(x) for x in include[0]],
105 [re_compile(x) for x in include[1]],
106 [re_compile(x) for x in include[2]],
110 self._include = ([], [], [], [])
112 include = property(lambda self: self._include, setInclude)
114 def setName(self, name):
120 def setMatch(self, match):
121 # XXX: a sanity check might be useful...
124 match = property(getMatch, setMatch)
126 def setServices(self, services):
128 self._services = services
132 services = property(lambda self: self._services, setServices)
134 def setTimespan(self, timespan):
135 if timespan is None or len(timespan) and timespan[0] is None:
136 self._timespan = (None,)
138 self._timespan = self.calculateDayspan(*timespan)
140 timespan = property(lambda self: self._timespan, setTimespan)
142 ### See if Attributes are set
144 def hasAfterEvent(self):
145 return len(self.afterevent)
147 def hasAfterEventTimespan(self):
148 for afterevent in self.afterevent:
149 if afterevent[1][0] is not None:
153 def hasCounter(self):
154 return self.matchCount != 0
156 def hasCounterFormatString(self):
157 return self.matchFormatString != ''
159 def hasDestination(self):
160 return self.destination is not None
162 def hasDuration(self):
163 return self.maxduration is not None
166 return len(self.tags) > 0
168 def hasTimespan(self):
169 return self.timespan[0] is not None
172 return self.offset is not None
177 Returns a tulple of (input begin, input end, begin earlier than end)
179 def calculateDayspan(self, begin, end, ignore = None):
180 if end[0] < begin[0] or (end[0] == begin[0] and end[1] <= begin[1]):
181 return (begin, end, True)
183 return (begin, end, False)
186 Returns if a given timestruct is in a timespan
188 def checkAnyTimespan(self, time, begin = None, end = None, haveDayspan = False):
192 # Check if we span a day
194 # Check if begin of event is later than our timespan starts
195 if time.tm_hour > begin[0] or (time.tm_hour == begin[0] and time.tm_min >= begin[1]):
196 # If so, event is in our timespan
198 # Check if begin of event is earlier than our timespan end
199 if time.tm_hour < end[0] or (time.tm_hour == end[0] and time.tm_min <= end[1]):
200 # If so, event is in our timespan
204 # Check if event begins earlier than our timespan starts
205 if time.tm_hour < begin[0] or (time.tm_hour == begin[0] and time.tm_min < begin[1]):
206 # Its out of our timespan then
208 # Check if event begins later than our timespan ends
209 if time.tm_hour > end[0] or (time.tm_hour == end[0] and time.tm_min > end[1]):
210 # Its out of our timespan then
215 Returns a list of all allowed services by listing the bouquets
217 def getFullServices(self):
218 list = self.services[:]
220 from enigma import eServiceReference, eServiceCenter
221 serviceHandler = eServiceCenter.getInstance()
222 for bouquet in self.bouquets:
223 myref = eServiceReference(str(bouquet))
224 mylist = serviceHandler.list(myref)
225 if mylist is not None:
228 # TODO: I wonder if its sane to assume we get services here (and not just new lists)
229 # We can ignore markers & directorys here because they won't match any event's service :-)
231 # strip all after last :
233 pos = value.rfind(':')
235 value = value[:pos+1]
244 Called when a timer based on this component was added
246 def update(self, begin, timestamp):
247 # Only update limit when we have new begin
248 if begin > self.lastBegin:
249 self.lastBegin = begin
252 # %m is Month, %U is week (sunday), %W is week (monday)
253 newLimit = strftime(self.matchFormatString, timestamp)
255 if newLimit != self.matchLimit:
256 self.matchLeft = self.matchCount
257 self.matchLimit = newLimit
259 ### Makes saving Config easier
261 getAvoidDuplicateDescription = lambda self: self.avoidDuplicateDescription
263 getBouquets = lambda self: self._bouquets
265 getCompleteAfterEvent = lambda self: self._afterevent
267 getCounter = lambda self: self.matchCount
268 getCounterFormatString = lambda self: self.matchFormatString
269 getCounterLeft = lambda self: self.matchLeft
270 getCounterLimit = lambda self: self.matchLimit
272 # XXX: as this function was not added by me (ritzMo) i'll leave it like this but i'm not really sure if this is right ;-)
273 getDestination = lambda self: self.destination is not None
275 getDuration = lambda self: self.maxduration/60
277 getEnabled = lambda self: self.enabled and "yes" or "no"
279 getExclude = lambda self: self._exclude
280 getExcludedDays = lambda self: self.exclude[3]
281 getExcludedDescription = lambda self: [x.pattern for x in self.exclude[2]]
282 getExcludedShort = lambda self: [x.pattern for x in self.exclude[1]]
283 getExcludedTitle = lambda self: [x.pattern for x in self.exclude[0]]
285 getInclude = lambda self: self._include
286 getIncludedTitle = lambda self: [x.pattern for x in self.include[0]]
287 getIncludedShort = lambda self: [x.pattern for x in self.include[1]]
288 getIncludedDescription = lambda self: [x.pattern for x in self.include[2]]
289 getIncludedDays = lambda self: self.include[3]
291 getJustplay = lambda self: self.justplay and "1" or "0"
293 getLastBegin = lambda self: self.lastBegin
295 getName = lambda self: self.name
297 getOffsetBegin = lambda self: self.offset[0]/60
298 getOffsetEnd = lambda self: self.offset[1]/60
300 getServices = lambda self: self._services
302 getTags = lambda self: self.tags
304 getTimespan = lambda self: self._timespan
305 getTimespanBegin = lambda self: '%02d:%02d' % (self.timespan[0][0], self.timespan[0][1])
306 getTimespanEnd = lambda self: '%02d:%02d' % (self.timespan[1][0], self.timespan[1][1])
308 isOffsetEqual = lambda self: self.offset[0] == self.offset[1]
310 ### Actual functionality
312 def applyOffset(self, begin, end):
313 if self.offset is None:
315 return (begin - self.offset[0], end + self.offset[1])
317 def checkCounter(self, timestamp):
318 # 0-Count is considered "unset"
319 if self.matchCount == 0:
322 # Check if event is in current timespan (we can only manage one!)
323 limit = strftime(self.matchFormatString, timestamp)
324 if limit != self.matchLimit:
327 if self.matchLeft > 0:
331 def checkDuration(self, length):
332 if self.maxduration is None:
334 return length > self.maxduration
336 def checkExcluded(self, title, short, extended, dayofweek):
337 if len(self.exclude[3]):
338 list = [x for x in self.exclude[3]]
339 if "weekend" in list:
340 list.extend(["5", "6"])
341 if "weekday" in list:
342 list.extend(["0", "1", "2", "3", "4"])
343 if dayofweek in list:
346 for exclude in self.exclude[0]:
347 if exclude.search(title):
349 for exclude in self.exclude[1]:
350 if exclude.search(short):
352 for exclude in self.exclude[2]:
353 if exclude.search(extended):
357 def checkFilter(self, title, short, extended, dayofweek):
358 if self.checkExcluded(title, short, extended, dayofweek):
361 return self.checkIncluded(title, short, extended, dayofweek)
363 def checkIncluded(self, title, short, extended, dayofweek):
364 if len(self.include[3]):
365 list = [x for x in self.include[3]]
366 if "weekend" in list:
367 list.extend(["5", "6"])
368 if "weekday" in list:
369 list.extend(["0", "1", "2", "3", "4"])
370 if dayofweek not in list:
373 for include in self.include[0]:
374 if not include.search(title):
376 for include in self.include[1]:
377 if not include.search(short):
379 for include in self.include[2]:
380 if not include.search(extended):
385 def checkServices(self, service):
386 if len(self.services) or len(self.bouquets):
387 return service not in self.getFullServices()
390 def checkTimespan(self, begin):
391 return self.checkAnyTimespan(begin, *self.timespan)
393 def decrementCounter(self):
394 if self.matchCount and self.matchLeft > 0:
397 def getAfterEvent(self):
398 for afterevent in self.afterevent:
399 if afterevent[1][0] is None:
403 def getAfterEventTimespan(self, end):
404 for afterevent in self.afterevent:
405 if not self.checkAnyTimespan(end, *afterevent[1]):
412 return self.__class__(
417 timespan = self.timespan,
418 services = self.services,
419 offset = self.offset,
420 afterevent = self.afterevent,
421 exclude = (self.getExcludedTitle(), self.getExcludedShort(), self.getExcludedDescription(), self.getExcludedDays()),
422 maxduration = self.maxduration,
423 destination = self.destination,
424 include = (self.getIncludedTitle(), self.getIncludedShort(), self.getIncludedDescription(), self.getIncludedDays()),
425 matchCount = self.matchCount,
426 matchLeft = self.matchLeft,
427 matchLimit = self.matchLimit,
428 matchFormatString = self.matchFormatString,
429 lastBegin = self.lastBegin,
430 justplay = self.justplay,
431 avoidDuplicateDescription = self.avoidDuplicateDescription,
432 bouquets = self.bouquets,
436 def __deepcopy__(self, memo):
437 return self.__class__(
442 timespan = self.timespan,
443 services = self.services[:],
444 offset = self.offset and self.offset[:],
445 afterevent = self.afterevent[:],
446 exclude = (self.getExcludedTitle(), self.getExcludedShort(), self.getExcludedDescription(), self.exclude[3][:]),
447 maxduration = self.maxduration,
448 destination = self.destination,
449 include = (self.getIncludedTitle(), self.getIncludedShort(), self.getIncludedDescription(), self.include[3][:]),
450 matchCount = self.matchCount,
451 matchLeft = self.matchLeft,
452 matchLimit = self.matchLimit,
453 matchFormatString = self.matchFormatString,
454 lastBegin = self.lastBegin,
455 justplay = self.justplay,
456 avoidDuplicateDescription = self.avoidDuplicateDescription,
457 bouquets = self.bouquets[:],
461 def __eq__(self, other):
462 if isinstance(other, AutoTimerComponent):
463 return self.id == other.id
466 def __lt__(self, other):
467 if isinstance(other, AutoTimerComponent):
468 return self.name.lower() < other.name.lower()
471 def __ne__(self, other):
472 return not self.__eq__(other)
484 str(self.afterevent),
485 str(([x.pattern for x in self.exclude[0]],
486 [x.pattern for x in self.exclude[1]],
487 [x.pattern for x in self.exclude[2]],
490 str(([x.pattern for x in self.include[0]],
491 [x.pattern for x in self.include[1]],
492 [x.pattern for x in self.include[2]],
495 str(self.maxduration),
497 str(self.destination),
498 str(self.matchCount),
500 str(self.matchLimit),
501 str(self.matchFormatString),
504 str(self.avoidDuplicateDescription),