[EPGSearch] - new search option with defined filters (AutoTimer must be installed...
[enigma2-plugins.git] / epgsearch / src / EPGSearchFilter.py
1 # for localized messages
2 from enigma import eEPGCache, eServiceReference, iServiceInformation, eServiceCenter
3 from ServiceReference import ServiceReference
4 from Screens.ChoiceBox import ChoiceBox
5 from Screens.Screen import Screen
6 from Components.ActionMap import ActionMap, HelpableActionMap
7 from Components.config import config
8 from Components.ConfigList import ConfigListScreen
9 from Components.config import getConfigListEntry
10
11 from time import localtime, time
12 from Tools.BoundFunction import boundFunction
13
14 # AutoTimer installed?
15 try:
16         from Plugins.Extensions.AutoTimer.AutoTimerEditor import \
17                 AutoTimerEditor, AutoTimerFilterEditor, AutoTimerServiceEditor, hasVps
18         from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
19         from Plugins.Extensions.AutoTimer.AutoTimerConfiguration import buildConfig
20         from Plugins.Extensions.AutoTimer.AutoTimerOverview import AutoTimerOverview
21         from Plugins.Extensions.AutoTimer.AutoTimerImporter import AutoTimerImporter
22 except ImportError:
23         AutoTimerEditor = AutoTimerFilterEditor = AutoTimerServiceEditor = Screen
24         AutoTimer = AutoTimerOverview = AutoTimerImporter = Screen
25         hasVps = False
26
27 class EPGSearchATEditor(AutoTimerEditor):
28         def __init__(self, session, timer, editingDefaults = False, **kwargs):
29                 AutoTimerEditor.__init__(self, session, timer, editingDefaults = False, **kwargs)
30                 
31                 self.skinName = ["EPGSearchATEditor", "AutoTimerEditor"]
32                 self.setup_title = _("SearchFilter Editor")
33                 self.partnerbox = False
34                 self.removeConfigListEntries()
35                 
36         def removeConfigListEntries(self):
37                 #remove config entries not use in EPGSearch filter
38                 try:
39                         self.list.remove(getConfigListEntry(_("Enabled"), self.enabled))
40                         self.list.remove(getConfigListEntry(_("Timer type"), self.justplay))
41                         self.list.remove(getConfigListEntry(_("Custom offset"), self.offset))
42                         #self.list.remove(getConfigListEntry(_("Offset before recording (in m)"), self.offsetbegin))
43                         #self.list.remove(getConfigListEntry(_("Offset after recording (in m)"), self.offsetend))
44                         self.list.remove(getConfigListEntry(_("After event"), self.afterevent))
45                         #self.list.remove(getConfigListEntry(_("Execute \"after event\" during timespan"), self.afterevent_timespan))
46                         #self.list.remove(getConfigListEntry(_("Begin of \"after event\" timespan"), self.afterevent_timespanbegin))
47                         #self.list.remove(getConfigListEntry(_("End of \"after event\" timespan"), self.afterevent_timespanend))
48                         self.list.remove(getConfigListEntry(_("Tags"), self.tags))
49                         self.list.remove(getConfigListEntry(_("Record a maximum of x times"), self.counter))
50                         self.list.remove(getConfigListEntry(_("Use a custom location"), self.useDestination))
51                         if hasVps:
52                                 self.list.remove(getConfigListEntry(_("Activate VPS"), self.vps_enabled))
53                 except:
54                         #import traceback
55                         #traceback.print_exc()
56                         pass
57         
58         def reloadList(self, value):
59                 self.refresh()
60                 self.removeConfigListEntries()
61                 self["config"].setList(self.list)
62
63         def setCustomTitle(self):
64                 self.setTitle(_("Edit EPGSearch search filter"))
65         
66         def editFilter(self):
67                 self.session.openWithCallback(
68                         self.editFilterCallback,
69                         EPSearchFilterEditor,
70                         self.filterSet,
71                         self.excludes,
72                         self.includes
73                 )
74         
75         def editServices(self):
76                 self.session.openWithCallback(
77                         self.editServicesCallback,
78                         EPSearchServiceEditor,
79                         self.serviceRestriction,
80                         self.services,
81                         self.bouquets
82                 )
83
84 class EPSearchFilterEditor(AutoTimerFilterEditor, ConfigListScreen):
85         def __init__(self, session, filterset, excludes, includes):
86                 AutoTimerFilterEditor.__init__(self, session, filterset, excludes, includes)
87                 
88                 self.skinName = ["EPGSearchATFilterEditor", "AutoTimerFilterEditor"]
89                 self.setup_title = _("EPGSearch Filters")
90         
91         def setCustomTitle(self):
92                 self.setTitle(_("Edit EPGSearch filter"))
93
94 class EPSearchServiceEditor(AutoTimerServiceEditor, ConfigListScreen):
95         def __init__(self, session, servicerestriction, servicelist, bouquetlist):
96                 AutoTimerServiceEditor.__init__(self, session, servicerestriction, servicelist, bouquetlist)
97                 
98                 self.skinName = ["EPGSearchATServiceEditor", "AutoTimerServiceEditor"]
99                 self.setup_title = _("EPGSearch Services")
100         
101         def setCustomTitle(self):
102                 self.setTitle(_("Edit EPGSearch Services"))
103
104 class EPGSearchAT(AutoTimer):
105         FILENAME = "/etc/enigma2/epgsearchAT.xml"
106         def readXml(self, **kwargs):
107                 if "xml_string" in kwargs:
108                         AutoTimer.readXml(self, **kwargs)
109
110         def load(self):
111                 result = False
112                 from os import path as os_path
113                 if os_path.exists(EPGSearchAT.FILENAME):
114                         with open(EPGSearchAT.FILENAME, 'r') as file:
115                                 data = file.read()
116                                 kwargs = {"xml_string": data}
117                                 self.readXml(**kwargs)
118                                 result = True
119                 return result
120
121         def save(self, timer=None):
122                 if timer:
123                         self.timers.append(timer)
124                 from Tools.IO import saveFile
125                 saveFile(EPGSearchAT.FILENAME, buildConfig(self.defaultTimer, self.timers))
126
127 def ATeditorCallback(session, save, timer):
128         if timer:
129                 epgsearchAT = EPGSearchAT()
130                 epgsearchAT.add(timer)
131                 total, new, modified, timers, conflicts, similars = epgsearchAT.parseEPG(simulateOnly = True)
132                 results = []
133                 if timers:
134                         epgcache = eEPGCache.getInstance()
135                         for t in timers:
136                                 if timer.hasOffset():
137                                         rbegin = t[1] + timer.offset[0]
138                                         rend = t[2] - timer.offset[1]
139                                 else:
140                                         rbegin = t[1] + config.recording.margin_before.value * 60
141                                         rend = t[2] - config.recording.margin_after.value * 60
142                                 evt = epgcache.lookupEventTime(eServiceReference(t[3]), rbegin)
143                                 if evt:
144                                         results.append((t[3], evt.getEventId(), rbegin, rend - rbegin, t[0]))
145                 
146                 from EPGSearch import EPGSearch
147                 if results:
148                         kwargs = {"AT": results}
149                         session.open(EPGSearch, **kwargs)
150                 else:
151                         session.open(EPGSearch)
152                 if save:
153                         if epgsearchAT.load():
154                                 epgsearchAT.save(timer)
155                         else:
156                                 epgsearchAT.save()
157                 epgsearchAT = None
158
159 def ATimporterCallback(ret):
160         if ret:
161                 ret, session = ret
162                 session.openWithCallback(boundFunction(ATeditorCallback, session, True), EPGSearchATEditor, ret)
163
164 def ATeditCallback(epgsearchAT):
165         if epgsearchAT is not None:
166                 epgsearchAT.save()
167
168 class EPGSearchATOverview(AutoTimerOverview):
169         def __init__(self, session, autotimer):
170                 AutoTimerOverview.__init__(self, session, autotimer)
171                 self["EPGSelectActions"].setEnabled(False)
172                 self["InfobarActions"].setEnabled(False)
173                 self.skinName = ["EPGSearchATOverview", "AutoTimerOverview"]
174                 
175                 self["InfobarActions"] = HelpableActionMap(self, "InfobarActions",
176                         {
177                                 "showMovies": (self.search, _("search for current search filter")),
178                         }
179                 )
180                 
181                 self["MenuActions"] = HelpableActionMap(self, "MenuActions",
182                         {
183                                 "menu": (self.menu, _("Open Context Menu"))
184                         }
185                 )
186
187         def ok(self):
188                 # Edit selected Timer
189                 current = self["entries"].getCurrent()
190                 if current is not None:
191                         self.session.openWithCallback(
192                                 self.editCallback,
193                                 EPGSearchATEditor,
194                                 current
195                         )
196
197         def cancel(self):
198                 if self.changed:
199                         self.session.openWithCallback(self.cancelConfirm, ChoiceBox, title=_('Really close without saving settings?\nWhat do you want to do?') , list=[(_('close without saving'), 'close'), (_('close and save'), 'close_save'),(_('cancel'), 'exit'), ])
200                 else:
201                         self.close(None)
202
203         def cancelConfirm(self, ret):
204                 ret = ret and ret[1]
205                 if ret == 'close':
206                         self.close(None)
207                 elif ret == 'close_save':
208                         self.close(self.autotimer)
209
210         def save(self):
211                 self.close(self.autotimer)
212
213         def search(self):
214                 current = self["entries"].getCurrent()
215                 if current:
216                         self.autotimer.save()
217                         self.changed = False
218                         ATeditorCallback(self.session, False, current)
219
220         def setCustomTitle(self):
221                 self.setTitle(_("EPGSearch search filter overview"))
222
223         def menu(self):
224                 list = [
225                         (_("search for current search filter"), "search filter")
226                 ]
227
228                 self.session.openWithCallback(
229                         self.menuCallback,
230                         ChoiceBox,
231                         list = list,
232                 )
233
234         def menuCallback(self, ret):
235                 ret = ret and ret[1]
236                 if ret:
237                         if ret == "search filter":
238                                 self.search()
239
240         def add(self):
241                 newTimer = self.autotimer.defaultTimer.clone()
242                 newTimer.id = self.autotimer.getUniqueId()
243                 
244                 self.session.openWithCallback(
245                                 self.addCallback,
246                                 EPGSearchATEditor,
247                                 newTimer
248                         )
249
250 class EPGSearchATImporter(AutoTimerImporter):
251         def __init__(self, session, autotimer, name, begin, end, disabled, sref, afterEvent, justplay, dirname, tags):
252                 AutoTimerImporter.__init__(self, session, autotimer, name, begin, end, disabled, sref, afterEvent, justplay, dirname, tags)
253                 self.skinName = ["EPGSearchATImporter", "AutoTimerImporter"]
254
255         def setCustomTitle(self):
256                 self.setTitle(_("Add EPGSearch search filter"))
257
258 def addEPGSearchATFromEvent(session, evt, service, importer_Callback):
259         epgsearchAT = EPGSearchAT()
260         epgsearchAT.load()
261         match = evt and evt.getEventName() or ""
262         name = match or "New Searchfilter"
263         sref = None
264         if service is not None:
265                 service = str(service)
266                 myref = eServiceReference(service)
267                 if not (myref.flags & eServiceReference.isGroup):
268                         # strip all after last :
269                         pos = service.rfind(':')
270                         if pos != -1:
271                                 if service[pos-1] == ':':
272                                         pos -= 1
273                                 service = service[:pos+1]
274
275                 sref = ServiceReference(myref)
276         if evt:
277                 # timespan defaults to +- 1h
278                 begin = evt.getBeginTime()-3600
279                 end = begin + evt.getDuration()+7200
280         else:
281                 begin = end = 0
282
283         # XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
284
285         newTimer = epgsearchAT.defaultTimer.clone()
286         newTimer.id = epgsearchAT.getUniqueId()
287         newTimer.name = name
288         newTimer.match = ''
289         newTimer.enabled = True
290
291         session.openWithCallback(
292                 importer_Callback,
293                 EPGSearchATImporter,
294                 newTimer,
295                 match,          # Proposed Match
296                 begin,          # Proposed Begin
297                 end,            # Proposed End
298                 None,           # Proposed Disabled
299                 sref,           # Proposed ServiceReference
300                 None,           # Proposed afterEvent
301                 None,           # Proposed justplay
302                 None,           # Proposed dirname, can we get anything useful here?
303                 []                      # Proposed tags
304         )
305
306 def addEPGSearchATFromService(session, service, event, importer_Callback):
307         epgsearchAT = EPGSearchAT()
308         epgsearchAT.load()
309         serviceHandler = eServiceCenter.getInstance()
310         info = serviceHandler.info(service)
311         match = (event and event.getEventName()) or (info and info.getName(service)) or ""
312         name = match or "New Searchfilter"
313         sref = info and info.getInfoString(service, iServiceInformation.sServiceref)
314         if sref:
315                 # strip all after last :
316                 pos = sref.rfind(':')
317                 if pos != -1:
318                         if sref[pos-1] == ':':
319                                 pos -= 1
320                         sref = sref[:pos+1]
321
322                 sref = ServiceReference(sref)
323         if info:
324                 begin = info.getInfo(service, iServiceInformation.sTimeCreate)
325                 end = begin + info.getLength(service)
326         else:
327                 begin = end = 0
328
329         newTimer = epgsearchAT.defaultTimer.clone()
330         newTimer.id = epgsearchAT.getUniqueId()
331         newTimer.name = name
332         newTimer.match = ''
333         newTimer.enabled = True
334
335         # XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
336
337         session.openWithCallback(
338                 importer_Callback,
339                 EPGSearchATImporter,
340                 newTimer,
341                 match,          # Proposed Match
342                 begin,          # Proposed Begin
343                 end,            # Proposed End
344                 None,           # Proposed Disabled
345                 sref,           # Proposed ServiceReference
346                 None,           # Proposed afterEvent
347                 None,           # Proposed justplay
348                 None,           # Proposed dirname
349                 None            # Proposed tags
350         )
351
352 # from pluginlist (WHERE_EPG_SELECTION_SINGLE_BLUE, WHERE_CHANNEL_SELECTION_RED)
353 def searchEventWithFilter(session, event, service):
354         if service.getPath() and service.getPath()[0] == "/":
355                 addEPGSearchATFromService(session, eServiceReference(str(service)), event, ATimporterCallback)
356         else:
357                 if event:
358                         addEPGSearchATFromEvent(session, event, service, ATimporterCallback)
359
360 # from pluginlist (WHERE_EPG_SELECTION_SINGLE_BLUE, WHERE_CHANNEL_SELECTION_RED)
361 def openSearchFilterList(session, event, service):
362         epgsearchAT = EPGSearchAT()
363         epgsearchAT.load()
364         session.openWithCallback(ATeditCallback, EPGSearchATOverview, epgsearchAT)
365
366 # from pluginlist (WHERE_MOVIELIST)
367 def addSearchFilterFromMovieList(session, service):
368         info = eServiceCenter.getInstance().info(service)
369         event = info and info.getEvent(service) or None
370         addEPGSearchATFromService(session, service, event, ATimporterCallback)