AutoTimer: add "Fast Scan" support
[vuplus_dvbapp-plugin] / autotimer / src / AutoTimerEditor.py
1 # -*- coding: UTF-8 -*-
2 # for localized messages
3 from . import _
4
5 # GUI (Screens)
6 from Screens.Screen import Screen
7 from Components.ConfigList import ConfigListScreen
8 from Screens.ChannelSelection import SimpleChannelSelection
9 from Screens.EpgSelection import EPGSelection
10 from Screens.MessageBox import MessageBox
11 from Screens.ChoiceBox import ChoiceBox
12
13 # GUI (Summary)
14 from Screens.Setup import SetupSummary
15
16 # GUI (Components)
17 from Components.ActionMap import ActionMap
18 from Components.Sources.StaticText import StaticText
19
20 # Configuration
21 from Components.config import getConfigListEntry, ConfigEnableDisable, \
22         ConfigYesNo, ConfigText, ConfigClock, ConfigNumber, ConfigSelection, \
23         config, NoSave
24
25 # Timer
26 from RecordTimer import AFTEREVENT
27
28 # Needed to convert our timestamp back and forth
29 from time import localtime, mktime
30
31 # Show ServiceName instead of ServiceReference
32 from ServiceReference import ServiceReference
33
34 # addAutotimerFromService, AutoTimerChannelSelection
35 from enigma import eServiceCenter, eServiceReference, iServiceInformation
36
37 # Default Record Directory
38 from Tools import Directories
39
40 # Tags
41 from Screens.MovieSelection import getPreferredTagEditor
42
43 weekdays = [
44         ("0", _("Monday")),
45         ("1", _("Tuesday")),
46         ("2", _("Wednesday")),
47         ("3", _("Thursday")),
48         ("4", _("Friday")),
49         ("5", _("Saturday")),
50         ("6", _("Sunday")),
51         ("weekend", _("Weekend")),
52         ("weekday", _("Weekday"))
53 ]
54
55 class ExtendedConfigText(ConfigText):
56         def __init__(self, default = "", fixed_size = True, visible_width = False):
57                 ConfigText.__init__(self, default = default, fixed_size = fixed_size, visible_width = visible_width)
58
59                 # Workaround some characters currently not "typeable" using NumericalTextInput
60                 mapping = self.mapping
61                 if mapping:
62                         if "&" not in mapping[0]:
63                                 mapping[0] += "&"
64                         if ";" not in mapping[0]:
65                                 mapping[0] += ";"
66                         if "%" not in mapping[0]:
67                                 mapping[0] += "%"
68
69 class SimpleBouquetSelection(SimpleChannelSelection):
70         def __init__(self, session, title):
71                 SimpleChannelSelection.__init__(self, session, title)
72                 self.skinName = "SimpleChannelSelection"
73
74         def channelSelected(self):
75                 ref = self.getCurrentSelection()
76                 if (ref.flags & 7) == 7:
77                         self.close(ref)
78                 else:
79                         # We return the currently active path here
80                         # Asking the user if this is what he wants might be better though
81                         self.close(self.servicePath[-1])
82
83 class AutoTimerChannelSelection(SimpleChannelSelection):
84         def __init__(self, session, autotimer):
85                 SimpleChannelSelection.__init__(self, session, _("Channel Selection"))
86                 self.skinName = "SimpleChannelSelection"
87                 self.autotimer = autotimer
88
89                 self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
90                         {
91                                 "showEPGList": self.channelSelected
92                         }
93                 )
94
95         def channelSelected(self):
96                 ref = self.getCurrentSelection()
97                 if (ref.flags & 7) == 7:
98                         self.enterPath(ref)
99                 elif not (ref.flags & eServiceReference.isMarker):
100                         self.session.open(
101                                 AutoTimerEPGSelection,
102                                 ref
103                         )
104
105 class AutoTimerEPGSelection(EPGSelection):
106         def __init__(self, *args):
107                 EPGSelection.__init__(self, *args)
108                 self.skinName = "EPGSelection"
109
110         def infoKeyPressed(self):
111                 self.timerAdd()
112
113         def timerAdd(self):
114                 cur = self["list"].getCurrent()
115                 evt = cur[0]
116                 sref = cur[1]
117                 if not evt:
118                         return
119
120                 addAutotimerFromEvent(self.session, evt = evt, service = sref)
121
122         def onSelectionChanged(self):
123                 pass
124
125 class AutoTimerEditorBase:
126         """ Base Class for all Editors """
127         def __init__(self, timer, editingDefaults = False):
128                 # Keep Timer
129                 self.timer = timer
130                 self.editingDefaults = editingDefaults
131
132                 # See if we are filtering some strings
133                 excludes = (
134                         timer.getExcludedTitle(),
135                         timer.getExcludedShort(),
136                         timer.getExcludedDescription(),
137                         timer.getExcludedDays()
138                 )
139                 includes = (
140                         timer.getIncludedTitle(),
141                         timer.getIncludedShort(),
142                         timer.getIncludedDescription(),
143                         timer.getIncludedDays()
144                 )
145                 if excludes[0] or excludes[1] \
146                                 or excludes[2] or excludes[3] \
147                                 or includes[0] or includes[1] \
148                                 or includes[2] or includes[3]:
149                         self.filterSet = True
150                 else:
151                         self.filterSet = False
152                 self.excludes = excludes
153                 self.includes = includes
154
155                 # See if services are restricted
156                 self.services = timer.services
157                 self.bouquets = timer.bouquets
158                 if self.services or self.bouquets:
159                         self.serviceRestriction = True
160                 else:
161                         self.serviceRestriction = False
162
163                 self.createSetup(timer)
164
165         def createSetup(self, timer):
166                 # Name
167                 self.name = NoSave(ExtendedConfigText(default = timer.name, fixed_size = False))
168
169                 # Match
170                 self.match = NoSave(ExtendedConfigText(default = timer.match, fixed_size = False))
171
172                 # Encoding
173                 default = timer.encoding
174                 selection = ['UTF-8', 'ISO8859-15']
175                 if default not in selection:
176                         selection.append(default)
177                 self.encoding = NoSave(ConfigSelection(choices = selection, default = default))
178
179                 # ...
180                 self.searchType = NoSave(ConfigSelection(choices = [("partial", _("partial match")), ("exact", _("exact match"))], default = timer.searchType))
181                 self.searchCase = NoSave(ConfigSelection(choices = [("sensitive", _("case-sensitive search")), ("insensitive", _("case-insensitive search"))], default = timer.searchCase))
182
183                 # Alternatives override
184                 self.overrideAlternatives = NoSave(ConfigYesNo(default = timer.overrideAlternatives))
185
186                 # Justplay
187                 self.justplay = NoSave(ConfigSelection(choices = [("zap", _("zap")), ("record", _("record"))], default = {0: "record", 1: "zap"}[int(timer.justplay)]))
188
189                 # Timespan
190                 now = [x for x in localtime()]
191                 if timer.hasTimespan():
192                         default = True
193                         now[3] = timer.timespan[0][0]
194                         now[4] = timer.timespan[0][1]
195                         begin = mktime(now)
196                         now[3] = timer.timespan[1][0]
197                         now[4] = timer.timespan[1][1]
198                         end = mktime(now)
199                 else:
200                         default = False
201                         now[3] = 20
202                         now[4] = 15
203                         begin = mktime(now)
204                         now[3] = 23
205                         now[4] = 15
206                         end = mktime(now)
207                 self.timespan = NoSave(ConfigEnableDisable(default = default))
208                 self.timespanbegin = NoSave(ConfigClock(default = begin))
209                 self.timespanend = NoSave(ConfigClock(default = end))
210
211                 # Services have their own Screen
212
213                 # Offset
214                 if timer.hasOffset():
215                         default = True
216                         begin = timer.getOffsetBegin()
217                         end = timer.getOffsetEnd()
218                 else:
219                         default = False
220                         begin = 5
221                         end = 5
222                 self.offset = NoSave(ConfigEnableDisable(default = default))
223                 self.offsetbegin = NoSave(ConfigNumber(default = begin))
224                 self.offsetend = NoSave(ConfigNumber(default = end))
225
226                 # AfterEvent
227                 if timer.hasAfterEvent():
228                         default = {
229                                 None: "default",
230                                 AFTEREVENT.NONE: "nothing",
231                                 AFTEREVENT.DEEPSTANDBY: "deepstandby",
232                                 AFTEREVENT.STANDBY: "standby",
233                                 AFTEREVENT.AUTO: "auto"
234                         }[timer.afterevent[0][0]]
235                 else:
236                         default = "default"
237                 self.afterevent = NoSave(ConfigSelection(choices = [
238                         ("default", _("standard")), ("nothing", _("do nothing")),
239                         ("standby", _("go to standby")),
240                         ("deepstandby", _("go to deep standby")),
241                         ("auto", _("auto"))], default = default))
242
243                 # AfterEvent (Timespan)
244                 if timer.hasAfterEvent() and timer.afterevent[0][1][0] is not None:
245                         default = True
246                         now[3] = timer.afterevent[0][1][0][0]
247                         now[4] = timer.afterevent[0][1][0][1]
248                         begin = mktime(now)
249                         now[3] = timer.afterevent[0][1][1][0]
250                         now[4] = timer.afterevent[0][1][1][1]
251                         end = mktime(now)
252                 else:
253                         default = False
254                         now[3] = 23
255                         now[4] = 15
256                         begin = mktime(now)
257                         now[3] = 7
258                         now[4] = 0
259                         end = mktime(now)
260                 self.afterevent_timespan = NoSave(ConfigEnableDisable(default = default))
261                 self.afterevent_timespanbegin = NoSave(ConfigClock(default = begin))
262                 self.afterevent_timespanend = NoSave(ConfigClock(default = end))
263
264                 # Enabled
265                 self.enabled = NoSave(ConfigYesNo(default = timer.enabled))
266
267                 # Maxduration
268                 if timer.hasDuration():
269                         default = True
270                         duration = timer.getDuration()
271                 else:
272                         default = False
273                         duration =70
274                 self.duration = NoSave(ConfigEnableDisable(default = default))
275                 self.durationlength = NoSave(ConfigNumber(default = duration))
276
277                 # Counter
278                 if timer.hasCounter():
279                         default = timer.matchCount
280                 else:
281                         default = 0
282                 self.counter = NoSave(ConfigNumber(default = default))
283                 self.counterLeft = NoSave(ConfigNumber(default = timer.matchLeft))
284                 default = timer.getCounterFormatString()
285                 selection = [("", _("Never")), ("%m", _("Monthly")), ("%U", _("Weekly (Sunday)")), ("%W", _("Weekly (Monday)"))]
286                 if default not in ('', '%m', '%U', '%W'):
287                         selection.append((default, _("Custom (%s)") % (default)))
288                 self.counterFormatString = NoSave(ConfigSelection(selection, default = default))
289
290                 # Avoid Duplicate Description
291                 self.avoidDuplicateDescription = NoSave(ConfigSelection([
292                                 ("0", _("No")),
293                                 ("1", _("On same service")),
294                                 ("2", _("On any service")),
295                         ],
296                         default = str(timer.getAvoidDuplicateDescription())
297                 ))
298
299                 # Custom Location
300                 if timer.hasDestination():
301                         default = True
302                 else:
303                         default = False
304
305                 self.useDestination = NoSave(ConfigYesNo(default = default))
306
307                 default = timer.destination or Directories.resolveFilename(Directories.SCOPE_HDD)
308                 choices = config.movielist.videodirs.value
309
310                 if default not in choices:
311                         choices.append(default)
312                 self.destination = NoSave(ConfigSelection(default = default, choices = choices))
313
314                 # Tags
315                 self.timerentry_tags = timer.tags
316                 self.tags = NoSave(ConfigSelection(choices = [len(self.timerentry_tags) == 0 and _("None") or ' '.join(self.timerentry_tags)]))
317
318         def pathSelected(self, res):
319                 if res is not None:
320                         # I'm pretty sure this will always fail
321                         if config.movielist.videodirs.value != self.destination.choices:
322                                         self.destination.setChoices(config.movielist.videodirs.value, default = res)
323                         self.destination.value = res
324
325         def chooseDestination(self):
326                 from Screens.LocationBox import MovieLocationBox
327
328                 self.session.openWithCallback(
329                         self.pathSelected,
330                         MovieLocationBox,
331                         _("Choose target folder"),
332                         self.destination.value,
333                         minFree = 100 # Same requirement as in Screens.TimerEntry
334                 )
335
336         def tagEditFinished(self, ret):
337                 if ret is not None:
338                         self.timerentry_tags = ret
339                         self.tags.setChoices([len(ret) == 0 and _("None") or ' '.join(ret)])
340
341         def chooseTags(self):
342                 preferredTagEditor = getPreferredTagEditor()
343                 if preferredTagEditor:
344                         self.session.openWithCallback(
345                                 self.tagEditFinished,
346                                 preferredTagEditor,
347                                 self.timerentry_tags
348                         )
349
350 class AutoTimerEditor(Screen, ConfigListScreen, AutoTimerEditorBase):
351         """Edit AutoTimer"""
352
353         skin = """<screen name="AutoTimerEditor" title="Edit AutoTimer" position="center,center" size="565,350">
354                 <ePixmap position="0,5" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
355                 <ePixmap position="140,5" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
356                 <ePixmap position="280,5" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
357                 <ePixmap position="420,5" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
358                 <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" />
359                 <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" />
360                 <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" />
361                 <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" />
362                 <widget name="config" position="5,50" size="555,225" scrollbarMode="showOnDemand" />
363                 <ePixmap pixmap="skin_default/div-h.png" position="0,275" zPosition="1" size="565,2" />
364                 <widget source="help" render="Label" position="5,280" size="555,63" font="Regular;21" />
365         </screen>"""
366
367         def __init__(self, session, timer, editingDefaults = False):
368                 Screen.__init__(self, session)
369
370                 AutoTimerEditorBase.__init__(self, timer, editingDefaults)
371
372                 # Summary
373                 self.setup_title = _("AutoTimer Editor")
374                 self.onChangedEntry = []
375
376                 # We might need to change shown items, so add some notifiers
377                 self.timespan.addNotifier(self.reloadList, initial_call = False)
378                 self.offset.addNotifier(self.reloadList, initial_call = False)
379                 self.duration.addNotifier(self.reloadList, initial_call = False)
380                 self.afterevent.addNotifier(self.reloadList, initial_call = False)
381                 self.afterevent_timespan.addNotifier(self.reloadList, initial_call = False)
382                 self.counter.addNotifier(self.reloadList, initial_call = False)
383                 self.useDestination.addNotifier(self.reloadList, initial_call = False)
384
385                 self.refresh()
386                 self.initHelpTexts()
387
388                 # XXX: no help for numericaltextinput since it is shown on top of our help
389                 ConfigListScreen.__init__(self, self.list, on_change = self.changed)
390                 self["config"].onSelectionChanged.append(self.updateHelp)
391
392                 # Initialize Buttons
393                 self["key_red"] = StaticText(_("Cancel"))
394                 self["key_green"] = StaticText(_("OK"))
395                 self["key_yellow"] = StaticText()
396                 self["key_blue"] = StaticText()
397
398                 self["help"] = StaticText()
399
400                 # Set Button texts
401                 self.renameServiceButton()
402                 self.renameFilterButton()
403
404                 # Define Actions
405                 self["actions"] = ActionMap(["SetupActions", "ColorActions"],
406                         {
407                                 "cancel": self.cancel,
408                                 "save": self.maybeSave,
409                                 "ok": self.ok,
410                                 "yellow": self.editFilter,
411                                 "blue": self.editServices
412                         }, -2
413                 )
414
415                 # Trigger change
416                 self.changed()
417
418                 self.onLayoutFinish.append(self.setCustomTitle)
419
420         def setCustomTitle(self):
421                 self.setTitle(_("Edit AutoTimer"))
422
423         def renameFilterButton(self):
424                 if self.filterSet:
425                         self["key_yellow"].text = _("edit filters")
426                 else:
427                         self["key_yellow"].text = _("add filters")
428
429         def renameServiceButton(self):
430                 if self.serviceRestriction:
431                         self["key_blue"].text = _("edit services")
432                 else:
433                         self["key_blue"].text = _("add services")
434
435         def updateHelp(self):
436                 cur = self["config"].getCurrent()
437                 if cur:
438                         self["help"].text = self.helpDict[cur[1]]
439
440         def changed(self):
441                 for x in self.onChangedEntry:
442                         try:
443                                 x()
444                         except Exception:
445                                 pass
446
447         def getCurrentEntry(self):
448                 return self["config"].getCurrent()[0]
449
450         def getCurrentValue(self):
451                 return str(self["config"].getCurrent()[1].getText())
452
453         def createSummary(self):
454                 return SetupSummary
455
456         def initHelpTexts(self):
457                 self.helpDict = {
458                         self.enabled: _("Set this NO to disable this AutoTimer."),
459                         self.name: _("This is a name you can give the AutoTimer. It will be shown in the Overview and the Preview."),
460                         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."),
461                         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."),
462                         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."),
463                         self.searchCase: _("Select whether or not you want to enforce case correctness."),
464                         self.justplay: _("Add zap timer instead of record timer?"),
465                         self.overrideAlternatives: _("With this option enabled the channel to record on can be changed to a alternative service it is restricted to."),
466                         self.timespan: _("Should this AutoTimer be restricted to a timespan?"),
467                         self.timespanbegin: _("Lower bound of timespan. Nothing before this time will be matched. Offsets are not taken into account!"),
468                         self.timespanend: _("Upper bound of timespan. Nothing after this time will be matched. Offsets are not taken into account!"),
469                         self.offset: _("Change default recording offset?"),
470                         self.offsetbegin: _("Time in minutes to prepend to recording."),
471                         self.offsetend: _("Time in minutes to append to recording."),
472                         self.duration: _("Should this AutoTimer only match up to a certain event duration?"),
473                         self.durationlength: _("Maximum event duration to match. If an event is longer than this ammount of time (without offset) it won't be matched."),
474                         self.afterevent: _("Power state to change to after recordings. Select \"standard\" to not change the default behavior of enigma2 or values changed by yourself."),
475                         self.afterevent_timespan: _("Restrict \"after event\" to a certain timespan?"),
476                         self.afterevent_timespanbegin: _("Lower bound of timespan."),
477                         self.afterevent_timespanend: _("Upper bound of timespan."),
478                         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."),
479                         self.counterLeft: _("Number of scheduled recordings left."),
480                         self.counterFormatString: _("The counter can automatically be reset to the limit at certain intervals."),
481                         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."),
482                         self.useDestination: _("Should timers created by this AutoTimer be recorded to a custom location?"),
483                         self.destination: _("Select the location to save the recording to."),
484                         self.tags: _("Tags the Timer/Recording will have."),
485                 }
486
487         def refresh(self):
488                 # First three entries are only showed when not editing defaults
489                 list = []
490                 if not self.editingDefaults:
491                         list.extend((
492                                 getConfigListEntry(_("Enabled"), self.enabled),
493                                 getConfigListEntry(_("Description"), self.name),
494                                 getConfigListEntry(_("Match title"), self.match),
495                         ))
496
497                 list.extend((
498                         getConfigListEntry(_("EPG encoding"), self.encoding),
499                         getConfigListEntry(_("Search type"), self.searchType),
500                         getConfigListEntry(_("Search strictness"), self.searchCase),
501                         getConfigListEntry(_("Timer type"), self.justplay),
502                         getConfigListEntry(_("Override found with alternative service"), self.overrideAlternatives),
503                         getConfigListEntry(_("Only match during timespan"), self.timespan)
504                 ))
505
506                 # Only allow editing timespan when it's enabled
507                 if self.timespan.value:
508                         list.extend((
509                                 getConfigListEntry(_("Begin of timespan"), self.timespanbegin),
510                                 getConfigListEntry(_("End of timespan"), self.timespanend)
511                         ))
512
513                 list.append(getConfigListEntry(_("Custom offset"), self.offset))
514
515                 # Only allow editing offsets when it's enabled
516                 if self.offset.value:
517                         list.extend((
518                                 getConfigListEntry(_("Offset before recording (in m)"), self.offsetbegin),
519                                 getConfigListEntry(_("Offset after recording (in m)"), self.offsetend)
520                         ))
521
522                 list.append(getConfigListEntry(_("Set maximum duration"), self.duration))
523
524                 # Only allow editing maxduration when it's enabled
525                 if self.duration.value:
526                         list.append(getConfigListEntry(_("Maximum duration (in m)"), self.durationlength))
527
528                 list.append(getConfigListEntry(_("After event"), self.afterevent))
529
530                 # Only allow setting afterevent timespan when afterevent is active
531                 if self.afterevent.value != "default":
532                         list.append(getConfigListEntry(_("Execute \"after event\" during timespan"), self.afterevent_timespan))
533
534                         # Only allow editing timespan when it's enabled
535                         if self.afterevent_timespan.value:
536                                 list.extend((
537                                         getConfigListEntry(_("Begin of \"after event\" timespan"), self.afterevent_timespanbegin),
538                                         getConfigListEntry(_("End of \"after event\" timespan"), self.afterevent_timespanend)
539                                 ))
540
541                 list.append(getConfigListEntry(_("Record a maximum of x times"), self.counter))
542
543                 # Only allow setting matchLeft when counting hits
544                 if self.counter.value:
545                         if not self.editingDefaults:
546                                 list.append(getConfigListEntry(_("Ammount of recordings left"), self.counterLeft))
547                         list.append(getConfigListEntry(_("Reset count"), self.counterFormatString))
548
549                 list.append(getConfigListEntry(_("Require description to be unique"), self.avoidDuplicateDescription))
550
551                 # We always add this option though its expert only in enigma2
552                 list.append(getConfigListEntry(_("Use a custom location"), self.useDestination))
553                 if self.useDestination.value:
554                         list.append(getConfigListEntry(_("Custom location"), self.destination))
555
556                 list.append(getConfigListEntry(_("Tags"), self.tags))
557
558                 self.list = list
559
560         def reloadList(self, value):
561                 self.refresh()
562                 self["config"].setList(self.list)
563
564         def editFilter(self):
565                 self.session.openWithCallback(
566                         self.editFilterCallback,
567                         AutoTimerFilterEditor,
568                         self.filterSet,
569                         self.excludes,
570                         self.includes
571                 )
572
573         def editFilterCallback(self, ret):
574                 if ret:
575                         self.filterSet = ret[0]
576                         self.excludes = ret[1]
577                         self.includes = ret[2]
578                         self.renameFilterButton()
579
580         def editServices(self):
581                 self.session.openWithCallback(
582                         self.editServicesCallback,
583                         AutoTimerServiceEditor,
584                         self.serviceRestriction,
585                         self.services,
586                         self.bouquets
587                 )
588
589         def editServicesCallback(self, ret):
590                 if ret:
591                         self.serviceRestriction = ret[0]
592                         self.services = ret[1][0]
593                         self.bouquets = ret[1][1]
594                         self.renameServiceButton()
595
596         def keyLeft(self):
597                 cur = self["config"].getCurrent()
598                 cur = cur and cur[1]
599                 if cur == self.tags:
600                         self.chooseTags()
601                 else:
602                         ConfigListScreen.keyLeft(self)
603
604         def keyRight(self):
605                 cur = self["config"].getCurrent()
606                 cur = cur and cur[1]
607                 if cur == self.tags:
608                         self.chooseTags()
609                 else:
610                         ConfigListScreen.keyRight(self)
611
612         def ok(self):
613                 cur = self["config"].getCurrent()
614                 cur = cur and cur[1]
615                 if cur == self.destination:
616                         self.chooseDestination()
617                 elif cur == self.tags:
618                         self.chooseTags()
619                 else:
620                         ConfigListScreen.keyOK(self)
621
622         def cancel(self):
623                 if self["config"].isChanged():
624                         self.session.openWithCallback(
625                                 self.cancelConfirm,
626                                 MessageBox,
627                                 _("Really close without saving settings?")
628                         )
629                 else:
630                         self.close(None)
631
632         def cancelConfirm(self, ret):
633                 if ret:
634                         self.close(None)
635
636         def maybeSave(self):
637                 if self.editingDefaults:
638                         self.save()
639                         return
640                 # Check if any match is set
641                 if not self.match.value.strip():
642                         self.session.open(
643                                         MessageBox,
644                                         _("The match attribute is mandatory."),
645                                         type = MessageBox.TYPE_ERROR,
646                                         timeout = 5
647                         )
648                 # Check if we have a trailing whitespace
649                 elif self.match.value[-1:] == " ":
650                         self.session.openWithCallback(
651                                 self.saveCallback,
652                                 MessageBox,
653                                 _('You entered "%s" as Text to match.\nDo you want to remove trailing whitespaces?') % (self.match.value)
654                         )
655                 # Just save else
656                 else:
657                         self.save()
658
659         def saveCallback(self, ret):
660                 if ret is not None:
661                         if ret:
662                                 self.match.value = self.match.value.rstrip()
663                         self.save()
664                 # Don't to anything if MessageBox was canceled!
665
666         def save(self):
667                 # Match
668                 self.timer.match = self.match.value
669
670                 # Name
671                 self.timer.name = self.name.value.strip() or self.timer.match
672
673                 # Encoding
674                 self.timer.encoding = self.encoding.value
675
676                 # ...
677                 self.timer.searchType = self.searchType.value
678                 self.timer.searchCase = self.searchCase.value
679
680                 # Alternatives
681                 self.timer.overrideAlternatives = self.overrideAlternatives.value
682
683                 # Enabled
684                 self.timer.enabled = self.enabled.value
685
686                 # Justplay
687                 self.timer.justplay = self.justplay.value == "zap"
688
689                 # Timespan
690                 if self.timespan.value:
691                         start = self.timespanbegin.value
692                         end = self.timespanend.value
693                         self.timer.timespan = (start, end)
694                 else:
695                         self.timer.timespan = None
696
697                 # Services
698                 if self.serviceRestriction:
699                         self.timer.services = self.services
700                         self.timer.bouquets = self.bouquets
701                 else:
702                         self.timer.services = None
703                         self.timer.bouquets = None
704
705                 # Offset
706                 if self.offset.value:
707                         self.timer.offset = (self.offsetbegin.value*60, self.offsetend.value*60)
708                 else:
709                         self.timer.offset = None
710
711                 # AfterEvent
712                 if self.afterevent.value == "default":
713                         self.timer.afterevent = []
714                 else:
715                         afterevent = {
716                                 "nothing": AFTEREVENT.NONE,
717                                 "deepstandby": AFTEREVENT.DEEPSTANDBY,
718                                 "standby": AFTEREVENT.STANDBY,
719                                 "auto": AFTEREVENT.AUTO
720                         }[self.afterevent.value]
721                         # AfterEvent Timespan
722                         if self.afterevent_timespan.value:
723                                 start = self.afterevent_timespanbegin.value
724                                 end = self.afterevent_timespanend.value
725                                 self.timer.afterevent = [(afterevent, (start, end))]
726                         else:
727                                 self.timer.afterevent = [(afterevent, None)]
728
729                 # Maxduration
730                 if self.duration.value:
731                         self.timer.maxduration = self.durationlength.value*60
732                 else:
733                         self.timer.maxduration = None
734
735                 # Ex-&Includes
736                 if self.filterSet:
737                         self.timer.exclude = self.excludes
738                         self.timer.include = self.includes
739                 else:
740                         self.timer.exclude = None
741                         self.timer.include = None
742
743                 # Counter
744                 if self.counter.value:
745                         self.timer.matchCount = self.counter.value
746                         if self.counterLeft.value <= self.counter.value:
747                                 self.timer.matchLeft = self.counterLeft.value
748                         else:
749                                 self.timer.matchLeft = self.counter.value
750                         if self.counterFormatString.value:
751                                 self.timer.matchFormatString = self.counterFormatString.value
752                         else:
753                                 self.timer.matchFormatString = ''
754                 else:
755                         self.timer.matchCount = 0
756                         self.timer.matchLeft = 0
757                         self.timer.matchFormatString = ''
758
759                 self.timer.avoidDuplicateDescription = int(self.avoidDuplicateDescription.value)
760
761                 if self.useDestination.value:
762                         self.timer.destination = self.destination.value
763                 else:
764                         self.timer.destination = None
765
766                 self.timer.tags = self.timerentry_tags
767
768                 # Close
769                 self.close(self.timer)
770
771 class AutoTimerFilterEditor(Screen, ConfigListScreen):
772         """Edit AutoTimer Filter"""
773
774         skin = """<screen name="AutoTimerFilterEditor" title="Edit AutoTimer Filters" position="center,center" size="565,280">
775                 <ePixmap position="0,0" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
776                 <ePixmap position="140,0" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
777                 <ePixmap position="280,0" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
778                 <ePixmap position="420,0" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
779                 <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" />
780                 <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" />
781                 <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" />
782                 <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" />
783                 <widget name="config" position="5,45" size="555,225" scrollbarMode="showOnDemand" />
784         </screen>"""
785
786         def __init__(self, session, filterset, excludes, includes):
787                 Screen.__init__(self, session)
788
789                 # Summary
790                 self.setup_title = _("AutoTimer Filters")
791                 self.onChangedEntry = []
792
793                 self.typeSelection = NoSave(ConfigSelection(choices = [
794                         ("title", _("in Title")),
795                         ("short", _("in Shortdescription")),
796                         ("desc", _("in Description")),
797                         ("day", _("on Weekday"))]
798                 ))
799                 self.typeSelection.addNotifier(self.refresh, initial_call = False)
800
801                 self.enabled = NoSave(ConfigEnableDisable(default = filterset))
802
803                 self.excludes = excludes
804                 self.includes = includes
805
806                 self.reloadList()
807
808                 ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
809
810                 # Initialize Buttons
811                 self["key_red"] = StaticText(_("Cancel"))
812                 self["key_green"] = StaticText(_("Save"))
813                 self["key_yellow"] = StaticText(_("delete"))
814                 self["key_blue"] = StaticText(_("New"))
815
816                 # Define Actions
817                 self["actions"] = ActionMap(["SetupActions", "ColorActions"],
818                         {
819                                 "cancel": self.cancel,
820                                 "save": self.save,
821                                 "yellow": self.remove,
822                                 "blue": self.new
823                         }
824                 )
825
826                 # Trigger change
827                 self.changed()
828
829                 self.onLayoutFinish.append(self.setCustomTitle)
830
831         def setCustomTitle(self):
832                 self.setTitle(_("Edit AutoTimer filters"))
833
834
835         def changed(self):
836                 for x in self.onChangedEntry:
837                         try:
838                                 x()
839                         except Exception:
840                                 pass
841
842         def getCurrentEntry(self):
843                 return self["config"].getCurrent()[0]
844
845         def getCurrentValue(self):
846                 return str(self["config"].getCurrent()[1].getText())
847
848         def createSummary(self):
849                 return SetupSummary
850
851         def saveCurrent(self):
852                 del self.excludes[self.idx][:]
853                 del self.includes[self.idx][:]
854
855                 # Warning, accessing a ConfigListEntry directly might be considered evil!
856
857                 idx = -1
858                 for item in self["config"].getList()[:]:
859                         idx += 1
860                         # Skip empty entries (and those which are no filters)
861                         if item[1].value == "" or idx < 2:
862                                 continue
863                         elif idx < self.lenExcludes:
864                                 self.excludes[self.idx].append(item[1].value.encode("UTF-8"))
865                         else:
866                                 self.includes[self.idx].append(item[1].value.encode("UTF-8"))
867
868         def refresh(self, *args, **kwargs):
869                 self.saveCurrent()
870
871                 self.reloadList()
872                 self["config"].setList(self.list)
873
874         def reloadList(self):
875                 self.list = [
876                         getConfigListEntry(_("Enable Filtering"), self.enabled),
877                         getConfigListEntry(_("Filter"), self.typeSelection)
878                 ]
879
880                 if self.typeSelection.value == "day":
881                         self.idx = 3
882
883                         # Weekdays are presented as ConfigSelection
884                         self.list.extend([
885                                 getConfigListEntry(_("Exclude"), NoSave(ConfigSelection(choices = weekdays, default = x)))
886                                         for x in self.excludes[3]
887                         ])
888                         self.lenExcludes = len(self.list)
889                         self.list.extend([
890                                 getConfigListEntry(_("Include"), NoSave(ConfigSelection(choices = weekdays, default = x)))
891                                         for x in self.includes[3]
892                         ])
893                         return
894                 elif self.typeSelection.value == "title":
895                         self.idx = 0
896                 elif self.typeSelection.value == "short":
897                         self.idx = 1
898                 else: # self.typeSelection.value == "desc":
899                         self.idx = 2
900
901                 self.list.extend([
902                         getConfigListEntry(_("Exclude"), NoSave(ExtendedConfigText(default = x, fixed_size = False)))
903                                 for x in self.excludes[self.idx]
904                 ])
905                 self.lenExcludes = len(self.list)
906                 self.list.extend([
907                         getConfigListEntry(_("Include"), NoSave(ExtendedConfigText(default = x, fixed_size = False)))
908                                 for x in self.includes[self.idx]
909                 ])
910
911         def remove(self):
912                 idx = self["config"].getCurrentIndex()
913                 if idx and idx > 1:
914                         if idx < self.lenExcludes:
915                                 self.lenExcludes -= 1
916
917                         list = self["config"].getList()
918                         list.remove(self["config"].getCurrent())
919                         self["config"].setList(list)
920
921         def new(self):
922                 self.session.openWithCallback(
923                         self.typeSelected,
924                         ChoiceBox,
925                         _("Select type of Filter"),
926                         [
927                                 (_("Exclude"), 0),
928                                 (_("Include"), 1),
929                         ]
930                 )
931
932         def typeSelected(self, ret):
933                 if ret is not None:
934                         list = self["config"].getList()
935
936                         if ret[1] == 0:
937                                 pos = self.lenExcludes
938                                 self.lenExcludes += 1
939                                 text = ret[0]
940                         else:
941                                 pos = len(self.list)
942                                 text = ret[0]
943
944                         if self.typeSelection.value == "day":
945                                 entry = getConfigListEntry(text, NoSave(ConfigSelection(choices = weekdays)))
946                         else:
947                                 entry = getConfigListEntry(text, NoSave(ExtendedConfigText(fixed_size = False)))
948
949                         list.insert(pos, entry)
950                         self["config"].setList(list)
951
952         def cancel(self):
953                 if self["config"].isChanged():
954                         self.session.openWithCallback(
955                                 self.cancelConfirm,
956                                 MessageBox,
957                                 _("Really close without saving settings?")
958                         )
959                 else:
960                         self.close(None)
961
962         def cancelConfirm(self, ret):
963                 if ret:
964                         self.close(None)
965
966         def save(self):
967                 self.refresh()
968
969                 self.close((
970                         self.enabled.value,
971                         self.excludes,
972                         self.includes
973                 ))
974
975 class AutoTimerServiceEditor(Screen, ConfigListScreen):
976         """Edit allowed Services of a AutoTimer"""
977
978         skin = """<screen name="AutoTimerServiceEditor" title="Edit AutoTimer Services" position="center,center" size="565,280">
979                 <ePixmap position="0,0" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
980                 <ePixmap position="140,0" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
981                 <ePixmap position="280,0" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
982                 <ePixmap position="420,0" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
983                 <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" />
984                 <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" />
985                 <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" />
986                 <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" />
987                 <widget name="config" position="5,45" size="555,225" scrollbarMode="showOnDemand" />
988         </screen>"""
989
990         def __init__(self, session, servicerestriction, servicelist, bouquetlist):
991                 Screen.__init__(self, session)
992
993                 # Summary
994                 self.setup_title = _("AutoTimer Services")
995                 self.onChangedEntry = []
996
997                 self.services = (
998                         servicelist[:],
999                         bouquetlist[:]
1000                 )
1001
1002                 self.enabled = NoSave(ConfigEnableDisable(default = servicerestriction))
1003                 self.typeSelection = NoSave(ConfigSelection(choices = [
1004                         ("channels", _("Channels")),
1005                         ("bouquets", _("Bouquets"))]
1006                 ))
1007                 self.typeSelection.addNotifier(self.refresh, initial_call = False)
1008
1009                 self.reloadList()
1010
1011                 ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
1012
1013                 # Initialize Buttons
1014                 self["key_red"] = StaticText(_("Cancel"))
1015                 self["key_green"] = StaticText(_("OK"))
1016                 self["key_yellow"] = StaticText(_("delete"))
1017                 self["key_blue"] = StaticText(_("New"))
1018
1019                 # Define Actions
1020                 self["actions"] = ActionMap(["SetupActions", "ColorActions"],
1021                         {
1022                                 "cancel": self.cancel,
1023                                 "save": self.save,
1024                                 "yellow": self.remove,
1025                                 "blue": self.new
1026                         }
1027                 )
1028
1029                 # Trigger change
1030                 self.changed()
1031
1032                 self.onLayoutFinish.append(self.setCustomTitle)
1033
1034         def setCustomTitle(self):
1035                 self.setTitle(_("Edit AutoTimer services"))
1036
1037         def saveCurrent(self):
1038                 del self.services[self.idx][:]
1039
1040                 # Warning, accessing a ConfigListEntry directly might be considered evil!
1041
1042                 myl = self["config"].getList()[:]
1043                 myl.pop(0) # Enabled
1044                 myl.pop(0) # Type
1045                 for item in myl:
1046                         self.services[self.idx].append(item[1].value)
1047
1048         def refresh(self, *args, **kwargs):
1049                 self.saveCurrent()
1050
1051                 self.reloadList()
1052                 self["config"].setList(self.list)
1053
1054         def reloadList(self):
1055                 self.list = [
1056                         getConfigListEntry(_("Enable Service Restriction"), self.enabled),
1057                         getConfigListEntry(_("Editing"), self.typeSelection)
1058                 ]
1059
1060                 if self.typeSelection.value == "channels":
1061                         self.idx = 0
1062                 else: # self.typeSelection.value == "bouquets":
1063                         self.idx = 1
1064
1065                 self.list.extend([
1066                         getConfigListEntry(_("Record on"), NoSave(ConfigSelection(choices = [(str(x), ServiceReference(str(x)).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))])))
1067                                 for x in self.services[self.idx]
1068                 ])
1069
1070         def changed(self):
1071                 for x in self.onChangedEntry:
1072                         try:
1073                                 x()
1074                         except Exception:
1075                                 pass
1076
1077         def getCurrentEntry(self):
1078                 return self["config"].getCurrent()[0]
1079
1080         def getCurrentValue(self):
1081                 return str(self["config"].getCurrent()[1].getText())
1082
1083         def createSummary(self):
1084                 return SetupSummary
1085
1086         def remove(self):
1087                 if self["config"].getCurrentIndex() != 0:
1088                         list = self["config"].getList()
1089                         list.remove(self["config"].getCurrent())
1090                         self["config"].setList(list)
1091
1092         def new(self):
1093                 if self.typeSelection.value == "channels":
1094                         self.session.openWithCallback(
1095                                 self.finishedServiceSelection,
1096                                 SimpleChannelSelection,
1097                                 _("Select channel to record on")
1098                         )
1099                 else: # self.typeSelection.value == "bouquets":
1100                         self.session.openWithCallback(
1101                                 self.finishedServiceSelection,
1102                                 SimpleBouquetSelection,
1103                                 _("Select bouquet to record on")
1104                         )
1105
1106         def finishedServiceSelection(self, *args):
1107                 if args:
1108                         list = self["config"].getList()
1109                         sname = args[0].toString()
1110
1111                         if self.typeSelection.value == "channels" and not (args[0].flags & eServiceReference.isGroup):
1112                                 # strip all after last : when adding a (non alternative) channel
1113                                 pos = sname.rfind(':')
1114                                 if pos != -1:
1115                                         if sname[pos-1] == ':':
1116                                                 pos -= 1
1117                                         sname = sname[:pos+1]
1118
1119                         list.append(getConfigListEntry(_("Record on"), NoSave(ConfigSelection(choices = [(sname, ServiceReference(args[0]).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))]))))
1120                         self["config"].setList(list)
1121
1122         def cancel(self):
1123                 if self["config"].isChanged():
1124                         self.session.openWithCallback(
1125                                 self.cancelConfirm,
1126                                 MessageBox,
1127                                 _("Really close without saving settings?")
1128                         )
1129                 else:
1130                         self.close(None)
1131
1132         def cancelConfirm(self, ret):
1133                 if ret:
1134                         self.close(None)
1135
1136         def save(self):
1137                 self.refresh()
1138
1139                 self.close((
1140                         self.enabled.value,
1141                         self.services
1142                 ))
1143
1144 def addAutotimerFromSearchString(session, match):
1145         from AutoTimerComponent import preferredAutoTimerComponent
1146         from AutoTimerImporter import AutoTimerImporter
1147         from plugin import autotimer
1148
1149         # Create instance if needed
1150         if autotimer is None:
1151                 from AutoTimer import AutoTimer
1152                 autotimer = AutoTimer()
1153                 autotimer.readXml()
1154
1155         session.openWithCallback(
1156                 importerCallback,
1157                 AutoTimerImporter,
1158                 preferredAutoTimerComponent(
1159                         autotimer.getUniqueId(),
1160                         match,
1161                         '',             # Match
1162                         True    # Enabled
1163                 ),
1164                 match,          # Proposed Match
1165                 None,           # Proposed Begin
1166                 None,           # Proposed End
1167                 None,           # Proposed Disabled
1168                 None,           # Proposed ServiceReference
1169                 None,           # Proposed afterEvent
1170                 None,           # Proposed justplay
1171                 None,           # Proposed dirname, can we get anything useful here?
1172                 []                      # Proposed tags
1173         )
1174
1175 def addAutotimerFromEvent(session, evt = None, service = None):
1176         from AutoTimerComponent import preferredAutoTimerComponent
1177         from AutoTimerImporter import AutoTimerImporter
1178         from plugin import autotimer
1179
1180         # Create instance if needed
1181         if autotimer is None:
1182                 from AutoTimer import AutoTimer
1183                 autotimer = AutoTimer()
1184                 autotimer.readXml()
1185
1186         match = evt and evt.getEventName() or ""
1187         name = match or "New AutoTimer"
1188         sref = None
1189         if service is not None:
1190                 service = str(service)
1191                 myref = eServiceReference(service)
1192                 if not (myref.flags & eServiceReference.isGroup):
1193                         # strip all after last :
1194                         pos = service.rfind(':')
1195                         if pos != -1:
1196                                 if service[pos-1] == ':':
1197                                         pos -= 1
1198                                 service = service[:pos+1]
1199
1200                 sref = ServiceReference(myref)
1201         if evt:
1202                 # timespan defaults to +- 1h
1203                 begin = evt.getBeginTime()-3600
1204                 end = begin + evt.getDuration()+7200
1205         else:
1206                 begin = end = 0
1207
1208         # XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
1209
1210         session.openWithCallback(
1211                 importerCallback,
1212                 AutoTimerImporter,
1213                 preferredAutoTimerComponent(
1214                         autotimer.getUniqueId(),
1215                         name,
1216                         '',             # Match
1217                         True    # Enabled
1218                 ),
1219                 match,          # Proposed Match
1220                 begin,          # Proposed Begin
1221                 end,            # Proposed End
1222                 None,           # Proposed Disabled
1223                 sref,           # Proposed ServiceReference
1224                 None,           # Proposed afterEvent
1225                 None,           # Proposed justplay
1226                 None,           # Proposed dirname, can we get anything useful here?
1227                 []                      # Proposed tags
1228         )
1229
1230 def addAutotimerFromService(session, service = None):
1231         from AutoTimerComponent import preferredAutoTimerComponent
1232         from AutoTimerImporter import AutoTimerImporter
1233         from plugin import autotimer
1234
1235         # Create instance if needed
1236         if autotimer is None:
1237                 from AutoTimer import AutoTimer
1238                 autotimer = AutoTimer()
1239                 autotimer.readXml()
1240
1241         serviceHandler = eServiceCenter.getInstance()
1242         info = serviceHandler.info(service)
1243
1244         match = info and info.getName(service) or ""
1245         name = match or "New AutoTimer"
1246         sref = info and info.getInfoString(service, iServiceInformation.sServiceref)
1247         if sref:
1248                 # strip all after last :
1249                 pos = sref.rfind(':')
1250                 if pos != -1:
1251                         if sref[pos-1] == ':':
1252                                 pos -= 1
1253                         sref = sref[:pos+1]
1254
1255                 sref = ServiceReference(sref)
1256         if info:
1257                 begin = info.getInfo(service, iServiceInformation.sTimeCreate)
1258                 end = begin + info.getLength(service)
1259         else:
1260                 begin = end = 0
1261
1262         from os.path import dirname
1263         path = dirname(service.getPath())
1264         if not path == '/':
1265                 path += '/'
1266
1267         tags = info.getInfoString(service, iServiceInformation.sTags)
1268         tags = tags and tags.split(' ') or []
1269
1270         # XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
1271
1272         session.openWithCallback(
1273                 importerCallback,
1274                 AutoTimerImporter,
1275                 preferredAutoTimerComponent(
1276                         autotimer.getUniqueId(),
1277                         name,
1278                         '',             # Match
1279                         True    # Enabled
1280                 ),
1281                 match,          # Proposed Match
1282                 begin,          # Proposed Begin
1283                 end,            # Proposed End
1284                 None,           # Proposed Disabled
1285                 sref,           # Proposed ServiceReference
1286                 None,           # Proposed afterEvent
1287                 None,           # Proposed justplay
1288                 path,           # Proposed dirname
1289                 tags            # Proposed tags
1290         )
1291
1292 def importerCallback(ret):
1293         if ret:
1294                 ret, session = ret
1295
1296                 session.openWithCallback(
1297                         editorCallback,
1298                         AutoTimerEditor,
1299                         ret
1300                 )
1301         else:
1302                 # Remove instance if not running in background
1303                 if not config.plugins.autotimer.autopoll.value:
1304                         from plugin import autotimer
1305                         autotimer = None
1306
1307 def editorCallback(ret):
1308         if ret:
1309                 from plugin import autotimer
1310
1311                 # Create instance if needed (should have been created by addAutotimerFrom* above though)
1312                 if autotimer is None:
1313                         from AutoTimer import AutoTimer
1314                         autotimer = AutoTimer()
1315                         autotimer.readXml()
1316
1317                 autotimer.add(ret)
1318
1319                 # Save modified xml
1320                 autotimer.writeXml()
1321
1322         # Remove instance if not running in background
1323         if not config.plugins.autotimer.autopoll.value:
1324                 autotimer = None
1325