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, \
44 tags = None, encoding = 'UTF-8', searchType = "partial", searchCase = "insensitive"):
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 []
65 self.encoding = encoding
66 self.searchType = searchType
67 self.searchCase = searchCase
69 ### Attributes / Properties
71 def setAfterEvent(self, afterevent):
72 del self._afterevent[:]
74 for definition in afterevent:
75 action, timespan = definition
77 self._afterevent.append((action, (None,)))
79 self._afterevent.append((action, self.calculateDayspan(*timespan)))
81 afterevent = property(lambda self: self._afterevent, setAfterEvent)
83 def setBouquets(self, bouquets):
85 self._bouquets = bouquets
89 bouquets = property(lambda self: self._bouquets , setBouquets)
91 def setEncoding(self, encoding):
93 self._encoding = encoding
95 encoding = property(lambda self: self._encoding, setEncoding)
97 def setExclude(self, exclude):
100 [re_compile(x) for x in exclude[0]],
101 [re_compile(x) for x in exclude[1]],
102 [re_compile(x) for x in exclude[2]],
106 self._exclude = ([], [], [], [])
108 exclude = property(lambda self: self._exclude, setExclude)
110 def setInclude(self, include):
113 [re_compile(x) for x in include[0]],
114 [re_compile(x) for x in include[1]],
115 [re_compile(x) for x in include[2]],
119 self._include = ([], [], [], [])
121 include = property(lambda self: self._include, setInclude)
123 def setMatch(self, match):
124 # XXX: a sanity check might be useful...
127 match = property(lambda self: self._match, setMatch)
129 def setSearchCase(self, case):
130 assert case in ("sensitive", "insensitive"), "search case must be sensitive or insensitive"
131 self._searchCase = case
133 searchCase = property(lambda self: self._searchCase, setSearchCase)
135 def setSearchType(self, type):
136 assert type in ("exact", "partial"), "search type must be exact or partial"
137 self._searchType = type
139 searchType = property(lambda self: self._searchType, setSearchType)
141 def setServices(self, services):
143 self._services = services
147 services = property(lambda self: self._services, setServices)
149 def setTimespan(self, timespan):
150 if timespan is None or len(timespan) and timespan[0] is None:
151 self._timespan = (None,)
153 self._timespan = self.calculateDayspan(*timespan)
155 timespan = property(lambda self: self._timespan, setTimespan)
157 ### See if Attributes are set
159 def hasAfterEvent(self):
160 return len(self.afterevent)
162 def hasAfterEventTimespan(self):
163 for afterevent in self.afterevent:
164 if afterevent[1][0] is not None:
168 def hasCounter(self):
169 return self.matchCount != 0
171 def hasCounterFormatString(self):
172 return self.matchFormatString != ''
174 def hasDestination(self):
175 return self.destination is not None
177 def hasDuration(self):
178 return self.maxduration is not None
181 return len(self.tags) > 0
183 def hasTimespan(self):
184 return self.timespan[0] is not None
187 return self.offset is not None
192 Returns a tulple of (input begin, input end, begin earlier than end)
194 def calculateDayspan(self, begin, end, ignore = None):
195 if end[0] < begin[0] or (end[0] == begin[0] and end[1] <= begin[1]):
196 return (begin, end, True)
198 return (begin, end, False)
201 Returns if a given timestruct is in a timespan
203 def checkAnyTimespan(self, time, begin = None, end = None, haveDayspan = False):
207 # Check if we span a day
209 # Check if begin of event is later than our timespan starts
210 if time.tm_hour > begin[0] or (time.tm_hour == begin[0] and time.tm_min >= begin[1]):
211 # If so, event is in our timespan
213 # Check if begin of event is earlier than our timespan end
214 if time.tm_hour < end[0] or (time.tm_hour == end[0] and time.tm_min <= end[1]):
215 # If so, event is in our timespan
219 # Check if event begins earlier than our timespan starts
220 if time.tm_hour < begin[0] or (time.tm_hour == begin[0] and time.tm_min < begin[1]):
221 # Its out of our timespan then
223 # Check if event begins later than our timespan ends
224 if time.tm_hour > end[0] or (time.tm_hour == end[0] and time.tm_min > end[1]):
225 # Its out of our timespan then
230 Returns a list of all allowed services by listing the bouquets
232 def getFullServices(self):
233 list = self.services[:]
235 from enigma import eServiceReference, eServiceCenter
236 serviceHandler = eServiceCenter.getInstance()
237 for bouquet in self.bouquets:
238 myref = eServiceReference(str(bouquet))
239 mylist = serviceHandler.list(myref)
240 if mylist is not None:
243 # TODO: I wonder if its sane to assume we get services here (and not just new lists)
244 # We can ignore markers & directorys here because they won't match any event's service :-)
246 # strip all after last :
248 pos = value.rfind(':')
250 value = value[:pos+1]
259 Called when a timer based on this component was added
261 def update(self, begin, timestamp):
262 # Only update limit when we have new begin
263 if begin > self.lastBegin:
264 self.lastBegin = begin
267 # %m is Month, %U is week (sunday), %W is week (monday)
268 newLimit = strftime(self.matchFormatString, timestamp)
270 if newLimit != self.matchLimit:
271 self.matchLeft = self.matchCount
272 self.matchLimit = newLimit
274 ### Makes saving Config easier
276 getAvoidDuplicateDescription = lambda self: self.avoidDuplicateDescription
278 getBouquets = lambda self: self._bouquets
280 getCompleteAfterEvent = lambda self: self._afterevent
282 getCounter = lambda self: self.matchCount
283 getCounterFormatString = lambda self: self.matchFormatString
284 getCounterLeft = lambda self: self.matchLeft
285 getCounterLimit = lambda self: self.matchLimit
287 # 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 ;-)
288 getDestination = lambda self: self.destination is not None
290 getDuration = lambda self: self.maxduration/60
292 getEnabled = lambda self: self.enabled and "yes" or "no"
294 getExclude = lambda self: self._exclude
295 getExcludedDays = lambda self: self.exclude[3]
296 getExcludedDescription = lambda self: [x.pattern for x in self.exclude[2]]
297 getExcludedShort = lambda self: [x.pattern for x in self.exclude[1]]
298 getExcludedTitle = lambda self: [x.pattern for x in self.exclude[0]]
300 getInclude = lambda self: self._include
301 getIncludedTitle = lambda self: [x.pattern for x in self.include[0]]
302 getIncludedShort = lambda self: [x.pattern for x in self.include[1]]
303 getIncludedDescription = lambda self: [x.pattern for x in self.include[2]]
304 getIncludedDays = lambda self: self.include[3]
306 getJustplay = lambda self: self.justplay and "1" or "0"
308 getLastBegin = lambda self: self.lastBegin
310 getName = lambda self: self.name
312 getOffsetBegin = lambda self: self.offset[0]/60
313 getOffsetEnd = lambda self: self.offset[1]/60
315 getServices = lambda self: self._services
317 getTags = lambda self: self.tags
319 getTimespan = lambda self: self._timespan
320 getTimespanBegin = lambda self: '%02d:%02d' % (self.timespan[0][0], self.timespan[0][1])
321 getTimespanEnd = lambda self: '%02d:%02d' % (self.timespan[1][0], self.timespan[1][1])
323 isOffsetEqual = lambda self: self.offset[0] == self.offset[1]
325 ### Actual functionality
327 def applyOffset(self, begin, end):
328 if self.offset is None:
330 return (begin - self.offset[0], end + self.offset[1])
332 def checkCounter(self, timestamp):
333 # 0-Count is considered "unset"
334 if self.matchCount == 0:
337 # Check if event is in current timespan (we can only manage one!)
338 limit = strftime(self.matchFormatString, timestamp)
339 if limit != self.matchLimit:
342 if self.matchLeft > 0:
346 def checkDuration(self, length):
347 if self.maxduration is None:
349 return length > self.maxduration
351 def checkExcluded(self, title, short, extended, dayofweek):
352 if len(self.exclude[3]):
353 list = [x for x in self.exclude[3]]
354 if "weekend" in list:
355 list.extend(["5", "6"])
356 if "weekday" in list:
357 list.extend(["0", "1", "2", "3", "4"])
358 if dayofweek in list:
361 for exclude in self.exclude[0]:
362 if exclude.search(title):
364 for exclude in self.exclude[1]:
365 if exclude.search(short):
367 for exclude in self.exclude[2]:
368 if exclude.search(extended):
372 def checkFilter(self, title, short, extended, dayofweek):
373 if self.checkExcluded(title, short, extended, dayofweek):
376 return self.checkIncluded(title, short, extended, dayofweek)
378 def checkIncluded(self, title, short, extended, dayofweek):
379 if len(self.include[3]):
380 list = [x for x in self.include[3]]
381 if "weekend" in list:
382 list.extend(["5", "6"])
383 if "weekday" in list:
384 list.extend(["0", "1", "2", "3", "4"])
385 if dayofweek not in list:
388 for include in self.include[0]:
389 if not include.search(title):
391 for include in self.include[1]:
392 if not include.search(short):
394 for include in self.include[2]:
395 if not include.search(extended):
400 def checkServices(self, service):
401 if len(self.services) or len(self.bouquets):
402 return service not in self.getFullServices()
405 def checkTimespan(self, begin):
406 return self.checkAnyTimespan(begin, *self.timespan)
408 def decrementCounter(self):
409 if self.matchCount and self.matchLeft > 0:
412 def getAfterEvent(self):
413 for afterevent in self.afterevent:
414 if afterevent[1][0] is None:
418 def getAfterEventTimespan(self, end):
419 for afterevent in self.afterevent:
420 if not self.checkAnyTimespan(end, *afterevent[1]):
427 return self.__class__(
432 timespan = self.timespan,
433 services = self.services,
434 offset = self.offset,
435 afterevent = self.afterevent,
436 exclude = (self.getExcludedTitle(), self.getExcludedShort(), self.getExcludedDescription(), self.getExcludedDays()),
437 maxduration = self.maxduration,
438 destination = self.destination,
439 include = (self.getIncludedTitle(), self.getIncludedShort(), self.getIncludedDescription(), self.getIncludedDays()),
440 matchCount = self.matchCount,
441 matchLeft = self.matchLeft,
442 matchLimit = self.matchLimit,
443 matchFormatString = self.matchFormatString,
444 lastBegin = self.lastBegin,
445 justplay = self.justplay,
446 avoidDuplicateDescription = self.avoidDuplicateDescription,
447 bouquets = self.bouquets,
451 def __deepcopy__(self, memo):
452 return self.__class__(
457 timespan = self.timespan,
458 services = self.services[:],
459 offset = self.offset and self.offset[:],
460 afterevent = self.afterevent[:],
461 exclude = (self.getExcludedTitle(), self.getExcludedShort(), self.getExcludedDescription(), self.exclude[3][:]),
462 maxduration = self.maxduration,
463 destination = self.destination,
464 include = (self.getIncludedTitle(), self.getIncludedShort(), self.getIncludedDescription(), self.include[3][:]),
465 matchCount = self.matchCount,
466 matchLeft = self.matchLeft,
467 matchLimit = self.matchLimit,
468 matchFormatString = self.matchFormatString,
469 lastBegin = self.lastBegin,
470 justplay = self.justplay,
471 avoidDuplicateDescription = self.avoidDuplicateDescription,
472 bouquets = self.bouquets[:],
476 def __eq__(self, other):
477 if isinstance(other, AutoTimerComponent):
478 return self.id == other.id
481 def __lt__(self, other):
482 if isinstance(other, AutoTimerComponent):
483 return self.name.lower() < other.name.lower()
486 def __ne__(self, other):
487 return not self.__eq__(other)
499 str(self.afterevent),
500 str(([x.pattern for x in self.exclude[0]],
501 [x.pattern for x in self.exclude[1]],
502 [x.pattern for x in self.exclude[2]],
505 str(([x.pattern for x in self.include[0]],
506 [x.pattern for x in self.include[1]],
507 [x.pattern for x in self.include[2]],
510 str(self.maxduration),
512 str(self.destination),
513 str(self.matchCount),
515 str(self.matchLimit),
516 str(self.matchFormatString),
519 str(self.avoidDuplicateDescription),