handle include/exclude strings as regular expressions
[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 setValues(self, name, match, enabled, timespan = None, services = None, offset = None, \
25                         afterevent = [], exclude = None, maxduration = None, destination = None, \
26                         include = None, matchCount = 0, matchLeft = 0, matchLimit = '', matchFormatString = '', \
27                         lastBegin = 0, justplay = False, avoidDuplicateDescription = False):
28                 self.name = name
29                 self.match = match
30                 self.timespan = timespan
31                 self.services = services
32                 self.offset = offset
33                 self.afterevent = afterevent
34                 self.exclude = exclude
35                 self.include = include
36                 self.maxduration = maxduration
37                 self.enabled = enabled
38                 self.destination = destination
39                 self.matchCount = matchCount
40                 self.matchLeft = matchLeft
41                 self.matchLimit = matchLimit
42                 self.matchFormatString = matchFormatString
43                 self.lastBegin = lastBegin
44                 self.justplay = justplay
45                 self.avoidDuplicateDescription = avoidDuplicateDescription
46
47         def calculateDayspan(self, begin, end):
48                 if end[0] < begin[0] or (end[0] == begin[0] and end[1] <= begin[1]):
49                         return (begin, end, True)
50                 else:
51                         return (begin, end, False)
52
53         def setTimespan(self, timespan):
54                 if timespan is None:
55                         self._timespan = (None,)
56                 else:
57                         self._timespan = self.calculateDayspan(*timespan)
58
59         def getTimespan(self):
60                 return self._timespan
61
62         timespan = property(getTimespan, setTimespan)
63
64         def setExclude(self, exclude):
65                 if exclude:
66                         self._exclude = (
67                                 [re_compile(x) for x in exclude[0]],
68                                 [re_compile(x) for x in exclude[1]], 
69                                 [re_compile(x) for x in exclude[2]], 
70                                 exclude[3]
71                         ) 
72                 else:
73                         self._exclude = ([], [], [], [])
74
75         def getExclude(self):
76                 return self._exclude
77
78         exclude = property(getExclude, setExclude)
79
80         def setInclude(self, include):
81                 if include:
82                         self._include = (
83                                 [re_compile(x) for x in include[0]],
84                                 [re_compile(x) for x in include[1]], 
85                                 [re_compile(x) for x in include[2]], 
86                                 include[3]
87                         ) 
88                 else:
89                         self._include = ([], [], [], [])
90
91         def getInclude(self):
92                 return self._include
93
94         include = property(getInclude, setInclude)
95
96         def setServices(self, services):
97                 if services:
98                         self._services = services
99                 else:
100                         self._services = []
101
102         def getServices(self):
103                 return self._services
104
105         services = property(getServices, setServices)
106
107         def setAfterEvent(self, afterevent):
108                 del self._afterevent[:]
109                 if len(afterevent):
110                         for definition in afterevent:
111                                 action, timespan = definition
112                                 if timespan is None:
113                                         self._afterevent.append((action, (None,)))
114                                 else:
115                                         self._afterevent.append((action, self.calculateDayspan(*timespan)))
116
117         def getCompleteAfterEvent(self):
118                 return self._afterevent
119
120         afterevent = property(getCompleteAfterEvent, setAfterEvent)
121
122         def hasTimespan(self):
123                 return self.timespan[0] is not None
124
125         def getTimespanBegin(self):
126                 return '%02d:%02d' % (self.timespan[0][0], self.timespan[0][1])
127
128         def getTimespanEnd(self):
129                 return '%02d:%02d' % (self.timespan[1][0], self.timespan[1][1])
130
131         def checkAnyTimespan(self, time, begin = None, end = None, haveDayspan = False):
132                 if begin is None:
133                         return False
134
135                 # Check if we span a day
136                 if haveDayspan:
137                         # Check if begin of event is later than our timespan starts
138                         if time.tm_hour > begin[0] or (time.tm_hour == begin[0] and time.tm_min >= begin[1]):
139                                 # If so, event is in our timespan
140                                 return False
141                         # Check if begin of event is earlier than our timespan end
142                         if time.tm_hour < end[0] or (time.tm_hour == end[0] and time.tm_min <= end[1]):
143                                 # If so, event is in our timespan
144                                 return False
145                         return True
146                 else:
147                         # Check if event begins earlier than our timespan starts 
148                         if time.tm_hour < begin[0] or (time.tm_hour == begin[0] and time.tm_min < begin[1]):
149                                 # Its out of our timespan then
150                                 return True
151                         # Check if event begins later than our timespan ends
152                         if time.tm_hour > end[0] or (time.tm_hour == end[0] and time.tm_min > end[1]):
153                                 # Its out of our timespan then
154                                 return True
155                         return False
156
157         def checkTimespan(self, begin):
158                 return self.checkAnyTimespan(begin, *self.timespan)
159
160         def hasDuration(self):
161                 return self.maxduration is not None
162
163         def getDuration(self):
164                 return self.maxduration/60
165
166         def checkDuration(self, length):
167                 if self.maxduration is None:
168                         return False
169                 return length > self.maxduration
170
171         def checkServices(self, service):
172                 if not len(self.services):
173                         return False
174                 return service not in self.services
175
176         def getExcludedTitle(self):
177                 return [x.pattern for x in self.exclude[0]]
178
179         def getExcludedShort(self):
180                 return [x.pattern for x in self.exclude[1]]
181
182         def getExcludedDescription(self):
183                 return [x.pattern for x in self.exclude[2]]
184
185         def getExcludedDays(self):
186                 return self.exclude[3]
187
188         def getIncludedTitle(self):
189                 return [x.pattern for x in self.include[0]]
190
191         def getIncludedShort(self):
192                 return [x.pattern for x in self.include[1]]
193
194         def getIncludedDescription(self):
195                 return [x.pattern for x in self.include[2]]
196
197         def getIncludedDays(self):
198                 return self.include[3]
199
200         def checkExcluded(self, title, short, extended, dayofweek):
201                 if len(self.exclude[3]):
202                         list = [x for x in self.exclude[3]]
203                         if "weekend" in list:
204                                 list.extend(["5", "6"])
205                         if "weekday" in list:
206                                 list.extend(["0", "1", "2", "3", "4"])
207                         if dayofweek in list:
208                                 return True
209
210                 for exclude in self.exclude[0]:
211                         if exclude.search(title):
212                                 return True
213                 for exclude in self.exclude[1]:
214                         if exclude.search(short):
215                                 return True
216                 for exclude in self.exclude[2]:
217                         if exclude.search(extended):
218                                 return True
219                 return False
220
221         def checkIncluded(self, title, short, extended, dayofweek):
222                 if len(self.include[3]):
223                         list = [x for x in self.include[3]]
224                         if "weekend" in list:
225                                 list.extend(["5", "6"])
226                         if "weekday" in list:
227                                 list.extend(["0", "1", "2", "3", "4"])
228                         if dayofweek not in list:
229                                 return True
230
231                 for include in self.include[0]:
232                         if not include.search(title):
233                                 return True
234                 for include in self.include[1]:
235                         if not include.search(short):
236                                 return True
237                 for include in self.include[2]:
238                         if not include.search(extended):
239                                 return True
240
241                 return False
242
243         def checkFilter(self, title, short, extended, dayofweek):
244                 if self.checkExcluded(title, short, extended, dayofweek):
245                         return True
246
247                 return self.checkIncluded(title, short, extended, dayofweek)
248
249         def hasOffset(self):
250                 return self.offset is not None
251
252         def isOffsetEqual(self):
253                 return self.offset[0] == self.offset[1]
254
255         def applyOffset(self, begin, end):
256                 if self.offset is None:
257                         return (begin, end)
258                 return (begin - self.offset[0], end + self.offset[1])
259
260         def getOffsetBegin(self):
261                 return self.offset[0]/60
262
263         def getOffsetEnd(self):
264                 return self.offset[1]/60
265
266         def hasAfterEvent(self):
267                 return len(self.afterevent)
268
269         def hasAfterEventTimespan(self):
270                 for afterevent in self.afterevent:
271                         if afterevent[1][0] is not None:
272                                 return True
273                 return False
274
275         def getAfterEventTimespan(self, end):
276                 for afterevent in self.afterevent:
277                         if not self.checkAnyTimespan(end, *afterevent[1]):
278                                 return afterevent[0]
279                 return None
280
281         def getAfterEvent(self):
282                 for afterevent in self.afterevent:
283                         if afterevent[1][0] is None:
284                                 return afterevent[0]
285                 return None
286
287         def getEnabled(self):
288                 return self.enabled and "yes" or "no"
289
290         def getJustplay(self):
291                 return self.justplay and "1" or "0"
292
293         def hasDestination(self):
294                 return self.destination is not None
295
296         def hasCounter(self):
297                 return self.matchCount != 0
298
299         def hasCounterFormatString(self):
300                 return self.matchFormatString != ''
301
302         def getCounter(self):
303                 return self.matchCount
304
305         def getCounterLeft(self):
306                 return self.matchLeft
307
308         def getCounterLimit(self):
309                 return self.matchLimit
310
311         def getCounterFormatString(self):
312                 return self.matchFormatString
313
314         def checkCounter(self, timestamp):
315                 # 0-Count is considered "unset"
316                 if self.matchCount == 0:
317                         return False
318
319                 # Check if event is in current timespan (we can only manage one!)
320                 limit = strftime(self.matchFormatString, timestamp)
321                 if limit != self.matchLimit:
322                         return True
323
324                 if self.matchLeft > 0:
325                         self.matchLeft -= 1
326                         return False
327                 return True
328
329         def update(self, begin, timestamp):
330                 # Only update limit when we have new begin
331                 if begin > self.lastBegin:
332                         self.lastBegin = begin
333
334                         # Update Counter:
335                         # %m is Month, %U is week (sunday), %W is week (monday)
336                         newLimit = strftime(self.matchFormatString, timestamp)
337
338                         if newLimit != self.matchLimit:
339                                 self.matchLeft = self.matchCount
340                                 self.matchLimit = newLimit
341
342         def getLastBegin(self):
343                 return self.lastBegin
344
345         def getAvoidDuplicateDescription(self):
346                 return self.avoidDuplicateDescription
347
348         def __repr__(self):
349                 return ''.join([
350                         '<AutomaticTimer ',
351                         self.name,
352                         ' (',
353                         ', '.join([
354                                         str(self.match),
355                                         str(self.timespan),
356                                         str(self.services),
357                                         str(self.offset),
358                                         str(self.afterevent),
359                                         str(self.exclude),
360                                         str(self.maxduration),
361                                         str(self.enabled),
362                                         str(self.destination),
363                                         str(self.matchCount),
364                                         str(self.matchLeft),
365                                         str(self.matchLimit),
366                                         str(self.matchFormatString),
367                                         str(self.lastBegin),
368                                         str(self.justplay)
369                          ]),
370                          ")>"
371                 ])