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