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):
69 if self.checkUnusedTimer.isActive():
70 self.checkUnusedTimer.stop()
73 self.flags = self.uflags = 0
74 self.flags |= (1<<flag)
76 self.checkUnusedTimer.start(0, True)
79 #this function is only called when no other action has handled this key
80 def actionB(self, key, flag):
82 self.uflags |= (1<<flag)
84 def checkUnused(self):
85 if self.flags == self.uflags:
86 self.unhandledKeyDialog.show()
87 self.hideTimer.start(2000, True)
89 class InfoBarShowHide:
90 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
98 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
100 "toggleShow": self.toggleShow,
102 }, 1) # lower prio to make it possible to override ok and cancel..
104 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
106 iPlayableService.evStart: self.serviceStarted,
109 self.__state = self.STATE_SHOWN
112 self.hideTimer = eTimer()
113 self.hideTimer.callback.append(self.doTimerHide)
114 self.hideTimer.start(5000, True)
116 self.onShow.append(self.__onShow)
117 self.onHide.append(self.__onHide)
119 def serviceStarted(self):
121 if config.usage.show_infobar_on_zap.value:
125 self.__state = self.STATE_SHOWN
126 self.startHideTimer()
128 def startHideTimer(self):
129 if self.__state == self.STATE_SHOWN and not self.__locked:
130 idx = config.usage.infobar_timeout.index
132 self.hideTimer.start(idx*1000, True)
135 self.__state = self.STATE_HIDDEN
139 self.startHideTimer()
141 def doTimerHide(self):
142 self.hideTimer.stop()
143 if self.__state == self.STATE_SHOWN:
146 def toggleShow(self):
147 if self.__state == self.STATE_SHOWN:
149 self.hideTimer.stop()
150 elif self.__state == self.STATE_HIDDEN:
154 self.__locked = self.__locked + 1
157 self.hideTimer.stop()
159 def unlockShow(self):
160 self.__locked = self.__locked - 1
162 self.startHideTimer()
164 # def startShow(self):
165 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
166 # self.__state = self.STATE_SHOWN
168 # def startHide(self):
169 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
170 # self.__state = self.STATE_HIDDEN
172 class NumberZap(Screen):
179 self.close(int(self["number"].getText()))
181 def keyNumberGlobal(self, number):
182 self.Timer.start(3000, True) #reset timer
183 self.field = self.field + str(number)
184 self["number"].setText(self.field)
185 if len(self.field) >= 4:
188 def __init__(self, session, number):
189 Screen.__init__(self, session)
190 self.field = str(number)
192 self["channel"] = Label(_("Channel:"))
194 self["number"] = Label(self.field)
196 self["actions"] = NumberActionMap( [ "SetupActions" ],
200 "1": self.keyNumberGlobal,
201 "2": self.keyNumberGlobal,
202 "3": self.keyNumberGlobal,
203 "4": self.keyNumberGlobal,
204 "5": self.keyNumberGlobal,
205 "6": self.keyNumberGlobal,
206 "7": self.keyNumberGlobal,
207 "8": self.keyNumberGlobal,
208 "9": self.keyNumberGlobal,
209 "0": self.keyNumberGlobal
212 self.Timer = eTimer()
213 self.Timer.callback.append(self.keyOK)
214 self.Timer.start(3000, True)
216 class InfoBarNumberZap:
217 """ Handles an initial number for NumberZapping """
219 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
221 "1": self.keyNumberGlobal,
222 "2": self.keyNumberGlobal,
223 "3": self.keyNumberGlobal,
224 "4": self.keyNumberGlobal,
225 "5": self.keyNumberGlobal,
226 "6": self.keyNumberGlobal,
227 "7": self.keyNumberGlobal,
228 "8": self.keyNumberGlobal,
229 "9": self.keyNumberGlobal,
230 "0": self.keyNumberGlobal,
233 def keyNumberGlobal(self, number):
234 # print "You pressed number " + str(number)
236 if isinstance(self, InfoBarPiP) and self.pipHandles0Action():
237 self.pipDoHandle0Action()
239 self.servicelist.recallPrevService()
241 if self.has_key("TimeshiftActions") and not self.timeshift_enabled:
242 self.session.openWithCallback(self.numberEntered, NumberZap, number)
244 def numberEntered(self, retval):
245 # print self.servicelist
247 self.zapToNumber(retval)
249 def searchNumberHelper(self, serviceHandler, num, bouquet):
250 servicelist = serviceHandler.list(bouquet)
251 if not servicelist is None:
253 serviceIterator = servicelist.getNext()
254 if not serviceIterator.valid(): #check end of list
256 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
259 if not num: #found service with searched number ?
260 return serviceIterator, 0
263 def zapToNumber(self, number):
264 bouquet = self.servicelist.bouquet_root
266 serviceHandler = eServiceCenter.getInstance()
267 if not config.usage.multibouquet.value:
268 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
270 bouquetlist = serviceHandler.list(bouquet)
271 if not bouquetlist is None:
273 bouquet = bouquetlist.getNext()
274 if not bouquet.valid(): #check end of list
276 if bouquet.flags & eServiceReference.isDirectory:
277 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
278 if not service is None:
279 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
280 self.servicelist.clearPath()
281 if self.servicelist.bouquet_root != bouquet:
282 self.servicelist.enterPath(self.servicelist.bouquet_root)
283 self.servicelist.enterPath(bouquet)
284 self.servicelist.setCurrentSelection(service) #select the service in servicelist
285 self.servicelist.zap()
287 config.misc.initialchannelselection = ConfigBoolean(default = True)
289 class InfoBarChannelSelection:
290 """ ChannelSelection - handles the channelSelection dialog and the initial
291 channelChange actions which open the channelSelection dialog """
294 self.servicelist = self.session.instantiateDialog(ChannelSelection)
296 if config.misc.initialchannelselection.value:
297 self.onShown.append(self.firstRun)
299 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
301 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
302 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
303 "zapUp": (self.zapUp, _("previous channel")),
304 "zapDown": (self.zapDown, _("next channel")),
305 "historyBack": (self.historyBack, _("previous channel in history")),
306 "historyNext": (self.historyNext, _("next channel in history")),
307 "openServiceList": (self.openServiceList, _("open servicelist")),
310 def showTvChannelList(self, zap=False):
311 self.servicelist.setModeTv()
313 self.servicelist.zap()
314 self.session.execDialog(self.servicelist)
316 def showRadioChannelList(self, zap=False):
317 self.servicelist.setModeRadio()
319 self.servicelist.zap()
320 self.session.execDialog(self.servicelist)
323 self.onShown.remove(self.firstRun)
324 config.misc.initialchannelselection.value = False
325 config.misc.initialchannelselection.save()
326 self.switchChannelDown()
328 def historyBack(self):
329 self.servicelist.historyBack()
331 def historyNext(self):
332 self.servicelist.historyNext()
334 def switchChannelUp(self):
335 self.servicelist.moveUp()
336 self.session.execDialog(self.servicelist)
338 def switchChannelDown(self):
339 self.servicelist.moveDown()
340 self.session.execDialog(self.servicelist)
342 def openServiceList(self):
343 self.session.execDialog(self.servicelist)
346 if self.servicelist.inBouquet():
347 prev = self.servicelist.getCurrentSelection()
349 prev = prev.toString()
351 if config.usage.quickzap_bouquet_change.value:
352 if self.servicelist.atBegin():
353 self.servicelist.prevBouquet()
354 self.servicelist.moveUp()
355 cur = self.servicelist.getCurrentSelection()
356 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
359 self.servicelist.moveUp()
360 self.servicelist.zap()
363 if self.servicelist.inBouquet():
364 prev = self.servicelist.getCurrentSelection()
366 prev = prev.toString()
368 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
369 self.servicelist.nextBouquet()
371 self.servicelist.moveDown()
372 cur = self.servicelist.getCurrentSelection()
373 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
376 self.servicelist.moveDown()
377 self.servicelist.zap()
380 """ Handles a menu action, to open the (main) menu """
382 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
384 "mainMenu": (self.mainMenu, _("Enter main menu...")),
386 self.session.infobar = None
389 print "loading mainmenu XML..."
390 menu = mdom.getroot()
391 assert menu.tag == "menu", "root element in menu must be 'menu'!"
393 self.session.infobar = self
394 # so we can access the currently active infobar from screens opened from within the mainmenu
395 # at the moment used from the SubserviceSelection
397 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu)
399 def mainMenuClosed(self, *val):
400 self.session.infobar = None
402 class InfoBarSimpleEventView:
403 """ Opens the Eventview for now/next """
405 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
407 "showEventInfo": (self.openEventView, _("show event details")),
408 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
411 def showEventInfoWhenNotVisible(self):
418 def openEventView(self):
420 self.epglist = epglist
421 service = self.session.nav.getCurrentService()
422 ref = self.session.nav.getCurrentlyPlayingServiceReference()
423 info = service.info()
431 self.session.open(EventViewSimple, epglist[0], ServiceReference(ref), self.eventViewCallback)
433 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
434 epglist = self.epglist
437 epglist[0] = epglist[1]
441 class SimpleServicelist:
442 def __init__(self, services):
443 self.services = services
444 self.length = len(services)
447 def selectService(self, service):
453 while self.services[self.current].ref != service:
455 if self.current >= self.length:
459 def nextService(self):
462 if self.current+1 < self.length:
467 def prevService(self):
470 if self.current-1 > -1:
473 self.current = self.length - 1
475 def currentService(self):
476 if not self.length or self.current >= self.length:
478 return self.services[self.current]
481 """ EPG - Opens an EPG list when the showEPGList action fires """
483 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
485 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
488 self.is_now_next = False
490 self.bouquetSel = None
491 self.eventView = None
492 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
494 "showEventInfo": (self.openEventView, _("show EPG...")),
495 "showEventInfoPlugin": (self.showEventInfoPlugins, _("show single service EPG...")),
496 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
499 def showEventInfoWhenNotVisible(self):
506 def zapToService(self, service):
507 if not service is None:
508 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
509 self.servicelist.clearPath()
510 if self.servicelist.bouquet_root != self.epg_bouquet:
511 self.servicelist.enterPath(self.servicelist.bouquet_root)
512 self.servicelist.enterPath(self.epg_bouquet)
513 self.servicelist.setCurrentSelection(service) #select the service in servicelist
514 self.servicelist.zap()
516 def getBouquetServices(self, bouquet):
518 servicelist = eServiceCenter.getInstance().list(bouquet)
519 if not servicelist is None:
521 service = servicelist.getNext()
522 if not service.valid(): #check if end of list
524 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
526 services.append(ServiceReference(service))
529 def openBouquetEPG(self, bouquet, withCallback=True):
530 services = self.getBouquetServices(bouquet)
532 self.epg_bouquet = bouquet
534 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
536 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
538 def changeBouquetCB(self, direction, epg):
541 self.bouquetSel.down()
544 bouquet = self.bouquetSel.getCurrent()
545 services = self.getBouquetServices(bouquet)
547 self.epg_bouquet = bouquet
548 epg.setServices(services)
550 def closed(self, ret=False):
551 closedScreen = self.dlg_stack.pop()
552 if self.bouquetSel and closedScreen == self.bouquetSel:
553 self.bouquetSel = None
554 elif self.eventView and closedScreen == self.eventView:
555 self.eventView = None
557 dlgs=len(self.dlg_stack)
559 self.dlg_stack[dlgs-1].close(dlgs > 1)
561 def openMultiServiceEPG(self, withCallback=True):
562 bouquets = self.servicelist.getBouquetList()
567 if cnt > 1: # show bouquet list
569 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
570 self.dlg_stack.append(self.bouquetSel)
572 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
574 self.openBouquetEPG(bouquets[0][1], withCallback)
576 def changeServiceCB(self, direction, epg):
579 self.serviceSel.nextService()
581 self.serviceSel.prevService()
582 epg.setService(self.serviceSel.currentService())
584 def SingleServiceEPGClosed(self, ret=False):
585 self.serviceSel = None
587 def openSingleServiceEPG(self):
588 ref=self.session.nav.getCurrentlyPlayingServiceReference()
590 if self.servicelist.getMutableList() is not None: # bouquet in channellist
591 current_path = self.servicelist.getRoot()
592 services = self.getBouquetServices(current_path)
593 self.serviceSel = SimpleServicelist(services)
594 if self.serviceSel.selectService(ref):
595 self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref, serviceChangeCB = self.changeServiceCB)
597 self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref)
599 self.session.open(EPGSelection, ref)
601 def showEventInfoPlugins(self):
602 list = [(p.name, boundFunction(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EVENTINFO)]
605 list.append((_("show single service EPG..."), self.openSingleServiceEPG))
606 self.session.openWithCallback(self.EventInfoPluginChosen, ChoiceBox, title=_("Please choose an extension..."), list = list, skin_name = "EPGExtensionsList")
608 self.openSingleServiceEPG()
610 def runPlugin(self, plugin):
611 plugin(session = self.session, servicelist = self.servicelist)
613 def EventInfoPluginChosen(self, answer):
614 if answer is not None:
617 def openSimilarList(self, eventid, refstr):
618 self.session.open(EPGSelection, refstr, None, eventid)
620 def getNowNext(self):
622 service = self.session.nav.getCurrentService()
623 info = service and service.info()
624 ptr = info and info.getEvent(0)
627 ptr = info and info.getEvent(1)
630 self.epglist = epglist
632 def __evEventInfoChanged(self):
633 if self.is_now_next and len(self.dlg_stack) == 1:
635 assert self.eventView
637 self.eventView.setEvent(self.epglist[0])
639 def openEventView(self):
640 ref = self.session.nav.getCurrentlyPlayingServiceReference()
642 epglist = self.epglist
644 self.is_now_next = False
645 epg = eEPGCache.getInstance()
646 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
649 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
653 self.is_now_next = True
655 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
656 self.dlg_stack.append(self.eventView)
658 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
659 self.openMultiServiceEPG(False)
661 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
662 epglist = self.epglist
665 epglist[0]=epglist[1]
669 class InfoBarRdsDecoder:
670 """provides RDS and Rass support/display"""
672 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
673 self.rass_interactive = None
675 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
677 iPlayableService.evEnd: self.__serviceStopped,
678 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
681 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
683 "startRassInteractive": self.startRassInteractive
686 self["RdsActions"].setEnabled(False)
688 self.onLayoutFinish.append(self.rds_display.show)
689 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
691 def RassInteractivePossibilityChanged(self, state):
692 self["RdsActions"].setEnabled(state)
694 def RassSlidePicChanged(self):
695 if not self.rass_interactive:
696 service = self.session.nav.getCurrentService()
697 decoder = service and service.rdsDecoder()
699 decoder.showRassSlidePicture()
701 def __serviceStopped(self):
702 if self.rass_interactive is not None:
703 rass_interactive = self.rass_interactive
704 self.rass_interactive = None
705 rass_interactive.close()
707 def startRassInteractive(self):
708 self.rds_display.hide()
709 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
711 def RassInteractiveClosed(self, *val):
712 if self.rass_interactive is not None:
713 self.rass_interactive = None
714 self.RassSlidePicChanged()
715 self.rds_display.show()
718 """handles actions like seeking, pause"""
720 SEEK_STATE_PLAY = (0, 0, 0, ">")
721 SEEK_STATE_PAUSE = (1, 0, 0, "||")
722 SEEK_STATE_EOF = (1, 0, 0, "END")
724 def __init__(self, actionmap = "InfobarSeekActions", useSeekBackHack=True):
725 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
727 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
728 iPlayableService.evStart: self.__serviceStarted,
730 iPlayableService.evEOF: self.__evEOF,
731 iPlayableService.evSOF: self.__evSOF,
734 class InfoBarSeekActionMap(HelpableActionMap):
735 def __init__(self, screen, *args, **kwargs):
736 HelpableActionMap.__init__(self, screen, *args, **kwargs)
739 def action(self, contexts, action):
740 print "action:", action
741 if action[:5] == "seek:":
742 time = int(action[5:])
743 self.screen.doSeekRelative(time * 90000)
745 elif action[:8] == "seekdef:":
746 key = int(action[8:])
747 time = (-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
748 -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
749 -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value)[key-1]
750 self.screen.doSeekRelative(time * 90000)
753 return HelpableActionMap.action(self, contexts, action)
755 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
757 "playpauseService": self.playpauseService,
758 "pauseService": (self.pauseService, _("pause")),
759 "unPauseService": (self.unPauseService, _("continue")),
761 "seekFwd": (self.seekFwd, _("skip forward")),
762 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
763 "seekBack": (self.seekBack, _("skip backward")),
764 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)"))
766 # give them a little more priority to win over color buttons
768 self["SeekActions"].setEnabled(False)
770 self.seekstate = self.SEEK_STATE_PLAY
771 self.lastseekstate = self.SEEK_STATE_PLAY
773 self.onPlayStateChanged = [ ]
775 self.lockedBecauseOfSkipping = False
777 self.__seekableStatusChanged()
779 def makeStateForward(self, n):
780 # minspeed = config.seek.stepwise_minspeed.value
781 # repeat = int(config.seek.stepwise_repeat.value)
782 # if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
783 # return (0, n * repeat, repeat, ">> %dx" % n)
785 return (0, n, 0, ">> %dx" % n)
787 def makeStateBackward(self, n):
788 # minspeed = config.seek.stepwise_minspeed.value
789 # repeat = int(config.seek.stepwise_repeat.value)
790 # if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
791 # return (0, -n * repeat, repeat, "<< %dx" % n)
793 return (0, -n, 0, "<< %dx" % n)
795 def makeStateSlowMotion(self, n):
796 return (0, 0, n, "/%d" % n)
798 def isStateForward(self, state):
801 def isStateBackward(self, state):
804 def isStateSlowMotion(self, state):
805 return state[1] == 0 and state[2] > 1
807 def getHigher(self, n, lst):
813 def getLower(self, n, lst):
821 def showAfterSeek(self):
822 if isinstance(self, InfoBarShowHide):
832 service = self.session.nav.getCurrentService()
836 seek = service.seek()
838 if seek is None or not seek.isCurrentlySeekable():
843 def isSeekable(self):
844 if self.getSeek() is None:
848 def __seekableStatusChanged(self):
849 # print "seekable status changed!"
850 if not self.isSeekable():
851 self["SeekActions"].setEnabled(False)
852 # print "not seekable, return to play"
853 self.setSeekState(self.SEEK_STATE_PLAY)
855 self["SeekActions"].setEnabled(True)
858 def __serviceStarted(self):
859 self.seekstate = self.SEEK_STATE_PLAY
860 self.__seekableStatusChanged()
862 def setSeekState(self, state):
863 service = self.session.nav.getCurrentService()
868 if not self.isSeekable():
869 if state not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE):
870 state = self.SEEK_STATE_PLAY
872 pauseable = service.pause()
874 if pauseable is None:
875 print "not pauseable."
876 state = self.SEEK_STATE_PLAY
878 self.seekstate = state
880 if pauseable is not None:
881 if self.seekstate[0]:
882 print "resolved to PAUSE"
884 elif self.seekstate[1]:
885 print "resolved to FAST FORWARD"
886 pauseable.setFastForward(self.seekstate[1])
887 elif self.seekstate[2]:
888 print "resolved to SLOW MOTION"
889 pauseable.setSlowMotion(self.seekstate[2])
891 print "resolved to PLAY"
894 for c in self.onPlayStateChanged:
897 self.checkSkipShowHideLock()
901 def playpauseService(self):
902 if self.seekstate != self.SEEK_STATE_PLAY:
903 self.unPauseService()
907 def pauseService(self):
908 if self.seekstate == self.SEEK_STATE_PAUSE:
909 if config.seek.on_pause.value == "play":
910 self.unPauseService()
911 elif config.seek.on_pause.value == "step":
912 self.doSeekRelative(1)
913 elif config.seek.on_pause.value == "last":
914 self.setSeekState(self.lastseekstate)
915 self.lastseekstate = self.SEEK_STATE_PLAY
917 if self.seekstate != self.SEEK_STATE_EOF:
918 self.lastseekstate = self.seekstate
919 self.setSeekState(self.SEEK_STATE_PAUSE);
921 def unPauseService(self):
923 if self.seekstate == self.SEEK_STATE_PLAY:
925 self.setSeekState(self.SEEK_STATE_PLAY)
927 def doSeek(self, pts):
928 seekable = self.getSeek()
933 def doSeekRelative(self, pts):
934 seekable = self.getSeek()
937 prevstate = self.seekstate
939 if self.seekstate == self.SEEK_STATE_EOF:
940 if prevstate == self.SEEK_STATE_PAUSE:
941 self.setSeekState(self.SEEK_STATE_PAUSE)
943 self.setSeekState(self.SEEK_STATE_PLAY)
944 seekable.seekRelative(pts<0 and -1 or 1, abs(pts))
945 if abs(pts) > 100 and config.usage.show_infobar_on_skip.value:
949 if self.seekstate == self.SEEK_STATE_PLAY:
950 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
951 elif self.seekstate == self.SEEK_STATE_PAUSE:
952 if len(config.seek.speeds_slowmotion.value):
953 self.setSeekState(self.makeStateSlowMotion(config.seek.speeds_slowmotion.value[-1]))
955 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
956 elif self.seekstate == self.SEEK_STATE_EOF:
958 elif self.isStateForward(self.seekstate):
959 speed = self.seekstate[1]
960 if self.seekstate[2]:
961 speed /= self.seekstate[2]
962 speed = self.getHigher(speed, config.seek.speeds_forward.value) or config.seek.speeds_forward.value[-1]
963 self.setSeekState(self.makeStateForward(speed))
964 elif self.isStateBackward(self.seekstate):
965 speed = -self.seekstate[1]
966 if self.seekstate[2]:
967 speed /= self.seekstate[2]
968 speed = self.getLower(speed, config.seek.speeds_backward.value)
970 self.setSeekState(self.makeStateBackward(speed))
972 self.setSeekState(self.SEEK_STATE_PLAY)
973 elif self.isStateSlowMotion(self.seekstate):
974 speed = self.getLower(self.seekstate[2], config.seek.speeds_slowmotion.value) or config.seek.speeds_slowmotion.value[0]
975 self.setSeekState(self.makeStateSlowMotion(speed))
978 seekstate = self.seekstate
979 if seekstate == self.SEEK_STATE_PLAY:
980 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
981 elif seekstate == self.SEEK_STATE_EOF:
982 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
983 self.doSeekRelative(-6)
984 elif seekstate == self.SEEK_STATE_PAUSE:
985 self.doSeekRelative(-1)
986 elif self.isStateForward(seekstate):
989 speed /= seekstate[2]
990 speed = self.getLower(speed, config.seek.speeds_forward.value)
992 self.setSeekState(self.makeStateForward(speed))
994 self.setSeekState(self.SEEK_STATE_PLAY)
995 elif self.isStateBackward(seekstate):
996 speed = -seekstate[1]
998 speed /= seekstate[2]
999 speed = self.getHigher(speed, config.seek.speeds_backward.value) or config.seek.speeds_backward.value[-1]
1000 self.setSeekState(self.makeStateBackward(speed))
1001 elif self.isStateSlowMotion(seekstate):
1002 speed = self.getHigher(seekstate[2], config.seek.speeds_slowmotion.value)
1004 self.setSeekState(self.makeStateSlowMotion(speed))
1006 self.setSeekState(self.SEEK_STATE_PAUSE)
1008 def seekFwdManual(self):
1009 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
1011 def fwdSeekTo(self, minutes):
1012 print "Seek", minutes, "minutes forward"
1013 self.doSeekRelative(minutes * 60 * 90000)
1015 def seekBackManual(self):
1016 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
1018 def rwdSeekTo(self, minutes):
1020 self.doSeekRelative(-minutes * 60 * 90000)
1022 def checkSkipShowHideLock(self):
1023 wantlock = self.seekstate != self.SEEK_STATE_PLAY
1025 if config.usage.show_infobar_on_skip.value:
1026 if self.lockedBecauseOfSkipping and not wantlock:
1028 self.lockedBecauseOfSkipping = False
1030 if wantlock and not self.lockedBecauseOfSkipping:
1032 self.lockedBecauseOfSkipping = True
1034 def calcRemainingTime(self):
1035 seekable = self.getSeek()
1036 if seekable is not None:
1037 len = seekable.getLength()
1039 tmp = self.cueGetEndCutPosition()
1044 pos = seekable.getPlayPosition()
1045 speednom = self.seekstate[1] or 1
1046 speedden = self.seekstate[2] or 1
1047 if not len[0] and not pos[0]:
1048 if len[1] <= pos[1]:
1050 time = (len[1] - pos[1])*speedden/(90*speednom)
1055 if self.seekstate == self.SEEK_STATE_EOF:
1058 # if we are seeking forward, we try to end up ~1s before the end, and pause there.
1059 seekstate = self.seekstate
1060 if self.seekstate != self.SEEK_STATE_PAUSE:
1061 self.setSeekState(self.SEEK_STATE_EOF)
1063 if seekstate not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE): # if we are seeking
1064 seekable = self.getSeek()
1065 if seekable is not None:
1067 if seekstate == self.SEEK_STATE_PLAY: # regular EOF
1068 self.doEofInternal(True)
1070 self.doEofInternal(False)
1072 def doEofInternal(self, playing):
1073 pass # Defined in subclasses
1076 self.setSeekState(self.SEEK_STATE_PLAY)
1079 from Screens.PVRState import PVRState, TimeshiftState
1081 class InfoBarPVRState:
1082 def __init__(self, screen=PVRState, force_show = False):
1083 self.onPlayStateChanged.append(self.__playStateChanged)
1084 self.pvrStateDialog = self.session.instantiateDialog(screen)
1085 self.onShow.append(self._mayShow)
1086 self.onHide.append(self.pvrStateDialog.hide)
1087 self.force_show = force_show
1090 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
1091 self.pvrStateDialog.show()
1093 def __playStateChanged(self, state):
1094 playstateString = state[3]
1095 self.pvrStateDialog["state"].setText(playstateString)
1097 # if we return into "PLAY" state, ensure that the dialog gets hidden if there will be no infobar displayed
1098 if not config.usage.show_infobar_on_skip.value and self.seekstate == self.SEEK_STATE_PLAY and not self.force_show:
1099 self.pvrStateDialog.hide()
1104 class InfoBarTimeshiftState(InfoBarPVRState):
1106 InfoBarPVRState.__init__(self, screen=TimeshiftState, force_show = True)
1109 if self.execing and self.timeshift_enabled and self.seekstate != self.SEEK_STATE_PLAY:
1110 self.pvrStateDialog.show()
1112 class InfoBarShowMovies:
1114 # i don't really like this class.
1115 # it calls a not further specified "movie list" on up/down/movieList,
1116 # so this is not more than an action map
1118 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
1120 "movieList": (self.showMovies, _("movie list")),
1121 "up": (self.showMovies, _("movie list")),
1122 "down": (self.showMovies, _("movie list"))
1125 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
1129 # Timeshift works the following way:
1130 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
1131 # - normal playback TUNER unused PLAY enable disable disable
1132 # - user presses "yellow" button. FILE record PAUSE enable disable enable
1133 # - user presess pause again FILE record PLAY enable disable enable
1134 # - user fast forwards FILE record FF enable disable enable
1135 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
1136 # - user backwards FILE record BACK # !! enable disable enable
1140 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1141 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1142 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1143 # - the user can now PVR around
1144 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1145 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1147 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1148 # - if the user rewinds, or press pause, timeshift will be activated again
1150 # note that a timeshift can be enabled ("recording") and
1151 # activated (currently time-shifting).
1153 class InfoBarTimeshift:
1155 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1157 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1158 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1160 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1162 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1163 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1164 }, prio=-1) # priority over record
1166 self.timeshift_enabled = 0
1167 self.timeshift_state = 0
1168 self.ts_rewind_timer = eTimer()
1169 self.ts_rewind_timer.callback.append(self.rewindService)
1171 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1173 iPlayableService.evStart: self.__serviceStarted,
1174 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1177 def getTimeshift(self):
1178 service = self.session.nav.getCurrentService()
1179 return service and service.timeshift()
1181 def startTimeshift(self):
1182 print "enable timeshift"
1183 ts = self.getTimeshift()
1185 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1186 print "no ts interface"
1189 if self.timeshift_enabled:
1190 print "hu, timeshift already enabled?"
1192 if not ts.startTimeshift():
1193 self.timeshift_enabled = 1
1195 # we remove the "relative time" for now.
1196 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1199 #self.setSeekState(self.SEEK_STATE_PAUSE)
1200 self.activateTimeshiftEnd(False)
1202 # enable the "TimeshiftEnableActions", which will override
1203 # the startTimeshift actions
1204 self.__seekableStatusChanged()
1206 print "timeshift failed"
1208 def stopTimeshift(self):
1209 if not self.timeshift_enabled:
1211 print "disable timeshift"
1212 ts = self.getTimeshift()
1215 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1217 def stopTimeshiftConfirmed(self, confirmed):
1221 ts = self.getTimeshift()
1226 self.timeshift_enabled = 0
1229 self.__seekableStatusChanged()
1231 # activates timeshift, and seeks to (almost) the end
1232 def activateTimeshiftEnd(self, back = True):
1233 ts = self.getTimeshift()
1234 print "activateTimeshiftEnd"
1239 if ts.isTimeshiftActive():
1240 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1244 ts.activateTimeshift() # activate timeshift will automatically pause
1245 self.setSeekState(self.SEEK_STATE_PAUSE)
1248 self.ts_rewind_timer.start(200, 1)
1250 def rewindService(self):
1251 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1253 # same as activateTimeshiftEnd, but pauses afterwards.
1254 def activateTimeshiftEndAndPause(self):
1255 print "activateTimeshiftEndAndPause"
1256 #state = self.seekstate
1257 self.activateTimeshiftEnd(False)
1259 def __seekableStatusChanged(self):
1262 # print "self.isSeekable", self.isSeekable()
1263 # print "self.timeshift_enabled", self.timeshift_enabled
1265 # when this service is not seekable, but timeshift
1266 # is enabled, this means we can activate
1268 if not self.isSeekable() and self.timeshift_enabled:
1271 # print "timeshift activate:", enabled
1272 self["TimeshiftActivateActions"].setEnabled(enabled)
1274 def __serviceStarted(self):
1275 self.timeshift_enabled = False
1276 self.__seekableStatusChanged()
1278 from Screens.PiPSetup import PiPSetup
1280 class InfoBarExtensions:
1281 EXTENSION_SINGLE = 0
1287 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1289 "extensions": (self.showExtensionSelection, _("view extensions...")),
1290 }, 1) # lower priority
1292 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1293 self.list.append((type, extension, key))
1295 def updateExtension(self, extension, key = None):
1296 self.extensionsList.append(extension)
1298 if self.extensionKeys.has_key(key):
1302 for x in self.availableKeys:
1303 if not self.extensionKeys.has_key(x):
1308 self.extensionKeys[key] = len(self.extensionsList) - 1
1310 def updateExtensions(self):
1311 self.extensionsList = []
1312 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1313 self.extensionKeys = {}
1315 if x[0] == self.EXTENSION_SINGLE:
1316 self.updateExtension(x[1], x[2])
1319 self.updateExtension(y[0], y[1])
1322 def showExtensionSelection(self):
1323 self.updateExtensions()
1324 extensionsList = self.extensionsList[:]
1327 for x in self.availableKeys:
1328 if self.extensionKeys.has_key(x):
1329 entry = self.extensionKeys[x]
1330 extension = self.extensionsList[entry]
1332 name = str(extension[0]())
1333 list.append((extension[0](), extension))
1335 extensionsList.remove(extension)
1337 extensionsList.remove(extension)
1338 list.extend([(x[0](), x) for x in extensionsList])
1340 keys += [""] * len(extensionsList)
1341 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys, skin_name = "ExtensionsList")
1343 def extensionCallback(self, answer):
1344 if answer is not None:
1347 from Tools.BoundFunction import boundFunction
1349 # depends on InfoBarExtensions
1351 class InfoBarPlugins:
1353 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1355 def getPluginName(self, name):
1358 def getPluginList(self):
1359 list = [((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU)]
1360 list.sort(key = lambda e: e[2]) # sort by name
1363 def runPlugin(self, plugin):
1364 if isinstance(self, InfoBarChannelSelection):
1365 plugin(session = self.session, servicelist = self.servicelist)
1367 plugin(session = self.session)
1369 from Components.Task import job_manager
1370 class InfoBarJobman:
1372 self.addExtension(extension = self.getJobList, type = InfoBarExtensions.EXTENSION_LIST)
1374 def getJobList(self):
1375 return [((boundFunction(self.getJobName, job), boundFunction(self.showJobView, job), lambda: True), None) for job in job_manager.getPendingJobs()]
1377 def getJobName(self, job):
1378 return "%s: %s (%d%%)" % (job.getStatustext(), job.name, int(100*job.progress/float(job.end)))
1380 def showJobView(self, job):
1381 from Screens.TaskView import JobView
1382 job_manager.in_background = False
1383 self.session.openWithCallback(self.JobViewCB, JobView, job)
1385 def JobViewCB(self, in_background):
1386 job_manager.in_background = in_background
1388 # depends on InfoBarExtensions
1392 self.session.pipshown
1394 self.session.pipshown = False
1395 if SystemInfo.get("NumVideoDecoders", 1) > 1:
1397 self.addExtension((self.getShowHideName, self.showPiP, lambda: True), "blue")
1398 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1399 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1401 self.addExtension((self.getShowHideName, self.showPiP, self.pipShown), "blue")
1402 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1405 return self.session.pipshown
1407 def pipHandles0Action(self):
1408 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1410 def getShowHideName(self):
1411 if self.session.pipshown:
1412 return _("Disable Picture in Picture")
1414 return _("Activate Picture in Picture")
1416 def getSwapName(self):
1417 return _("Swap Services")
1419 def getMoveName(self):
1420 return _("Move Picture in Picture")
1423 if self.session.pipshown:
1424 del self.session.pip
1425 self.session.pipshown = False
1427 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1428 self.session.pip.show()
1429 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1430 if self.session.pip.playService(newservice):
1431 self.session.pipshown = True
1432 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1434 self.session.pipshown = False
1435 del self.session.pip
1436 self.session.nav.playService(newservice)
1439 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1440 if self.session.pip.servicePath:
1441 servicepath = self.servicelist.getCurrentServicePath()
1442 ref=servicepath[len(servicepath)-1]
1443 pipref=self.session.pip.getCurrentService()
1444 self.session.pip.playService(swapservice)
1445 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1446 if pipref.toString() != ref.toString(): # is a subservice ?
1447 self.session.nav.stopService() # stop portal
1448 self.session.nav.playService(pipref) # start subservice
1449 self.session.pip.servicePath=servicepath
1452 self.session.open(PiPSetup, pip = self.session.pip)
1454 def pipDoHandle0Action(self):
1455 use = config.usage.pip_zero_button.value
1458 elif "swapstop" == use:
1464 from RecordTimer import parseEvent, RecordTimerEntry
1466 class InfoBarInstantRecord:
1467 """Instant Record - handles the instantRecord action in order to
1468 start/stop instant records"""
1470 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1472 "instantRecord": (self.instantRecord, _("Instant Record...")),
1476 def stopCurrentRecording(self, entry = -1):
1477 if entry is not None and entry != -1:
1478 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1479 self.recording.remove(self.recording[entry])
1481 def startInstantRecording(self, limitEvent = False):
1482 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1484 # try to get event info
1487 service = self.session.nav.getCurrentService()
1488 epg = eEPGCache.getInstance()
1489 event = epg.lookupEventTime(serviceref, -1, 0)
1491 info = service.info()
1492 ev = info.getEvent(0)
1498 end = begin + 3600 # dummy
1499 name = "instant record"
1503 if event is not None:
1504 curEvent = parseEvent(event)
1506 description = curEvent[3]
1507 eventid = curEvent[4]
1512 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1514 if isinstance(serviceref, eServiceReference):
1515 serviceref = ServiceReference(serviceref)
1517 recording = RecordTimerEntry(serviceref, begin, end, name, description, eventid, dirname = preferredInstantRecordPath())
1518 recording.dontSave = True
1520 if event is None or limitEvent == False:
1521 recording.autoincrease = True
1522 if recording.setAutoincreaseEnd():
1523 self.session.nav.RecordTimer.record(recording)
1524 self.recording.append(recording)
1526 simulTimerList = self.session.nav.RecordTimer.record(recording)
1527 if simulTimerList is not None: # conflict with other recording
1528 name = simulTimerList[1].name
1529 name_date = ' '.join((name, strftime('%c', localtime(simulTimerList[1].begin))))
1530 print "[TIMER] conflicts with", name_date
1531 recording.autoincrease = True # start with max available length, then increment
1532 if recording.setAutoincreaseEnd():
1533 self.session.nav.RecordTimer.record(recording)
1534 self.recording.append(recording)
1535 self.session.open(MessageBox, _("Record time limited due to conflicting timer %s") % name_date, MessageBox.TYPE_INFO)
1537 self.session.open(MessageBox, _("Couldn't record due to conflicting timer %s") % name, MessageBox.TYPE_INFO)
1538 recording.autoincrease = False
1540 self.recording.append(recording)
1542 def isInstantRecordRunning(self):
1543 print "self.recording:", self.recording
1545 for x in self.recording:
1550 def recordQuestionCallback(self, answer):
1551 print "pre:\n", self.recording
1553 if answer is None or answer[1] == "no":
1556 recording = self.recording[:]
1558 if not x in self.session.nav.RecordTimer.timer_list:
1559 self.recording.remove(x)
1560 elif x.dontSave and x.isRunning():
1561 list.append((x, False))
1563 if answer[1] == "changeduration":
1564 if len(self.recording) == 1:
1565 self.changeDuration(0)
1567 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1568 elif answer[1] == "changeendtime":
1569 if len(self.recording) == 1:
1572 self.session.openWithCallback(self.setEndtime, TimerSelection, list)
1573 elif answer[1] == "stop":
1574 if len(self.recording) == 1:
1575 self.stopCurrentRecording(0)
1577 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1578 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1579 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1580 if answer[1] == "manualduration":
1581 self.changeDuration(len(self.recording)-1)
1582 elif answer[1] == "manualendtime":
1583 self.setEndtime(len(self.recording)-1)
1584 print "after:\n", self.recording
1586 def setEndtime(self, entry):
1587 if entry is not None and entry >= 0:
1588 self.selectedEntry = entry
1589 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1590 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1591 dlg.setTitle(_("Please change recording endtime"))
1593 def TimeDateInputClosed(self, ret):
1596 localendtime = localtime(ret[1])
1597 print "stopping recording at", strftime("%c", localendtime)
1598 if self.recording[self.selectedEntry].end != ret[1]:
1599 self.recording[self.selectedEntry].autoincrease = False
1600 self.recording[self.selectedEntry].end = ret[1]
1601 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1603 def changeDuration(self, entry):
1604 if entry is not None and entry >= 0:
1605 self.selectedEntry = entry
1606 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1608 def inputCallback(self, value):
1609 if value is not None:
1610 print "stopping recording after", int(value), "minutes."
1611 entry = self.recording[self.selectedEntry]
1613 entry.autoincrease = False
1614 entry.end = int(time()) + 60 * int(value)
1615 self.session.nav.RecordTimer.timeChanged(entry)
1617 def instantRecord(self):
1618 dir = preferredInstantRecordPath()
1619 if not dir or not fileExists(dir, 'w'):
1620 dir = defaultMoviePath()
1624 # XXX: this message is a little odd as we might be recording to a remote device
1625 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1628 if self.isInstantRecordRunning():
1629 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1630 title=_("A recording is currently running.\nWhat do you want to do?"), \
1631 list=((_("stop recording"), "stop"), \
1632 (_("add recording (stop after current event)"), "event"), \
1633 (_("add recording (indefinitely)"), "indefinitely"), \
1634 (_("add recording (enter recording duration)"), "manualduration"), \
1635 (_("add recording (enter recording endtime)"), "manualendtime"), \
1636 (_("change recording (duration)"), "changeduration"), \
1637 (_("change recording (endtime)"), "changeendtime"), \
1638 (_("do nothing"), "no")))
1640 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1641 title=_("Start recording?"), \
1642 list=((_("add recording (stop after current event)"), "event"), \
1643 (_("add recording (indefinitely)"), "indefinitely"), \
1644 (_("add recording (enter recording duration)"), "manualduration"), \
1645 (_("add recording (enter recording endtime)"), "manualendtime"), \
1646 (_("don't record"), "no")))
1648 from Tools.ISO639 import LanguageCodes
1650 class InfoBarAudioSelection:
1652 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1654 "audioSelection": (self.audioSelection, _("Audio Options...")),
1657 def audioSelection(self):
1658 service = self.session.nav.getCurrentService()
1659 self.audioTracks = audio = service and service.audioTracks()
1660 n = audio and audio.getNumberOfTracks() or 0
1663 self.audioChannel = service.audioChannel()
1668 i = audio.getTrackInfo(idx)
1669 languages = i.getLanguage().split('/')
1670 description = i.getDescription()
1673 for lang in languages:
1676 if LanguageCodes.has_key(lang):
1677 language += LanguageCodes[lang][0]
1682 if len(description):
1683 description += " (" + language + ")"
1685 description = language
1687 tlist.append((description, idx))
1690 tlist.sort(key=lambda x: x[0])
1692 selectedAudio = self.audioTracks.getCurrentTrack()
1697 if x[1] != selectedAudio:
1705 if SystemInfo["CanDownmixAC3"]:
1706 flist = [(_("AC3 downmix") + " - " +(_("Off"), _("On"))[config.av.downmix_ac3.value and 1 or 0], "CALLFUNC", self.changeAC3Downmix),
1707 ((_("Left"), _("Stereo"), _("Right"))[self.audioChannel.getCurrentChannel()], "mode")]
1708 usedKeys.extend(["red", "green"])
1709 availableKeys.extend(["yellow", "blue"])
1712 flist = [((_("Left"), _("Stereo"), _("Right"))[self.audioChannel.getCurrentChannel()], "mode")]
1713 usedKeys.extend(["red"])
1714 availableKeys.extend(["green", "yellow", "blue"])
1717 if hasattr(self, "runPlugin"):
1719 def __init__(self, fnc, *args):
1722 def __call__(self, *args, **kwargs):
1723 self.fnc(*self.args)
1725 Plugins = [ (p.name, PluginCaller(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_AUDIOMENU) ]
1729 flist.append((p[0], "CALLFUNC", p[1]))
1731 usedKeys.append(availableKeys[0])
1732 del availableKeys[0]
1736 flist.append(("--", ""))
1740 keys = usedKeys + [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" ] + [""] * n
1741 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = flist + tlist, selection = selection, keys = keys, skin_name = "AudioTrackSelection")
1743 del self.audioTracks
1745 def changeAC3Downmix(self, arg):
1746 choicelist = self.session.current_dialog["list"]
1747 list = choicelist.list
1749 list[0][1]=(t[0], t[1], t[2], t[3], t[4], t[5], t[6],
1750 _("AC3 downmix") + " - " + (_("On"), _("Off"))[config.av.downmix_ac3.value and 1 or 0])
1751 choicelist.setList(list)
1752 if config.av.downmix_ac3.value:
1753 config.av.downmix_ac3.value = False
1755 config.av.downmix_ac3.value = True
1756 config.av.downmix_ac3.save()
1758 def audioSelected(self, audio):
1759 if audio is not None:
1760 if isinstance(audio[1], str):
1761 if audio[1] == "mode":
1762 keys = ["red", "green", "yellow"]
1763 selection = self.audioChannel.getCurrentChannel()
1764 tlist = ((_("left"), 0), (_("stereo"), 1), (_("right"), 2))
1765 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys, skin_name ="AudioModeSelection")
1767 del self.audioChannel
1768 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1769 self.audioTracks.selectTrack(audio[1])
1771 del self.audioChannel
1772 del self.audioTracks
1774 def modeSelected(self, mode):
1775 if mode is not None:
1776 self.audioChannel.selectChannel(mode[1])
1777 del self.audioChannel
1779 class InfoBarSubserviceSelection:
1781 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1783 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1786 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1788 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1789 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1791 self["SubserviceQuickzapAction"].setEnabled(False)
1793 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1795 iPlayableService.evUpdatedEventInfo: self.checkSubservicesAvail
1800 def checkSubservicesAvail(self):
1801 service = self.session.nav.getCurrentService()
1802 subservices = service and service.subServices()
1803 if not subservices or subservices.getNumberOfSubservices() == 0:
1804 self["SubserviceQuickzapAction"].setEnabled(False)
1806 def nextSubservice(self):
1807 self.changeSubservice(+1)
1809 def prevSubservice(self):
1810 self.changeSubservice(-1)
1812 def changeSubservice(self, direction):
1813 service = self.session.nav.getCurrentService()
1814 subservices = service and service.subServices()
1815 n = subservices and subservices.getNumberOfSubservices()
1818 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1821 if subservices.getSubservice(idx).toString() == ref.toString():
1826 selection += direction
1831 newservice = subservices.getSubservice(selection)
1832 if newservice.valid():
1835 self.session.nav.playService(newservice, False)
1837 def subserviceSelection(self):
1838 service = self.session.nav.getCurrentService()
1839 subservices = service and service.subServices()
1840 self.bouquets = self.servicelist.getBouquetList()
1841 n = subservices and subservices.getNumberOfSubservices()
1844 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1848 i = subservices.getSubservice(idx)
1849 if i.toString() == ref.toString():
1851 tlist.append((i.getName(), i))
1854 if self.bouquets and len(self.bouquets):
1855 keys = ["red", "blue", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1856 if config.usage.multibouquet.value:
1857 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1859 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1862 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1863 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1866 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys, skin_name = "SubserviceSelection")
1868 def subserviceSelected(self, service):
1870 if not service is None:
1871 if isinstance(service[1], str):
1872 if service[1] == "quickzap":
1873 from Screens.SubservicesQuickzap import SubservicesQuickzap
1874 self.session.open(SubservicesQuickzap, service[2])
1876 self["SubserviceQuickzapAction"].setEnabled(True)
1877 self.session.nav.playService(service[1], False)
1879 def addSubserviceToBouquetCallback(self, service):
1880 if len(service) > 1 and isinstance(service[1], eServiceReference):
1881 self.selectedSubservice = service
1882 if self.bouquets is None:
1885 cnt = len(self.bouquets)
1886 if cnt > 1: # show bouquet list
1887 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1888 elif cnt == 1: # add to only one existing bouquet
1889 self.addSubserviceToBouquet(self.bouquets[0][1])
1890 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1892 def bouquetSelClosed(self, confirmed):
1894 del self.selectedSubservice
1896 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1898 def addSubserviceToBouquet(self, dest):
1899 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1901 self.bsel.close(True)
1903 del self.selectedSubservice
1905 class InfoBarAdditionalInfo:
1908 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0 and config.misc.rcused.value == 1)
1909 self["TimeshiftPossible"] = self["RecordingPossible"]
1910 self["ShowTimeshiftOnYellow"] = Boolean(fixed=(not config.misc.rcused.value == 0))
1911 self["ShowAudioOnYellow"] = Boolean(fixed=config.misc.rcused.value == 0)
1912 self["ShowRecordOnRed"] = Boolean(fixed=config.misc.rcused.value == 1)
1913 self["ExtensionsAvailable"] = Boolean(fixed=1)
1915 class InfoBarNotifications:
1917 self.onExecBegin.append(self.checkNotifications)
1918 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1919 self.onClose.append(self.__removeNotification)
1921 def __removeNotification(self):
1922 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1924 def checkNotificationsIfExecing(self):
1926 self.checkNotifications()
1928 def checkNotifications(self):
1929 notifications = Notifications.notifications
1931 n = notifications[0]
1933 del notifications[0]
1936 if n[3].has_key("onSessionOpenCallback"):
1937 n[3]["onSessionOpenCallback"]()
1938 del n[3]["onSessionOpenCallback"]
1941 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1943 dlg = self.session.open(n[1], *n[2], **n[3])
1945 # remember that this notification is currently active
1947 Notifications.current_notifications.append(d)
1948 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1950 def __notificationClosed(self, d):
1951 Notifications.current_notifications.remove(d)
1953 class InfoBarServiceNotifications:
1955 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1957 iPlayableService.evEnd: self.serviceHasEnded
1960 def serviceHasEnded(self):
1961 print "service end!"
1964 self.setSeekState(self.SEEK_STATE_PLAY)
1968 class InfoBarCueSheetSupport:
1974 ENABLE_RESUME_SUPPORT = False
1976 def __init__(self, actionmap = "InfobarCueSheetActions"):
1977 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1979 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1980 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1981 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1985 self.is_closing = False
1986 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1988 iPlayableService.evStart: self.__serviceStarted,
1991 def __serviceStarted(self):
1994 print "new service started! trying to download cuts!"
1995 self.downloadCuesheet()
1997 if self.ENABLE_RESUME_SUPPORT:
2000 for (pts, what) in self.cut_list:
2001 if what == self.CUT_TYPE_LAST:
2004 if last is not None:
2005 self.resume_point = last
2006 if config.usage.on_movie_start.value == "ask":
2007 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
2008 elif config.usage.on_movie_start.value == "resume":
2009 # TRANSLATORS: The string "Resuming playback" flashes for a moment
2010 # TRANSLATORS: at the start of a movie, when the user has selected
2011 # TRANSLATORS: "Resume from last position" as start behavior.
2012 # TRANSLATORS: The purpose is to notify the user that the movie starts
2013 # TRANSLATORS: in the middle somewhere and not from the beginning.
2014 # TRANSLATORS: (Some translators seem to have interpreted it as a
2015 # TRANSLATORS: question or a choice, but it is a statement.)
2016 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Resuming playback"), timeout=2, type=MessageBox.TYPE_INFO)
2018 def playLastCB(self, answer):
2020 self.doSeek(self.resume_point)
2021 self.hideAfterResume()
2023 def hideAfterResume(self):
2024 if isinstance(self, InfoBarShowHide):
2027 def __getSeekable(self):
2028 service = self.session.nav.getCurrentService()
2031 return service.seek()
2033 def cueGetCurrentPosition(self):
2034 seek = self.__getSeekable()
2037 r = seek.getPlayPosition()
2042 def cueGetEndCutPosition(self):
2045 for cp in self.cut_list:
2046 if cp[1] == self.CUT_TYPE_OUT:
2050 elif cp[1] == self.CUT_TYPE_IN:
2054 def jumpPreviousNextMark(self, cmp, start=False):
2055 current_pos = self.cueGetCurrentPosition()
2056 if current_pos is None:
2058 mark = self.getNearestCutPoint(current_pos, cmp=cmp, start=start)
2059 if mark is not None:
2067 def jumpPreviousMark(self):
2068 # we add 2 seconds, so if the play position is <2s after
2069 # the mark, the mark before will be used
2070 self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
2072 def jumpNextMark(self):
2073 if not self.jumpPreviousNextMark(lambda x: x):
2076 def getNearestCutPoint(self, pts, cmp=abs, start=False):
2082 bestdiff = cmp(0 - pts)
2084 nearest = [0, False]
2085 for cp in self.cut_list:
2086 if beforecut and cp[1] in (self.CUT_TYPE_IN, self.CUT_TYPE_OUT):
2088 if cp[1] == self.CUT_TYPE_IN: # Start is here, disregard previous marks
2089 diff = cmp(cp[0] - pts)
2095 if cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
2096 diff = cmp(cp[0] - pts)
2097 if diff >= 0 and (nearest is None or bestdiff > diff):
2102 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
2103 current_pos = self.cueGetCurrentPosition()
2104 if current_pos is None:
2105 print "not seekable"
2108 nearest_cutpoint = self.getNearestCutPoint(current_pos)
2110 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
2112 return nearest_cutpoint
2114 self.removeMark(nearest_cutpoint)
2115 elif not onlyremove and not onlyreturn:
2116 self.addMark((current_pos, self.CUT_TYPE_MARK))
2121 def addMark(self, point):
2122 insort(self.cut_list, point)
2123 self.uploadCuesheet()
2124 self.showAfterCuesheetOperation()
2126 def removeMark(self, point):
2127 self.cut_list.remove(point)
2128 self.uploadCuesheet()
2129 self.showAfterCuesheetOperation()
2131 def showAfterCuesheetOperation(self):
2132 if isinstance(self, InfoBarShowHide):
2135 def __getCuesheet(self):
2136 service = self.session.nav.getCurrentService()
2139 return service.cueSheet()
2141 def uploadCuesheet(self):
2142 cue = self.__getCuesheet()
2145 print "upload failed, no cuesheet interface"
2147 cue.setCutList(self.cut_list)
2149 def downloadCuesheet(self):
2150 cue = self.__getCuesheet()
2153 print "download failed, no cuesheet interface"
2156 self.cut_list = cue.getCutList()
2158 class InfoBarSummary(Screen):
2160 <screen position="0,0" size="132,64">
2161 <widget source="global.CurrentTime" render="Label" position="62,46" size="82,18" font="Regular;16" >
2162 <convert type="ClockToText">WithSeconds</convert>
2164 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="82,18" zPosition="1" >
2165 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2166 <convert type="ConditionalShowHide">Blink</convert>
2168 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2169 <convert type="ServiceName">Name</convert>
2171 <widget source="session.Event_Now" render="Progress" position="6,46" size="46,18" borderWidth="1" >
2172 <convert type="EventTime">Progress</convert>
2176 # for picon: (path="piconlcd" will use LCD picons)
2177 # <widget source="session.CurrentService" render="Picon" position="6,0" size="120,64" path="piconlcd" >
2178 # <convert type="ServiceName">Reference</convert>
2181 class InfoBarSummarySupport:
2185 def createSummary(self):
2186 return InfoBarSummary
2188 class InfoBarMoviePlayerSummary(Screen):
2190 <screen position="0,0" size="132,64">
2191 <widget source="global.CurrentTime" render="Label" position="62,46" size="64,18" font="Regular;16" halign="right" >
2192 <convert type="ClockToText">WithSeconds</convert>
2194 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="64,18" zPosition="1" >
2195 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2196 <convert type="ConditionalShowHide">Blink</convert>
2198 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2199 <convert type="ServiceName">Name</convert>
2201 <widget source="session.CurrentService" render="Progress" position="6,46" size="56,18" borderWidth="1" >
2202 <convert type="ServicePosition">Position</convert>
2206 class InfoBarMoviePlayerSummarySupport:
2210 def createSummary(self):
2211 return InfoBarMoviePlayerSummary
2213 class InfoBarTeletextPlugin:
2215 self.teletext_plugin = None
2217 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
2218 self.teletext_plugin = p
2220 if self.teletext_plugin is not None:
2221 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
2223 "startTeletext": (self.startTeletext, _("View teletext..."))
2226 print "no teletext plugin found!"
2228 def startTeletext(self):
2229 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
2231 class InfoBarSubtitleSupport(object):
2233 object.__init__(self)
2234 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
2235 self.__subtitles_enabled = False
2237 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2239 iPlayableService.evEnd: self.__serviceStopped,
2240 iPlayableService.evUpdatedInfo: self.__updatedInfo
2242 self.cached_subtitle_checked = False
2243 self.__selected_subtitle = None
2245 def __serviceStopped(self):
2246 self.cached_subtitle_checked = False
2247 if self.__subtitles_enabled:
2248 self.subtitle_window.hide()
2249 self.__subtitles_enabled = False
2250 self.__selected_subtitle = None
2252 def __updatedInfo(self):
2253 if not self.cached_subtitle_checked:
2254 self.cached_subtitle_checked = True
2255 subtitle = self.getCurrentServiceSubtitle()
2256 self.setSelectedSubtitle(subtitle and subtitle.getCachedSubtitle())
2257 if self.__selected_subtitle:
2258 self.setSubtitlesEnable(True)
2260 def getCurrentServiceSubtitle(self):
2261 service = self.session.nav.getCurrentService()
2262 return service and service.subtitle()
2264 def setSubtitlesEnable(self, enable=True):
2265 subtitle = self.getCurrentServiceSubtitle()
2267 if self.__selected_subtitle:
2268 if subtitle and not self.__subtitles_enabled:
2269 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2270 self.subtitle_window.show()
2271 self.__subtitles_enabled = True
2274 subtitle.disableSubtitles(self.subtitle_window.instance)
2275 self.__selected_subtitle = False
2276 self.__subtitles_enabled = False
2277 self.subtitle_window.hide()
2279 def setSelectedSubtitle(self, subtitle):
2280 self.__selected_subtitle = subtitle
2282 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
2283 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
2285 class InfoBarServiceErrorPopupSupport:
2287 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2289 iPlayableService.evTuneFailed: self.__tuneFailed,
2290 iPlayableService.evStart: self.__serviceStarted
2292 self.__serviceStarted()
2294 def __serviceStarted(self):
2295 self.last_error = None
2296 Notifications.RemovePopup(id = "ZapError")
2298 def __tuneFailed(self):
2299 service = self.session.nav.getCurrentService()
2300 info = service and service.info()
2301 error = info and info.getInfo(iServiceInformation.sDVBState)
2303 if error == self.last_error:
2306 self.last_error = error
2309 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2310 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2311 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2312 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2313 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2314 eDVBServicePMTHandler.eventNewProgramInfo: None,
2315 eDVBServicePMTHandler.eventTuned: None,
2316 eDVBServicePMTHandler.eventSOF: None,
2317 eDVBServicePMTHandler.eventEOF: None,
2318 eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
2319 }.get(error) #this returns None when the key not exist in the dict
2321 if error is not None:
2322 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2324 Notifications.RemovePopup(id = "ZapError")