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