[EPGSearch] - some changes for searchfilter
[enigma2-plugins.git] / epgsearch / src / EPGSearch.py
1 # for localized messages
2 from enigma import eEPGCache, eServiceCenter, eServiceReference, RT_HALIGN_LEFT, \
3                 RT_HALIGN_RIGHT, RT_VALIGN_CENTER, eListboxPythonMultiContent
4
5 from Tools.LoadPixmap import LoadPixmap
6 from Tools.Directories import fileExists, resolveFilename, SCOPE_PLUGINS
7 from ServiceReference import ServiceReference
8
9 from EPGSearchSetup import EPGSearchSetup
10 from EPGSearchFilter import openSearchFilterList as EPGSearchFilter_openSearchFilterList
11
12 from Screens.ChannelSelection import SimpleChannelSelection
13 from Screens.ChoiceBox import ChoiceBox
14 from Screens.EpgSelection import EPGSelection
15 from Screens.ChannelSelection import ChannelSelectionBase
16 from Screens.EventView import EventViewEPGSelect, EventViewBase
17 from Screens.MessageBox import MessageBox
18 from Screens.InfoBar import InfoBar
19 from Screens.Screen import Screen
20 from Plugins.SystemPlugins.Toolkit.NTIVirtualKeyBoard import NTIVirtualKeyBoard
21 from Plugins.Plugin import PluginDescriptor
22
23 from Components.ActionMap import ActionMap, HelpableActionMap
24 from Components.Button import Button
25 from Components.config import config
26 from Components.EpgList import EPGList, EPG_TYPE_SINGLE, EPG_TYPE_MULTI
27 from Components.TimerList import TimerList
28 from Components.Sources.ServiceEvent import ServiceEvent
29 from Components.Sources.Event import Event
30 from Components.ServiceList import ServiceList, PiconLoader
31 from Components.PluginComponent import plugins
32
33 #add Timer
34 from RecordTimer import RecordTimerEntry, parseEvent, AFTEREVENT
35 from Screens.TimerEntry import TimerEntry
36 from Components.UsageConfig import preferredTimerPath
37
38 from . import SearchType
39 from time import localtime, time
40 from operator import itemgetter
41 from Tools.BoundFunction import boundFunction
42 from skin import componentSizes
43
44 # Partnerbox installed and icons in epglist enabled?
45 try:
46         from Plugins.Extensions.Partnerbox.PartnerboxEPGList import \
47                         isInRemoteTimer, getRemoteClockPixmap
48         from Plugins.Extensions.Partnerbox.plugin import \
49                         showPartnerboxIconsinEPGList
50         PartnerBoxIconsEnabled = showPartnerboxIconsinEPGList()
51 except ImportError:
52         PartnerBoxIconsEnabled = False
53
54 # AutoTimer installed?
55 try:
56         from Plugins.Extensions.AutoTimer.AutoTimerEditor import \
57                         addAutotimerFromEvent, addAutotimerFromSearchString
58
59         autoTimerAvailable = True
60 except ImportError:
61         autoTimerAvailable = False
62
63 def searchEvent(session, event, service):
64         if not event:
65                 return
66         session.open(EPGSearch, event.getEventName())
67
68 # Overwrite pzyP4T.__init__ with our modified one
69 basePzyP4T__init__ = None
70 def pzyP4TInit():
71         global basePzyP4T__init__
72         try:
73                 from Plugins.Extensions.pzyP4T.plugin import PzyP4T
74                 if basePzyP4T__init__ is None:
75                         basePzyP4T__init__ = PzyP4T.__init__
76                 PzyP4T.__init__ = PzyP4T__init__
77         except:
78                 basepzyP4T__init__ = None
79
80 # Modified PzyP4T__init__ for audio-key
81 def PzyP4T__init__(self, session):
82         basePzyP4T__init__(self, session)
83
84         def openEPGSearch():
85                 event = event = self["Event"].getCurrentEvent()
86                 if event:
87                         eventName = event.getEventName()
88                         self.session.open(EPGSearch, eventName)
89
90         self["InfobarAudioSelectionActions"] = ActionMap(["InfobarAudioSelectionActions"],
91                         {
92                                 "audioSelection": openEPGSearch,
93                         })
94
95 # Modified EPGSearchList with support for PartnerBox
96 class EPGSearchList(EPGList):
97         def __init__(self, type=EPG_TYPE_SINGLE, selChangedCB=None, timer=None):
98                 EPGList.__init__(self, type, selChangedCB, timer)
99                 self.l.setBuildFunc(self.buildEPGSearchEntry)
100
101                 self.piconLoader = PiconLoader()
102
103                 sizes = componentSizes[EPGList.SKIN_COMPONENT_KEY]
104                 self._iconWidth = sizes.get(EPGList.SKIN_COMPONENT_ICON_WIDTH, 21)
105                 self._iconHeight = sizes.get(EPGList.SKIN_COMPONENT_ICON_HEIGHT, 21)
106                 self._iconHPos = sizes.get(EPGList.SKIN_COMPONENT_ICON_HPOS, 4)
107                 self._itemMargin = sizes.get(EPGList.SKIN_COMPONENT_ITEM_MARGIN, 10)
108
109                 servicelist_sizes = componentSizes["ServiceList"]
110                 self._picon_width = servicelist_sizes.get(ServiceList.KEY_PICON_WIDTH, 58)
111
112                 if PartnerBoxIconsEnabled:
113                         # Partnerbox Clock Icons
114                         self.remote_clock_pixmap = LoadPixmap('/usr/lib/enigma2/python/Plugins/Extensions/Partnerbox/icons/remote_epgclock.png')
115                         self.remote_clock_add_pixmap = LoadPixmap('/usr/lib/enigma2/python/Plugins/Extensions/Partnerbox/icons/remote_epgclock_add.png')
116                         self.remote_clock_pre_pixmap = LoadPixmap('/usr/lib/enigma2/python/Plugins/Extensions/Partnerbox/icons/remote_epgclock_pre.png')
117                         self.remote_clock_post_pixmap = LoadPixmap('/usr/lib/enigma2/python/Plugins/Extensions/Partnerbox/icons/remote_epgclock_post.png')
118                         self.remote_clock_prepost_pixmap = LoadPixmap('/usr/lib/enigma2/python/Plugins/Extensions/Partnerbox/icons/remote_epgclock_prepost.png')
119
120         def buildEPGSearchEntry(self, service, eventId, beginTime, duration, EventName):
121                 rec1 = beginTime and self.timer.isInTimer(eventId, beginTime, duration, service)
122                 # Partnerbox
123                 if PartnerBoxIconsEnabled:
124                         rec2 = beginTime and isInRemoteTimer(self,beginTime, duration, service)
125                 else:
126                         rec2 = False
127                 r1 = self.weekday_rect
128                 r2 = self.datetime_rect
129                 r3 = self.descr_rect
130                 t = localtime(beginTime)
131                 serviceref = ServiceReference(service) # for Servicename
132                 serviceName = serviceref.getServiceName() + ": "
133
134                 #delete serviceName if set it in setup and it is most matched service
135                 if config.plugins.epgsearch.show_sname_in_title.value and service == self.mostSearchService:
136                         serviceName = ""
137
138                 res = [
139                         None, # no private data needed
140                         (eListboxPythonMultiContent.TYPE_TEXT, r1.left(), r1.top(), r1.width(), r1.height(), 0, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, self.days[t[6]]),
141                         (eListboxPythonMultiContent.TYPE_TEXT, r2.left(), r2.top(), r2.width(), r1.height(), 0, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%02d.%02d, %02d:%02d"%(t[2],t[1],t[3],t[4]))
142                 ]
143
144                 #add picon if set this option in setup
145                 picon = None
146                 if config.plugins.epgsearch.show_picon.value:
147                         picon = self.piconLoader.getPicon(service)
148                 left_pos = r3.left()
149                 if picon is not None:
150                         res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHABLEND, left_pos, 2, self._picon_width, r3.height()-3, picon))
151                         left_pos = r3.left() + self._picon_width + self._itemMargin
152                         serviceName = "" #if load picon delete servicename
153
154                 if rec1 or rec2:
155                         if rec1:
156                                 clock_pic = self.getClockPixmap(service, beginTime, duration, eventId)
157                                 # maybe Partnerbox too
158                                 if rec2:
159                                         clock_pic_partnerbox = getRemoteClockPixmap(self,service, beginTime, duration, eventId)
160                         else:
161                                 clock_pic = getRemoteClockPixmap(self,service, beginTime, duration, eventId)
162                         if rec1 and rec2:
163                                 # Partnerbox and local
164                                 res.extend((
165                                         (eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, left_pos, self._iconHPos, self._iconWidth, self._iconHeight, clock_pic),
166                                         (eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, left_pos + self._iconWidth + self._itemMargin, self._iconHPos, self._iconWidth, self._iconHeight, clock_pic_partnerbox),
167                                         (eListboxPythonMultiContent.TYPE_TEXT, left_pos + self._iconWidth*2 + self._itemMargin*2, r3.top(), r3.width(), r3.height(), 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, serviceName + EventName)))
168                         else:
169                                 res.extend((
170                                         (eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, left_pos, self._iconHPos, self._iconWidth, self._iconHeight, clock_pic),
171                                         (eListboxPythonMultiContent.TYPE_TEXT, left_pos + self._iconWidth + self._itemMargin, r3.top(), r3.width(), r3.height(), 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, serviceName + EventName)))
172                 else:
173                         res.append((eListboxPythonMultiContent.TYPE_TEXT, left_pos, r3.top(), r3.width(), r3.height(), 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, serviceName + EventName))
174                 return res
175
176 # main class of plugin
177 class EPGSearch(EPGSelection):
178         def __init__(self, session, *args, **kwargs):
179                 Screen.__init__(self, session)
180                 self.skinName = ["EPGSearch", "EPGSelection"]
181
182                 self.searchargs = args
183                 self.searchkwargs = kwargs
184                 self.currSearch = ""
185                 
186                 self.currSearchSave = False
187                 self.currSearchDescription = False
188                 
189                 # XXX: we lose sort begin/end here
190                 self["key_yellow"] = Button(_("New Search"))
191                 self["key_blue"] = Button(_("History"))
192
193                 # begin stripped copy of EPGSelection.__init__
194                 self.bouquetChangeCB = None
195                 self.serviceChangeCB = None
196                 self.ask_time = -1 #now
197                 self["key_red"] = Button("")
198                 self.closeRecursive = False
199                 self.saved_title = None
200                 self["Service"] = ServiceEvent()
201                 self["Event"] = Event()
202                 self.type = EPG_TYPE_SINGLE
203                 self.currentService=None
204                 self.zapFunc = None
205                 self.sort_type = 0
206                 self["key_green"] = Button(_("Add timer"))
207                 self.key_green_choice = self.ADD_TIMER
208                 self.key_red_choice = self.EMPTY
209                 self["list"] = EPGSearchList(type = self.type, selChangedCB = self.onSelectionChanged, timer = session.nav.RecordTimer)
210                 self["actions"] = ActionMap(["EPGSelectActions", "OkCancelActions", "MenuActions", "InputActions", "InfobarAudioSelectionActions"],
211                         {
212                                 "menu": self.menu,
213                                 "cancel": self.closeScreen,
214                                 "ok": self.eventSelected,
215                                 "timerAdd": self.timerAdd,
216                                 "yellow": self.yellowButtonPressed,
217                                 "blue": self.blueButtonPressed,
218                                 "info": self.infoKeyPressed,
219                                 "red": self.zapTo, # needed --> Partnerbox
220                                 "nextBouquet": self.nextBouquet, # just used in multi epg yet
221                                 "prevBouquet": self.prevBouquet, # just used in multi epg yet
222                                 "nextService": self.nextService, # just used in single epg yet
223                                 "prevService": self.prevService, # just used in single epg yet
224                                 "1": self.importFromTimer,
225                                 "2": self.importFromEPG,
226                                 "3": self.importFromAutoTimer,
227                                 "4": self.addAutoTimer,
228                                 "5": self.exportAutoTimer,
229                                 "6": self.openSPInfoScreen,
230                                 "7": self.openImdb,
231                                 "8": self.openTMDb,
232                                 "9": self.openTMDbSerie,
233                                 "0": self.setup,
234                                 "audioSelection": self.searchNoNumber,
235                         })
236                 
237                 if autoTimerAvailable:
238                         self["EPGSeachFilterActions"] = ActionMap(["WizardActions"],
239                         {
240                                 "video": self.openSearchFilterList, 
241                         })
242                 
243                 self["actions"].csel = self
244                 self["list"].mostSearchService = ""
245                 self.onLayoutFinish.append(self.onCreate)
246                 # end stripped copy of EPGSelection.__init__
247                 
248                 # Partnerbox
249                 if PartnerBoxIconsEnabled:
250                         EPGSelection.PartnerboxInit(self, False)
251                 
252                 self.pluginList = [(p.name, p) for p in plugins.getPlugins(where = [PluginDescriptor.WHERE_EPG_SELECTION_SINGLE_BLUE, PluginDescriptor.WHERE_CHANNEL_SELECTION_RED])]
253
254         def onCreate(self):
255                 self.setTitle(_("EPG Search"))
256                 self.searchtimerlist = None
257                 
258                 if self.searchkwargs and self.searchkwargs.has_key("AT"):
259                         #show matches from SearchFilter
260                         l = self["list"]
261                         l.recalcEntrySize()
262                         timerlist = self.searchkwargs["AT"]
263                         self.searchtimerlist = timerlist
264                         if config.plugins.epgsearch.show_shortdesc.value and len(timerlist):
265                                 epgcache = eEPGCache.getInstance()
266                                 timerlist = self.addShortDescription(epgcache, timerlist)
267                         l.list = timerlist
268                         l.l.setList(timerlist)
269                 elif self.searchargs:
270                         self.doSearchEPG(*self.searchargs)
271                 else:
272                         l = self["list"]
273                         l.recalcEntrySize()
274                         l.list = []
275                         l.l.setList(l.list)
276                 del self.searchargs
277                 del self.searchkwargs
278                 
279                 # Partnerbox
280                 if PartnerBoxIconsEnabled:
281                         EPGSelection.GetPartnerboxTimerlist(self)
282
283         def timerAdd(self):
284                 cur = self["list"].getCurrent()
285                 event = cur[0]
286                 serviceref = cur[1]
287                 if event is None:
288                         return
289                 eventid = event.getEventId()
290                 refstr = serviceref.ref.toString()
291                 for timer in self.session.nav.RecordTimer.timer_list:
292                         if timer.eit == eventid and timer.service_ref.ref.toString() == refstr:
293                                 cb_func = lambda ret : not ret or self.removeTimer(timer)
294                                 self.session.openWithCallback(cb_func, MessageBox, _("Do you really want to delete %s?") % event.getEventName())
295                                 break
296                 else:
297                         event = parseEvent(event)
298                         if self.searchtimerlist:
299                                 #add org searchTitle from search filter to timer (perhaps if changed from SeriesPlugin)
300                                 idx = 0
301                                 for timer in self["list"].list:
302                                         if timer[1] == eventid:
303                                                 break
304                                         idx += 1
305                                 try:
306                                         event_lst = list(event)
307                                         event_lst[2] = self.searchtimerlist[idx][4]
308                                         event = tuple(event_lst)
309                                 except:
310                                         import traceback
311                                         traceback.print_exc()
312
313                         newEntry = RecordTimerEntry(serviceref, checkOldTimers = True, dirname = preferredTimerPath(), *event)
314                         self.session.openWithCallback(self.finishedAdd, TimerEntry, newEntry)
315
316         def closeScreen(self):
317                 # Save our history
318                 config.plugins.epgsearch.save()
319                 EPGSelection.closeScreen(self)
320
321         def yellowButtonPressed(self):
322                 self.session.openWithCallback(
323                         self.searchEPG,
324                         NTIVirtualKeyBoard,
325                         title = _("Enter text to search for"),
326                         text = self.currSearch
327                 )
328
329         def infoKeyPressed(self):
330                 cur = self["list"].getCurrent()
331                 event = cur[0]
332                 service = cur[1]
333                 if event is not None:
334                         self.session.open(EventViewEPGSelect, event, service, self.eventViewCallback, self.openSingleServiceEPG, InfoBar.instance.openMultiServiceEPG, self.openSimilarList)
335
336         def openSearchFilterList(self):
337                 import EPGSearchFilter as EPGSearchFilterFile
338                 reload (EPGSearchFilterFile)
339                 from EPGSearchFilter import openSearchFilterList as EPGSearchFilter_openSearchFilterList
340                 EPGSearchFilter_openSearchFilterList(self.session, None, None)
341
342         def openSimilarList(self, eventid, refstr):
343                 self.session.open(EPGSelection, refstr, None, eventid)
344
345         def openSingleServiceEPG(self):
346                 cur = self["list"].getCurrent()
347                 event = cur[0]
348                 service = cur[1]
349                 if event is not None:
350                         self.session.open(EPGSelection, cur[1].ref)
351
352         def menu(self):
353                 options = [
354                         (_("Import from Timer"), self.importFromTimer),
355                         (_("Import from EPG"), self.importFromEPG),
356                 ]
357                 keys = ["1","2"]
358
359                 if autoTimerAvailable:
360                         options.extend((
361                                 (_("Import from AutoTimer"), self.importFromAutoTimer),
362                                 (_("Save search as AutoTimer"), self.addAutoTimer),
363                                 (_("Export selected as AutoTimer"), self.exportAutoTimer),
364                         ))
365                         keys.extend(("3","4","5"))
366                 if fileExists(resolveFilename(SCOPE_PLUGINS, "Extensions/SeriesPlugin/plugin.py")):
367                         options.append((_("Show series info (SP)"), self.openSPInfoScreen))
368                         keys.append("6")
369
370                 if fileExists(resolveFilename(SCOPE_PLUGINS, "Extensions/IMDb/plugin.py")):
371                         options.append((_("Open selected in IMDb"), self.openImdb))
372                         keys.append("7")
373
374                 if fileExists(resolveFilename(SCOPE_PLUGINS, "Extensions/AdvancedMovieSelection/plugin.py")):
375                         options.append((_("Open selected in TMDB Info (AMS)"), self.openTMDb))
376                         options.append((_("Open selected in TMDB Serie Info (AMS)"), self.openTMDbSerie))
377                         keys.extend(("8","9"))
378
379                 options.append((_("Setup"), self.setup))
380                 keys.append("0")
381
382                 for p in self.pluginList:
383                         if not p in options and p[0] != _("Search EPG"):
384                                 options.append(p)
385
386                 self.session.openWithCallback(
387                         self.menuCallback,
388                         ChoiceBox,
389                         list = options,
390                         keys = keys,
391                         title = _("EPGSearch menu")
392                 )
393
394         def menuCallback(self, ret):
395                 if ret in self.pluginList:
396                         cur = self['list'].getCurrent()
397                         event = cur and cur[0]
398                         service = cur and cur[1]
399                         if event:
400                                 ret[1](self.session, event, service)
401                 else:
402                         ret and ret[1]()
403
404         def importFromTimer(self):
405                 self.session.openWithCallback(
406                         self.searchEPG,
407                         EPGSearchTimerImport
408                 )
409
410         def importFromEPG(self):
411                 self.session.openWithCallback(
412                         self.searchEPG,
413                         EPGSearchChannelSelection
414                 )
415
416         def importFromAutoTimer(self):
417                 removeInstance = False
418                 try:
419                         # Import Instance
420                         from Plugins.Extensions.AutoTimer.plugin import autotimer
421
422                         if autotimer is None:
423                                 removeInstance = True
424                                 # Create an instance
425                                 from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
426                                 autotimer = AutoTimer()
427
428                         # Read in configuration
429                         autotimer.readXml()
430                 except Exception as e:
431                         self.session.open(
432                                 MessageBox,
433                                 _("Could not read AutoTimer timer list: %s") % e,
434                                 type = MessageBox.TYPE_ERROR
435                         )
436                 else:
437                         # Fetch match strings
438                         # XXX: we could use the timer title as description
439                         options = [(x.match, x.match) for x in autotimer.getTimerList()]
440
441                         self.session.openWithCallback(
442                                 self.searchEPGWrapper,
443                                 ChoiceBox,
444                                 title = _("Select text to search for"),
445                                 list = options
446                         )
447                 finally:
448                         # Remove instance if there wasn't one before
449                         if removeInstance:
450                                 autotimer = None
451
452         def addAutoTimer(self):
453                 if autoTimerAvailable:
454                         addAutotimerFromSearchString(self.session, self.currSearch)
455
456         def exportAutoTimer(self):
457                 cur = self['list'].getCurrent()
458                 if cur is None:
459                         return
460                 if autoTimerAvailable:
461                         addAutotimerFromEvent(self.session, cur[0], cur[1])
462
463         def openSPInfoScreen(self):
464                 cur = self['list'].getCurrent()
465                 if cur is None:
466                         return
467                 try:
468                         from Plugins.Extensions.SeriesPlugin.SeriesPluginInfoScreen import SeriesPluginInfoScreen
469                         service=cur[1]
470                         event = cur[0]
471                         self.session.open(SeriesPluginInfoScreen, service, event)
472                 except ImportError as ie:
473                         pass
474
475         def openImdb(self):
476                 cur = self['list'].getCurrent()
477                 if cur is None:
478                         return
479                 try:
480                         from Plugins.Extensions.IMDb.plugin import IMDB
481                         self.session.open(IMDB, cur[0].getEventName())
482                 except ImportError as ie:
483                         pass
484
485         def openTMDb(self):
486                 cur = self['list'].getCurrent()
487                 if cur is None:
488                         return
489                 try:
490                         from Plugins.Extensions.AdvancedMovieSelection.plugin import tmdbInfo
491                         tmdbInfo(self.session, cur[0].getEventName())
492                 except ImportError as ie:
493                         pass
494
495         def openTMDbSerie(self):
496                 cur = self['list'].getCurrent()
497                 if cur is None:
498                         return
499                 try:
500                         from Plugins.Extensions.AdvancedMovieSelection.plugin import tmdbSeriesInfo
501                         tmdbSeriesInfo(self.session, cur[0].getEventName())
502                 except ImportError as ie:
503                         pass
504
505         def setup(self):
506                 self.session.openWithCallback(self.closeSetupCallback, EPGSearchSetup)
507
508         def closeSetupCallback(self):
509                 if self.searchtimerlist:
510                         self.searchargs = None
511                         self.searchkwargs = {"AT": self.searchtimerlist}
512                         self.onCreate()
513                 else:
514                         self.doSearchEPG(self.currSearch, self.currSearchSave, self.currSearchDescription)
515
516         def searchNoNumber(self):
517                 search_txt = self.currSearch
518                 search_txt = search_txt.translate(None, "1234567890(/)").strip()
519                 self.doSearchEPG(search_txt, self.currSearchSave, self.currSearchDescription)
520
521         def blueButtonPressed(self):
522                 options = [(x, x) for x in config.plugins.epgsearch.history.value]
523
524                 if options:
525                         self.session.openWithCallback(
526                                 self.searchEPGWrapper,
527                                 ChoiceBox,
528                                 title = _("Select text to search for"),
529                                 list = options
530                         )
531                 else:
532                         self.session.open(
533                                 MessageBox,
534                                 _("No history"),
535                                 type = MessageBox.TYPE_INFO
536                         )
537
538         def searchEPGWrapper(self, ret):
539                 if ret:
540                         self.searchEPG(ret[1])
541
542         def searchEPG(self, searchString = None, searchSave = True):
543                 if not searchString:
544                         return
545                 searchType = config.plugins.epgsearch.search_type.value
546                 if  searchType == SearchType.ASK:
547                         boundCallback = boundFunction(self.onSearchEPGCallback, searchString=searchString, searchSave=searchSave)
548                         choices = [ (_("Title only"), False),
549                                                 (_("Title and Description"), True) ]
550                         self.session.openWithCallback(boundCallback, ChoiceBox, list=choices, title=_("Where to search for '%s'?") %(searchString), windowTitle=_("EPG Search"))
551                 else:
552                         searchDescription = searchType == SearchType.TITLE_DESCRIPTION
553                         self.doSearchEPG(searchString, searchSave, searchDescription)
554
555         def onSearchEPGCallback(self, answer, searchString=None, searchSave=True):
556                 searchDescription = answer and answer[1]
557                 self.doSearchEPG(searchString, searchSave, searchDescription)
558
559         def doSearchEPG(self, searchString = None, searchSave = True, searchDescription=False):
560                 self.currSearchSave = searchSave
561                 self.currSearchDescription = searchDescription
562                 if searchString:
563                         self.currSearch = searchString
564                         if searchSave:
565                                 # Maintain history
566                                 history = config.plugins.epgsearch.history.value
567                                 if searchString not in history:
568                                         history.insert(0, searchString)
569                                         maxLen = config.plugins.epgsearch.history_length.value
570                                         if len(history) > maxLen:
571                                                 del history[maxLen:]
572                                 else:
573                                         history.remove(searchString)
574                                         history.insert(0, searchString)
575
576                         # Search EPG, default to empty list
577                         searchType = eEPGCache.PARTIAL_TITLE_SEARCH
578                         if config.plugins.epgsearch.search_type.value == "exact_title":
579                                 searchType = eEPGCache.EXACT_TITLE_SEARCH
580                         epgcache = eEPGCache.getInstance() # XXX: the EPGList also keeps an instance of the cache but we better make sure that we get what we want :-)
581                         ret = epgcache.search(('RIBDT', 1000, searchType, searchString, eEPGCache.NO_CASE_CHECK)) or []
582                         if searchDescription:
583                                 ret += epgcache.search(('RIBDT', 1000, eEPGCache.PARTIAL_DESCRIPTION_SEARCH, searchString, eEPGCache.NO_CASE_CHECK)) or []
584                                 #condense by eventids
585                                 condensed = {}
586                                 for item in ret:
587                                         condensed[item[1]] = item
588                                 ret = condensed.values()
589                         ret.sort(key=itemgetter(2)) # sort by time
590
591                         #filter epg-matches for selected bouquet from settings
592                         if config.plugins.epgsearch.search_scope.value != "all" and len(ret):
593                                 ret = self.filterEPGmatches(ret)
594
595                         #add short description to search result
596                         if config.plugins.epgsearch.show_shortdesc.value and len(ret):
597                                 ret = self.addShortDescription(epgcache, ret)
598
599                         #get most searched service
600                         mostSearchService = ""
601                         if not config.plugins.epgsearch.show_picon.value and config.plugins.epgsearch.show_sname_in_title.value and len(ret):
602                                 mostSearchService = self.getMostSearchService(ret)
603
604                         # Update List
605                         l = self["list"]
606
607                         #set mostsearchservice to screen-title
608                         title = _("EPG Search")
609                         l.mostSearchService = mostSearchService #save the value also to EPGList-Class
610                         if not config.plugins.epgsearch.show_picon.value and mostSearchService != "":
611                                 serviceref = ServiceReference(mostSearchService) # for Servicename
612                                 serviceName = serviceref.getServiceName()
613                                 title += " - " + serviceName
614                         self.setTitle(title)
615                         l.recalcEntrySize()
616                         l.list = ret
617                         l.l.setList(ret)
618
619         def getMostSearchService(self, matches):
620                 services = [x[0]for x in matches]
621                 mostSearchService = max(services, key = services.count)
622                 return mostSearchService
623
624         def filterEPGmatches(self, matches):
625                 services = self.getBouquetServiceList(config.plugins.epgsearch.search_scope.value)
626                 if len(services): #only if return services to check
627                         ret1 = []
628                         for event in matches:
629                                 timecheck=True
630                                 if config.plugins.epgsearch.show_events.value == "current_future" and int(event[2])+int(event[3]) < time():
631                                         timecheck = False #if is an old event
632                                 elif config.plugins.epgsearch.show_events.value == "future" and int(event[2]) < time():
633                                         timecheck = False #if is a current or old event
634                                 if config.plugins.epgsearch.show_events.value == "current" and (int(event[2]) > time() or int(event[2])+int(event[3]) < time()):
635                                         timecheck = False #if is a future or an old event
636                                 if str(event[0]) in services and timecheck:
637                                         ret1.append(event)
638                         matches = ret1
639                 return matches
640
641         def addShortDescription(self, epgcache, events):
642                 new_events=[]
643                 for event in events:
644                         epgEvent = epgcache.lookupEventId(eServiceReference(event[0]), int(event[1]))
645                         if epgEvent:
646                                 shortdesc = str(epgEvent.getShortDescription())
647                                 if len(shortdesc) > 0:
648                                         event_lst = list(event)
649                                         event_lst[4] = event_lst[4] + "  |  " + shortdesc
650                                         event = tuple(event_lst)
651                         new_events.append(event)
652
653                 return new_events
654
655         def getBouquetServiceList(self, bouquet="current"):
656                 infoBarInstance = InfoBar.instance
657                 if infoBarInstance is not None:
658                         servicelist = infoBarInstance.servicelist
659                         if bouquet == "current":
660                                 bouquet = servicelist.getRoot().toString()
661                         services = infoBarInstance.getBouquetServices(eServiceReference(bouquet))
662
663                         service_list = []
664                         for service in services:
665                                 service_ref = service.ref.toString()
666
667                                 serviceref_split = service_ref.split(":")
668                                 if len(serviceref_split)>10: #perhaps on ip-tv or renamed service
669                                         serviceref_split[0]="1"
670                                         serviceref_split[1]="0"
671                                         #cut the service_ref
672                                         service_ref = ":".join(serviceref_split[:10]) + ":"
673
674                                 service_list.append(service_ref)
675
676                         return service_list
677
678 class EPGSearchTimerImport(Screen):
679         def __init__(self, session):
680                 Screen.__init__(self, session)
681                 self.skinName = ["EPGSearchTimerImport", "TimerEditList"]
682
683                 self.list = []
684                 self.fillTimerList()
685
686                 self["timerlist"] = TimerList(self.list)
687
688                 self["key_red"] = Button(_("Cancel"))
689                 self["key_green"] = Button(_("OK"))
690                 self["key_yellow"] = Button("")
691                 self["key_blue"] = Button("")
692
693                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"],
694                 {
695                         "ok": self.search,
696                         "cancel": self.cancel,
697                         "green": self.search,
698                         "red": self.cancel
699                 }, -1)
700                 self.onLayoutFinish.append(self.setCustomTitle)
701
702         def setCustomTitle(self):
703                 self.setTitle(_("Select a timer to search"))
704
705         def fillTimerList(self):
706                 l = self.list
707                 del l[:]
708
709                 for timer in self.session.nav.RecordTimer.timer_list:
710                         l.append((timer, False))
711
712                 for timer in self.session.nav.RecordTimer.processed_timers:
713                         l.append((timer, True))
714                 l.sort(key = lambda x: x[0].begin)
715
716         def search(self):
717                 cur = self["timerlist"].getCurrent()
718                 if cur:
719                         self.close(cur.name)
720
721         def cancel(self):
722                 self.close(None)
723
724 class EPGSearchChannelSelection(SimpleChannelSelection):
725         def __init__(self, session):
726                 SimpleChannelSelection.__init__(self, session, _("Channel Selection"))
727                 self.skinName = ["EPGSearchChannelSelection", "SimpleChannelSelection"]
728
729                 self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
730                 {
731                                 "showEPGList": self.channelSelected
732                 })
733
734         def channelSelected(self):
735                 ref = self.getCurrentSelection()
736                 if (ref.flags & 7) == 7:
737                         self.enterPath(ref)
738                 elif not (ref.flags & eServiceReference.isMarker):
739                         self.session.openWithCallback(
740                                 self.epgClosed,
741                                 EPGSearchEPGSelection,
742                                 ref,
743                                 False
744                         )
745
746         def epgClosed(self, ret = None):
747                 if ret:
748                         self.close(ret)
749
750 class EPGSearchEPGSelection(EPGSelection):
751         def __init__(self, session, ref, openPlugin):
752                 EPGSelection.__init__(self, session, ref)
753                 self.skinName = ["EPGSearchEPGSelection", "EPGSelection"]
754                 self["key_green"].text = _("Search")
755                 self.openPlugin = openPlugin
756
757         def infoKeyPressed(self):
758                 self.timerAdd()
759
760         def timerAdd(self):
761                 cur = self["list"].getCurrent()
762                 evt = cur[0]
763                 sref = cur[1]
764                 if not evt:
765                         return
766
767                 if self.openPlugin:
768                         self.session.open(EPGSearch,evt.getEventName())
769                 else:
770                         self.close(evt.getEventName())