inserted two hooks for the webinterface
[vuplus_dvbapp-plugin] / autotimer / src / AutoTimerComponent.py
1 # Format Counter
2 from time import strftime
3
4 # regular expression
5 from re import compile as re_compile
6
7 class AutoTimerComponent(object):
8         """AutoTimer Component which also handles validity checks"""
9
10         def __init__(self, id, *args, **kwargs):
11                 self.id = id
12                 self._afterevent = []
13                 self.setValues(*args, **kwargs)
14
15         def __eq__(self, other):
16                 try:
17                         return self.id == other.id
18                 except AttributeError:
19                         return False
20
21         def __ne__(self, other):
22                 return not self.__eq__(other)
23
24         def __copy__(self):
25                 return self.__class__(
26                         self.id,
27                         self.name,
28                         self.match,
29                         self.enabled,
30                         timespan = self.timespan,
31                         services = self.services,
32                         offset = self.offset,
33                         afterevent = self.afterevent,
34                         exclude = (self.getExcludedTitle(), self.getExcludedShort(), self.getExcludedDescription(), self.getExcludedDays()),
35                         include = (self.getIncludedTitle(), self.getIncludedShort(), self.getIncludedDescription(), self.getIncludedDays()),
36                         maxduration = self.maxduration,
37                         destination = self.destination,
38                         matchCount = self.matchCount,
39                         matchLeft = self.matchLeft,
40                         matchLimit = self.matchLimit,
41                         matchFormatString = self.matchFormatString,
42                         lastBegin = self.lastBegin,
43                         justplay = self.justplay,
44                         avoidDuplicateDescription = self.avoidDuplicateDescription,
45                         bouquets = self.bouquets,
46                         tags = self.tags
47                 )
48
49         def __deepcopy__(self, memo):
50                 return self.__class__(
51                         self.id,
52                         self.name,
53                         self.match,
54                         self.enabled,
55                         timespan = self.timespan,
56                         services = self.services[:],
57                         offset = self.offset and self.offset[:],
58                         afterevent = self.afterevent[:],
59                         exclude = (self.getExcludedTitle(), self.getExcludedShort(), self.getExcludedDescription(), self.exclude[3][:]),
60                         include = (self.getIncludedTitle(), self.getIncludedShort(), self.getIncludedDescription(), self.include[3][:]),
61                         maxduration = self.maxduration,
62                         destination = self.destination,
63                         matchCount = self.matchCount,
64                         matchLeft = self.matchLeft,
65                         matchLimit = self.matchLimit,
66                         matchFormatString = self.matchFormatString,
67                         lastBegin = self.lastBegin,
68                         justplay = self.justplay,
69                         avoidDuplicateDescription = self.avoidDuplicateDescription,
70                         bouquets = self.bouquets[:],
71                         tags = self.tags[:]
72                 )
73
74         def clone(self):
75                 return self.__deepcopy__({})
76
77         def setValues(self, name, match, enabled, timespan = None, services = None, offset = None, \
78                         afterevent = [], exclude = None, maxduration = None, destination = None, \
79                         include = None, matchCount = 0, matchLeft = 0, matchLimit = '', matchFormatString = '', \
80                         lastBegin = 0, justplay = False, avoidDuplicateDescription = False, bouquets = None, \
81                         tags = None):
82                 self.name = name
83                 self.match = match
84                 self.timespan = timespan
85                 self.services = services
86                 self.offset = offset
87                 self.afterevent = afterevent
88                 self.exclude = exclude
89                 self.include = include
90                 self.maxduration = maxduration
91                 self.enabled = enabled
92                 self.destination = destination
93                 self.matchCount = matchCount
94                 self.matchLeft = matchLeft
95                 self.matchLimit = matchLimit
96                 self.matchFormatString = matchFormatString
97                 self.lastBegin = lastBegin
98                 self.justplay = justplay
99                 self.avoidDuplicateDescription = avoidDuplicateDescription
100                 self.bouquets = bouquets
101                 self.tags = tags or []
102         
103         def getName(self):
104                 return self.name
105         
106         def setName(self, name):
107                 self.name = name
108         
109         def getMatch(self):
110                 return self.match
111         
112         def setMatch(self, match):
113                 self.match = match
114         
115         def getEntry(self):
116                 return self
117         
118         def calculateDayspan(self, begin, end, ignore = None):
119                 if end[0] < begin[0] or (end[0] == begin[0] and end[1] <= begin[1]):
120                         return (begin, end, True)
121                 else:
122                         return (begin, end, False)
123
124         def setTimespan(self, timespan):
125                 if timespan is None or len(timespan) and timespan[0] is None:
126                         self._timespan = (None,)
127                 else:
128                         self._timespan = self.calculateDayspan(*timespan)
129
130         def getTimespan(self):
131                 return self._timespan
132
133         timespan = property(getTimespan, setTimespan)
134
135         def setExclude(self, exclude):
136                 if exclude:
137                         self._exclude = (
138                                 [re_compile(x) for x in exclude[0]],
139                                 [re_compile(x) for x in exclude[1]],
140                                 [re_compile(x) for x in exclude[2]],
141                                 exclude[3]
142                         )
143                 else:
144                         self._exclude = ([], [], [], [])
145
146         def getExclude(self):
147                 return self._exclude
148
149         exclude = property(getExclude, setExclude)
150
151         def setInclude(self, include):
152                 if include:
153                         self._include = (
154                                 [re_compile(x) for x in include[0]],
155                                 [re_compile(x) for x in include[1]],
156                                 [re_compile(x) for x in include[2]],
157                                 include[3]
158                         )
159                 else:
160                         self._include = ([], [], [], [])
161
162         def getInclude(self):
163                 return self._include
164
165         include = property(getInclude, setInclude)
166
167         def setServices(self, services):
168                 if services:
169                         self._services = services
170                 else:
171                         self._services = []
172
173         def getServices(self):
174                 return self._services
175
176         services = property(getServices, setServices)
177
178         def setBouquets(self, bouquets):
179                 if bouquets:
180                         self._bouquets = bouquets
181                 else:
182                         self._bouquets = []
183
184         def getBouquets(self):
185                 return self._bouquets
186
187         bouquets = property(getBouquets, setBouquets)
188
189         def setAfterEvent(self, afterevent):
190                 del self._afterevent[:]
191                 if len(afterevent):
192                         for definition in afterevent:
193                                 action, timespan = definition
194                                 if timespan is None:
195                                         self._afterevent.append((action, (None,)))
196                                 else:
197                                         self._afterevent.append((action, self.calculateDayspan(*timespan)))
198
199         def getCompleteAfterEvent(self):
200                 return self._afterevent
201
202         afterevent = property(getCompleteAfterEvent, setAfterEvent)
203
204         def hasTimespan(self):
205                 return self.timespan[0] is not None
206
207         def getTimespanBegin(self):
208                 return '%02d:%02d' % (self.timespan[0][0], self.timespan[0][1])
209
210         def getTimespanEnd(self):
211                 return '%02d:%02d' % (self.timespan[1][0], self.timespan[1][1])
212
213         def checkAnyTimespan(self, time, begin = None, end = None, haveDayspan = False):
214                 if begin is None:
215                         return False
216
217                 # Check if we span a day
218                 if haveDayspan:
219                         # Check if begin of event is later than our timespan starts
220                         if time.tm_hour > begin[0] or (time.tm_hour == begin[0] and time.tm_min >= begin[1]):
221                                 # If so, event is in our timespan
222                                 return False
223                         # Check if begin of event is earlier than our timespan end
224                         if time.tm_hour < end[0] or (time.tm_hour == end[0] and time.tm_min <= end[1]):
225                                 # If so, event is in our timespan
226                                 return False
227                         return True
228                 else:
229                         # Check if event begins earlier than our timespan starts 
230                         if time.tm_hour < begin[0] or (time.tm_hour == begin[0] and time.tm_min < begin[1]):
231                                 # Its out of our timespan then
232                                 return True
233                         # Check if event begins later than our timespan ends
234                         if time.tm_hour > end[0] or (time.tm_hour == end[0] and time.tm_min > end[1]):
235                                 # Its out of our timespan then
236                                 return True
237                         return False
238
239         def checkTimespan(self, begin):
240                 return self.checkAnyTimespan(begin, *self.timespan)
241
242         def hasDuration(self):
243                 return self.maxduration is not None
244
245         def getDuration(self):
246                 return self.maxduration/60
247
248         def checkDuration(self, length):
249                 if self.maxduration is None:
250                         return False
251                 return length > self.maxduration
252
253         def getFullServices(self):
254                 list = self.services[:]
255
256                 from enigma import eServiceReference, eServiceCenter
257                 serviceHandler = eServiceCenter.getInstance()
258                 for bouquet in self.bouquets:
259                         myref = eServiceReference(str(bouquet))
260                         mylist = serviceHandler.list(myref)
261                         if mylist is not None:
262                                 while 1:
263                                         s = mylist.getNext()
264                                         # TODO: I wonder if its sane to assume we get services here (and not just new lists)
265                                         # We can ignore markers & directorys here because they won't match any event's service :-)
266                                         if s.valid():
267                                                 # strip all after last :
268                                                 value = s.toString()
269                                                 pos = value.rfind(':')
270                                                 if pos != -1:
271                                                         value = value[:pos+1]
272
273                                                 list.append(value)
274                                         else:
275                                                 break
276
277                 return list
278
279         def checkServices(self, service):
280                 if len(self.services) or len(self.bouquets): 
281                         return service not in self.getFullServices()
282                 return False
283
284         def getExcludedTitle(self):
285                 return [x.pattern for x in self.exclude[0]]
286
287         def getExcludedShort(self):
288                 return [x.pattern for x in self.exclude[1]]
289
290         def getExcludedDescription(self):
291                 return [x.pattern for x in self.exclude[2]]
292
293         def getExcludedDays(self):
294                 return self.exclude[3]
295
296         def getIncludedTitle(self):
297                 return [x.pattern for x in self.include[0]]
298
299         def getIncludedShort(self):
300                 return [x.pattern for x in self.include[1]]
301
302         def getIncludedDescription(self):
303                 return [x.pattern for x in self.include[2]]
304
305         def getIncludedDays(self):
306                 return self.include[3]
307
308         def checkExcluded(self, title, short, extended, dayofweek):
309                 if len(self.exclude[3]):
310                         list = [x for x in self.exclude[3]]
311                         if "weekend" in list:
312                                 list.extend(["5", "6"])
313                         if "weekday" in list:
314                                 list.extend(["0", "1", "2", "3", "4"])
315                         if dayofweek in list:
316                                 return True
317
318                 for exclude in self.exclude[0]:
319                         if exclude.search(title):
320                                 return True
321                 for exclude in self.exclude[1]:
322                         if exclude.search(short):
323                                 return True
324                 for exclude in self.exclude[2]:
325                         if exclude.search(extended):
326                                 return True
327                 return False
328
329         def checkIncluded(self, title, short, extended, dayofweek):
330                 if len(self.include[3]):
331                         list = [x for x in self.include[3]]
332                         if "weekend" in list:
333                                 list.extend(["5", "6"])
334                         if "weekday" in list:
335                                 list.extend(["0", "1", "2", "3", "4"])
336                         if dayofweek not in list:
337                                 return True
338
339                 for include in self.include[0]:
340                         if not include.search(title):
341                                 return True
342                 for include in self.include[1]:
343                         if not include.search(short):
344                                 return True
345                 for include in self.include[2]:
346                         if not include.search(extended):
347                                 return True
348
349                 return False
350
351         def checkFilter(self, title, short, extended, dayofweek):
352                 if self.checkExcluded(title, short, extended, dayofweek):
353                         return True
354
355                 return self.checkIncluded(title, short, extended, dayofweek)
356
357         def hasOffset(self):
358                 return self.offset is not None
359
360         def isOffsetEqual(self):
361                 return self.offset[0] == self.offset[1]
362
363         def applyOffset(self, begin, end):
364                 if self.offset is None:
365                         return (begin, end)
366                 return (begin - self.offset[0], end + self.offset[1])
367
368         def getOffsetBegin(self):
369                 return self.offset[0]/60
370
371         def getOffsetEnd(self):
372                 return self.offset[1]/60
373
374         def hasAfterEvent(self):
375                 return len(self.afterevent)
376
377         def hasAfterEventTimespan(self):
378                 for afterevent in self.afterevent:
379                         if afterevent[1][0] is not None:
380                                 return True
381                 return False
382
383         def getAfterEventTimespan(self, end):
384                 for afterevent in self.afterevent:
385                         if not self.checkAnyTimespan(end, *afterevent[1]):
386                                 return afterevent[0]
387                 return None
388
389         def getAfterEvent(self):
390                 for afterevent in self.afterevent:
391                         if afterevent[1][0] is None:
392                                 return afterevent[0]
393                 return None
394
395         def getEnabled(self):
396                 return self.enabled and "yes" or "no"
397
398         def getJustplay(self):
399                 return self.justplay and "1" or "0"
400
401         def hasDestination(self):
402                 return self.destination is not None
403         
404         def getDestination(self):
405                 return self.destination is not None
406
407         def hasCounter(self):
408                 return self.matchCount != 0
409
410         def hasCounterFormatString(self):
411                 return self.matchFormatString != ''
412
413         def getCounter(self):
414                 return self.matchCount
415
416         def getCounterLeft(self):
417                 return self.matchLeft
418
419         def getCounterLimit(self):
420                 return self.matchLimit
421
422         def getCounterFormatString(self):
423                 return self.matchFormatString
424
425         def checkCounter(self, timestamp):
426                 # 0-Count is considered "unset"
427                 if self.matchCount == 0:
428                         return False
429
430                 # Check if event is in current timespan (we can only manage one!)
431                 limit = strftime(self.matchFormatString, timestamp)
432                 if limit != self.matchLimit:
433                         return True
434
435                 if self.matchLeft > 0:
436                         self.matchLeft -= 1
437                         return False
438                 return True
439
440         def update(self, begin, timestamp):
441                 # Only update limit when we have new begin
442                 if begin > self.lastBegin:
443                         self.lastBegin = begin
444
445                         # Update Counter:
446                         # %m is Month, %U is week (sunday), %W is week (monday)
447                         newLimit = strftime(self.matchFormatString, timestamp)
448
449                         if newLimit != self.matchLimit:
450                                 self.matchLeft = self.matchCount
451                                 self.matchLimit = newLimit
452
453         def getLastBegin(self):
454                 return self.lastBegin
455
456         def getAvoidDuplicateDescription(self):
457                 return self.avoidDuplicateDescription
458
459         def hasTags(self):
460                 return len(self.tags) > 0
461         
462         def getTags(self):
463                 return self.tags
464
465         def __repr__(self):
466                 return ''.join([
467                         '<AutomaticTimer ',
468                         self.name,
469                         ' (',
470                         ', '.join([
471                                         str(self.match),
472                                         str(self.timespan),
473                                         str(self.services),
474                                         str(self.offset),
475                                         str(self.afterevent),
476                                         str(([x.pattern for x in self.exclude[0]],
477                                                 [x.pattern for x in self.exclude[1]],
478                                                 [x.pattern for x in self.exclude[2]],
479                                                 self.exclude[3]
480                                         )),
481                                         str(([x.pattern for x in self.include[0]],
482                                                 [x.pattern for x in self.include[1]],
483                                                 [x.pattern for x in self.include[2]],
484                                                 self.include[3]
485                                         )),
486                                         str(self.maxduration),
487                                         str(self.enabled),
488                                         str(self.destination),
489                                         str(self.matchCount),
490                                         str(self.matchLeft),
491                                         str(self.matchLimit),
492                                         str(self.matchFormatString),
493                                         str(self.lastBegin),
494                                         str(self.justplay),
495                                         str(self.avoidDuplicateDescription),
496                                         str(self.bouquets),
497                                         str(self.tags)
498                          ]),
499                          ")>"
500                 ])