AutoTimer: add "Fast Scan" support
[vuplus_dvbapp-plugin] / autotimer / src / AutoTimerEditor.py
index d389dff..0d623de 100644 (file)
@@ -1,7 +1,12 @@
+# -*- coding: UTF-8 -*-
+# for localized messages
+from . import _
+
 # GUI (Screens)
 from Screens.Screen import Screen
 from Components.ConfigList import ConfigListScreen
 from Screens.ChannelSelection import SimpleChannelSelection
+from Screens.EpgSelection import EPGSelection
 from Screens.MessageBox import MessageBox
 from Screens.ChoiceBox import ChoiceBox
 
@@ -10,10 +15,12 @@ from Screens.Setup import SetupSummary
 
 # GUI (Components)
 from Components.ActionMap import ActionMap
-from Components.Button import Button
+from Components.Sources.StaticText import StaticText
 
 # Configuration
-from Components.config import getConfigListEntry, ConfigEnableDisable, ConfigYesNo, ConfigText, ConfigClock, ConfigInteger, ConfigSelection
+from Components.config import getConfigListEntry, ConfigEnableDisable, \
+       ConfigYesNo, ConfigText, ConfigClock, ConfigNumber, ConfigSelection, \
+       config, NoSave
 
 # Timer
 from RecordTimer import AFTEREVENT
@@ -24,134 +31,160 @@ from time import localtime, mktime
 # Show ServiceName instead of ServiceReference
 from ServiceReference import ServiceReference
 
-weekdays = [("0", _("Monday")), ("1", _("Tuesday")),  ("2", _("Wednesday")),  ("3", _("Thursday")),  ("4", _("Friday")),  ("5", _("Saturday")),  ("6", _("Sunday")), ("weekend", _("Weekend"))]
+# addAutotimerFromService, AutoTimerChannelSelection
+from enigma import eServiceCenter, eServiceReference, iServiceInformation
+
+# Default Record Directory
+from Tools import Directories
+
+# Tags
+from Screens.MovieSelection import getPreferredTagEditor
+
+weekdays = [
+       ("0", _("Monday")),
+       ("1", _("Tuesday")),
+       ("2", _("Wednesday")),
+       ("3", _("Thursday")),
+       ("4", _("Friday")),
+       ("5", _("Saturday")),
+       ("6", _("Sunday")),
+       ("weekend", _("Weekend")),
+       ("weekday", _("Weekday"))
+]
+
+class ExtendedConfigText(ConfigText):
+       def __init__(self, default = "", fixed_size = True, visible_width = False):
+               ConfigText.__init__(self, default = default, fixed_size = fixed_size, visible_width = visible_width)
+
+               # Workaround some characters currently not "typeable" using NumericalTextInput
+               mapping = self.mapping
+               if mapping:
+                       if "&" not in mapping[0]:
+                               mapping[0] += "&"
+                       if ";" not in mapping[0]:
+                               mapping[0] += ";"
+                       if "%" not in mapping[0]:
+                               mapping[0] += "%"
+
+class SimpleBouquetSelection(SimpleChannelSelection):
+       def __init__(self, session, title):
+               SimpleChannelSelection.__init__(self, session, title)
+               self.skinName = "SimpleChannelSelection"
+
+       def channelSelected(self):
+               ref = self.getCurrentSelection()
+               if (ref.flags & 7) == 7:
+                       self.close(ref)
+               else:
+                       # We return the currently active path here
+                       # Asking the user if this is what he wants might be better though
+                       self.close(self.servicePath[-1])
 
-class AutoTimerEditor(Screen, ConfigListScreen):
-       """Edit AutoTimer"""
+class AutoTimerChannelSelection(SimpleChannelSelection):
+       def __init__(self, session, autotimer):
+               SimpleChannelSelection.__init__(self, session, _("Channel Selection"))
+               self.skinName = "SimpleChannelSelection"
+               self.autotimer = autotimer
 
-       skin = """<screen name="AutoTimerEdit" title="Edit AutoTimer" position="75,155" size="565,280">
-               <widget name="config" position="5,5" size="555,225" scrollbarMode="showOnDemand" />
-               <ePixmap position="0,235" zPosition="4" size="140,40" pixmap="skin_default/key-red.png" transparent="1" alphatest="on" />
-               <ePixmap position="140,235" zPosition="4" size="140,40" pixmap="skin_default/key-green.png" transparent="1" alphatest="on" />
-               <ePixmap position="280,235" zPosition="4" size="140,40" pixmap="skin_default/key-yellow.png" transparent="1" alphatest="on" />
-               <ePixmap position="420,235" zPosition="4" size="140,40" pixmap="skin_default/key-blue.png" transparent="1" alphatest="on" />
-               <widget name="key_red" position="0,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-               <widget name="key_green" position="140,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-               <widget name="key_yellow" position="280,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-               <widget name="key_blue" position="420,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-       </screen>"""
+               self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
+                       {
+                               "showEPGList": self.channelSelected
+                       }
+               )
 
-       def __init__(self, session, timer):
-               Screen.__init__(self, session)
+       def channelSelected(self):
+               ref = self.getCurrentSelection()
+               if (ref.flags & 7) == 7:
+                       self.enterPath(ref)
+               elif not (ref.flags & eServiceReference.isMarker):
+                       self.session.open(
+                               AutoTimerEPGSelection,
+                               ref
+                       )
 
+class AutoTimerEPGSelection(EPGSelection):
+       def __init__(self, *args):
+               EPGSelection.__init__(self, *args)
+               self.skinName = "EPGSelection"
+
+       def infoKeyPressed(self):
+               self.timerAdd()
+
+       def timerAdd(self):
+               cur = self["list"].getCurrent()
+               evt = cur[0]
+               sref = cur[1]
+               if not evt:
+                       return
+
+               addAutotimerFromEvent(self.session, evt = evt, service = sref)
+
+       def onSelectionChanged(self):
+               pass
+
+class AutoTimerEditorBase:
+       """ Base Class for all Editors """
+       def __init__(self, timer, editingDefaults = False):
                # Keep Timer
                self.timer = timer
-
-               # Summary
-               self.setup_title = "AutoTimer Editor"
-               self.onChangedEntry = []
+               self.editingDefaults = editingDefaults
 
                # See if we are filtering some strings
