1 from ChannelSelection import ChannelSelection, BouquetSelector, SilentBouquetSelector
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)
50 self.dishDialog.setAnimationMode(0)
52 class InfoBarUnhandledKey:
54 self.unhandledKeyDialog = self.session.instantiateDialog(UnhandledKey)
55 self.unhandledKeyDialog.setAnimationMode(0)
56 self.hideUnhandledKeySymbolTimer = eTimer()
57 self.hideUnhandledKeySymbolTimer.callback.append(self.unhandledKeyDialog.hide)
58 self.checkUnusedTimer = eTimer()
59 self.checkUnusedTimer.callback.append(self.checkUnused)
60 self.onLayoutFinish.append(self.unhandledKeyDialog.hide)
61 eActionMap.getInstance().bindAction('', -0x7FFFFFFF, self.actionA) #highest prio
62 eActionMap.getInstance().bindAction('', 0x7FFFFFFF, self.actionB) #lowest prio
66 #this function is called on every keypress!
67 def actionA(self, key, flag):
69 if self.flags & (1<<1):
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.hideUnhandledKeySymbolTimer.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, _("list of EPG views...")),
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 config.usage.multiepg_ask_bouquet.value:
565 self.openMultiServiceEPGAskBouquet(bouquets, cnt, withCallback)
567 self.openMultiServiceEPGSilent(bouquets, cnt, withCallback)
569 def openMultiServiceEPGAskBouquet(self, bouquets, cnt, withCallback):
570 if cnt > 1: # show bouquet list
572 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
573 self.dlg_stack.append(self.bouquetSel)
575 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
577 self.openBouquetEPG(bouquets[0][1], withCallback)
579 def openMultiServiceEPGSilent(self, bouquets, cnt, withCallback):
580 root = self.servicelist.getRoot()
581 rootstr = root.toCompareString()
583 for bouquet in bouquets:
584 if bouquet[1].toCompareString() == rootstr:
589 if cnt > 1: # create bouquet list for bouq+/-
590 self.bouquetSel = SilentBouquetSelector(bouquets, True, self.servicelist.getBouquetNumOffset(root))
592 self.openBouquetEPG(root, withCallback)
594 def changeServiceCB(self, direction, epg):
597 self.serviceSel.nextService()
599 self.serviceSel.prevService()
600 epg.setService(self.serviceSel.currentService())
602 def SingleServiceEPGClosed(self, ret=False):
603 self.serviceSel = None
605 def openSingleServiceEPG(self):
606 ref=self.session.nav.getCurrentlyPlayingServiceReference()
608 if self.servicelist.getMutableList() is not None: # bouquet in channellist
609 current_path = self.servicelist.getRoot()
610 services = self.getBouquetServices(current_path)
611 self.serviceSel = SimpleServicelist(services)
612 if self.serviceSel.selectService(ref):
613 self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref, serviceChangeCB = self.changeServiceCB)
615 self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref)
617 self.session.open(EPGSelection, ref)
619 def showEventInfoPlugins(self):
620 list = [(p.name, boundFunction(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EVENTINFO)]
623 list.append((_("show single service EPG..."), self.openSingleServiceEPG))
624 list.append((_("Multi EPG"), self.openMultiServiceEPG))
625 self.session.openWithCallback(self.EventInfoPluginChosen, ChoiceBox, title=_("Please choose an extension..."), list = list, skin_name = "EPGExtensionsList")
627 self.openSingleServiceEPG()
629 def runPlugin(self, plugin):
630 plugin(session = self.session, servicelist = self.servicelist)
632 def EventInfoPluginChosen(self, answer):
633 if answer is not None:
636 def openSimilarList(self, eventid, refstr):
637 self.session.open(EPGSelection, refstr, None, eventid)
639 def getNowNext(self):
641 service = self.session.nav.getCurrentService()
642 info = service and service.info()
643 ptr = info and info.getEvent(0)
646 ptr = info and info.getEvent(1)
649 self.epglist = epglist
651 def __evEventInfoChanged(self):
652 if self.is_now_next and len(self.dlg_stack) == 1:
654 assert self.eventView
656 self.eventView.setEvent(self.epglist[0])
658 def openEventView(self):
659 ref = self.session.nav.getCurrentlyPlayingServiceReference()
661 epglist = self.epglist
663 self.is_now_next = False
664 epg = eEPGCache.getInstance()
665 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
668 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
672 self.is_now_next = True
674 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
675 self.dlg_stack.append(self.eventView)
677 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
678 self.openMultiServiceEPG(False)
680 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
681 epglist = self.epglist
684 epglist[0]=epglist[1]
688 class InfoBarRdsDecoder:
689 """provides RDS and Rass support/display"""
691 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
692 self.rds_display.setAnimationMode(0)
693 self.rass_interactive = None
695 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
697 iPlayableService.evEnd: self.__serviceStopped,
698 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
701 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
703 "startRassInteractive": self.startRassInteractive
706 self["RdsActions"].setEnabled(False)
708 self.onLayoutFinish.append(self.rds_display.show)
709 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
711 def RassInteractivePossibilityChanged(self, state):
712 self["RdsActions"].setEnabled(state)
714 def RassSlidePicChanged(self):
715 if not self.rass_interactive:
716 service = self.session.nav.getCurrentService()
717 decoder = service and service.rdsDecoder()
719 decoder.showRassSlidePicture()
721 def __serviceStopped(self):
722 if self.rass_interactive is not None:
723 rass_interactive = self.rass_interactive
724 self.rass_interactive = None
725 rass_interactive.close()
727 def startRassInteractive(self):
728 self.rds_display.hide()
729 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
731 def RassInteractiveClosed(self, *val):
732 if self.rass_interactive is not None:
733 self.rass_interactive = None
734 self.RassSlidePicChanged()
735 self.rds_display.show()
738 """handles actions like seeking, pause"""
740 SEEK_STATE_PLAY = (0, 0, 0, ">")
741 SEEK_STATE_PAUSE = (1, 0, 0, "||")
742 SEEK_STATE_EOF = (1, 0, 0, "END")
744 def __init__(self, actionmap = "InfobarSeekActions"):
745 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
747 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
748 iPlayableService.evStart: self.__serviceStarted,
750 iPlayableService.evEOF: self.__evEOF,
751 iPlayableService.evSOF: self.__evSOF,
753 self.fast_winding_hint_message_showed = False
755 class InfoBarSeekActionMap(HelpableActionMap):
756 def __init__(self, screen, *args, **kwargs):
757 HelpableActionMap.__init__(self, screen, *args, **kwargs)
760 def action(self, contexts, action):
761 print "action:", action
762 if action[:5] == "seek:":
763 time = int(action[5:])
764 self.screen.doSeekRelative(time * 90000)
766 elif action[:8] == "seekdef:":
767 key = int(action[8:])
768 time = (-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
769 -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
770 -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value)[key-1]
771 self.screen.doSeekRelative(time * 90000)
774 return HelpableActionMap.action(self, contexts, action)
776 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
778 "playpauseService": self.playpauseService,
779 "pauseService": (self.pauseService, _("pause")),
780 "unPauseService": (self.unPauseService, _("continue")),
782 "seekFwd": (self.seekFwd, _("skip forward")),
783 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
784 "seekBack": (self.seekBack, _("skip backward")),
785 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)"))
787 # give them a little more priority to win over color buttons
789 self["SeekActions"].setEnabled(False)
791 self.seekstate = self.SEEK_STATE_PLAY
792 self.lastseekstate = self.SEEK_STATE_PLAY
794 self.onPlayStateChanged = [ ]
796 self.lockedBecauseOfSkipping = False
798 self.__seekableStatusChanged()
800 def makeStateForward(self, n):
801 return (0, n, 0, ">> %dx" % n)
803 def makeStateBackward(self, n):
804 return (0, -n, 0, "<< %dx" % n)
806 def makeStateSlowMotion(self, n):
807 return (0, 0, n, "/%d" % n)
809 def isStateForward(self, state):
812 def isStateBackward(self, state):
815 def isStateSlowMotion(self, state):
816 return state[1] == 0 and state[2] > 1
818 def getHigher(self, n, lst):
824 def getLower(self, n, lst):
832 def showAfterSeek(self):
833 if isinstance(self, InfoBarShowHide):
843 service = self.session.nav.getCurrentService()
847 seek = service.seek()
849 if seek is None or not seek.isCurrentlySeekable():
854 def isSeekable(self):
855 if self.getSeek() is None:
859 def __seekableStatusChanged(self):
860 # print "seekable status changed!"
861 if not self.isSeekable():
862 self["SeekActions"].setEnabled(False)
863 # print "not seekable, return to play"
864 self.setSeekState(self.SEEK_STATE_PLAY)
866 self["SeekActions"].setEnabled(True)
869 def __serviceStarted(self):
870 self.fast_winding_hint_message_showed = False
871 self.seekstate = self.SEEK_STATE_PLAY
872 self.__seekableStatusChanged()
874 def setSeekState(self, state):
875 service = self.session.nav.getCurrentService()
880 if not self.isSeekable():
881 if state not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE):
882 state = self.SEEK_STATE_PLAY
884 pauseable = service.pause()
886 if pauseable is None:
887 print "not pauseable."
888 state = self.SEEK_STATE_PLAY
890 self.seekstate = state
892 if pauseable is not None:
893 if self.seekstate[0]:
894 print "resolved to PAUSE"
896 elif self.seekstate[1]:
897 print "resolved to FAST FORWARD"
898 pauseable.setFastForward(self.seekstate[1])
899 elif self.seekstate[2]:
900 print "resolved to SLOW MOTION"
901 pauseable.setSlowMotion(self.seekstate[2])
903 print "resolved to PLAY"
906 for c in self.onPlayStateChanged:
909 self.checkSkipShowHideLock()
913 def playpauseService(self):
914 if self.seekstate != self.SEEK_STATE_PLAY:
915 self.unPauseService()
919 def pauseService(self):
920 if self.seekstate == self.SEEK_STATE_PAUSE:
921 if config.seek.on_pause.value == "play":
922 self.unPauseService()
923 elif config.seek.on_pause.value == "step":
924 self.doSeekRelative(1)
925 elif config.seek.on_pause.value == "last":
926 self.setSeekState(self.lastseekstate)
927 self.lastseekstate = self.SEEK_STATE_PLAY
929 if self.seekstate != self.SEEK_STATE_EOF:
930 self.lastseekstate = self.seekstate
931 self.setSeekState(self.SEEK_STATE_PAUSE);
933 def unPauseService(self):
935 if self.seekstate == self.SEEK_STATE_PLAY:
937 self.setSeekState(self.SEEK_STATE_PLAY)
939 def doSeek(self, pts):
940 seekable = self.getSeek()
945 def doSeekRelative(self, pts):
946 seekable = self.getSeek()
949 prevstate = self.seekstate
951 if self.seekstate == self.SEEK_STATE_EOF:
952 if prevstate == self.SEEK_STATE_PAUSE:
953 self.setSeekState(self.SEEK_STATE_PAUSE)
955 self.setSeekState(self.SEEK_STATE_PLAY)
956 seekable.seekRelative(pts<0 and -1 or 1, abs(pts))
957 if abs(pts) > 100 and config.usage.show_infobar_on_skip.value:
961 seek = self.getSeek()
962 if seek and not (seek.isCurrentlySeekable() & 2):
963 if not self.fast_winding_hint_message_showed and (seek.isCurrentlySeekable() & 1):
964 self.session.open(MessageBox, _("No fast winding possible yet.. but you can use the number buttons to skip forward/backward!"), MessageBox.TYPE_INFO, timeout=10)
965 self.fast_winding_hint_message_showed = True
967 return 0 # trade as unhandled action
968 if self.seekstate == self.SEEK_STATE_PLAY:
969 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
970 elif self.seekstate == self.SEEK_STATE_PAUSE:
971 if len(config.seek.speeds_slowmotion.value):
972 self.setSeekState(self.makeStateSlowMotion(config.seek.speeds_slowmotion.value[-1]))
974 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
975 elif self.seekstate == self.SEEK_STATE_EOF:
977 elif self.isStateForward(self.seekstate):
978 speed = self.seekstate[1]
979 if self.seekstate[2]:
980 speed /= self.seekstate[2]
981 speed = self.getHigher(speed, config.seek.speeds_forward.value) or config.seek.speeds_forward.value[-1]
982 self.setSeekState(self.makeStateForward(speed))
983 elif self.isStateBackward(self.seekstate):
984 speed = -self.seekstate[1]
985 if self.seekstate[2]:
986 speed /= self.seekstate[2]
987 speed = self.getLower(speed, config.seek.speeds_backward.value)
989 self.setSeekState(self.makeStateBackward(speed))
991 self.setSeekState(self.SEEK_STATE_PLAY)
992 elif self.isStateSlowMotion(self.seekstate):
993 speed = self.getLower(self.seekstate[2], config.seek.speeds_slowmotion.value) or config.seek.speeds_slowmotion.value[0]
994 self.setSeekState(self.makeStateSlowMotion(speed))
997 seek = self.getSeek()
998 if seek and not (seek.isCurrentlySeekable() & 2):
999 if not self.fast_winding_hint_message_showed and (seek.isCurrentlySeekable() & 1):
1000 self.session.open(MessageBox, _("No fast winding possible yet.. but you can use the number buttons to skip forward/backward!"), MessageBox.TYPE_INFO, timeout=10)
1001 self.fast_winding_hint_message_showed = True
1003 return 0 # trade as unhandled action
1004 seekstate = self.seekstate
1005 if seekstate == self.SEEK_STATE_PLAY:
1006 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1007 elif seekstate == self.SEEK_STATE_EOF:
1008 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1009 self.doSeekRelative(-6)
1010 elif seekstate == self.SEEK_STATE_PAUSE:
1011 self.doSeekRelative(-1)
1012 elif self.isStateForward(seekstate):
1013 speed = seekstate[1]
1015 speed /= seekstate[2]
1016 speed = self.getLower(speed, config.seek.speeds_forward.value)
1018 self.setSeekState(self.makeStateForward(speed))
1020 self.setSeekState(self.SEEK_STATE_PLAY)
1021 elif self.isStateBackward(seekstate):
1022 speed = -seekstate[1]
1024 speed /= seekstate[2]
1025 speed = self.getHigher(speed, config.seek.speeds_backward.value) or config.seek.speeds_backward.value[-1]
1026 self.setSeekState(self.makeStateBackward(speed))
1027 elif self.isStateSlowMotion(seekstate):
1028 speed = self.getHigher(seekstate[2], config.seek.speeds_slowmotion.value)
1030 self.setSeekState(self.makeStateSlowMotion(speed))
1032 self.setSeekState(self.SEEK_STATE_PAUSE)
1034 def seekFwdManual(self):
1035 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
1037 def fwdSeekTo(self, minutes):
1038 print "Seek", minutes, "minutes forward"
1039 self.doSeekRelative(minutes * 60 * 90000)
1041 def seekBackManual(self):
1042 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
1044 def rwdSeekTo(self, minutes):
1046 self.doSeekRelative(-minutes * 60 * 90000)
1048 def checkSkipShowHideLock(self):
1049 wantlock = self.seekstate != self.SEEK_STATE_PLAY
1051 if config.usage.show_infobar_on_skip.value:
1052 if self.lockedBecauseOfSkipping and not wantlock:
1054 self.lockedBecauseOfSkipping = False
1056 if wantlock and not self.lockedBecauseOfSkipping:
1058 self.lockedBecauseOfSkipping = True
1060 def calcRemainingTime(self):
1061 seekable = self.getSeek()
1062 if seekable is not None:
1063 len = seekable.getLength()
1065 tmp = self.cueGetEndCutPosition()
1070 pos = seekable.getPlayPosition()
1071 speednom = self.seekstate[1] or 1
1072 speedden = self.seekstate[2] or 1
1073 if not len[0] and not pos[0]:
1074 if len[1] <= pos[1]:
1076 time = (len[1] - pos[1])*speedden/(90*speednom)
1081 if self.seekstate == self.SEEK_STATE_EOF:
1084 # if we are seeking forward, we try to end up ~1s before the end, and pause there.
1085 seekstate = self.seekstate
1086 if self.seekstate != self.SEEK_STATE_PAUSE:
1087 self.setSeekState(self.SEEK_STATE_EOF)
1089 if seekstate not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE): # if we are seeking
1090 seekable = self.getSeek()
1091 if seekable is not None:
1093 if seekstate == self.SEEK_STATE_PLAY: # regular EOF
1094 self.doEofInternal(True)
1096 self.doEofInternal(False)
1098 def doEofInternal(self, playing):
1099 pass # Defined in subclasses
1102 self.setSeekState(self.SEEK_STATE_PLAY)
1105 from Screens.PVRState import PVRState, TimeshiftState
1107 class InfoBarPVRState:
1108 def __init__(self, screen=PVRState, force_show = False):
1109 self.onPlayStateChanged.append(self.__playStateChanged)
1110 self.pvrStateDialog = self.session.instantiateDialog(screen)
1111 self.pvrStateDialog.setAnimationMode(0)
1112 self.onShow.append(self._mayShow)
1113 self.onHide.append(self.pvrStateDialog.hide)
1114 self.force_show = force_show
1117 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
1118 self.pvrStateDialog.show()
1120 def __playStateChanged(self, state):
1121 playstateString = state[3]
1122 self.pvrStateDialog["state"].setText(playstateString)
1124 # if we return into "PLAY" state, ensure that the dialog gets hidden if there will be no infobar displayed
1125 if not config.usage.show_infobar_on_skip.value and self.seekstate == self.SEEK_STATE_PLAY and not self.force_show:
1126 self.pvrStateDialog.hide()
1130 class InfoBarTimeshiftState(InfoBarPVRState):
1132 InfoBarPVRState.__init__(self, screen=TimeshiftState, force_show = True)
1133 self.__hideTimer = eTimer()
1134 self.__hideTimer.callback.append(self.__hideTimeshiftState)
1137 if self.execing and self.timeshift_enabled:
1138 self.pvrStateDialog.show()
1139 if self.seekstate == self.SEEK_STATE_PLAY and not self.shown:
1140 self.__hideTimer.start(5*1000, True)
1142 def __hideTimeshiftState(self):
1143 self.pvrStateDialog.hide()
1145 class InfoBarShowMovies:
1147 # i don't really like this class.
1148 # it calls a not further specified "movie list" on up/down/movieList,
1149 # so this is not more than an action map
1151 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
1153 "movieList": (self.showMovies, _("movie list")),
1154 "up": (self.showMovies, _("movie list")),
1155 "down": (self.showMovies, _("movie list"))
1158 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
1162 # Timeshift works the following way:
1163 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
1164 # - normal playback TUNER unused PLAY enable disable disable
1165 # - user presses "yellow" button. FILE record PAUSE enable disable enable
1166 # - user presess pause again FILE record PLAY enable disable enable
1167 # - user fast forwards FILE record FF enable disable enable
1168 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
1169 # - user backwards FILE record BACK # !! enable disable enable
1173 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1174 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1175 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1176 # - the user can now PVR around
1177 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1178 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1180 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1181 # - if the user rewinds, or press pause, timeshift will be activated again
1183 # note that a timeshift can be enabled ("recording") and
1184 # activated (currently time-shifting).
1186 class InfoBarTimeshift:
1188 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1190 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1191 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1193 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1195 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1196 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1197 }, prio=-1) # priority over record
1199 self.timeshift_enabled = 0
1200 self.timeshift_state = 0
1201 self.ts_rewind_timer = eTimer()
1202 self.ts_rewind_timer.callback.append(self.rewindService)
1204 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1206 iPlayableService.evStart: self.__serviceStarted,
1207 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1210 def getTimeshift(self):
1211 service = self.session.nav.getCurrentService()
1212 return service and service.timeshift()
1214 def startTimeshift(self):
1215 print "enable timeshift"
1216 ts = self.getTimeshift()
1218 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1219 print "no ts interface"
1222 if self.timeshift_enabled:
1223 print "hu, timeshift already enabled?"
1225 if not ts.startTimeshift():
1226 self.timeshift_enabled = 1
1228 # we remove the "relative time" for now.
1229 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1232 #self.setSeekState(self.SEEK_STATE_PAUSE)
1233 self.activateTimeshiftEnd(False)
1235 # enable the "TimeshiftEnableActions", which will override
1236 # the startTimeshift actions
1237 self.__seekableStatusChanged()
1239 print "timeshift failed"
1241 def stopTimeshift(self):
1242 if not self.timeshift_enabled:
1244 print "disable timeshift"
1245 ts = self.getTimeshift()
1248 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1250 def stopTimeshiftConfirmed(self, confirmed):
1254 ts = self.getTimeshift()
1259 self.timeshift_enabled = 0
1262 self.__seekableStatusChanged()
1264 # activates timeshift, and seeks to (almost) the end
1265 def activateTimeshiftEnd(self, back = True):
1266 ts = self.getTimeshift()
1267 print "activateTimeshiftEnd"
1272 if ts.isTimeshiftActive():
1273 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1277 ts.activateTimeshift() # activate timeshift will automatically pause
1278 self.setSeekState(self.SEEK_STATE_PAUSE)
1281 self.ts_rewind_timer.start(200, 1)
1283 def rewindService(self):
1284 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1286 # same as activateTimeshiftEnd, but pauses afterwards.
1287 def activateTimeshiftEndAndPause(self):
1288 print "activateTimeshiftEndAndPause"
1289 #state = self.seekstate
1290 self.activateTimeshiftEnd(False)
1292 def __seekableStatusChanged(self):
1295 # print "self.isSeekable", self.isSeekable()
1296 # print "self.timeshift_enabled", self.timeshift_enabled
1298 # when this service is not seekable, but timeshift
1299 # is enabled, this means we can activate
1301 if not self.isSeekable() and self.timeshift_enabled:
1304 # print "timeshift activate:", enabled
1305 self["TimeshiftActivateActions"].setEnabled(enabled)
1307 def __serviceStarted(self):
1308 self.timeshift_enabled = False
1309 self.__seekableStatusChanged()
1311 from Screens.PiPSetup import PiPSetup
1313 class InfoBarExtensions:
1314 EXTENSION_SINGLE = 0
1320 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1322 "extensions": (self.showExtensionSelection, _("view extensions...")),
1323 }, 1) # lower priority
1325 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1326 self.list.append((type, extension, key))
1328 def updateExtension(self, extension, key = None):
1329 self.extensionsList.append(extension)
1331 if self.extensionKeys.has_key(key):
1335 for x in self.availableKeys:
1336 if not self.extensionKeys.has_key(x):
1341 self.extensionKeys[key] = len(self.extensionsList) - 1
1343 def updateExtensions(self):
1344 self.extensionsList = []
1345 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1346 self.extensionKeys = {}
1348 if x[0] == self.EXTENSION_SINGLE:
1349 self.updateExtension(x[1], x[2])
1352 self.updateExtension(y[0], y[1])
1355 def showExtensionSelection(self):
1356 self.updateExtensions()
1357 extensionsList = self.extensionsList[:]
1360 for x in self.availableKeys:
1361 if self.extensionKeys.has_key(x):
1362 entry = self.extensionKeys[x]
1363 extension = self.extensionsList[entry]
1365 name = str(extension[0]())
1366 list.append((extension[0](), extension))
1368 extensionsList.remove(extension)
1370 extensionsList.remove(extension)
1371 list.extend([(x[0](), x) for x in extensionsList])
1373 keys += [""] * len(extensionsList)
1374 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys, skin_name = "ExtensionsList")
1376 def extensionCallback(self, answer):
1377 if answer is not None:
1380 from Tools.BoundFunction import boundFunction
1383 # depends on InfoBarExtensions
1385 class InfoBarPlugins:
1387 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1389 def getPluginName(self, name):
1392 def getPluginList(self):
1394 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1395 args = inspect.getargspec(p.__call__)[0]
1396 if len(args) == 1 or len(args) == 2 and isinstance(self, InfoBarChannelSelection):
1397 l.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name))
1398 l.sort(key = lambda e: e[2]) # sort by name
1401 def runPlugin(self, plugin):
1402 if isinstance(self, InfoBarChannelSelection):
1403 plugin(session = self.session, servicelist = self.servicelist)
1405 plugin(session = self.session)
1407 from Components.Task import job_manager
1408 class InfoBarJobman:
1410 self.addExtension(extension = self.getJobList, type = InfoBarExtensions.EXTENSION_LIST)
1412 def getJobList(self):
1413 return [((boundFunction(self.getJobName, job), boundFunction(self.showJobView, job), lambda: True), None) for job in job_manager.getPendingJobs()]
1415 def getJobName(self, job):
1416 return "%s: %s (%d%%)" % (job.getStatustext(), job.name, int(100*job.progress/float(job.end)))
1418 def showJobView(self, job):
1419 from Screens.TaskView import JobView
1420 job_manager.in_background = False
1421 self.session.openWithCallback(self.JobViewCB, JobView, job)
1423 def JobViewCB(self, in_background):
1424 job_manager.in_background = in_background
1426 # depends on InfoBarExtensions
1430 self.session.pipshown
1432 self.session.pipshown = False
1433 if SystemInfo.get("NumVideoDecoders", 1) > 1:
1435 self.addExtension((self.getShowHideName, self.showPiP, lambda: True), "blue")
1436 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1437 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1439 self.addExtension((self.getShowHideName, self.showPiP, self.pipShown), "blue")
1440 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1443 return self.session.pipshown
1445 def pipHandles0Action(self):
1446 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1448 def getShowHideName(self):
1449 if self.session.pipshown:
1450 return _("Disable Picture in Picture")
1452 return _("Activate Picture in Picture")
1454 def getSwapName(self):
1455 return _("Swap Services")
1457 def getMoveName(self):
1458 return _("Move Picture in Picture")
1461 if self.session.pipshown:
1462 del self.session.pip
1463 self.session.pipshown = False
1465 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1466 self.session.pip.setAnimationMode(0)
1467 self.session.pip.show()
1468 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1469 if self.session.pip.playService(newservice):
1470 self.session.pipshown = True
1471 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1473 self.session.pipshown = False
1474 del self.session.pip
1475 self.session.nav.playService(newservice)
1478 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1479 if self.session.pip.servicePath:
1480 servicepath = self.servicelist.getCurrentServicePath()
1481 ref=servicepath[len(servicepath)-1]
1482 pipref=self.session.pip.getCurrentService()
1483 self.session.pip.playService(swapservice)
1484 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1485 if pipref.toString() != ref.toString(): # is a subservice ?
1486 self.session.nav.stopService() # stop portal
1487 self.session.nav.playService(pipref) # start subservice
1488 self.session.pip.servicePath=servicepath
1491 self.session.open(PiPSetup, pip = self.session.pip)
1493 def pipDoHandle0Action(self):
1494 use = config.usage.pip_zero_button.value
1497 elif "swapstop" == use:
1503 from RecordTimer import parseEvent, RecordTimerEntry
1505 class InfoBarInstantRecord:
1506 """Instant Record - handles the instantRecord action in order to
1507 start/stop instant records"""
1509 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1511 "instantRecord": (self.instantRecord, _("Instant Record...")),
1515 def stopCurrentRecording(self, entry = -1):
1516 if entry is not None and entry != -1:
1517 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1518 self.recording.remove(self.recording[entry])
1520 def startInstantRecording(self, limitEvent = False):
1521 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1523 # try to get event info
1526 service = self.session.nav.getCurrentService()
1527 epg = eEPGCache.getInstance()
1528 event = epg.lookupEventTime(serviceref, -1, 0)
1530 info = service.info()
1531 ev = info.getEvent(0)
1537 end = begin + 3600 # dummy
1538 name = "instant record"
1542 if event is not None:
1543 curEvent = parseEvent(event)
1545 description = curEvent[3]
1546 eventid = curEvent[4]
1551 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1553 if isinstance(serviceref, eServiceReference):
1554 serviceref = ServiceReference(serviceref)
1556 recording = RecordTimerEntry(serviceref, begin, end, name, description, eventid, dirname = preferredInstantRecordPath())
1557 recording.dontSave = True
1559 if event is None or limitEvent == False:
1560 recording.autoincrease = True
1561 recording.setAutoincreaseEnd()
1563 simulTimerList = self.session.nav.RecordTimer.record(recording)
1565 if simulTimerList is None: # no conflict
1566 self.recording.append(recording)
1568 if len(simulTimerList) > 1: # with other recording
1569 name = simulTimerList[1].name
1570 name_date = ' '.join((name, strftime('%c', localtime(simulTimerList[1].begin))))
1571 print "[TIMER] conflicts with", name_date
1572 recording.autoincrease = True # start with max available length, then increment
1573 if recording.setAutoincreaseEnd():
1574 self.session.nav.RecordTimer.record(recording)
1575 self.recording.append(recording)
1576 self.session.open(MessageBox, _("Record time limited due to conflicting timer %s") % name_date, MessageBox.TYPE_INFO)
1578 self.session.open(MessageBox, _("Couldn't record due to conflicting timer %s") % name, MessageBox.TYPE_INFO)
1580 self.session.open(MessageBox, _("Couldn't record due to invalid service %s") % serviceref, MessageBox.TYPE_INFO)
1581 recording.autoincrease = False
1583 def isInstantRecordRunning(self):
1584 print "self.recording:", self.recording
1586 for x in self.recording:
1591 def recordQuestionCallback(self, answer):
1592 print "pre:\n", self.recording
1594 if answer is None or answer[1] == "no":
1597 recording = self.recording[:]
1599 if not x in self.session.nav.RecordTimer.timer_list:
1600 self.recording.remove(x)
1601 elif x.dontSave and x.isRunning():
1602 list.append((x, False))
1604 if answer[1] == "changeduration":
1605 if len(self.recording) == 1:
1606 self.changeDuration(0)
1608 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1609 elif answer[1] == "changeendtime":
1610 if len(self.recording) == 1:
1613 self.session.openWithCallback(self.setEndtime, TimerSelection, list)
1614 elif answer[1] == "stop":
1615 if len(self.recording) == 1:
1616 self.stopCurrentRecording(0)
1618 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1619 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1620 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1621 if answer[1] == "manualduration":
1622 self.changeDuration(len(self.recording)-1)
1623 elif answer[1] == "manualendtime":
1624 self.setEndtime(len(self.recording)-1)
1625 print "after:\n", self.recording
1627 def setEndtime(self, entry):
1628 if entry is not None and entry >= 0:
1629 self.selectedEntry = entry
1630 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1631 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1632 dlg.setTitle(_("Please change recording endtime"))
1634 def TimeDateInputClosed(self, ret):
1637 localendtime = localtime(ret[1])
1638 print "stopping recording at", strftime("%c", localendtime)
1639 if self.recording[self.selectedEntry].end != ret[1]:
1640 self.recording[self.selectedEntry].autoincrease = False
1641 self.recording[self.selectedEntry].end = ret[1]
1642 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1644 def changeDuration(self, entry):
1645 if entry is not None and entry >= 0:
1646 self.selectedEntry = entry
1647 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1649 def inputCallback(self, value):
1650 if value is not None:
1651 print "stopping recording after", int(value), "minutes."
1652 entry = self.recording[self.selectedEntry]
1654 entry.autoincrease = False
1655 entry.end = int(time()) + 60 * int(value)
1656 self.session.nav.RecordTimer.timeChanged(entry)
1658 def instantRecord(self):
1659 dir = preferredInstantRecordPath()
1660 if not dir or not fileExists(dir, 'w'):
1661 dir = defaultMoviePath()
1663 if not fileExists("/hdd", 0):
1664 print "not found /hdd"
1665 system("ln -s /media/hdd /hdd")
1670 # XXX: this message is a little odd as we might be recording to a remote device
1671 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1674 if self.isInstantRecordRunning():
1675 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1676 title=_("A recording is currently running.\nWhat do you want to do?"), \
1677 list=((_("stop recording"), "stop"), \
1678 (_("add recording (stop after current event)"), "event"), \
1679 (_("add recording (indefinitely)"), "indefinitely"), \
1680 (_("add recording (enter recording duration)"), "manualduration"), \
1681 (_("add recording (enter recording endtime)"), "manualendtime"), \
1682 (_("change recording (duration)"), "changeduration"), \
1683 (_("change recording (endtime)"), "changeendtime"), \
1684 (_("do nothing"), "no")))
1686 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1687 title=_("Start recording?"), \
1688 list=((_("add recording (stop after current event)"), "event"), \
1689 (_("add recording (indefinitely)"), "indefinitely"), \
1690 (_("add recording (enter recording duration)"), "manualduration"), \
1691 (_("add recording (enter recording endtime)"), "manualendtime"), \
1692 (_("don't record"), "no")))
1694 from Tools.ISO639 import LanguageCodes
1696 class InfoBarAudioSelection:
1698 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1700 "audioSelection": (self.audioSelection, _("Audio Options...")),
1703 def audioSelection(self):
1704 from Screens.AudioSelection import AudioSelection
1705 self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self)
1707 def audioSelected(self, ret=None):
1708 print "[infobar::audioSelected]", ret
1710 class InfoBarSubserviceSelection:
1712 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1714 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1717 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1719 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1720 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1722 self["SubserviceQuickzapAction"].setEnabled(False)
1724 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1726 iPlayableService.evUpdatedEventInfo: self.checkSubservicesAvail
1731 def checkSubservicesAvail(self):
1732 service = self.session.nav.getCurrentService()
1733 subservices = service and service.subServices()
1734 if not subservices or subservices.getNumberOfSubservices() == 0:
1735 self["SubserviceQuickzapAction"].setEnabled(False)
1737 def nextSubservice(self):
1738 self.changeSubservice(+1)
1740 def prevSubservice(self):
1741 self.changeSubservice(-1)
1743 def changeSubservice(self, direction):
1744 service = self.session.nav.getCurrentService()
1745 subservices = service and service.subServices()
1746 n = subservices and subservices.getNumberOfSubservices()
1749 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1752 if subservices.getSubservice(idx).toString() == ref.toString():
1757 selection += direction
1762 newservice = subservices.getSubservice(selection)
1763 if newservice.valid():
1766 self.session.nav.playService(newservice, False)
1768 def subserviceSelection(self):
1769 service = self.session.nav.getCurrentService()
1770 subservices = service and service.subServices()
1771 self.bouquets = self.servicelist.getBouquetList()
1772 n = subservices and subservices.getNumberOfSubservices()
1775 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1779 i = subservices.getSubservice(idx)
1780 if i.toString() == ref.toString():
1782 tlist.append((i.getName(), i))
1785 if self.bouquets and len(self.bouquets):
1786 keys = ["red", "blue", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1787 if config.usage.multibouquet.value:
1788 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1790 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1793 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1794 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1797 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys, skin_name = "SubserviceSelection")
1799 def subserviceSelected(self, service):
1801 if not service is None:
1802 if isinstance(service[1], str):
1803 if service[1] == "quickzap":
1804 from Screens.SubservicesQuickzap import SubservicesQuickzap
1805 self.session.open(SubservicesQuickzap, service[2])
1807 self["SubserviceQuickzapAction"].setEnabled(True)
1808 self.session.nav.playService(service[1], False)
1810 def addSubserviceToBouquetCallback(self, service):
1811 if len(service) > 1 and isinstance(service[1], eServiceReference):
1812 self.selectedSubservice = service
1813 if self.bouquets is None:
1816 cnt = len(self.bouquets)
1817 if cnt > 1: # show bouquet list
1818 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1819 elif cnt == 1: # add to only one existing bouquet
1820 self.addSubserviceToBouquet(self.bouquets[0][1])
1821 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1823 def bouquetSelClosed(self, confirmed):
1825 del self.selectedSubservice
1827 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1829 def addSubserviceToBouquet(self, dest):
1830 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1832 self.bsel.close(True)
1834 del self.selectedSubservice
1836 from Components.Sources.HbbtvApplication import HbbtvApplication
1837 gHbbtvApplication = HbbtvApplication()
1838 class InfoBarRedButton:
1840 if not (config.misc.rcused.value == 1):
1841 self["RedButtonActions"] = HelpableActionMap(self, "InfobarRedButtonActions",
1843 "activateRedButton": (self.activateRedButton, _("Red button...")),
1845 self["HbbtvApplication"] = gHbbtvApplication
1847 self["HbbtvApplication"] = Boolean(fixed=0)
1848 self["HbbtvApplication"].name = "" #is this a hack?
1850 self.onHBBTVActivation = [ ]
1851 self.onRedButtonActivation = [ ]
1852 self.onReadyForAIT = [ ]
1853 self.__et = ServiceEventTracker(screen=self, eventmap=
1855 iPlayableService.evHBBTVInfo: self.detectedHbbtvApplication,
1856 iPlayableService.evUpdatedInfo: self.updateInfomation
1859 def updateAIT(self, orgId=0):
1860 for x in self.onReadyForAIT:
1863 except Exception, ErrMsg:
1865 #self.onReadyForAIT.remove(x)
1867 def updateInfomation(self):
1869 self["HbbtvApplication"].setApplicationName("")
1871 except Exception, ErrMsg:
1874 def detectedHbbtvApplication(self):
1875 service = self.session.nav.getCurrentService()
1876 info = service and service.info()
1878 for x in info.getInfoObject(iServiceInformation.sHBBTVUrl):
1881 self.updateAIT(x[3])
1882 self["HbbtvApplication"].setApplicationName(x[1])
1884 except Exception, ErrMsg:
1887 def activateRedButton(self):
1888 service = self.session.nav.getCurrentService()
1889 info = service and service.info()
1890 if info and info.getInfoString(iServiceInformation.sHBBTVUrl) != "":
1891 for x in self.onHBBTVActivation:
1893 elif False: # TODO: other red button services
1894 for x in self.onRedButtonActivation:
1897 class InfoBarAdditionalInfo:
1900 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0 and config.misc.rcused.value == 1)
1901 self["TimeshiftPossible"] = self["RecordingPossible"]
1902 self["ShowTimeshiftOnYellow"] = Boolean(fixed=(not config.misc.rcused.value == 0))
1903 self["ShowAudioOnYellow"] = Boolean(fixed=config.misc.rcused.value == 0)
1904 self["ShowRecordOnRed"] = Boolean(fixed=config.misc.rcused.value == 1)
1905 self["ExtensionsAvailable"] = Boolean(fixed=1)
1907 class InfoBarNotifications:
1909 self.onExecBegin.append(self.checkNotifications)
1910 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1911 self.onClose.append(self.__removeNotification)
1913 def __removeNotification(self):
1914 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1916 def checkNotificationsIfExecing(self):
1918 self.checkNotifications()
1920 def checkNotifications(self):
1921 notifications = Notifications.notifications
1923 n = notifications[0]
1925 del notifications[0]
1928 if n[3].has_key("onSessionOpenCallback"):
1929 n[3]["onSessionOpenCallback"]()
1930 del n[3]["onSessionOpenCallback"]
1933 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1935 dlg = self.session.open(n[1], *n[2], **n[3])
1937 # remember that this notification is currently active
1939 Notifications.current_notifications.append(d)
1940 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1942 def __notificationClosed(self, d):
1943 Notifications.current_notifications.remove(d)
1945 class InfoBarServiceNotifications:
1947 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1949 iPlayableService.evEnd: self.serviceHasEnded
1952 def serviceHasEnded(self):
1953 print "service end!"
1956 self.setSeekState(self.SEEK_STATE_PLAY)
1960 class InfoBarCueSheetSupport:
1966 ENABLE_RESUME_SUPPORT = False
1968 def __init__(self, actionmap = "InfobarCueSheetActions"):
1969 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1971 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1972 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1973 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1977 self.is_closing = False
1978 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1980 iPlayableService.evStart: self.__serviceStarted,
1983 def __serviceStarted(self):
1986 print "new service started! trying to download cuts!"
1987 self.downloadCuesheet()
1989 if self.ENABLE_RESUME_SUPPORT:
1992 for (pts, what) in self.cut_list:
1993 if what == self.CUT_TYPE_LAST:
1996 if last is not None:
1997 self.resume_point = last
2000 if config.usage.on_movie_start.value == "ask":
2001 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?") + "\n" + (_("Resume position at %s") % ("%d:%02d:%02d" % (l/3600, l%3600/60, l%60))), timeout=10)
2002 elif config.usage.on_movie_start.value == "resume":
2003 # TRANSLATORS: The string "Resuming playback" flashes for a moment
2004 # TRANSLATORS: at the start of a movie, when the user has selected
2005 # TRANSLATORS: "Resume from last position" as start behavior.
2006 # TRANSLATORS: The purpose is to notify the user that the movie starts
2007 # TRANSLATORS: in the middle somewhere and not from the beginning.
2008 # TRANSLATORS: (Some translators seem to have interpreted it as a
2009 # TRANSLATORS: question or a choice, but it is a statement.)
2010 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Resuming playback"), timeout=2, type=MessageBox.TYPE_INFO)
2012 def playLastCB(self, answer):
2014 self.doSeek(self.resume_point)
2015 self.hideAfterResume()
2017 def hideAfterResume(self):
2018 if isinstance(self, InfoBarShowHide):
2021 def __getSeekable(self):
2022 service = self.session.nav.getCurrentService()
2025 return service.seek()
2027 def cueGetCurrentPosition(self):
2028 seek = self.__getSeekable()
2031 r = seek.getPlayPosition()
2036 def cueGetEndCutPosition(self):
2039 for cp in self.cut_list:
2040 if cp[1] == self.CUT_TYPE_OUT:
2044 elif cp[1] == self.CUT_TYPE_IN:
2048 def jumpPreviousNextMark(self, cmp, start=False):
2049 current_pos = self.cueGetCurrentPosition()
2050 if current_pos is None:
2052 mark = self.getNearestCutPoint(current_pos, cmp=cmp, start=start)
2053 if mark is not None:
2061 def jumpPreviousMark(self):
2062 # we add 5 seconds, so if the play position is <5s after
2063 # the mark, the mark before will be used
2064 self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
2066 def jumpNextMark(self):
2067 if not self.jumpPreviousNextMark(lambda x: x-90000):
2070 def getNearestCutPoint(self, pts, cmp=abs, start=False):
2077 bestdiff = cmp(0 - pts)
2079 nearest = [0, False]
2080 for cp in self.cut_list:
2081 if beforecut and cp[1] in (self.CUT_TYPE_IN, self.CUT_TYPE_OUT):
2083 if cp[1] == self.CUT_TYPE_IN: # Start is here, disregard previous marks
2084 diff = cmp(cp[0] - pts)
2085 if start and diff >= 0:
2091 if cp[1] == self.CUT_TYPE_IN:
2093 elif cp[1] == self.CUT_TYPE_OUT:
2095 elif cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
2096 diff = cmp(cp[0] - pts)
2097 if instate and 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.subtitle_window.setAnimationMode(0)
2236 self.__subtitles_enabled = False
2238 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2240 iPlayableService.evEnd: self.__serviceStopped,
2241 iPlayableService.evUpdatedInfo: self.__updatedInfo
2243 self.cached_subtitle_checked = False
2244 self.__selected_subtitle = None
2246 def __serviceStopped(self):
2247 self.cached_subtitle_checked = False
2248 if self.__subtitles_enabled:
2249 self.subtitle_window.hide()
2250 self.__subtitles_enabled = False
2251 self.__selected_subtitle = None
2253 def __updatedInfo(self):
2254 if not self.cached_subtitle_checked:
2255 self.cached_subtitle_checked = True
2256 subtitle = self.getCurrentServiceSubtitle()
2257 self.setSelectedSubtitle(subtitle and subtitle.getCachedSubtitle())
2258 if self.__selected_subtitle:
2259 self.setSubtitlesEnable(True)
2261 def getCurrentServiceSubtitle(self):
2262 service = self.session.nav.getCurrentService()
2263 return service and service.subtitle()
2265 def setSubtitlesEnable(self, enable=True):
2266 subtitle = self.getCurrentServiceSubtitle()
2268 if self.__selected_subtitle:
2269 if subtitle and not self.__subtitles_enabled:
2270 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2271 self.subtitle_window.show()
2272 self.__subtitles_enabled = True
2275 subtitle.disableSubtitles(self.subtitle_window.instance)
2276 self.__selected_subtitle = False
2277 self.__subtitles_enabled = False
2278 self.subtitle_window.hide()
2280 def setSelectedSubtitle(self, subtitle):
2281 self.__selected_subtitle = subtitle
2283 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
2284 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
2286 class InfoBarServiceErrorPopupSupport:
2288 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2290 iPlayableService.evTuneFailed: self.__tuneFailed,
2291 iPlayableService.evStart: self.__serviceStarted
2293 self.__serviceStarted()
2295 def __serviceStarted(self):
2296 self.last_error = None
2297 Notifications.RemovePopup(id = "ZapError")
2299 def __tuneFailed(self):
2300 service = self.session.nav.getCurrentService()
2301 info = service and service.info()
2302 error = info and info.getInfo(iServiceInformation.sDVBState)
2304 if error == self.last_error:
2307 self.last_error = error
2310 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2311 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2312 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2313 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2314 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2315 eDVBServicePMTHandler.eventNewProgramInfo: None,
2316 eDVBServicePMTHandler.eventTuned: None,
2317 eDVBServicePMTHandler.eventSOF: None,
2318 eDVBServicePMTHandler.eventEOF: None,
2319 eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
2320 }.get(error) #this returns None when the key not exist in the dict
2322 if error is not None:
2323 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2325 Notifications.RemovePopup(id = "ZapError")