1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.Harddisk import harddiskmanager
6 from Components.Input import Input
7 from Components.Label import Label
8 from Components.PluginComponent import plugins
9 from Components.ServiceEventTracker import ServiceEventTracker
10 from Components.Sources.Boolean import Boolean
11 from Components.config import config, ConfigBoolean, ConfigClock
12 from Components.SystemInfo import SystemInfo
13 from Components.UsageConfig import preferredInstantRecordPath, defaultMoviePath
14 from EpgSelection import EPGSelection
15 from Plugins.Plugin import PluginDescriptor
17 from Screen import Screen
18 from Screens.ChoiceBox import ChoiceBox
19 from Screens.Dish import Dish
20 from Screens.EventView import EventViewEPGSelect, EventViewSimple
21 from Screens.InputBox import InputBox
22 from Screens.MessageBox import MessageBox
23 from Screens.MinuteInput import MinuteInput
24 from Screens.TimerSelection import TimerSelection
25 from Screens.PictureInPicture import PictureInPicture
26 from Screens.SubtitleDisplay import SubtitleDisplay
27 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
28 from Screens.TimeDateInput import TimeDateInput
29 from Screens.UnhandledKey import UnhandledKey
30 from ServiceReference import ServiceReference
32 from Tools import Notifications
33 from Tools.Directories import fileExists
35 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
36 iPlayableService, eServiceReference, eEPGCache, eActionMap
38 from time import time, localtime, strftime
39 from os import stat as os_stat
40 from bisect import insort
42 from RecordTimer import RecordTimerEntry, RecordTimer
45 from Menu import MainMenu, mdom
49 self.dishDialog = self.session.instantiateDialog(Dish)
51 class InfoBarUnhandledKey:
53 self.unhandledKeyDialog = self.session.instantiateDialog(UnhandledKey)
54 self.hideTimer = eTimer()
55 self.hideTimer.callback.append(self.unhandledKeyDialog.hide)
56 self.checkUnusedTimer = eTimer()
57 self.checkUnusedTimer.callback.append(self.checkUnused)
58 self.onLayoutFinish.append(self.unhandledKeyDialog.hide)
59 eActionMap.getInstance().bindAction('', -0x7FFFFFFF, self.actionA) #highest prio
60 eActionMap.getInstance().bindAction('', 0x7FFFFFFF, self.actionB) #lowest prio
65 #this function is called on every keypress!
66 def actionA(self, key, flag):
70 self.flags = self.uflags = 0
71 self.flags |= (1<<flag)
73 self.checkUnusedTimer.start(0, True)
76 #this function is only called when no other action has handled this key
77 def actionB(self, key, flag):
79 self.uflags |= (1<<flag)
81 def checkUnused(self):
82 if self.flags == self.uflags:
83 self.unhandledKeyDialog.show()
84 self.hideTimer.start(2000, True)
86 class InfoBarShowHide:
87 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
95 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
97 "toggleShow": self.toggleShow,
99 }, 1) # lower prio to make it possible to override ok and cancel..
101 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
103 iPlayableService.evStart: self.serviceStarted,
106 self.__state = self.STATE_SHOWN
109 self.hideTimer = eTimer()
110 self.hideTimer.callback.append(self.doTimerHide)
111 self.hideTimer.start(5000, True)
113 self.onShow.append(self.__onShow)
114 self.onHide.append(self.__onHide)
116 def serviceStarted(self):
118 if config.usage.show_infobar_on_zap.value:
122 self.__state = self.STATE_SHOWN
123 self.startHideTimer()
125 def startHideTimer(self):
126 if self.__state == self.STATE_SHOWN and not self.__locked:
127 idx = config.usage.infobar_timeout.index
129 self.hideTimer.start(idx*1000, True)
132 self.__state = self.STATE_HIDDEN
136 self.startHideTimer()
138 def doTimerHide(self):
139 self.hideTimer.stop()
140 if self.__state == self.STATE_SHOWN:
143 def toggleShow(self):
144 if self.__state == self.STATE_SHOWN:
146 self.hideTimer.stop()
147 elif self.__state == self.STATE_HIDDEN:
151 self.__locked = self.__locked + 1
154 self.hideTimer.stop()
156 def unlockShow(self):
157 self.__locked = self.__locked - 1
159 self.startHideTimer()
161 # def startShow(self):
162 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
163 # self.__state = self.STATE_SHOWN
165 # def startHide(self):
166 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
167 # self.__state = self.STATE_HIDDEN
169 class NumberZap(Screen):
176 self.close(int(self["number"].getText()))
178 def keyNumberGlobal(self, number):
179 self.Timer.start(3000, True) #reset timer
180 self.field = self.field + str(number)
181 self["number"].setText(self.field)
182 if len(self.field) >= 4:
185 def __init__(self, session, number):
186 Screen.__init__(self, session)
187 self.field = str(number)
189 self["channel"] = Label(_("Channel:"))
191 self["number"] = Label(self.field)
193 self["actions"] = NumberActionMap( [ "SetupActions" ],
197 "1": self.keyNumberGlobal,
198 "2": self.keyNumberGlobal,
199 "3": self.keyNumberGlobal,
200 "4": self.keyNumberGlobal,
201 "5": self.keyNumberGlobal,
202 "6": self.keyNumberGlobal,
203 "7": self.keyNumberGlobal,
204 "8": self.keyNumberGlobal,
205 "9": self.keyNumberGlobal,
206 "0": self.keyNumberGlobal
209 self.Timer = eTimer()
210 self.Timer.callback.append(self.keyOK)
211 self.Timer.start(3000, True)
213 class InfoBarNumberZap:
214 """ Handles an initial number for NumberZapping """
216 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
218 "1": self.keyNumberGlobal,
219 "2": self.keyNumberGlobal,
220 "3": self.keyNumberGlobal,
221 "4": self.keyNumberGlobal,
222 "5": self.keyNumberGlobal,
223 "6": self.keyNumberGlobal,
224 "7": self.keyNumberGlobal,
225 "8": self.keyNumberGlobal,
226 "9": self.keyNumberGlobal,
227 "0": self.keyNumberGlobal,
230 def keyNumberGlobal(self, number):
231 # print "You pressed number " + str(number)
233 if isinstance(self, InfoBarPiP) and self.pipHandles0Action():
234 self.pipDoHandle0Action()
236 self.servicelist.recallPrevService()
238 if self.has_key("TimeshiftActions") and not self.timeshift_enabled:
239 self.session.openWithCallback(self.numberEntered, NumberZap, number)
241 def numberEntered(self, retval):
242 # print self.servicelist
244 self.zapToNumber(retval)
246 def searchNumberHelper(self, serviceHandler, num, bouquet):
247 servicelist = serviceHandler.list(bouquet)
248 if not servicelist is None:
250 serviceIterator = servicelist.getNext()
251 if not serviceIterator.valid(): #check end of list
253 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
256 if not num: #found service with searched number ?
257 return serviceIterator, 0
260 def zapToNumber(self, number):
261 bouquet = self.servicelist.bouquet_root
263 serviceHandler = eServiceCenter.getInstance()
264 if not config.usage.multibouquet.value:
265 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
267 bouquetlist = serviceHandler.list(bouquet)
268 if not bouquetlist is None:
270 bouquet = bouquetlist.getNext()
271 if not bouquet.valid(): #check end of list
273 if bouquet.flags & eServiceReference.isDirectory:
274 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
275 if not service is None:
276 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
277 self.servicelist.clearPath()
278 if self.servicelist.bouquet_root != bouquet:
279 self.servicelist.enterPath(self.servicelist.bouquet_root)
280 self.servicelist.enterPath(bouquet)
281 self.servicelist.setCurrentSelection(service) #select the service in servicelist
282 self.servicelist.zap()
284 config.misc.initialchannelselection = ConfigBoolean(default = True)
286 class InfoBarChannelSelection:
287 """ ChannelSelection - handles the channelSelection dialog and the initial
288 channelChange actions which open the channelSelection dialog """
291 self.servicelist = self.session.instantiateDialog(ChannelSelection)
293 if config.misc.initialchannelselection.value:
294 self.onShown.append(self.firstRun)
296 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
298 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
299 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
300 "zapUp": (self.zapUp, _("previous channel")),
301 "zapDown": (self.zapDown, _("next channel")),
302 "historyBack": (self.historyBack, _("previous channel in history")),
303 "historyNext": (self.historyNext, _("next channel in history")),
304 "openServiceList": (self.openServiceList, _("open servicelist")),
307 def showTvChannelList(self, zap=False):
308 self.servicelist.setModeTv()
310 self.servicelist.zap()
311 self.session.execDialog(self.servicelist)
313 def showRadioChannelList(self, zap=False):
314 self.servicelist.setModeRadio()
316 self.servicelist.zap()
317 self.session.execDialog(self.servicelist)
320 self.onShown.remove(self.firstRun)
321 config.misc.initialchannelselection.value = False
322 config.misc.initialchannelselection.save()
323 self.switchChannelDown()
325 def historyBack(self):
326 self.servicelist.historyBack()
328 def historyNext(self):
329 self.servicelist.historyNext()
331 def switchChannelUp(self):
332 self.servicelist.moveUp()
333 self.session.execDialog(self.servicelist)
335 def switchChannelDown(self):
336 self.servicelist.moveDown()
337 self.session.execDialog(self.servicelist)
339 def openServiceList(self):
340 self.session.execDialog(self.servicelist)
343 if self.servicelist.inBouquet():
344 prev = self.servicelist.getCurrentSelection()
346 prev = prev.toString()
348 if config.usage.quickzap_bouquet_change.value:
349 if self.servicelist.atBegin():
350 self.servicelist.prevBouquet()
351 self.servicelist.moveUp()
352 cur = self.servicelist.getCurrentSelection()
353 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
356 self.servicelist.moveUp()
357 self.servicelist.zap()
360 if self.servicelist.inBouquet():
361 prev = self.servicelist.getCurrentSelection()
363 prev = prev.toString()
365 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
366 self.servicelist.nextBouquet()
368 self.servicelist.moveDown()
369 cur = self.servicelist.getCurrentSelection()
370 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
373 self.servicelist.moveDown()
374 self.servicelist.zap()
377 """ Handles a menu action, to open the (main) menu """
379 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
381 "mainMenu": (self.mainMenu, _("Enter main menu...")),
383 self.session.infobar = None
386 print "loading mainmenu XML..."
387 menu = mdom.getroot()
388 assert menu.tag == "menu", "root element in menu must be 'menu'!"
390 self.session.infobar = self
391 # so we can access the currently active infobar from screens opened from within the mainmenu
392 # at the moment used from the SubserviceSelection
394 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu)
396 def mainMenuClosed(self, *val):
397 self.session.infobar = None
399 class InfoBarSimpleEventView:
400 """ Opens the Eventview for now/next """
402 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
404 "showEventInfo": (self.openEventView, _("show event details")),
405 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
408 def showEventInfoWhenNotVisible(self):
415 def openEventView(self):
417 self.epglist = epglist
418 service = self.session.nav.getCurrentService()
419 ref = self.session.nav.getCurrentlyPlayingServiceReference()
420 info = service.info()
428 self.session.open(EventViewSimple, epglist[0], ServiceReference(ref), self.eventViewCallback)
430 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
431 epglist = self.epglist
434 epglist[0] = epglist[1]
438 class SimpleServicelist:
439 def __init__(self, services):
440 self.services = services
441 self.length = len(services)
444 def selectService(self, service):
450 while self.services[self.current].ref != service:
452 if self.current >= self.length:
456 def nextService(self):
459 if self.current+1 < self.length:
464 def prevService(self):
467 if self.current-1 > -1:
470 self.current = self.length - 1
472 def currentService(self):
473 if not self.length or self.current >= self.length:
475 return self.services[self.current]
478 """ EPG - Opens an EPG list when the showEPGList action fires """
480 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
482 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
485 self.is_now_next = False
487 self.bouquetSel = None
488 self.eventView = None
489 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
491 "showEventInfo": (self.openEventView, _("show EPG...")),
492 "showEventInfoPlugin": (self.showEventInfoPlugins, _("show single service EPG...")),
493 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
496 def showEventInfoWhenNotVisible(self):
503 def zapToService(self, service):
504 if not service is None:
505 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
506 self.servicelist.clearPath()
507 if self.servicelist.bouquet_root != self.epg_bouquet:
508 self.servicelist.enterPath(self.servicelist.bouquet_root)
509 self.servicelist.enterPath(self.epg_bouquet)
510 self.servicelist.setCurrentSelection(service) #select the service in servicelist
511 self.servicelist.zap()
513 def getBouquetServices(self, bouquet):
515 servicelist = eServiceCenter.getInstance().list(bouquet)
516 if not servicelist is None:
518 service = servicelist.getNext()
519 if not service.valid(): #check if end of list
521 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
523 services.append(ServiceReference(service))
526 def openBouquetEPG(self, bouquet, withCallback=True):
527 services = self.getBouquetServices(bouquet)
529 self.epg_bouquet = bouquet
531 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
533 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
535 def changeBouquetCB(self, direction, epg):
538 self.bouquetSel.down()
541 bouquet = self.bouquetSel.getCurrent()
542 services = self.getBouquetServices(bouquet)
544 self.epg_bouquet = bouquet
545 epg.setServices(services)
547 def closed(self, ret=False):
548 closedScreen = self.dlg_stack.pop()
549 if self.bouquetSel and closedScreen == self.bouquetSel:
550 self.bouquetSel = None
551 elif self.eventView and closedScreen == self.eventView:
552 self.eventView = None
554 dlgs=len(self.dlg_stack)
556 self.dlg_stack[dlgs-1].close(dlgs > 1)
558 def openMultiServiceEPG(self, withCallback=True):
559 bouquets = self.servicelist.getBouquetList()
564 if cnt > 1: # show bouquet list
566 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
567 self.dlg_stack.append(self.bouquetSel)
569 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
571 self.openBouquetEPG(bouquets[0][1], withCallback)
573 def changeServiceCB(self, direction, epg):
576 self.serviceSel.nextService()
578 self.serviceSel.prevService()
579 epg.setService(self.serviceSel.currentService())
581 def SingleServiceEPGClosed(self, ret=False):
582 self.serviceSel = None
584 def openSingleServiceEPG(self):
585 ref=self.session.nav.getCurrentlyPlayingServiceReference()
587 if self.servicelist.getMutableList() is not None: # bouquet in channellist
588 current_path = self.servicelist.getRoot()
589 services = self.getBouquetServices(current_path)
590 self.serviceSel = SimpleServicelist(services)
591 if self.serviceSel.selectService(ref):
592 self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref, serviceChangeCB = self.changeServiceCB)
594 self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref)
596 self.session.open(EPGSelection, ref)
598 def showEventInfoPlugins(self):
599 list = [(p.name, boundFunction(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EVENTINFO)]
602 list.append((_("show single service EPG..."), self.openSingleServiceEPG))
603 self.session.openWithCallback(self.EventInfoPluginChosen, ChoiceBox, title=_("Please choose an extension..."), list = list, skin_name = "EPGExtensionsList")
605 self.openSingleServiceEPG()
607 def runPlugin(self, plugin):
608 plugin(session = self.session, servicelist = self.servicelist)
610 def EventInfoPluginChosen(self, answer):
611 if answer is not None:
614 def openSimilarList(self, eventid, refstr):
615 self.session.open(EPGSelection, refstr, None, eventid)
617 def getNowNext(self):
619 service = self.session.nav.getCurrentService()
620 info = service and service.info()
621 ptr = info and info.getEvent(0)
624 ptr = info and info.getEvent(1)
627 self.epglist = epglist
629 def __evEventInfoChanged(self):
630 if self.is_now_next and len(self.dlg_stack) == 1:
632 assert self.eventView
634 self.eventView.setEvent(self.epglist[0])
636 def openEventView(self):
637 ref = self.session.nav.getCurrentlyPlayingServiceReference()
639 epglist = self.epglist
641 self.is_now_next = False
642 epg = eEPGCache.getInstance()
643 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
646 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
650 self.is_now_next = True
652 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
653 self.dlg_stack.append(self.eventView)
655 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
656 self.openMultiServiceEPG(False)
658 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
659 epglist = self.epglist
662 epglist[0]=epglist[1]
666 class InfoBarRdsDecoder:
667 """provides RDS and Rass support/display"""
669 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
670 self.rass_interactive = None
672 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
674 iPlayableService.evEnd: self.__serviceStopped,
675 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
678 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
680 "startRassInteractive": self.startRassInteractive
683 self["RdsActions"].setEnabled(False)
685 self.onLayoutFinish.append(self.rds_display.show)
686 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
688 def RassInteractivePossibilityChanged(self, state):
689 self["RdsActions"].setEnabled(state)
691 def RassSlidePicChanged(self):
692 if not self.rass_interactive:
693 service = self.session.nav.getCurrentService()
694 decoder = service and service.rdsDecoder()
696 decoder.showRassSlidePicture()
698 def __serviceStopped(self):
699 if self.rass_interactive is not None:
700 rass_interactive = self.rass_interactive
701 self.rass_interactive = None
702 rass_interactive.close()
704 def startRassInteractive(self):
705 self.rds_display.hide()
706 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
708 def RassInteractiveClosed(self, *val):
709 if self.rass_interactive is not None:
710 self.rass_interactive = None
711 self.RassSlidePicChanged()
712 self.rds_display.show()
715 """handles actions like seeking, pause"""
717 SEEK_STATE_PLAY = (0, 0, 0, ">")
718 SEEK_STATE_PAUSE = (1, 0, 0, "||")
719 SEEK_STATE_EOF = (1, 0, 0, "END")
721 def __init__(self, actionmap = "InfobarSeekActions", useSeekBackHack=True):
722 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
724 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
725 iPlayableService.evStart: self.__serviceStarted,
727 iPlayableService.evEOF: self.__evEOF,
728 iPlayableService.evSOF: self.__evSOF,
731 class InfoBarSeekActionMap(HelpableActionMap):
732 def __init__(self, screen, *args, **kwargs):
733 HelpableActionMap.__init__(self, screen, *args, **kwargs)
736 def action(self, contexts, action):
737 print "action:", action
738 if action[:5] == "seek:":
739 time = int(action[5:])
740 self.screen.doSeekRelative(time * 90000)
742 elif action[:8] == "seekdef:":
743 key = int(action[8:])
744 time = (-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
745 -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
746 -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value)[key-1]
747 self.screen.doSeekRelative(time * 90000)
750 return HelpableActionMap.action(self, contexts, action)
752 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
754 "playpauseService": self.playpauseService,
755 "pauseService": (self.pauseService, _("pause")),
756 "unPauseService": (self.unPauseService, _("continue")),
758 "seekFwd": (self.seekFwd, _("skip forward")),
759 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
760 "seekBack": (self.seekBack, _("skip backward")),
761 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)"))
763 # give them a little more priority to win over color buttons
765 self["SeekActions"].setEnabled(False)
767 self.seekstate = self.SEEK_STATE_PLAY
768 self.lastseekstate = self.SEEK_STATE_PLAY
770 self.onPlayStateChanged = [ ]
772 self.lockedBecauseOfSkipping = False
774 self.__seekableStatusChanged()
776 def makeStateForward(self, n):
777 # minspeed = config.seek.stepwise_minspeed.value
778 # repeat = int(config.seek.stepwise_repeat.value)
779 # if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
780 # return (0, n * repeat, repeat, ">> %dx" % n)
782 return (0, n, 0, ">> %dx" % n)
784 def makeStateBackward(self, n):
785 # minspeed = config.seek.stepwise_minspeed.value
786 # repeat = int(config.seek.stepwise_repeat.value)
787 # if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
788 # return (0, -n * repeat, repeat, "<< %dx" % n)
790 return (0, -n, 0, "<< %dx" % n)
792 def makeStateSlowMotion(self, n):
793 return (0, 0, n, "/%d" % n)
795 def isStateForward(self, state):
798 def isStateBackward(self, state):
801 def isStateSlowMotion(self, state):
802 return state[1] == 0 and state[2] > 1
804 def getHigher(self, n, lst):
810 def getLower(self, n, lst):
818 def showAfterSeek(self):
819 if isinstance(self, InfoBarShowHide):
829 service = self.session.nav.getCurrentService()
833 seek = service.seek()
835 if seek is None or not seek.isCurrentlySeekable():
840 def isSeekable(self):
841 if self.getSeek() is None:
845 def __seekableStatusChanged(self):
846 # print "seekable status changed!"
847 if not self.isSeekable():
848 self["SeekActions"].setEnabled(False)
849 # print "not seekable, return to play"
850 self.setSeekState(self.SEEK_STATE_PLAY)
852 self["SeekActions"].setEnabled(True)
855 def __serviceStarted(self):
856 self.seekstate = self.SEEK_STATE_PLAY
857 self.__seekableStatusChanged()
859 def setSeekState(self, state):
860 service = self.session.nav.getCurrentService()
865 if not self.isSeekable():
866 if state not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE):
867 state = self.SEEK_STATE_PLAY
869 pauseable = service.pause()
871 if pauseable is None:
872 print "not pauseable."
873 state = self.SEEK_STATE_PLAY
875 self.seekstate = state
877 if pauseable is not None:
878 if self.seekstate[0]:
879 print "resolved to PAUSE"
881 elif self.seekstate[1]:
882 print "resolved to FAST FORWARD"
883 pauseable.setFastForward(self.seekstate[1])
884 elif self.seekstate[2]:
885 print "resolved to SLOW MOTION"
886 pauseable.setSlowMotion(self.seekstate[2])
888 print "resolved to PLAY"
891 for c in self.onPlayStateChanged:
894 self.checkSkipShowHideLock()
898 def playpauseService(self):
899 if self.seekstate != self.SEEK_STATE_PLAY:
900 self.unPauseService()
904 def pauseService(self):
905 if self.seekstate == self.SEEK_STATE_PAUSE:
906 if config.seek.on_pause.value == "play":
907 self.unPauseService()
908 elif config.seek.on_pause.value == "step":
909 self.doSeekRelative(1)
910 elif config.seek.on_pause.value == "last":
911 self.setSeekState(self.lastseekstate)
912 self.lastseekstate = self.SEEK_STATE_PLAY
914 if self.seekstate != self.SEEK_STATE_EOF:
915 self.lastseekstate = self.seekstate
916 self.setSeekState(self.SEEK_STATE_PAUSE);
918 def unPauseService(self):
920 if self.seekstate == self.SEEK_STATE_PLAY:
922 self.setSeekState(self.SEEK_STATE_PLAY)
924 def doSeek(self, pts):
925 seekable = self.getSeek()
930 def doSeekRelative(self, pts):
931 seekable = self.getSeek()
934 prevstate = self.seekstate
936 if self.seekstate == self.SEEK_STATE_EOF:
937 if prevstate == self.SEEK_STATE_PAUSE:
938 self.setSeekState(self.SEEK_STATE_PAUSE)
940 self.setSeekState(self.SEEK_STATE_PLAY)
941 seekable.seekRelative(pts<0 and -1 or 1, abs(pts))
942 if abs(pts) > 100 and config.usage.show_infobar_on_skip.value:
946 if self.seekstate == self.SEEK_STATE_PLAY:
947 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
948 elif self.seekstate == self.SEEK_STATE_PAUSE:
949 if len(config.seek.speeds_slowmotion.value):
950 self.setSeekState(self.makeStateSlowMotion(config.seek.speeds_slowmotion.value[-1]))
952 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
953 elif self.seekstate == self.SEEK_STATE_EOF:
955 elif self.isStateForward(self.seekstate):
956 speed = self.seekstate[1]
957 if self.seekstate[2]:
958 speed /= self.seekstate[2]
959 speed = self.getHigher(speed, config.seek.speeds_forward.value) or config.seek.speeds_forward.value[-1]
960 self.setSeekState(self.makeStateForward(speed))
961 elif self.isStateBackward(self.seekstate):
962 speed = -self.seekstate[1]
963 if self.seekstate[2]:
964 speed /= self.seekstate[2]
965 speed = self.getLower(speed, config.seek.speeds_backward.value)
967 self.setSeekState(self.makeStateBackward(speed))
969 self.setSeekState(self.SEEK_STATE_PLAY)
970 elif self.isStateSlowMotion(self.seekstate):
971 speed = self.getLower(self.seekstate[2], config.seek.speeds_slowmotion.value) or config.seek.speeds_slowmotion.value[0]
972 self.setSeekState(self.makeStateSlowMotion(speed))
975 seekstate = self.seekstate
976 if seekstate == self.SEEK_STATE_PLAY:
977 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
978 elif seekstate == self.SEEK_STATE_EOF:
979 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
980 self.doSeekRelative(-6)
981 elif seekstate == self.SEEK_STATE_PAUSE:
982 self.doSeekRelative(-1)
983 elif self.isStateForward(seekstate):
986 speed /= seekstate[2]
987 speed = self.getLower(speed, config.seek.speeds_forward.value)
989 self.setSeekState(self.makeStateForward(speed))
991 self.setSeekState(self.SEEK_STATE_PLAY)
992 elif self.isStateBackward(seekstate):
993 speed = -seekstate[1]
995 speed /= seekstate[2]
996 speed = self.getHigher(speed, config.seek.speeds_backward.value) or config.seek.speeds_backward.value[-1]
997 self.setSeekState(self.makeStateBackward(speed))
998 elif self.isStateSlowMotion(seekstate):
999 speed = self.getHigher(seekstate[2], config.seek.speeds_slowmotion.value)
1001 self.setSeekState(self.makeStateSlowMotion(speed))
1003 self.setSeekState(self.SEEK_STATE_PAUSE)
1005 def seekFwdManual(self):
1006 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
1008 def fwdSeekTo(self, minutes):
1009 print "Seek", minutes, "minutes forward"
1010 self.doSeekRelative(minutes * 60 * 90000)
1012 def seekBackManual(self):
1013 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
1015 def rwdSeekTo(self, minutes):
1017 self.doSeekRelative(-minutes * 60 * 90000)
1019 def checkSkipShowHideLock(self):
1020 wantlock = self.seekstate != self.SEEK_STATE_PLAY
1022 if config.usage.show_infobar_on_skip.value:
1023 if self.lockedBecauseOfSkipping and not wantlock:
1025 self.lockedBecauseOfSkipping = False
1027 if wantlock and not self.lockedBecauseOfSkipping:
1029 self.lockedBecauseOfSkipping = True
1031 def calcRemainingTime(self):
1032 seekable = self.getSeek()
1033 if seekable is not None:
1034 len = seekable.getLength()
1036 tmp = self.cueGetEndCutPosition()
1041 pos = seekable.getPlayPosition()
1042 speednom = self.seekstate[1] or 1
1043 speedden = self.seekstate[2] or 1
1044 if not len[0] and not pos[0]:
1045 if len[1] <= pos[1]:
1047 time = (len[1] - pos[1])*speedden/(90*speednom)
1052 if self.seekstate == self.SEEK_STATE_EOF:
1055 # if we are seeking forward, we try to end up ~1s before the end, and pause there.
1056 seekstate = self.seekstate
1057 if self.seekstate != self.SEEK_STATE_PAUSE:
1058 self.setSeekState(self.SEEK_STATE_EOF)
1060 if seekstate not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE): # if we are seeking
1061 seekable = self.getSeek()
1062 if seekable is not None:
1064 if seekstate == self.SEEK_STATE_PLAY: # regular EOF
1065 self.doEofInternal(True)
1067 self.doEofInternal(False)
1069 def doEofInternal(self, playing):
1070 pass # Defined in subclasses
1073 self.setSeekState(self.SEEK_STATE_PLAY)
1076 from Screens.PVRState import PVRState, TimeshiftState
1078 class InfoBarPVRState:
1079 def __init__(self, screen=PVRState, force_show = False):
1080 self.onPlayStateChanged.append(self.__playStateChanged)
1081 self.pvrStateDialog = self.session.instantiateDialog(screen)
1082 self.onShow.append(self._mayShow)
1083 self.onHide.append(self.pvrStateDialog.hide)
1084 self.force_show = force_show
1087 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
1088 self.pvrStateDialog.show()
1090 def __playStateChanged(self, state):
1091 playstateString = state[3]
1092 self.pvrStateDialog["state"].setText(playstateString)
1094 # if we return into "PLAY" state, ensure that the dialog gets hidden if there will be no infobar displayed
1095 if not config.usage.show_infobar_on_skip.value and self.seekstate == self.SEEK_STATE_PLAY and not self.force_show:
1096 self.pvrStateDialog.hide()
1101 class InfoBarTimeshiftState(InfoBarPVRState):
1103 InfoBarPVRState.__init__(self, screen=TimeshiftState, force_show = True)
1106 if self.execing and self.timeshift_enabled and self.seekstate != self.SEEK_STATE_PLAY:
1107 self.pvrStateDialog.show()
1109 class InfoBarShowMovies:
1111 # i don't really like this class.
1112 # it calls a not further specified "movie list" on up/down/movieList,
1113 # so this is not more than an action map
1115 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
1117 "movieList": (self.showMovies, _("movie list")),
1118 "up": (self.showMovies, _("movie list")),
1119 "down": (self.showMovies, _("movie list"))
1122 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
1126 # Timeshift works the following way:
1127 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
1128 # - normal playback TUNER unused PLAY enable disable disable
1129 # - user presses "yellow" button. FILE record PAUSE enable disable enable
1130 # - user presess pause again FILE record PLAY enable disable enable
1131 # - user fast forwards FILE record FF enable disable enable
1132 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
1133 # - user backwards FILE record BACK # !! enable disable enable
1137 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1138 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1139 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1140 # - the user can now PVR around
1141 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1142 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1144 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1145 # - if the user rewinds, or press pause, timeshift will be activated again
1147 # note that a timeshift can be enabled ("recording") and
1148 # activated (currently time-shifting).
1150 class InfoBarTimeshift:
1152 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1154 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1155 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1157 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1159 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1160 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1161 }, prio=-1) # priority over record
1163 self.timeshift_enabled = 0
1164 self.timeshift_state = 0
1165 self.ts_rewind_timer = eTimer()
1166 self.ts_rewind_timer.callback.append(self.rewindService)
1168 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1170 iPlayableService.evStart: self.__serviceStarted,
1171 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1174 def getTimeshift(self):
1175 service = self.session.nav.getCurrentService()
1176 return service and service.timeshift()
1178 def startTimeshift(self):
1179 print "enable timeshift"
1180 ts = self.getTimeshift()
1182 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1183 print "no ts interface"
1186 if self.timeshift_enabled:
1187 print "hu, timeshift already enabled?"
1189 if not ts.startTimeshift():
1190 self.timeshift_enabled = 1
1192 # we remove the "relative time" for now.
1193 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1196 #self.setSeekState(self.SEEK_STATE_PAUSE)
1197 self.activateTimeshiftEnd(False)
1199 # enable the "TimeshiftEnableActions", which will override
1200 # the startTimeshift actions
1201 self.__seekableStatusChanged()
1203 print "timeshift failed"
1205 def stopTimeshift(self):
1206 if not self.timeshift_enabled:
1208 print "disable timeshift"
1209 ts = self.getTimeshift()
1212 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1214 def stopTimeshiftConfirmed(self, confirmed):
1218 ts = self.getTimeshift()
1223 self.timeshift_enabled = 0
1226 self.__seekableStatusChanged()
1228 # activates timeshift, and seeks to (almost) the end
1229 def activateTimeshiftEnd(self, back = True):
1230 ts = self.getTimeshift()
1231 print "activateTimeshiftEnd"
1236 if ts.isTimeshiftActive():
1237 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1241 ts.activateTimeshift() # activate timeshift will automatically pause
1242 self.setSeekState(self.SEEK_STATE_PAUSE)
1245 self.ts_rewind_timer.start(200, 1)
1247 def rewindService(self):
1248 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1250 # same as activateTimeshiftEnd, but pauses afterwards.
1251 def activateTimeshiftEndAndPause(self):
1252 print "activateTimeshiftEndAndPause"
1253 #state = self.seekstate
1254 self.activateTimeshiftEnd(False)
1256 def __seekableStatusChanged(self):
1259 # print "self.isSeekable", self.isSeekable()
1260 # print "self.timeshift_enabled", self.timeshift_enabled
1262 # when this service is not seekable, but timeshift
1263 # is enabled, this means we can activate
1265 if not self.isSeekable() and self.timeshift_enabled:
1268 # print "timeshift activate:", enabled
1269 self["TimeshiftActivateActions"].setEnabled(enabled)
1271 def __serviceStarted(self):
1272 self.timeshift_enabled = False
1273 self.__seekableStatusChanged()
1275 from Screens.PiPSetup import PiPSetup
1277 class InfoBarExtensions:
1278 EXTENSION_SINGLE = 0
1284 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1286 "extensions": (self.showExtensionSelection, _("view extensions...")),
1287 }, 1) # lower priority
1289 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1290 self.list.append((type, extension, key))
1292 def updateExtension(self, extension, key = None):
1293 self.extensionsList.append(extension)
1295 if self.extensionKeys.has_key(key):
1299 for x in self.availableKeys:
1300 if not self.extensionKeys.has_key(x):
1305 self.extensionKeys[key] = len(self.extensionsList) - 1
1307 def updateExtensions(self):
1308 self.extensionsList = []
1309 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1310 self.extensionKeys = {}
1312 if x[0] == self.EXTENSION_SINGLE:
1313 self.updateExtension(x[1], x[2])
1316 self.updateExtension(y[0], y[1])
1319 def showExtensionSelection(self):
1320 self.updateExtensions()
1321 extensionsList = self.extensionsList[:]
1324 for x in self.availableKeys:
1325 if self.extensionKeys.has_key(x):
1326 entry = self.extensionKeys[x]
1327 extension = self.extensionsList[entry]
1329 name = str(extension[0]())
1330 list.append((extension[0](), extension))
1332 extensionsList.remove(extension)
1334 extensionsList.remove(extension)
1335 list.extend([(x[0](), x) for x in extensionsList])
1337 keys += [""] * len(extensionsList)
1338 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys, skin_name = "ExtensionsList")
1340 def extensionCallback(self, answer):
1341 if answer is not None:
1344 from Tools.BoundFunction import boundFunction
1346 # depends on InfoBarExtensions
1348 class InfoBarPlugins:
1350 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1352 def getPluginName(self, name):
1355 def getPluginList(self):
1356 list = [((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU)]
1357 list.sort(key = lambda e: e[2]) # sort by name
1360 def runPlugin(self, plugin):
1361 if isinstance(self, InfoBarChannelSelection):
1362 plugin(session = self.session, servicelist = self.servicelist)
1364 plugin(session = self.session)
1366 from Components.Task import job_manager
1367 class InfoBarJobman:
1369 self.addExtension(extension = self.getJobList, type = InfoBarExtensions.EXTENSION_LIST)
1371 def getJobList(self):
1372 return [((boundFunction(self.getJobName, job), boundFunction(self.showJobView, job), lambda: True), None) for job in job_manager.getPendingJobs()]
1374 def getJobName(self, job):
1375 return "%s: %s (%d%%)" % (job.getStatustext(), job.name, int(100*job.progress/float(job.end)))
1377 def showJobView(self, job):
1378 from Screens.TaskView import JobView
1379 job_manager.in_background = False
1380 self.session.openWithCallback(self.JobViewCB, JobView, job)
1382 def JobViewCB(self, in_background):
1383 job_manager.in_background = in_background
1385 # depends on InfoBarExtensions
1389 self.session.pipshown
1391 self.session.pipshown = False
1392 if SystemInfo.get("NumVideoDecoders", 1) > 1:
1394 self.addExtension((self.getShowHideName, self.showPiP, lambda: True), "blue")
1395 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1396 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1398 self.addExtension((self.getShowHideName, self.showPiP, self.pipShown), "blue")
1399 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1402 return self.session.pipshown
1404 def pipHandles0Action(self):
1405 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1407 def getShowHideName(self):
1408 if self.session.pipshown:
1409 return _("Disable Picture in Picture")
1411 return _("Activate Picture in Picture")
1413 def getSwapName(self):
1414 return _("Swap Services")
1416 def getMoveName(self):
1417 return _("Move Picture in Picture")
1420 if self.session.pipshown:
1421 del self.session.pip
1422 self.session.pipshown = False
1424 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1425 self.session.pip.show()
1426 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1427 if self.session.pip.playService(newservice):
1428 self.session.pipshown = True
1429 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1431 self.session.pipshown = False
1432 del self.session.pip
1433 self.session.nav.playService(newservice)
1436 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1437 if self.session.pip.servicePath:
1438 servicepath = self.servicelist.getCurrentServicePath()
1439 ref=servicepath[len(servicepath)-1]
1440 pipref=self.session.pip.getCurrentService()
1441 self.session.pip.playService(swapservice)
1442 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1443 if pipref.toString() != ref.toString(): # is a subservice ?
1444 self.session.nav.stopService() # stop portal
1445 self.session.nav.playService(pipref) # start subservice
1446 self.session.pip.servicePath=servicepath
1449 self.session.open(PiPSetup, pip = self.session.pip)
1451 def pipDoHandle0Action(self):
1452 use = config.usage.pip_zero_button.value
1455 elif "swapstop" == use:
1461 from RecordTimer import parseEvent, RecordTimerEntry
1463 class InfoBarInstantRecord:
1464 """Instant Record - handles the instantRecord action in order to
1465 start/stop instant records"""
1467 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1469 "instantRecord": (self.instantRecord, _("Instant Record...")),
1473 def stopCurrentRecording(self, entry = -1):
1474 if entry is not None and entry != -1:
1475 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1476 self.recording.remove(self.recording[entry])
1478 def startInstantRecording(self, limitEvent = False):
1479 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1481 # try to get event info
1484 service = self.session.nav.getCurrentService()
1485 epg = eEPGCache.getInstance()
1486 event = epg.lookupEventTime(serviceref, -1, 0)
1488 info = service.info()
1489 ev = info.getEvent(0)
1495 end = begin + 3600 # dummy
1496 name = "instant record"
1500 if event is not None:
1501 curEvent = parseEvent(event)
1503 description = curEvent[3]
1504 eventid = curEvent[4]
1509 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1511 if isinstance(serviceref, eServiceReference):
1512 serviceref = ServiceReference(serviceref)
1514 recording = RecordTimerEntry(serviceref, begin, end, name, description, eventid, dirname = preferredInstantRecordPath())
1515 recording.dontSave = True
1517 if event is None or limitEvent == False:
1518 recording.autoincrease = True
1519 if recording.setAutoincreaseEnd():
1520 self.session.nav.RecordTimer.record(recording)
1521 self.recording.append(recording)
1523 simulTimerList = self.session.nav.RecordTimer.record(recording)
1524 if simulTimerList is not None: # conflict with other recording
1525 name = simulTimerList[1].name
1526 name_date = ' '.join((name, strftime('%c', localtime(simulTimerList[1].begin))))
1527 print "[TIMER] conflicts with", name_date
1528 recording.autoincrease = True # start with max available length, then increment
1529 if recording.setAutoincreaseEnd():
1530 self.session.nav.RecordTimer.record(recording)
1531 self.recording.append(recording)
1532 self.session.open(MessageBox, _("Record time limited due to conflicting timer %s") % name_date, MessageBox.TYPE_INFO)
1534 self.session.open(MessageBox, _("Couldn't record due to conflicting timer %s") % name, MessageBox.TYPE_INFO)
1535 recording.autoincrease = False
1537 self.recording.append(recording)
1539 def isInstantRecordRunning(self):
1540 print "self.recording:", self.recording
1542 for x in self.recording:
1547 def recordQuestionCallback(self, answer):
1548 print "pre:\n", self.recording
1550 if answer is None or answer[1] == "no":
1553 recording = self.recording[:]
1555 if not x in self.session.nav.RecordTimer.timer_list:
1556 self.recording.remove(x)
1557 elif x.dontSave and x.isRunning():
1558 list.append((x, False))
1560 if answer[1] == "changeduration":
1561 if len(self.recording) == 1:
1562 self.changeDuration(0)
1564 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1565 elif answer[1] == "changeendtime":
1566 if len(self.recording) == 1:
1569 self.session.openWithCallback(self.setEndtime, TimerSelection, list)
1570 elif answer[1] == "stop":
1571 if len(self.recording) == 1:
1572 self.stopCurrentRecording(0)
1574 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1575 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1576 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1577 if answer[1] == "manualduration":
1578 self.changeDuration(len(self.recording)-1)
1579 elif answer[1] == "manualendtime":
1580 self.setEndtime(len(self.recording)-1)
1581 print "after:\n", self.recording
1583 def setEndtime(self, entry):
1584 if entry is not None and entry >= 0:
1585 self.selectedEntry = entry
1586 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1587 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1588 dlg.setTitle(_("Please change recording endtime"))
1590 def TimeDateInputClosed(self, ret):
1593 localendtime = localtime(ret[1])
1594 print "stopping recording at", strftime("%c", localendtime)
1595 if self.recording[self.selectedEntry].end != ret[1]:
1596 self.recording[self.selectedEntry].autoincrease = False
1597 self.recording[self.selectedEntry].end = ret[1]
1598 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1600 def changeDuration(self, entry):
1601 if entry is not None and entry >= 0:
1602 self.selectedEntry = entry
1603 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1605 def inputCallback(self, value):
1606 if value is not None:
1607 print "stopping recording after", int(value), "minutes."
1608 entry = self.recording[self.selectedEntry]
1610 entry.autoincrease = False
1611 entry.end = int(time()) + 60 * int(value)
1612 self.session.nav.RecordTimer.timeChanged(entry)
1614 def instantRecord(self):
1615 dir = preferredInstantRecordPath()
1616 if not dir or not fileExists(dir, 'w'):
1617 dir = defaultMoviePath()
1621 # XXX: this message is a little odd as we might be recording to a remote device
1622 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1625 if self.isInstantRecordRunning():
1626 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1627 title=_("A recording is currently running.\nWhat do you want to do?"), \
1628 list=((_("stop recording"), "stop"), \
1629 (_("add recording (stop after current event)"), "event"), \
1630 (_("add recording (indefinitely)"), "indefinitely"), \
1631 (_("add recording (enter recording duration)"), "manualduration"), \
1632 (_("add recording (enter recording endtime)"), "manualendtime"), \
1633 (_("change recording (duration)"), "changeduration"), \
1634 (_("change recording (endtime)"), "changeendtime"), \
1635 (_("do nothing"), "no")))
1637 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1638 title=_("Start recording?"), \
1639 list=((_("add recording (stop after current event)"), "event"), \
1640 (_("add recording (indefinitely)"), "indefinitely"), \
1641 (_("add recording (enter recording duration)"), "manualduration"), \
1642 (_("add recording (enter recording endtime)"), "manualendtime"), \
1643 (_("don't record"), "no")))
1645 from Tools.ISO639 import LanguageCodes
1647 class InfoBarAudioSelection:
1649 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1651 "audioSelection": (self.audioSelection, _("Audio Options...")),
1654 def audioSelection(self):
1655 service = self.session.nav.getCurrentService()
1656 self.audioTracks = audio = service and service.audioTracks()
1657 n = audio and audio.getNumberOfTracks() or 0
1660 self.audioChannel = service.audioChannel()
1665 i = audio.getTrackInfo(idx)
1666 languages = i.getLanguage().split('/')
1667 description = i.getDescription()
1670 for lang in languages:
1673 if LanguageCodes.has_key(lang):
1674 language += LanguageCodes[lang][0]
1679 if len(description):
1680 description += " (" + language + ")"
1682 description = language
1684 tlist.append((description, idx))
1687 tlist.sort(key=lambda x: x[0])
1689 selectedAudio = self.audioTracks.getCurrentTrack()
1694 if x[1] != selectedAudio:
1702 if SystemInfo["CanDownmixAC3"]:
1703 flist = [(_("AC3 downmix") + " - " +(_("Off"), _("On"))[config.av.downmix_ac3.value and 1 or 0], "CALLFUNC", self.changeAC3Downmix),
1704 ((_("Left"), _("Stereo"), _("Right"))[self.audioChannel.getCurrentChannel()], "mode")]
1705 usedKeys.extend(["red", "green"])
1706 availableKeys.extend(["yellow", "blue"])
1709 flist = [((_("Left"), _("Stereo"), _("Right"))[self.audioChannel.getCurrentChannel()], "mode")]
1710 usedKeys.extend(["red"])
1711 availableKeys.extend(["green", "yellow", "blue"])
1714 if hasattr(self, "runPlugin"):
1716 def __init__(self, fnc, *args):
1719 def __call__(self, *args, **kwargs):
1720 self.fnc(*self.args)
1722 Plugins = [ (p.name, PluginCaller(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_AUDIOMENU) ]
1726 flist.append((p[0], "CALLFUNC", p[1]))
1728 usedKeys.append(availableKeys[0])
1729 del availableKeys[0]
1733 flist.append(("--", ""))
1737 keys = usedKeys + [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" ] + [""] * n
1738 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = flist + tlist, selection = selection, keys = keys, skin_name = "AudioTrackSelection")
1740 del self.audioTracks
1742 def changeAC3Downmix(self, arg):
1743 choicelist = self.session.current_dialog["list"]
1744 list = choicelist.list
1746 list[0][1]=(t[0], t[1], t[2], t[3], t[4], t[5], t[6],
1747 _("AC3 downmix") + " - " + (_("On"), _("Off"))[config.av.downmix_ac3.value and 1 or 0])
1748 choicelist.setList(list)
1749 if config.av.downmix_ac3.value:
1750 config.av.downmix_ac3.value = False
1752 config.av.downmix_ac3.value = True
1753 config.av.downmix_ac3.save()
1755 def audioSelected(self, audio):
1756 if audio is not None:
1757 if isinstance(audio[1], str):
1758 if audio[1] == "mode":
1759 keys = ["red", "green", "yellow"]
1760 selection = self.audioChannel.getCurrentChannel()
1761 tlist = ((_("left"), 0), (_("stereo"), 1), (_("right"), 2))
1762 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys, skin_name ="AudioModeSelection")
1764 del self.audioChannel
1765 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1766 self.audioTracks.selectTrack(audio[1])
1768 del self.audioChannel
1769 del self.audioTracks
1771 def modeSelected(self, mode):
1772 if mode is not None:
1773 self.audioChannel.selectChannel(mode[1])
1774 del self.audioChannel
1776 class InfoBarSubserviceSelection:
1778 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1780 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1783 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1785 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1786 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1788 self["SubserviceQuickzapAction"].setEnabled(False)
1790 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1792 iPlayableService.evUpdatedEventInfo: self.checkSubservicesAvail
1797 def checkSubservicesAvail(self):
1798 service = self.session.nav.getCurrentService()
1799 subservices = service and service.subServices()
1800 if not subservices or subservices.getNumberOfSubservices() == 0:
1801 self["SubserviceQuickzapAction"].setEnabled(False)
1803 def nextSubservice(self):
1804 self.changeSubservice(+1)
1806 def prevSubservice(self):
1807 self.changeSubservice(-1)
1809 def changeSubservice(self, direction):
1810 service = self.session.nav.getCurrentService()
1811 subservices = service and service.subServices()
1812 n = subservices and subservices.getNumberOfSubservices()
1815 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1818 if subservices.getSubservice(idx).toString() == ref.toString():
1823 selection += direction
1828 newservice = subservices.getSubservice(selection)
1829 if newservice.valid():
1832 self.session.nav.playService(newservice, False)
1834 def subserviceSelection(self):
1835 service = self.session.nav.getCurrentService()
1836 subservices = service and service.subServices()
1837 self.bouquets = self.servicelist.getBouquetList()
1838 n = subservices and subservices.getNumberOfSubservices()
1841 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1845 i = subservices.getSubservice(idx)
1846 if i.toString() == ref.toString():
1848 tlist.append((i.getName(), i))
1851 if self.bouquets and len(self.bouquets):
1852 keys = ["red", "blue", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1853 if config.usage.multibouquet.value:
1854 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1856 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1859 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1860 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1863 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys, skin_name = "SubserviceSelection")
1865 def subserviceSelected(self, service):
1867 if not service is None:
1868 if isinstance(service[1], str):
1869 if service[1] == "quickzap":
1870 from Screens.SubservicesQuickzap import SubservicesQuickzap
1871 self.session.open(SubservicesQuickzap, service[2])
1873 self["SubserviceQuickzapAction"].setEnabled(True)
1874 self.session.nav.playService(service[1], False)
1876 def addSubserviceToBouquetCallback(self, service):
1877 if len(service) > 1 and isinstance(service[1], eServiceReference):
1878 self.selectedSubservice = service
1879 if self.bouquets is None:
1882 cnt = len(self.bouquets)
1883 if cnt > 1: # show bouquet list
1884 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1885 elif cnt == 1: # add to only one existing bouquet
1886 self.addSubserviceToBouquet(self.bouquets[0][1])
1887 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1889 def bouquetSelClosed(self, confirmed):
1891 del self.selectedSubservice
1893 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1895 def addSubserviceToBouquet(self, dest):
1896 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1898 self.bsel.close(True)
1900 del self.selectedSubservice
1902 class InfoBarAdditionalInfo:
1905 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0 and config.misc.rcused.value == 1)
1906 self["TimeshiftPossible"] = self["RecordingPossible"]
1907 self["ShowTimeshiftOnYellow"] = Boolean(fixed=(not config.misc.rcused.value == 0))
1908 self["ShowAudioOnYellow"] = Boolean(fixed=config.misc.rcused.value == 0)
1909 self["ShowRecordOnRed"] = Boolean(fixed=config.misc.rcused.value == 1)
1910 self["ExtensionsAvailable"] = Boolean(fixed=1)
1912 class InfoBarNotifications:
1914 self.onExecBegin.append(self.checkNotifications)
1915 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1916 self.onClose.append(self.__removeNotification)
1918 def __removeNotification(self):
1919 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1921 def checkNotificationsIfExecing(self):
1923 self.checkNotifications()
1925 def checkNotifications(self):
1926 notifications = Notifications.notifications
1928 n = notifications[0]
1930 del notifications[0]
1933 if n[3].has_key("onSessionOpenCallback"):
1934 n[3]["onSessionOpenCallback"]()
1935 del n[3]["onSessionOpenCallback"]
1938 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1940 dlg = self.session.open(n[1], *n[2], **n[3])
1942 # remember that this notification is currently active
1944 Notifications.current_notifications.append(d)
1945 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1947 def __notificationClosed(self, d):
1948 Notifications.current_notifications.remove(d)
1950 class InfoBarServiceNotifications:
1952 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1954 iPlayableService.evEnd: self.serviceHasEnded
1957 def serviceHasEnded(self):
1958 print "service end!"
1961 self.setSeekState(self.SEEK_STATE_PLAY)
1965 class InfoBarCueSheetSupport:
1971 ENABLE_RESUME_SUPPORT = False
1973 def __init__(self, actionmap = "InfobarCueSheetActions"):
1974 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1976 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1977 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1978 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1982 self.is_closing = False
1983 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1985 iPlayableService.evStart: self.__serviceStarted,
1988 def __serviceStarted(self):
1991 print "new service started! trying to download cuts!"
1992 self.downloadCuesheet()
1994 if self.ENABLE_RESUME_SUPPORT:
1997 for (pts, what) in self.cut_list:
1998 if what == self.CUT_TYPE_LAST:
2001 if last is not None:
2002 self.resume_point = last
2003 if config.usage.on_movie_start.value == "ask":
2004 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
2005 elif config.usage.on_movie_start.value == "resume":
2006 # TRANSLATORS: The string "Resuming playback" flashes for a moment
2007 # TRANSLATORS: at the start of a movie, when the user has selected
2008 # TRANSLATORS: "Resume from last position" as start behavior.
2009 # TRANSLATORS: The purpose is to notify the user that the movie starts
2010 # TRANSLATORS: in the middle somewhere and not from the beginning.
2011 # TRANSLATORS: (Some translators seem to have interpreted it as a
2012 # TRANSLATORS: question or a choice, but it is a statement.)
2013 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Resuming playback"), timeout=2, type=MessageBox.TYPE_INFO)
2015 def playLastCB(self, answer):
2017 self.doSeek(self.resume_point)
2018 self.hideAfterResume()
2020 def hideAfterResume(self):
2021 if isinstance(self, InfoBarShowHide):
2024 def __getSeekable(self):
2025 service = self.session.nav.getCurrentService()
2028 return service.seek()
2030 def cueGetCurrentPosition(self):
2031 seek = self.__getSeekable()
2034 r = seek.getPlayPosition()
2039 def cueGetEndCutPosition(self):
2042 for cp in self.cut_list:
2043 if cp[1] == self.CUT_TYPE_OUT:
2047 elif cp[1] == self.CUT_TYPE_IN:
2051 def jumpPreviousNextMark(self, cmp, start=False):
2052 current_pos = self.cueGetCurrentPosition()
2053 if current_pos is None:
2055 mark = self.getNearestCutPoint(current_pos, cmp=cmp, start=start)
2056 if mark is not None:
2064 def jumpPreviousMark(self):
2065 # we add 2 seconds, so if the play position is <2s after
2066 # the mark, the mark before will be used
2067 self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
2069 def jumpNextMark(self):
2070 if not self.jumpPreviousNextMark(lambda x: x):
2073 def getNearestCutPoint(self, pts, cmp=abs, start=False):
2079 bestdiff = cmp(0 - pts)
2081 nearest = [0, False]
2082 for cp in self.cut_list:
2083 if beforecut and cp[1] in (self.CUT_TYPE_IN, self.CUT_TYPE_OUT):
2085 if cp[1] == self.CUT_TYPE_IN: # Start is here, disregard previous marks
2086 diff = cmp(cp[0] - pts)
2092 if cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
2093 diff = cmp(cp[0] - pts)
2094 if diff >= 0 and (nearest is None or bestdiff > diff):
2099 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
2100 current_pos = self.cueGetCurrentPosition()
2101 if current_pos is None:
2102 print "not seekable"
2105 nearest_cutpoint = self.getNearestCutPoint(current_pos)
2107 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
2109 return nearest_cutpoint
2111 self.removeMark(nearest_cutpoint)
2112 elif not onlyremove and not onlyreturn:
2113 self.addMark((current_pos, self.CUT_TYPE_MARK))
2118 def addMark(self, point):
2119 insort(self.cut_list, point)
2120 self.uploadCuesheet()
2121 self.showAfterCuesheetOperation()
2123 def removeMark(self, point):
2124 self.cut_list.remove(point)
2125 self.uploadCuesheet()
2126 self.showAfterCuesheetOperation()
2128 def showAfterCuesheetOperation(self):
2129 if isinstance(self, InfoBarShowHide):
2132 def __getCuesheet(self):
2133 service = self.session.nav.getCurrentService()
2136 return service.cueSheet()
2138 def uploadCuesheet(self):
2139 cue = self.__getCuesheet()
2142 print "upload failed, no cuesheet interface"
2144 cue.setCutList(self.cut_list)
2146 def downloadCuesheet(self):
2147 cue = self.__getCuesheet()
2150 print "download failed, no cuesheet interface"
2153 self.cut_list = cue.getCutList()
2155 class InfoBarSummary(Screen):
2157 <screen position="0,0" size="132,64">
2158 <widget source="global.CurrentTime" render="Label" position="62,46" size="82,18" font="Regular;16" >
2159 <convert type="ClockToText">WithSeconds</convert>
2161 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="82,18" zPosition="1" >
2162 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2163 <convert type="ConditionalShowHide">Blink</convert>
2165 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2166 <convert type="ServiceName">Name</convert>
2168 <widget source="session.Event_Now" render="Progress" position="6,46" size="46,18" borderWidth="1" >
2169 <convert type="EventTime">Progress</convert>
2173 # for picon: (path="piconlcd" will use LCD picons)
2174 # <widget source="session.CurrentService" render="Picon" position="6,0" size="120,64" path="piconlcd" >
2175 # <convert type="ServiceName">Reference</convert>
2178 class InfoBarSummarySupport:
2182 def createSummary(self):
2183 return InfoBarSummary
2185 class InfoBarMoviePlayerSummary(Screen):
2187 <screen position="0,0" size="132,64">
2188 <widget source="global.CurrentTime" render="Label" position="62,46" size="64,18" font="Regular;16" halign="right" >
2189 <convert type="ClockToText">WithSeconds</convert>
2191 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="64,18" zPosition="1" >
2192 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2193 <convert type="ConditionalShowHide">Blink</convert>
2195 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2196 <convert type="ServiceName">Name</convert>
2198 <widget source="session.CurrentService" render="Progress" position="6,46" size="56,18" borderWidth="1" >
2199 <convert type="ServicePosition">Position</convert>
2203 class InfoBarMoviePlayerSummarySupport:
2207 def createSummary(self):
2208 return InfoBarMoviePlayerSummary
2210 class InfoBarTeletextPlugin:
2212 self.teletext_plugin = None
2214 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
2215 self.teletext_plugin = p
2217 if self.teletext_plugin is not None:
2218 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
2220 "startTeletext": (self.startTeletext, _("View teletext..."))
2223 print "no teletext plugin found!"
2225 def startTeletext(self):
2226 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
2228 class InfoBarSubtitleSupport(object):
2230 object.__init__(self)
2231 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
2232 self.__subtitles_enabled = False
2234 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2236 iPlayableService.evEnd: self.__serviceStopped,
2237 iPlayableService.evUpdatedInfo: self.__updatedInfo
2239 self.cached_subtitle_checked = False
2240 self.__selected_subtitle = None
2242 def __serviceStopped(self):
2243 self.cached_subtitle_checked = False
2244 if self.__subtitles_enabled:
2245 self.subtitle_window.hide()
2246 self.__subtitles_enabled = False
2247 self.__selected_subtitle = None
2249 def __updatedInfo(self):
2250 if not self.cached_subtitle_checked:
2251 self.cached_subtitle_checked = True
2252 subtitle = self.getCurrentServiceSubtitle()
2253 self.setSelectedSubtitle(subtitle and subtitle.getCachedSubtitle())
2254 if self.__selected_subtitle:
2255 self.setSubtitlesEnable(True)
2257 def getCurrentServiceSubtitle(self):
2258 service = self.session.nav.getCurrentService()
2259 return service and service.subtitle()
2261 def setSubtitlesEnable(self, enable=True):
2262 subtitle = self.getCurrentServiceSubtitle()
2264 if self.__selected_subtitle:
2265 if subtitle and not self.__subtitles_enabled:
2266 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2267 self.subtitle_window.show()
2268 self.__subtitles_enabled = True
2271 subtitle.disableSubtitles(self.subtitle_window.instance)
2272 self.__selected_subtitle = False
2273 self.__subtitles_enabled = False
2274 self.subtitle_window.hide()
2276 def setSelectedSubtitle(self, subtitle):
2277 self.__selected_subtitle = subtitle
2279 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
2280 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
2282 class InfoBarServiceErrorPopupSupport:
2284 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2286 iPlayableService.evTuneFailed: self.__tuneFailed,
2287 iPlayableService.evStart: self.__serviceStarted
2289 self.__serviceStarted()
2291 def __serviceStarted(self):
2292 self.last_error = None
2293 Notifications.RemovePopup(id = "ZapError")
2295 def __tuneFailed(self):
2296 service = self.session.nav.getCurrentService()
2297 info = service and service.info()
2298 error = info and info.getInfo(iServiceInformation.sDVBState)
2300 if error == self.last_error:
2303 self.last_error = error
2306 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2307 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2308 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2309 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2310 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2311 eDVBServicePMTHandler.eventNewProgramInfo: None,
2312 eDVBServicePMTHandler.eventTuned: None,
2313 eDVBServicePMTHandler.eventSOF: None,
2314 eDVBServicePMTHandler.eventEOF: None,
2315 eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
2316 }.get(error) #this returns None when the key not exist in the dict
2318 if error is not None:
2319 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2321 Notifications.RemovePopup(id = "ZapError")