-               self.excludes = (
+               excludes = (
                        timer.getExcludedTitle(),
                        timer.getExcludedShort(),
                        timer.getExcludedDescription(),
                        timer.getExcludedDays()
                )
-               self.includes = (
+               includes = (
                        timer.getIncludedTitle(),
                        timer.getIncludedShort(),
                        timer.getIncludedDescription(),
                        timer.getIncludedDays()
                )
-               if len(self.excludes[0]) or len(self.excludes[1]) or len(self.excludes[2]) \
-                               or len(self.excludes[3]) or len(self.includes[0]) or len(self.includes[1]) \
-                               or len(self.includes[2]) or len(self.includes[3]):
+               if excludes[0] or excludes[1] \
+                               or excludes[2] or excludes[3] \
+                               or includes[0] or includes[1] \
+                               or includes[2] or includes[3]:
                        self.filterSet = True
                else:
                        self.filterSet = False
+               self.excludes = excludes
+               self.includes = includes
 
                # See if services are restricted
-               self.services = timer.getServices()
-               if len(self.services):
+               self.services = timer.services
+               self.bouquets = timer.bouquets
+               if self.services or self.bouquets:
                        self.serviceRestriction = True
                else:
                        self.serviceRestriction = False
 
                self.createSetup(timer)
 
-               # We might need to change shown items, so add some notifiers
-               self.timespan.addNotifier(self.reloadList, initial_call = False)
-               self.offset.addNotifier(self.reloadList, initial_call = False)
-               self.duration.addNotifier(self.reloadList, initial_call = False)
-               self.afterevent.addNotifier(self.reloadList, initial_call = False)
-               self.afterevent_timespan.addNotifier(self.reloadList, initial_call = False)
-               self.counter.addNotifier(self.reloadList, initial_call = False)
-
-               self.refresh()
-
-               ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
-
-               # Initialize Buttons
-               self["key_red"] = Button(_("Cancel"))
-               self["key_green"] = Button(_("OK"))
-               self["key_yellow"] = Button()
-               self["key_blue"] = Button()
-
-               # Set Button texts
-               self.renameChannelButton()
-               self.renameFilterButton()
-
-               # Define Actions
-               self["actions"] = ActionMap(["SetupActions", "ColorActions"],
-                       {
-                               "cancel": self.cancel,
-                               "save": self.maybeSave,
-                               "yellow": self.editFilter,
-                               "blue": self.editChannels
-                       }
-               )
-
-               # Trigger change
-               self.changed()
-
-       def renameFilterButton(self):
-               if self.filterSet:
-                       self["key_yellow"].setText(_("Edit Filters"))
-               else:
-                       self["key_yellow"].setText(_("Add Filters"))
-
-       def renameChannelButton(self):
-               if self.serviceRestriction:
-                       self["key_blue"].setText(_("Edit Channels"))
-               else:
-                       self["key_blue"].setText(_("Add Channels"))
-
-       def changed(self):
-               for x in self.onChangedEntry:
-                       try:
-                               x()
-                       except:
-                               pass
-
-       def getCurrentEntry(self):
-               return self["config"].getCurrent()[0]
-
-       def getCurrentValue(self):
-               return str(self["config"].getCurrent()[1].getText())
-
-       def createSummary(self):
-               return SetupSummary
-
        def createSetup(self, timer):
                # Name
-               self.name = ConfigText(default = timer.name, fixed_size = False)
+               self.name = NoSave(ExtendedConfigText(default = timer.name, fixed_size = False))
 
                # Match
-               self.match = ConfigText(default = timer.match, fixed_size = False)
+               self.match = NoSave(ExtendedConfigText(default = timer.match, fixed_size = False))
+
+               # Encoding
+               default = timer.encoding
+               selection = ['UTF-8', 'ISO8859-15']
+               if default not in selection:
+                       selection.append(default)
+               self.encoding = NoSave(ConfigSelection(choices = selection, default = default))
+
+               # ...
+               self.searchType = NoSave(ConfigSelection(choices = [("partial", _("partial match")), ("exact", _("exact match"))], default = timer.searchType))
+               self.searchCase = NoSave(ConfigSelection(choices = [("sensitive", _("case-sensitive search")), ("insensitive", _("case-insensitive search"))], default = timer.searchCase))
+
+               # Alternatives override
+               self.overrideAlternatives = NoSave(ConfigYesNo(default = timer.overrideAlternatives))
 
                # Justplay
-               self.justplay = ConfigSelection(choices = [("zap", _("zap")), ("record", _("record"))], default = {0: "record", 1: "zap"}[int(timer.justplay)])
+               self.justplay = NoSave(ConfigSelection(choices = [("zap", _("zap")), ("record", _("record"))], default = {0: "record", 1: "zap"}[int(timer.justplay)]))
 
                # Timespan
                now = [x for x in localtime()]
@@ -171,9 +204,9 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                        now[3] = 23
                        now[4] = 15
                        end = mktime(now)
-               self.timespan = ConfigEnableDisable(default = default)
-               self.timespanbegin = ConfigClock(default = begin)
-               self.timespanend = ConfigClock(default = end)
+               self.timespan = NoSave(ConfigEnableDisable(default = default))
+               self.timespanbegin = NoSave(ConfigClock(default = begin))
+               self.timespanend = NoSave(ConfigClock(default = end))
 
                # Services have their own Screen
 
@@ -186,16 +219,26 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                        default = False
                        begin = 5
                        end = 5
-               self.offset = ConfigEnableDisable(default = default)
-               self.offsetbegin = ConfigInteger(default = begin, limits = (0, 60))
-               self.offsetend = ConfigInteger(default = end, limits = (0, 60))
+               self.offset = NoSave(ConfigEnableDisable(default = default))
+               self.offsetbegin = NoSave(ConfigNumber(default = begin))
+               self.offsetend = NoSave(ConfigNumber(default = end))
 
                # AfterEvent
                if timer.hasAfterEvent():
-                       afterevent = { None: "default", AFTEREVENT.NONE: "nothing", AFTEREVENT.DEEPSTANDBY: "deepstandby", AFTEREVENT.STANDBY: "standby"}[timer.afterevent[0][0]]
+                       default = {
+                               None: "default",
+                               AFTEREVENT.NONE: "nothing",
+                               AFTEREVENT.DEEPSTANDBY: "deepstandby",
+                               AFTEREVENT.STANDBY: "standby",
+                               AFTEREVENT.AUTO: "auto"
+                       }[timer.afterevent[0][0]]
                else:
-                       afterevent = "default"
-               self.afterevent = ConfigSelection(choices = [("default", _("standard")), ("nothing", _("do nothing")), ("standby", _("go to standby")), ("deepstandby", _("go to deep standby"))], default = afterevent)
+                       default = "default"
+               self.afterevent = NoSave(ConfigSelection(choices = [
+                       ("default", _("standard")), ("nothing", _("do nothing")),
+                       ("standby", _("go to standby")),
+                       ("deepstandby", _("go to deep standby")),
+                       ("auto", _("auto"))], default = default))
 
                # AfterEvent (Timespan)
                if timer.hasAfterEvent() and timer.afterevent[0][1][0] is not None:
@@ -214,12 +257,12 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                        now[3] = 7
                        now[4] = 0
                        end = mktime(now)
-               self.afterevent_timespan = ConfigEnableDisable(default = default)
-               self.afterevent_timespanbegin = ConfigClock(default = begin)
-               self.afterevent_timespanend = ConfigClock(default = end)
+               self.afterevent_timespan = NoSave(ConfigEnableDisable(default = default))
+               self.afterevent_timespanbegin = NoSave(ConfigClock(default = begin))
+               self.afterevent_timespanend = NoSave(ConfigClock(default = end))
 
                # Enabled
-               self.enabled = ConfigYesNo(default = timer.enabled)
+               self.enabled = NoSave(ConfigYesNo(default = timer.enabled))
 
                # Maxduration
                if timer.hasDuration():
@@ -228,79 +271,291 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                else:
                        default = False
                        duration =70
-               self.duration = ConfigEnableDisable(default = default)
-               self.durationlength = ConfigInteger(default = duration, limits = (0, 600))
+               self.duration = NoSave(ConfigEnableDisable(default = default))
+               self.durationlength = NoSave(ConfigNumber(default = duration))
 
                # Counter
                if timer.hasCounter():
                        default = timer.matchCount
                else:
                        default = 0
-               self.counter = ConfigInteger(default = default, limits = (0, 50))
-               self.counterLeft = ConfigInteger(default = timer.matchLeft, limits = (0, 50))
+               self.counter = NoSave(ConfigNumber(default = default))
+               self.counterLeft = NoSave(ConfigNumber(default = timer.matchLeft))
+               default = timer.getCounterFormatString()
                selection = [("", _("Never")), ("%m", _("Monthly")), ("%U", _("Weekly (Sunday)")), ("%W", _("Weekly (Monday)"))]
-               if timer.getCounterFormatString() not in ["", "%m", "%U", "%W"]:
-                       selection.append((timer.getCounterFormatString(), _("Custom")))
-               self.counterFormatString = ConfigSelection(selection, default = timer.getCounterFormatString())
+               if default not in ('', '%m', '%U', '%W'):
+                       selection.append((default, _("Custom (%s)") % (default)))
+               self.counterFormatString = NoSave(ConfigSelection(selection, default = default))
 
                # Avoid Duplicate Description
-               self.avoidDuplicateDescription = ConfigEnableDisable(default = timer.getAvoidDuplicateDescription())
+               self.avoidDuplicateDescription = NoSave(ConfigSelection([
+                               ("0", _("No")),
+                               ("1", _("On same service")),
+                               ("2", _("On any service")),
+                       ],
+                       default = str(timer.getAvoidDuplicateDescription())
+               ))
+
+               # Custom Location
+               if timer.hasDestination():
+                       default = True
+               else:
+                       default = False
+
+               self.useDestination = NoSave(ConfigYesNo(default = default))
+
+               default = timer.destination or Directories.resolveFilename(Directories.SCOPE_HDD)
+               choices = config.movielist.videodirs.value
+
+               if default not in choices:
+                       choices.append(default)
+               self.destination = NoSave(ConfigSelection(default = default, choices = choices))
+
+               # Tags
+               self.timerentry_tags = timer.tags
+               self.tags = NoSave(ConfigSelection(choices = [len(self.timerentry_tags) == 0 and _("None") or ' '.join(self.timerentry_tags)]))
+
+       def pathSelected(self, res):
+               if res is not None:
+                       # I'm pretty sure this will always fail
+                       if config.movielist.videodirs.value != self.destination.choices:
+                                       self.destination.setChoices(config.movielist.videodirs.value, default = res)
+                       self.destination.value = res
+
+       def chooseDestination(self):
+               from Screens.LocationBox import MovieLocationBox
+
+               self.session.openWithCallback(
+                       self.pathSelected,
+                       MovieLocationBox,
+                       _("Choose target folder"),
+                       self.destination.value,
+                       minFree = 100 # Same requirement as in Screens.TimerEntry
+               )
+
+       def tagEditFinished(self, ret):
+               if ret is not None:
+                       self.timerentry_tags = ret
+                       self.tags.setChoices([len(ret) == 0 and _("None") or ' '.join(ret)])
+
+       def chooseTags(self):
+               preferredTagEditor = getPreferredTagEditor()
+               if preferredTagEditor:
+                       self.session.openWithCallback(
+                               self.tagEditFinished,
+                               preferredTagEditor,
+                               self.timerentry_tags
+                       )
+
+class AutoTimerEditor(Screen, ConfigListScreen, AutoTimerEditorBase):
+       """Edit AutoTimer"""
+
+       skin = """<screen name="AutoTimerEditor" title="Edit AutoTimer" position="center,center" size="565,350">
+               <ePixmap position="0,5" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+               <ePixmap position="140,5" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+               <ePixmap position="280,5" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+               <ePixmap position="420,5" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+               <widget source="key_red" render="Label" position="0,5" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget source="key_green" render="Label" position="140,5" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget source="key_yellow" render="Label" position="280,5" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget source="key_blue" render="Label" position="420,5" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget name="config" position="5,50" size="555,225" scrollbarMode="showOnDemand" />
+               <ePixmap pixmap="skin_default/div-h.png" position="0,275" zPosition="1" size="565,2" />
+               <widget source="help" render="Label" position="5,280" size="555,63" font="Regular;21" />
+       </screen>"""
+
+       def __init__(self, session, timer, editingDefaults = False):
+               Screen.__init__(self, session)
+
+               AutoTimerEditorBase.__init__(self, timer, editingDefaults)
+
+               # Summary
+               self.setup_title = _("AutoTimer Editor")
+               self.onChangedEntry = []
+
+               # We might need to change shown items, so add some notifiers
+               self.timespan.addNotifier(self.reloadList, initial_call = False)
+               self.offset.addNotifier(self.reloadList, initial_call = False)
+               self.duration.addNotifier(self.reloadList, initial_call = False)
+               self.afterevent.addNotifier(self.reloadList, initial_call = False)
+               self.afterevent_timespan.addNotifier(self.reloadList, initial_call = False)
+               self.counter.addNotifier(self.reloadList, initial_call = False)
+               self.useDestination.addNotifier(self.reloadList, initial_call = False)
+
+               self.refresh()
+               self.initHelpTexts()
+
+               # XXX: no help for numericaltextinput since it is shown on top of our help
+               ConfigListScreen.__init__(self, self.list, on_change = self.changed)
+               self["config"].onSelectionChanged.append(self.updateHelp)
+
+               # Initialize Buttons
+               self["key_red"] = StaticText(_("Cancel"))
+               self["key_green"] = StaticText(_("OK"))
+               self["key_yellow"] = StaticText()
+               self["key_blue"] = StaticText()
+
+               self["help"] = StaticText()
+
+               # Set Button texts
+               self.renameServiceButton()
+               self.renameFilterButton()
+
+               # Define Actions
+               self["actions"] = ActionMap(["SetupActions", "ColorActions"],
+                       {
+                               "cancel": self.cancel,
+                               "save": self.maybeSave,
+                               "ok": self.ok,
+                               "yellow": self.editFilter,
+                               "blue": self.editServices
+                       }, -2
+               )
+
+               # Trigger change
+               self.changed()
+
+               self.onLayoutFinish.append(self.setCustomTitle)
+
+       def setCustomTitle(self):
+               self.setTitle(_("Edit AutoTimer"))
+
+       def renameFilterButton(self):
+               if self.filterSet:
+                       self["key_yellow"].text = _("edit filters")
+               else:
+                       self["key_yellow"].text = _("add filters")
+
+       def renameServiceButton(self):
+               if self.serviceRestriction:
+                       self["key_blue"].text = _("edit services")
+               else:
+                       self["key_blue"].text = _("add services")
+
+       def updateHelp(self):
+               cur = self["config"].getCurrent()
+               if cur:
+                       self["help"].text = self.helpDict[cur[1]]
+
+       def changed(self):
+               for x in self.onChangedEntry:
+                       try:
+                               x()
+                       except Exception:
+                               pass
+
+       def getCurrentEntry(self):
+               return self["config"].getCurrent()[0]
+
+       def getCurrentValue(self):
+               return str(self["config"].getCurrent()[1].getText())
+
+       def createSummary(self):
+               return SetupSummary
+
+       def initHelpTexts(self):
+               self.helpDict = {
+                       self.enabled: _("Set this NO to disable this AutoTimer."),
+                       self.name: _("This is a name you can give the AutoTimer. It will be shown in the Overview and the Preview."),
+                       self.match: _("This is what will be looked for in event titles. Note that looking for e.g. german umlauts can be tricky as you have to know the encoding the channel uses."),
+                       self.encoding: _("Encoding the channel uses for it's EPG data. You only need to change this if you're searching for special characters like the german umlauts."),
+                       self.searchType: _("Select \"exact match\" to enforce \"Match title\" to match exactly or \"partial match\" if you only want to search for a part of the event title."),
+                       self.searchCase: _("Select whether or not you want to enforce case correctness."),
+                       self.justplay: _("Add zap timer instead of record timer?"),
+                       self.overrideAlternatives: _("With this option enabled the channel to record on can be changed to a alternative service it is restricted to."),
+                       self.timespan: _("Should this AutoTimer be restricted to a timespan?"),
+                       self.timespanbegin: _("Lower bound of timespan. Nothing before this time will be matched. Offsets are not taken into account!"),
+                       self.timespanend: _("Upper bound of timespan. Nothing after this time will be matched. Offsets are not taken into account!"),
+                       self.offset: _("Change default recording offset?"),
+                       self.offsetbegin: _("Time in minutes to prepend to recording."),
+                       self.offsetend: _("Time in minutes to append to recording."),
+                       self.duration: _("Should this AutoTimer only match up to a certain event duration?"),
+                       self.durationlength: _("Maximum event duration to match. If an event is longer than this ammount of time (without offset) it won't be matched."),
+                       self.afterevent: _("Power state to change to after recordings. Select \"standard\" to not change the default behavior of enigma2 or values changed by yourself."),
+                       self.afterevent_timespan: _("Restrict \"after event\" to a certain timespan?"),
+                       self.afterevent_timespanbegin: _("Lower bound of timespan."),
+                       self.afterevent_timespanend: _("Upper bound of timespan."),
+                       self.counter: _("With this option you can restrict the AutoTimer to a certain ammount of scheduled recordings. Set this to 0 to disable this functionality."),
+                       self.counterLeft: _("Number of scheduled recordings left."),
+                       self.counterFormatString: _("The counter can automatically be reset to the limit at certain intervals."),
+                       self.avoidDuplicateDescription: _("When this option is enabled the AutoTimer won't match events where another timer with the same description already exists in the timer list."),
+                       self.useDestination: _("Should timers created by this AutoTimer be recorded to a custom location?"),
+                       self.destination: _("Select the location to save the recording to."),
+                       self.tags: _("Tags the Timer/Recording will have."),
+               }
 
        def refresh(self):
-               # First four entries are always shown
-               self.list = [
-                       getConfigListEntry(_("Enabled"), self.enabled),
-                       getConfigListEntry(_("Description"), self.name),
-                       getConfigListEntry(_("Match Title"), self.match),
-                       getConfigListEntry(_("Timer Type"), self.justplay),
-                       getConfigListEntry(_("Only match during Timespan"), self.timespan)
-               ]
+               # First three entries are only showed when not editing defaults
+               list = []
+               if not self.editingDefaults:
+                       list.extend((
+                               getConfigListEntry(_("Enabled"), self.enabled),
+                               getConfigListEntry(_("Description"), self.name),
+                               getConfigListEntry(_("Match title"), self.match),
+                       ))
+
+               list.extend((
+                       getConfigListEntry(_("EPG encoding"), self.encoding),
+                       getConfigListEntry(_("Search type"), self.searchType),
+                       getConfigListEntry(_("Search strictness"), self.searchCase),
+                       getConfigListEntry(_("Timer type"), self.justplay),
+                       getConfigListEntry(_("Override found with alternative service"), self.overrideAlternatives),
+                       getConfigListEntry(_("Only match during timespan"), self.timespan)
+               ))
 
                # Only allow editing timespan when it's enabled
                if self.timespan.value:
-                       self.list.extend([
-                               getConfigListEntry(_("Begin of Timespan"), self.timespanbegin),
-                               getConfigListEntry(_("End of Timespan"), self.timespanend)
-                       ])
+                       list.extend((
+                               getConfigListEntry(_("Begin of timespan"), self.timespanbegin),
+                               getConfigListEntry(_("End of timespan"), self.timespanend)
+                       ))
 
-               self.list.append(getConfigListEntry(_("Custom offset"), self.offset))
+               list.append(getConfigListEntry(_("Custom offset"), self.offset))
 
                # Only allow editing offsets when it's enabled
                if self.offset.value:
-                       self.list.extend([
+                       list.extend((
                                getConfigListEntry(_("Offset before recording (in m)"), self.offsetbegin),
                                getConfigListEntry(_("Offset after recording (in m)"), self.offsetend)
-                       ])
+                       ))
 
-               self.list.append(getConfigListEntry(_("Set maximum Duration"), self.duration))
+               list.append(getConfigListEntry(_("Set maximum duration"), self.duration))
 
                # Only allow editing maxduration when it's enabled
                if self.duration.value:
-                       self.list.extend([
-                               getConfigListEntry(_("Maximum Duration (in m)"), self.durationlength)
-                       ])
+                       list.append(getConfigListEntry(_("Maximum duration (in m)"), self.durationlength))
 
-               self.list.append(getConfigListEntry(_("After event"), self.afterevent))
+               list.append(getConfigListEntry(_("After event"), self.afterevent))
 
                # Only allow setting afterevent timespan when afterevent is active
                if self.afterevent.value != "default":
-                       self.list.append(getConfigListEntry(_("Execute after Event during Timespan"), self.afterevent_timespan))
+                       list.append(getConfigListEntry(_("Execute \"after event\" during timespan"), self.afterevent_timespan))
 
                        # Only allow editing timespan when it's enabled
                        if self.afterevent_timespan.value:
-                               self.list.extend([
-                                       getConfigListEntry(_("Begin of after Event Timespan"), self.afterevent_timespanbegin),
-                                       getConfigListEntry(_("End of after Event Timespan"), self.afterevent_timespanend)
-                               ])
+                               list.extend((
+                                       getConfigListEntry(_("Begin of \"after event\" timespan"), self.afterevent_timespanbegin),
+                                       getConfigListEntry(_("End of \"after event\" timespan"), self.afterevent_timespanend)
+                               ))
 
-               self.list.append(getConfigListEntry(_("Record a maximum of x times"), self.counter))
+               list.append(getConfigListEntry(_("Record a maximum of x times"), self.counter))
 
                # Only allow setting matchLeft when counting hits
                if self.counter.value:
-                       self.list.append(getConfigListEntry(_("Ammount of recordings left"), self.counterLeft))
-                       self.list.append(getConfigListEntry(_("Reset Count"), self.counterFormatString))
+                       if not self.editingDefaults:
+                               list.append(getConfigListEntry(_("Ammount of recordings left"), self.counterLeft))
+                       list.append(getConfigListEntry(_("Reset count"), self.counterFormatString))
+
+               list.append(getConfigListEntry(_("Require description to be unique"), self.avoidDuplicateDescription))
+
+               # We always add this option though its expert only in enigma2
+               list.append(getConfigListEntry(_("Use a custom location"), self.useDestination))
+               if self.useDestination.value:
+                       list.append(getConfigListEntry(_("Custom location"), self.destination))
+
+               list.append(getConfigListEntry(_("Tags"), self.tags))
 
-               self.list.append(getConfigListEntry(_("Require Description to be unique"), self.avoidDuplicateDescription))
+               self.list = list
 
        def reloadList(self, value):
                self.refresh()
@@ -322,23 +577,55 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                        self.includes = ret[2]
                        self.renameFilterButton()
 
-       def editChannels(self):
+       def editServices(self):
                self.session.openWithCallback(
-                       self.editChannelsCallback,
-                       AutoTimerChannelEditor,
+                       self.editServicesCallback,
+                       AutoTimerServiceEditor,
                        self.serviceRestriction,
-                       self.services
+                       self.services,
+                       self.bouquets
                )
 
-       def editChannelsCallback(self, ret):
+       def editServicesCallback(self, ret):
                if ret:
                        self.serviceRestriction = ret[0]
-                       self.services = ret[1]
-                       self.renameChannelButton()
+                       self.services = ret[1][0]
+                       self.bouquets = ret[1][1]
+                       self.renameServiceButton()
+
+       def keyLeft(self):
+               cur = self["config"].getCurrent()
+               cur = cur and cur[1]
+               if cur == self.tags:
+                       self.chooseTags()
+               else:
+                       ConfigListScreen.keyLeft(self)
+
+       def keyRight(self):
+               cur = self["config"].getCurrent()
+               cur = cur and cur[1]
+               if cur == self.tags:
+                       self.chooseTags()
+               else:
+                       ConfigListScreen.keyRight(self)
+
+       def ok(self):
+               cur = self["config"].getCurrent()
+               cur = cur and cur[1]
+               if cur == self.destination:
+                       self.chooseDestination()
+               elif cur == self.tags:
+                       self.chooseTags()
+               else:
+                       ConfigListScreen.keyOK(self)
 
        def cancel(self):
                if self["config"].isChanged():
-                       self.session.openWithCallback(self.cancelConfirm, MessageBox, _("Really close without saving settings?"))
+                       self.session.openWithCallback(
+                               self.cancelConfirm,
+                               MessageBox,
+                               _("Really close without saving settings?")
+                       )
                else:
                        self.close(None)
 
@@ -347,8 +634,19 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                        self.close(None)
 
        def maybeSave(self):
+               if self.editingDefaults:
+                       self.save()
+                       return
+               # Check if any match is set
+               if not self.match.value.strip():
+                       self.session.open(
+                                       MessageBox,
+                                       _("The match attribute is mandatory."),
+                                       type = MessageBox.TYPE_ERROR,
+                                       timeout = 5
+                       )
                # Check if we have a trailing whitespace
-               if self.match.value[-1:] == " ":
+               elif self.match.value[-1:] == " ":
                        self.session.openWithCallback(
                                self.saveCallback,
                                MessageBox,
@@ -370,7 +668,17 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                self.timer.match = self.match.value
 
                # Name
-               self.timer.name = self.name.value or self.timer.match
+               self.timer.name = self.name.value.strip() or self.timer.match
+
+               # Encoding
+               self.timer.encoding = self.encoding.value
+
+               # ...
+               self.timer.searchType = self.searchType.value
+               self.timer.searchCase = self.searchCase.value
+
+               # Alternatives
+               self.timer.overrideAlternatives = self.overrideAlternatives.value
 
                # Enabled
                self.timer.enabled = self.enabled.value
@@ -389,8 +697,10 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                # Services
                if self.serviceRestriction:
                        self.timer.services = self.services
+                       self.timer.bouquets = self.bouquets
                else:
                        self.timer.services = None
+                       self.timer.bouquets = None
 
                # Offset
                if self.offset.value:
@@ -402,7 +712,12 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                if self.afterevent.value == "default":
                        self.timer.afterevent = []
                else:
-                       afterevent = {"nothing": AFTEREVENT.NONE, "deepstandby": AFTEREVENT.DEEPSTANDBY, "standby": AFTEREVENT.STANDBY}[self.afterevent.value]
+                       afterevent = {
+                               "nothing": AFTEREVENT.NONE,
+                               "deepstandby": AFTEREVENT.DEEPSTANDBY,
+                               "standby": AFTEREVENT.STANDBY,
+                               "auto": AFTEREVENT.AUTO
+                       }[self.afterevent.value]
                        # AfterEvent Timespan
                        if self.afterevent_timespan.value:
                                start = self.afterevent_timespanbegin.value
@@ -441,7 +756,14 @@ class AutoTimerEditor(Screen, ConfigListScreen):
                        self.timer.matchLeft = 0
                        self.timer.matchFormatString = ''
 
-               self.timer.avoidDuplicateDescription = self.avoidDuplicateDescription.value
+               self.timer.avoidDuplicateDescription = int(self.avoidDuplicateDescription.value)
+
+               if self.useDestination.value:
+                       self.timer.destination = self.destination.value
+               else:
+                       self.timer.destination = None
+
+               self.timer.tags = self.timerentry_tags
 
                # Close
                self.close(self.timer)
@@ -449,29 +771,34 @@ class AutoTimerEditor(Screen, ConfigListScreen):
 class AutoTimerFilterEditor(Screen, ConfigListScreen):
        """Edit AutoTimer Filter"""
 
-       skin = """<screen name="AutoFilterEditor" title="Edit AutoTimer Filters" position="75,150" size="565,245">
-               <widget name="config" position="5,5" size="555,200" scrollbarMode="showOnDemand" />
-               <ePixmap position="5,205" zPosition="4" size="140,40" pixmap="skin_default/key-red.png" transparent="1" alphatest="on" />
-               <ePixmap position="145,205" zPosition="4" size="140,40" pixmap="skin_default/key-green.png" transparent="1" alphatest="on" />
-               <ePixmap position="285,205" zPosition="4" size="140,40" pixmap="skin_default/key-yellow.png" transparent="1" alphatest="on" />
-               <ePixmap position="425,205" zPosition="4" size="140,40" pixmap="skin_default/key-blue.png" transparent="1" alphatest="on" />
-               <widget name="key_red" position="5,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-               <widget name="key_green" position="145,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-               <widget name="key_yellow" position="285,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-               <widget name="key_blue" position="425,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+       skin = """<screen name="AutoTimerFilterEditor" title="Edit AutoTimer Filters" position="center,center" size="565,280">
+               <ePixmap position="0,0" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+               <ePixmap position="140,0" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+               <ePixmap position="280,0" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+               <ePixmap position="420,0" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+               <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget name="config" position="5,45" size="555,225" scrollbarMode="showOnDemand" />
        </screen>"""
 
        def __init__(self, session, filterset, excludes, includes):
                Screen.__init__(self, session)
 
                # Summary
-               self.setup_title = "AutoTimer Filters"
+               self.setup_title = _("AutoTimer Filters")
                self.onChangedEntry = []
 
-               self.typeSelection = ConfigSelection(choices = [("title", _("in Title")), ("short", _("in Shortdescription")), ("desc", _("in Description")), ("day", _("on Weekday"))])
+               self.typeSelection = NoSave(ConfigSelection(choices = [
+                       ("title", _("in Title")),
+                       ("short", _("in Shortdescription")),
+                       ("desc", _("in Description")),
+                       ("day", _("on Weekday"))]
+               ))
                self.typeSelection.addNotifier(self.refresh, initial_call = False)
 
-               self.enabled = ConfigEnableDisable(default = filterset)
+               self.enabled = NoSave(ConfigEnableDisable(default = filterset))
 
                self.excludes = excludes
                self.includes = includes
@@ -481,10 +808,10 @@ class AutoTimerFilterEditor(Screen, ConfigListScreen):
                ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
 
                # Initialize Buttons
-               self["key_red"] = Button(_("Cancel"))
-               self["key_green"] = Button(_("Save"))
-               self["key_yellow"] = Button(_("delete"))
-               self["key_blue"] = Button(_("New"))
+               self["key_red"] = StaticText(_("Cancel"))
+               self["key_green"] = StaticText(_("Save"))
+               self["key_yellow"] = StaticText(_("delete"))
+               self["key_blue"] = StaticText(_("New"))
 
                # Define Actions
                self["actions"] = ActionMap(["SetupActions", "ColorActions"],
@@ -499,11 +826,17 @@ class AutoTimerFilterEditor(Screen, ConfigListScreen):
                # Trigger change
                self.changed()
 
+               self.onLayoutFinish.append(self.setCustomTitle)
+
+       def setCustomTitle(self):
+               self.setTitle(_("Edit AutoTimer filters"))
+
+
        def changed(self):
                for x in self.onChangedEntry:
                        try:
                                x()
-                       except:
+                       except Exception:
                                pass
 
        def getCurrentEntry(self):
@@ -522,7 +855,7 @@ class AutoTimerFilterEditor(Screen, ConfigListScreen):
                # Warning, accessing a ConfigListEntry directly might be considered evil!
 
                idx = -1
-               for item in self["config"].getList():
+               for item in self["config"].getList()[:]:
                        idx += 1
                        # Skip empty entries (and those which are no filters)
                        if item[1].value == "" or idx < 2:
@@ -532,7 +865,7 @@ class AutoTimerFilterEditor(Screen, ConfigListScreen):
                        else:
                                self.includes[self.idx].append(item[1].value.encode("UTF-8"))
 
-       def refresh(self, value):
+       def refresh(self, *args, **kwargs):
                self.saveCurrent()
 
                self.reloadList()
@@ -549,12 +882,12 @@ class AutoTimerFilterEditor(Screen, ConfigListScreen):
 
                        # Weekdays are presented as ConfigSelection
                        self.list.extend([
-                               getConfigListEntry(_("Exclude"), ConfigSelection(choices = weekdays, default = x))
+                               getConfigListEntry(_("Exclude"), NoSave(ConfigSelection(choices = weekdays, default = x)))
                                        for x in self.excludes[3]
                        ])
                        self.lenExcludes = len(self.list)
                        self.list.extend([
-                               getConfigListEntry(_("Include"), ConfigSelection(choices = weekdays, default = x))
+                               getConfigListEntry(_("Include"), NoSave(ConfigSelection(choices = weekdays, default = x)))
                                        for x in self.includes[3]
                        ])
                        return
@@ -566,12 +899,12 @@ class AutoTimerFilterEditor(Screen, ConfigListScreen):
                        self.idx = 2
 
                self.list.extend([
-                       getConfigListEntry(_("Exclude"), ConfigText(default = x, fixed_size = False))
+                       getConfigListEntry(_("Exclude"), NoSave(ExtendedConfigText(default = x, fixed_size = False)))
                                for x in self.excludes[self.idx]
                ])
                self.lenExcludes = len(self.list)
                self.list.extend([
-                       getConfigListEntry(_("Include"), ConfigText(default = x, fixed_size = False))
+                       getConfigListEntry(_("Include"), NoSave(ExtendedConfigText(default = x, fixed_size = False)))
                                for x in self.includes[self.idx]
                ])
 
@@ -609,16 +942,20 @@ class AutoTimerFilterEditor(Screen, ConfigListScreen):
                                text = ret[0]
 
                        if self.typeSelection.value == "day":
-                               entry = getConfigListEntry(text, ConfigSelection(choices = weekdays))
+                               entry = getConfigListEntry(text, NoSave(ConfigSelection(choices = weekdays)))
                        else:
-                               entry = getConfigListEntry(text, ConfigText(fixed_size = False))
+                               entry = getConfigListEntry(text, NoSave(ExtendedConfigText(fixed_size = False)))
 
                        list.insert(pos, entry)
                        self["config"].setList(list)
 
        def cancel(self):
                if self["config"].isChanged():
-                       self.session.openWithCallback(self.cancelConfirm, MessageBox, _("Really close without saving settings?"))
+                       self.session.openWithCallback(
+                               self.cancelConfirm,
+                               MessageBox,
+                               _("Really close without saving settings?")
+                       )
                else:
                        self.close(None)
 
@@ -627,7 +964,7 @@ class AutoTimerFilterEditor(Screen, ConfigListScreen):
                        self.close(None)
 
        def save(self):
-               self.saveCurrent()
+               self.refresh()
 
                self.close((
                        self.enabled.value,
@@ -635,63 +972,106 @@ class AutoTimerFilterEditor(Screen, ConfigListScreen):
                        self.includes
                ))
 
-class AutoTimerChannelEditor(Screen, ConfigListScreen):
-       """Edit allowed Channels of a AutoTimer"""
-
-       skin = """<screen name="AutoChannelEditor" title="Edit AutoTimer Channels" position="75,150" size="565,245">
-               <widget name="config" position="5,5" size="555,200" scrollbarMode="showOnDemand" />
-               <ePixmap position="5,205" zPosition="4" size="140,40" pixmap="skin_default/key-red.png" transparent="1" alphatest="on" />
-               <ePixmap position="145,205" zPosition="4" size="140,40" pixmap="skin_default/key-green.png" transparent="1" alphatest="on" />
-               <ePixmap position="285,205" zPosition="4" size="140,40" pixmap="skin_default/key-yellow.png" transparent="1" alphatest="on" />
-               <ePixmap position="425,205" zPosition="4" size="140,40" pixmap="skin_default/key-blue.png" transparent="1" alphatest="on" />
-               <widget name="key_red" position="5,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-               <widget name="key_green" position="145,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-               <widget name="key_yellow" position="285,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
-               <widget name="key_blue" position="425,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+class AutoTimerServiceEditor(Screen, ConfigListScreen):
+       """Edit allowed Services of a AutoTimer"""
+
+       skin = """<screen name="AutoTimerServiceEditor" title="Edit AutoTimer Services" position="center,center" size="565,280">
+               <ePixmap position="0,0" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+               <ePixmap position="140,0" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+               <ePixmap position="280,0" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+               <ePixmap position="420,0" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+               <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+               <widget name="config" position="5,45" size="555,225" scrollbarMode="showOnDemand" />
        </screen>"""
 
-       def __init__(self, session, servicerestriction, servicelist):
+       def __init__(self, session, servicerestriction, servicelist, bouquetlist):
                Screen.__init__(self, session)
 
                # Summary
-               self.setup_title = "AutoTimer Channels"
+               self.setup_title = _("AutoTimer Services")
                self.onChangedEntry = []
 
-               self.list = [
-                       getConfigListEntry(_("Enable Channel Restriction"), ConfigEnableDisable(default = servicerestriction))
-               ]
+               self.services = (
+                       servicelist[:],
+                       bouquetlist[:]
+               )
 
-               self.list.extend([
-                       getConfigListEntry(_("Record on"), ConfigSelection(choices = [(str(x), ServiceReference(str(x)).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))]))
-                               for x in servicelist
-               ])
+               self.enabled = NoSave(ConfigEnableDisable(default = servicerestriction))
+               self.typeSelection = NoSave(ConfigSelection(choices = [
+                       ("channels", _("Channels")),
+                       ("bouquets", _("Bouquets"))]
+               ))
+               self.typeSelection.addNotifier(self.refresh, initial_call = False)
+
+               self.reloadList()
 
                ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
 
                # Initialize Buttons
-               self["key_red"] = Button(_("Cancel"))
-               self["key_green"] = Button(_("OK"))
-               self["key_yellow"] = Button(_("delete"))
-               self["key_blue"] = Button(_("New"))
+               self["key_red"] = StaticText(_("Cancel"))
+               self["key_green"] = StaticText(_("OK"))
+               self["key_yellow"] = StaticText(_("delete"))
+               self["key_blue"] = StaticText(_("New"))
 
                # Define Actions
                self["actions"] = ActionMap(["SetupActions", "ColorActions"],
                        {
                                "cancel": self.cancel,
                                "save": self.save,
-                               "yellow": self.removeChannel,
-                               "blue": self.newChannel
+                               "yellow": self.remove,
+                               "blue": self.new
                        }
                )
 
                # Trigger change
                self.changed()
 
+               self.onLayoutFinish.append(self.setCustomTitle)
+
+       def setCustomTitle(self):
+               self.setTitle(_("Edit AutoTimer services"))
+
+       def saveCurrent(self):
+               del self.services[self.idx][:]
+
+               # Warning, accessing a ConfigListEntry directly might be considered evil!
+
+               myl = self["config"].getList()[:]
+               myl.pop(0) # Enabled
+               myl.pop(0) # Type
+               for item in myl:
+                       self.services[self.idx].append(item[1].value)
+
+       def refresh(self, *args, **kwargs):
+               self.saveCurrent()
+
+               self.reloadList()
+               self["config"].setList(self.list)
+
+       def reloadList(self):
+               self.list = [
+                       getConfigListEntry(_("Enable Service Restriction"), self.enabled),
+                       getConfigListEntry(_("Editing"), self.typeSelection)
+               ]
+
+               if self.typeSelection.value == "channels":
+                       self.idx = 0
+               else: # self.typeSelection.value == "bouquets":
+                       self.idx = 1
+
+               self.list.extend([
+                       getConfigListEntry(_("Record on"), NoSave(ConfigSelection(choices = [(str(x), ServiceReference(str(x)).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))])))
+                               for x in self.services[self.idx]
+               ])
+
        def changed(self):
                for x in self.onChangedEntry:
                        try:
                                x()
-                       except:
+                       except Exception:
                                pass
 
        def getCurrentEntry(self):
@@ -703,35 +1083,49 @@ class AutoTimerChannelEditor(Screen, ConfigListScreen):
        def createSummary(self):
                return SetupSummary
 
-       def removeChannel(self):
+       def remove(self):
                if self["config"].getCurrentIndex() != 0:
                        list = self["config"].getList()
                        list.remove(self["config"].getCurrent())
                        self["config"].setList(list)
 
-       def newChannel(self):
-               self.session.openWithCallback(
-                       self.finishedChannelSelection,
-                       SimpleChannelSelection,
-                       _("Select channel to record from")
-               )
+       def new(self):
+               if self.typeSelection.value == "channels":
+                       self.session.openWithCallback(
+                               self.finishedServiceSelection,
+                               SimpleChannelSelection,
+                               _("Select channel to record on")
+                       )
+               else: # self.typeSelection.value == "bouquets":
+                       self.session.openWithCallback(
+                               self.finishedServiceSelection,
+                               SimpleBouquetSelection,
+                               _("Select bouquet to record on")
+                       )
 
-       def finishedChannelSelection(self, *args):
-               if len(args):
+       def finishedServiceSelection(self, *args):
+               if args:
                        list = self["config"].getList()
                        sname = args[0].toString()
 
-                       # strip all after last :
-                       pos = sname.rfind(':')
-                       if pos != -1:
-                               sname = sname[:pos+1]
+                       if self.typeSelection.value == "channels" and not (args[0].flags & eServiceReference.isGroup):
+                               # strip all after last : when adding a (non alternative) channel
+                               pos = sname.rfind(':')
+                               if pos != -1:
+                                       if sname[pos-1] == ':':
+                                               pos -= 1
+                                       sname = sname[:pos+1]
 
-                       list.append(getConfigListEntry(_("Record on"), ConfigSelection(choices = [(sname, ServiceReference(args[0]).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))])))
+                       list.append(getConfigListEntry(_("Record on"), NoSave(ConfigSelection(choices = [(sname, ServiceReference(args[0]).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))]))))
                        self["config"].setList(list)
 
        def cancel(self):
                if self["config"].isChanged():
