AutoTimer: add "Fast Scan" support
[vuplus_dvbapp-plugin] / autotimer / src / AutoTimerComponent.py
index 051d78a..363e8e6 100644 (file)
@@ -1,9 +1,15 @@
-# Format Counter
+# Format counter
 from time import strftime
 
 # regular expression
 from re import compile as re_compile
 
+# Alternatives and service restriction
+from enigma import eServiceReference, eServiceCenter
+
+# To get preferred component
+from Components.config import config
+
 class AutoTimerComponent(object):
        """AutoTimer Component which also handles validity checks"""
 
@@ -41,7 +47,8 @@ class AutoTimerComponent(object):
                        afterevent = [], exclude = None, maxduration = None, destination = None, \
                        include = None, matchCount = 0, matchLeft = 0, matchLimit = '', matchFormatString = '', \
                        lastBegin = 0, justplay = False, avoidDuplicateDescription = 0, bouquets = None, \
-                       tags = None, encoding = 'UTF-8', searchType = "partial", searchCase = "insensitive"):
+                       tags = None, encoding = 'UTF-8', searchType = "partial", searchCase = "insensitive", \
+                       overrideAlternatives = False):
                self.name = name
                self.match = match
                self.enabled = enabled
@@ -65,27 +72,21 @@ class AutoTimerComponent(object):
                self.encoding = encoding
                self.searchType = searchType
                self.searchCase = searchCase
+               self.overrideAlternatives = overrideAlternatives
 
 ### Attributes / Properties
 
        def setAfterEvent(self, afterevent):
                if afterevent is not self._afterevent:
                        del self._afterevent[:]
+               else:
+                       self._afterevent = []
 
-               Len = len(afterevent)
-               if Len:
-                       for x in range(0, Len):
-                               action, timespan = afterevent[x]
-
-                               # Remove original entry
-                               del afterevent[x]
-                               # If the second argument is a tuple we assume the entry is already parsed
-                               if isinstance(timespan, tuple):
-                                       self._afterevent.insert(x, (action, timespan))
-                               elif timespan is None:
-                                       self._afterevent.insert(x, (action, (None,)))
-                               else:
-                                       self._afterevent.insert(x, (action, self.calculateDayspan(*timespan)))
+               for action, timespan in afterevent:
+                       if timespan is None or timespan[0] is None:
+                               self._afterevent.append((action, (None,)))
+                       else:
+                               self._afterevent.append((action, self.calculateDayspan(*timespan)))
 
        afterevent = property(lambda self: self._afterevent, setAfterEvent)
 
@@ -150,7 +151,7 @@ class AutoTimerComponent(object):
        services = property(lambda self: self._services, setServices)
 
        def setTimespan(self, timespan):
-               if timespan is None or len(timespan) and timespan[0] is None:
+               if timespan is None or timespan and timespan[0] is None:
                        self._timespan = (None,)
                else:
                        self._timespan = self.calculateDayspan(*timespan)
@@ -181,7 +182,7 @@ class AutoTimerComponent(object):
                return self.maxduration is not None
 
        def hasTags(self):
-               return len(self.tags) > 0
+               return len(self.tags)
 
        def hasTimespan(self):
                return self.timespan[0] is not None
@@ -230,35 +231,6 @@ class AutoTimerComponent(object):
                        return False
 
        """
-        Returns a list of all allowed services by listing the bouquets
-       """
-       def getFullServices(self):
-               list = self.services[:]
-
-               from enigma import eServiceReference, eServiceCenter
-               serviceHandler = eServiceCenter.getInstance()
-               for bouquet in self.bouquets:
-                       myref = eServiceReference(str(bouquet))
-                       mylist = serviceHandler.list(myref)
-                       if mylist is not None:
-                               while 1:
-                                       s = mylist.getNext()
-                                       # TODO: I wonder if its sane to assume we get services here (and not just new lists)
-                                       # We can ignore markers & directorys here because they won't match any event's service :-)
-                                       if s.valid():
-                                               # strip all after last :
-                                               value = s.toString()
-                                               pos = value.rfind(':')
-                                               if pos != -1:
-                                                       value = value[:pos+1]
-
-                                               list.append(value)
-                                       else:
-                                               break
-
-               return list
-
-       """
         Called when a timer based on this component was added
        """
        def update(self, begin, timestamp):
@@ -316,6 +288,8 @@ class AutoTimerComponent(object):
        getOffsetBegin = lambda self: self.offset[0]/60
        getOffsetEnd = lambda self: self.offset[1]/60
 
