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