-                       self.session.openWithCallback(self.cancelConfirm, MessageBox, _("Really close without saving settings?"))
+                       self.session.openWithCallback(
+                               self.cancelConfirm,
+                               MessageBox,
+                               _("Really close without saving settings?")
+                       )
                else:
                        self.close(None)
 
@@ -740,14 +1134,192 @@ class AutoTimerChannelEditor(Screen, ConfigListScreen):
                        self.close(None)
 
        def save(self):
-               list = self["config"].getList()
-               restriction = list.pop(0)
+               self.refresh()
 
-               # Warning, accessing a ConfigListEntry directly might be considered evil!
                self.close((
-                       restriction[1].value,
-                       [
-                               x[1].value.encode("UTF-8")
-                                       for x in list
-                       ]
+                       self.enabled.value,
+                       self.services
                ))
+
+def addAutotimerFromSearchString(session, match):
+       from AutoTimerComponent import preferredAutoTimerComponent
+       from AutoTimerImporter import AutoTimerImporter
+       from plugin import autotimer
+
+       # Create instance if needed
+       if autotimer is None:
+               from AutoTimer import AutoTimer
+               autotimer = AutoTimer()
+               autotimer.readXml()
+
+       session.openWithCallback(
+               importerCallback,
+               AutoTimerImporter,
+               preferredAutoTimerComponent(
+                       autotimer.getUniqueId(),
+                       match,
+                       '',             # Match
+                       True    # Enabled
+               ),
+               match,          # Proposed Match
+               None,           # Proposed Begin
+               None,           # Proposed End
+               None,           # Proposed Disabled
+               None,           # Proposed ServiceReference
+               None,           # Proposed afterEvent
+               None,           # Proposed justplay
+               None,           # Proposed dirname, can we get anything useful here?
+               []                      # Proposed tags
+       )
+
+def addAutotimerFromEvent(session, evt = None, service = None):
+       from AutoTimerComponent import preferredAutoTimerComponent
+       from AutoTimerImporter import AutoTimerImporter
+       from plugin import autotimer
+
+       # Create instance if needed
+       if autotimer is None:
+               from AutoTimer import AutoTimer
+               autotimer = AutoTimer()
+               autotimer.readXml()
+
+       match = evt and evt.getEventName() or ""
+       name = match or "New AutoTimer"
+       sref = None
+       if service is not None:
+               service = str(service)
+               myref = eServiceReference(service)
+               if not (myref.flags & eServiceReference.isGroup):
+                       # strip all after last :
+                       pos = service.rfind(':')
+                       if pos != -1:
+                               if service[pos-1] == ':':
+                                       pos -= 1
+                               service = service[:pos+1]
+
+               sref = ServiceReference(myref)
+       if evt:
+               # timespan defaults to +- 1h
+               begin = evt.getBeginTime()-3600
+               end = begin + evt.getDuration()+7200
+       else:
+               begin = end = 0
+
+       # XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
+
+       session.openWithCallback(
+               importerCallback,
+               AutoTimerImporter,
+               preferredAutoTimerComponent(
+                       autotimer.getUniqueId(),
+                       name,
+                       '',             # Match
+                       True    # Enabled
+               ),
+               match,          # Proposed Match
+               begin,          # Proposed Begin
+               end,            # Proposed End
+               None,           # Proposed Disabled
+               sref,           # Proposed ServiceReference
+               None,           # Proposed afterEvent
+               None,           # Proposed justplay
+               None,           # Proposed dirname, can we get anything useful here?
+               []                      # Proposed tags
+       )
+
+def addAutotimerFromService(session, service = None):
+       from AutoTimerComponent import preferredAutoTimerComponent
+       from AutoTimerImporter import AutoTimerImporter
+       from plugin import autotimer
+
+       # Create instance if needed
+       if autotimer is None:
+               from AutoTimer import AutoTimer
+               autotimer = AutoTimer()
+               autotimer.readXml()
+
+       serviceHandler = eServiceCenter.getInstance()
+       info = serviceHandler.info(service)
+
+       match = info and info.getName(service) or ""
+       name = match or "New AutoTimer"
+       sref = info and info.getInfoString(service, iServiceInformation.sServiceref)
+       if sref:
+               # strip all after last :
+               pos = sref.rfind(':')
+               if pos != -1:
+                       if sref[pos-1] == ':':
+                               pos -= 1
+                       sref = sref[:pos+1]
+
+               sref = ServiceReference(sref)
+       if info:
+               begin = info.getInfo(service, iServiceInformation.sTimeCreate)
+               end = begin + info.getLength(service)
+       else:
+               begin = end = 0
+
+       from os.path import dirname
+       path = dirname(service.getPath())
+       if not path == '/':
+               path += '/'
+
+       tags = info.getInfoString(service, iServiceInformation.sTags)
+       tags = tags and tags.split(' ') or []
+
+       # XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
+
+       session.openWithCallback(
+               importerCallback,
+               AutoTimerImporter,
+               preferredAutoTimerComponent(
+                       autotimer.getUniqueId(),
+                       name,
+                       '',             # Match
+                       True    # Enabled
+               ),
+               match,          # Proposed Match
+               begin,          # Proposed Begin
+               end,            # Proposed End
+               None,           # Proposed Disabled
+               sref,           # Proposed ServiceReference
+               None,           # Proposed afterEvent
+               None,           # Proposed justplay
+               path,           # Proposed dirname
+               tags            # Proposed tags
+       )
+
+def importerCallback(ret):
+       if ret:
+               ret, session = ret
+
+               session.openWithCallback(
+                       editorCallback,
+                       AutoTimerEditor,
+                       ret
+               )
+       else:
+               # Remove instance if not running in background
+               if not config.plugins.autotimer.autopoll.value:
+                       from plugin import autotimer
+                       autotimer = None
+
+def editorCallback(ret):
+       if ret:
+               from plugin import autotimer
+
+               # Create instance if needed (should have been created by addAutotimerFrom* above though)
+               if autotimer is None:
+                       from AutoTimer import AutoTimer
+                       autotimer = AutoTimer()
+                       autotimer.readXml()
+
+               autotimer.add(ret)
+
+               # Save modified xml
+               autotimer.writeXml()
+
+       # Remove instance if not running in background
+       if not config.plugins.autotimer.autopoll.value:
+               autotimer = None
+