+       getOverrideAlternatives = lambda self: self.overrideAlternatives and "1" or "0"
+
        getServices = lambda self: self._services
 
        getTags = lambda self: self.tags
@@ -353,14 +327,14 @@ class AutoTimerComponent(object):
                return length > self.maxduration
 
        def checkExcluded(self, title, short, extended, dayofweek):
-               if len(self.exclude[3]):
-                       list = [x for x in self.exclude[3]]
-                       if "weekend" in list:
-                               list.extend(["5", "6"])
-                       if "weekday" in list:
-                               list.extend(["0", "1", "2", "3", "4"])
+               if self.exclude[3]:
+                       list = self.exclude[3]
                        if dayofweek in list:
                                return True
+                       if "weekend" in list and dayofweek in ("5", "6"):
+                               return True
+                       if "weekday" in list and dayofweek in ("0", "1", "2", "3", "4"):
+                               return True
 
                for exclude in self.exclude[0]:
                        if exclude.search(title):
@@ -380,12 +354,12 @@ class AutoTimerComponent(object):
                return self.checkIncluded(title, short, extended, dayofweek)
 
        def checkIncluded(self, title, short, extended, dayofweek):
-               if len(self.include[3]):
-                       list = [x for x in self.include[3]]
+               if self.include[3]:
+                       list = self.include[3][:]
                        if "weekend" in list:
-                               list.extend(["5", "6"])
+                               list.extend(("5", "6"))
                        if "weekday" in list:
-                               list.extend(["0", "1", "2", "3", "4"])
+                               list.extend(("0", "1", "2", "3", "4"))
                        if dayofweek not in list:
                                return True
 
@@ -401,16 +375,22 @@ class AutoTimerComponent(object):
 
                return False
 
-       def checkServices(self, service):
+       def checkServices(self, check_service):
                services = self.services
                bouquets = self.bouquets
-               if len(services) or len(bouquets):
-                       if service in services:
-                               return False
+               if services or bouquets:
+                       addbouquets = []
+
+                       for service in services:
+                               if service == check_service:
+                                       return False
+
+                               myref = eServiceReference(str(service))
+                               if myref.flags & eServiceReference.isGroup:
+                                       addbouquets.append(service)
 
-                       from enigma import eServiceReference, eServiceCenter
                        serviceHandler = eServiceCenter.getInstance()
-                       for bouquet in bouquets:
+                       for bouquet in bouquets + addbouquets:
                                myref = eServiceReference(str(bouquet))
                                mylist = serviceHandler.list(myref)
                                if mylist is not None:
@@ -423,15 +403,48 @@ class AutoTimerComponent(object):
                                                        value = s.toString()
                                                        pos = value.rfind(':')
                                                        if pos != -1:
+                                                               if value[pos-1] == ':':
+                                                                       pos -= 1
                                                                value = value[:pos+1]
 
-                                                       if value == service:
+                                                       if value == check_service:
                                                                return False
                                                else:
                                                        break
                        return True
                return False
 
+       """
+       Return alternative service including a given ref.
+       Note that this only works for alternatives that the autotimer is restricted to.
+       """
+       def getAlternative(self, override_service):
+               services = self.services
+               if services:
+                       serviceHandler = eServiceCenter.getInstance()
+
+                       for service in services:
+                               myref = eServiceReference(str(service))
+                               if myref.flags & eServiceReference.isGroup:
+                                       mylist = serviceHandler.list(myref)
+                                       if mylist is not None:
+                                               while 1:
+                                                       s = mylist.getNext()
+                                                       if s.valid():
+                                                               # strip all after last :
+                                                               value = s.toString()
+                                                               pos = value.rfind(':')
+                                                               if pos != -1:
+                                                                       if value[pos-1] == ':':
+                                                                               pos -= 1
+                                                                       value = value[:pos+1]
+
+                                                               if value == override_service:
+                                                                       return service
+                                                       else:
+                                                               break
+               return override_service
+
        def checkTimespan(self, begin):
                return self.checkAnyTimespan(begin, *self.timespan)
 
@@ -478,7 +491,8 @@ class AutoTimerComponent(object):
                        tags = self.tags,
                        encoding = self.encoding,
                        searchType = self.searchType,
-                       searchCase = self.searchCase
+                       searchCase = self.searchCase,
+                       overrideAlternatives = self.overrideAlternatives
                )
 
        def __deepcopy__(self, memo):
@@ -506,7 +520,8 @@ class AutoTimerComponent(object):
                        tags = self.tags[:],
                        encoding = self.encoding,
                        searchType = self.searchType,
-                       searchCase = self.searchCase
+                       searchCase = self.searchCase,
+                       overrideAlternatives = self.overrideAlternatives
                )
 
        def __eq__(self, other):
@@ -523,11 +538,11 @@ class AutoTimerComponent(object):
                return not self.__eq__(other)
 
        def __repr__(self):
-               return ''.join([
+               return ''.join((
                        '<AutomaticTimer ',
                        self.name,
                        ' (',
-                       ', '.join([
+                       ', '.join((
                                        str(self.match),
                                        str(self.encoding),
                                        str(self.searchCase),
@@ -557,8 +572,100 @@ class AutoTimerComponent(object):
                                        str(self.justplay),
                                        str(self.avoidDuplicateDescription),
                                        str(self.bouquets),
-                                       str(self.tags)
-                        ]),
+                                       str(self.tags),
+                                       str(self.overrideAlternatives),
+                        )),
                         ")>"
-               ])
+               ))
+
+class AutoTimerFastscanComponent(AutoTimerComponent):
+       def __init__(self, *args, **kwargs):
+               AutoTimerComponent.__init__(self, *args, **kwargs)
+               self._fastServices = None
+
+       def setBouquets(self, bouquets):
+               AutoTimerComponent.setBouquets(self, bouquets)
+               self._fastServices = None
+
+       def setServices(self, services):
+               AutoTimerComponent.setServices(self, services)
+               self._fastServices = None
+
+       def getFastServices(self):
+               if self._fastServices is None:
+                       fastServices = []
+                       append = fastServices.append
+                       addbouquets = []
+                       for service in self.services:
+                               myref = eServiceReference(str(service))
+                               if myref.flags & eServiceReference.isGroup:
+                                       addbouquets.append(service)
+                               else:
+                                       comp = service.split(':')
+                                       append(':'.join(comp[3:]))
+
+                       serviceHandler = eServiceCenter.getInstance()
+                       for bouquet in bouquets + addbouquets:
+                               myref = eServiceReference(str(bouquet))
+                               mylist = serviceHandler.list(myref)
+                               if mylist is not None:
+                                       while 1:
+                                               s = mylist.getNext()
+                                               # TODO: I wonder if its sane to assume we get services here (and not just new lists)
+                                               # We can ignore markers & directorys here because they won't match any event's service :-)
+                                               if s.valid():
+                                                       # strip all after last :
+                                                       value = s.toString()
+                                                       pos = value.rfind(':')
+                                                       if pos != -1:
+                                                               if value[pos-1] == ':':
+                                                                       pos -= 1
+                                                               value = value[:pos+1]
+
+                                                       comp = value.split(':')
+                                                       append(':'.join(value[3:]))
+                                               else:
+                                                       break
+                       self._fastServices = fastServices
+               return self._fastServices
+
+       def checkServices(self, check_service):
+               services = self.getFastServices()
+               if services:
+                       check = ':'.join(check_service.split(':')[3:])
+                       for service in services:
+                               if service == check:
+                                       return False # included
+                       return True # not included
+               return False # no restriction
+
+       def getAlternative(self, override_service):
+               services = self.services
+               if services:
+                       override = ':'.join(override_service.split(':')[3:])
+                       serviceHandler = eServiceCenter.getInstance()
 
+                       for service in services:
+                               myref = eServiceReference(str(service))
+                               if myref.flags & eServiceReference.isGroup:
+                                       mylist = serviceHandler.list(myref)
+                                       if mylist is not None:
+                                               while 1:
+                                                       s = mylist.getNext()
+                                                       if s.valid():
+                                                               # strip all after last :
+                                                               value = s.toString()
+                                                               pos = value.rfind(':')
+                                                               if pos != -1:
+                                                                       if value[pos-1] == ':':
+                                                                               pos -= 1
+                                                                       value = value[:pos+1]
+
+                                                               if ':'.join(value.split(':')[3:]) == override:
+                                                                       return service
+                                                       else:
+                                                               break
+               return override_service
+
+# very basic factory ;-)
+preferredAutoTimerComponent = lambda *args, **kwargs: AutoTimerFastscanComponent(*args, **kwargs) if config.plugins.autotimer.fastscan.value else AutoTimerComponent(*args, **kwargs)