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 for p in plugins.getPlugins(PluginDescriptor.WHERE_EXTENSIONSINGLE):
1328 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1329 self.list.append((type, extension, key))
1331 def updateExtension(self, extension, key = None):
1332 self.extensionsList.append(extension)
1334 if self.extensionKeys.has_key(key):
1338 for x in self.availableKeys:
1339 if not self.extensionKeys.has_key(x):
1344 self.extensionKeys[key] = len(self.extensionsList) - 1
1346 def updateExtensions(self):
1347 self.extensionsList = []
1348 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1349 self.extensionKeys = {}
1351 if x[0] == self.EXTENSION_SINGLE:
1352 self.updateExtension(x[1], x[2])
1355 self.updateExtension(y[0], y[1])
1358 def showExtensionSelection(self):
1359 self.updateExtensions()
1360 extensionsList = self.extensionsList[:]
1363 for x in self.availableKeys:
1364 if self.extensionKeys.has_key(x):
1365 entry = self.extensionKeys[x]
1366 extension = self.extensionsList[entry]
1368 name = str(extension[0]())
1369 list.append((extension[0](), extension))
1371 extensionsList.remove(extension)
1373 extensionsList.remove(extension)
1374 list.extend([(x[0](), x) for x in extensionsList])
1376 keys += [""] * len(extensionsList)
1377 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys, skin_name = "ExtensionsList")
1379 def extensionCallback(self, answer):
1380 if answer is not None:
1383 from Tools.BoundFunction import boundFunction
1386 # depends on InfoBarExtensions
1388 class InfoBarPlugins:
1390 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1392 def getPluginName(self, name):
1395 def getPluginList(self):
1397 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1398 args = inspect.getargspec(p.__call__)[0]
1399 if len(args) == 1 or len(args) == 2 and isinstance(self, InfoBarChannelSelection):
1400 l.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name))
1401 l.sort(key = lambda e: e[2]) # sort by name
1404 def runPlugin(self, plugin):
1405 if isinstance(self, InfoBarChannelSelection):
1406 plugin(session = self.session, servicelist = self.servicelist)
1408 plugin(session = self.session)
1410 from Components.Task import job_manager
1411 class InfoBarJobman:
1413 self.addExtension(extension = self.getJobList, type = InfoBarExtensions.EXTENSION_LIST)
1415 def getJobList(self):
1416 return [((boundFunction(self.getJobName, job), boundFunction(self.showJobView, job), lambda: True), None) for job in job_manager.getPendingJobs()]
1418 def getJobName(self, job):
1419 return "%s: %s (%d%%)" % (job.getStatustext(), job.name, int(100*job.progress/float(job.end)))
1421 def showJobView(self, job):
1422 from Screens.TaskView import JobView
1423 job_manager.in_background = False
1424 self.session.openWithCallback(self.JobViewCB, JobView, job)
1426 def JobViewCB(self, in_background):
1427 job_manager.in_background = in_background
1429 # depends on InfoBarExtensions
1433 self.session.pipshown
1435 self.session.pipshown = False
1436 if SystemInfo.get("NumVideoDecoders", 1) > 1:
1438 self.addExtension((self.getShowHideName, self.showPiP, lambda: True), "blue")
1439 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1440 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1442 self.addExtension((self.getShowHideName, self.showPiP, self.pipShown), "blue")
1443 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1446 return self.session.pipshown
1448 def pipHandles0Action(self):
1449 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1451 def getShowHideName(self):
1452 if self.session.pipshown:
1453 return _("Disable Picture in Picture")
1455 return _("Activate Picture in Picture")
1457 def getSwapName(self):
1458 return _("Swap Services")
1460 def getMoveName(self):
1461 return _("Move Picture in Picture")
1464 if self.session.pipshown:
1465 del self.session.pip
1466 self.session.pipshown = False
1468 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1469 self.session.pip.setAnimationMode(0)
1470 self.session.pip.show()
1471 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1472 if self.session.pip.playService(newservice):
1473 self.session.pipshown = True
1474 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1476 self.session.pipshown = False
1477 del self.session.pip
1478 self.session.nav.playService(newservice)
1481 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1482 if self.session.pip.servicePath:
1483 servicepath = self.servicelist.getCurrentServicePath()
1484 ref=servicepath[len(servicepath)-1]
1485 pipref=self.session.pip.getCurrentService()
1486 self.session.pip.playService(swapservice)
1487 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1488 if pipref.toString() != ref.toString(): # is a subservice ?
1489 self.session.nav.stopService() # stop portal
1490 self.session.nav.playService(pipref) # start subservice
1491 self.session.pip.servicePath=servicepath
1494 self.session.open(PiPSetup, pip = self.session.pip)
1496 def pipDoHandle0Action(self):
1497 use = config.usage.pip_zero_button.value
1500 elif "swapstop" == use:
1506 from RecordTimer import parseEvent, RecordTimerEntry
1508 class InfoBarInstantRecord:
1509 """Instant Record - handles the instantRecord action in order to
1510 start/stop instant records"""
1512 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1514 "instantRecord": (self.instantRecord, _("Instant Record...")),
1518 def stopCurrentRecording(self, entry = -1):
1519 if entry is not None and entry != -1:
1520 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1521 self.recording.remove(self.recording[entry])
1523 def startInstantRecording(self, limitEvent = False):
1524 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1526 # try to get event info
1529 service = self.session.nav.getCurrentService()
1530 epg = eEPGCache.getInstance()
1531 event = epg.lookupEventTime(serviceref, -1, 0)
1533 info = service.info()
1534 ev = info.getEvent(0)
1540 end = begin + 3600 # dummy
1541 name = "instant record"
1545 if event is not None:
1546 curEvent = parseEvent(event)
1548 description = curEvent[3]
1549 eventid = curEvent[4]
1554 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1556 if isinstance(serviceref, eServiceReference):
1557 serviceref = ServiceReference(serviceref)
1559 recording = RecordTimerEntry(serviceref, begin, end, name, description, eventid, dirname = preferredInstantRecordPath())
1560 recording.dontSave = True
1562 if event is None or limitEvent == False:
1563 recording.autoincrease = True
1564 recording.setAutoincreaseEnd()
1566 simulTimerList = self.session.nav.RecordTimer.record(recording)
1568 if simulTimerList is None: # no conflict
1569 self.recording.append(recording)
1571 if len(simulTimerList) > 1: # with other recording
1572 name = simulTimerList[1].name
1573 name_date = ' '.join((name, strftime('%c', localtime(simulTimerList[1].begin))))
1574 print "[TIMER] conflicts with", name_date
1575 recording.autoincrease = True # start with max available length, then increment
1576 if recording.setAutoincreaseEnd():
1577 self.session.nav.RecordTimer.record(recording)
1578 self.recording.append(recording)
1579 self.session.open(MessageBox, _("Record time limited due to conflicting timer %s") % name_date, MessageBox.TYPE_INFO)
1581 self.session.open(MessageBox, _("Couldn't record due to conflicting timer %s") % name, MessageBox.TYPE_INFO)
1583 self.session.open(MessageBox, _("Couldn't record due to invalid service %s") % serviceref, MessageBox.TYPE_INFO)
1584 recording.autoincrease = False
1586 def isInstantRecordRunning(self):
1587 print "self.recording:", self.recording
1589 for x in self.recording:
1594 def recordQuestionCallback(self, answer):
1595 print "pre:\n", self.recording
1597 if answer is None or answer[1] == "no":
1600 recording = self.recording[:]
1602 if not x in self.session.nav.RecordTimer.timer_list:
1603 self.recording.remove(x)
1604 elif x.dontSave and x.isRunning():
1605 list.append((x, False))
1607 if answer[1] == "changeduration":
1608 if len(self.recording) == 1:
1609 self.changeDuration(0)
1611 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1612 elif answer[1] == "changeendtime":
1613 if len(self.recording) == 1:
1616 self.session.openWithCallback(self.setEndtime, TimerSelection, list)
1617 elif answer[1] == "stop":
1618 if len(self.recording) == 1:
1619 self.stopCurrentRecording(0)
1621 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1622 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1623 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1624 if answer[1] == "manualduration":
1625 self.changeDuration(len(self.recording)-1)
1626 elif answer[1] == "manualendtime":
1627 self.setEndtime(len(self.recording)-1)
1628 print "after:\n", self.recording
1630 def setEndtime(self, entry):
1631 if entry is not None and entry >= 0:
1632 self.selectedEntry = entry
1633 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1634 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1635 dlg.setTitle(_("Please change recording endtime"))
1637 def TimeDateInputClosed(self, ret):
1640 localendtime = localtime(ret[1])
1641 print "stopping recording at", strftime("%c", localendtime)
1642 if self.recording[self.selectedEntry].end != ret[1]:
1643 self.recording[self.selectedEntry].autoincrease = False
1644 self.recording[self.selectedEntry].end = ret[1]
1645 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1647 def changeDuration(self, entry):
1648 if entry is not None and entry >= 0:
1649 self.selectedEntry = entry
1650 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1652 def inputCallback(self, value):
1653 if value is not None:
1654 print "stopping recording after", int(value), "minutes."
1655 entry = self.recording[self.selectedEntry]
1657 entry.autoincrease = False
1658 entry.end = int(time()) + 60 * int(value)
1659 self.session.nav.RecordTimer.timeChanged(entry)
1661 def instantRecord(self):
1662 dir = preferredInstantRecordPath()
1663 if not dir or not fileExists(dir, 'w'):
1664 dir = defaultMoviePath()
1666 if not fileExists("/hdd", 0):
1667 print "not found /hdd"
1668 system("ln -s /media/hdd /hdd")
1673 # XXX: this message is a little odd as we might be recording to a remote device
1674 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1677 if self.isInstantRecordRunning():
1678 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1679 title=_("A recording is currently running.\nWhat do you want to do?"), \
1680 list=((_("stop recording"), "stop"), \
1681 (_("add recording (stop after current event)"), "event"), \
1682 (_("add recording (indefinitely)"), "indefinitely"), \
1683 (_("add recording (enter recording duration)"), "manualduration"), \
1684 (_("add recording (enter recording endtime)"), "manualendtime"), \
1685 (_("change recording (duration)"), "changeduration"), \
1686 (_("change recording (endtime)"), "changeendtime"), \
1687 (_("do nothing"), "no")))
1689 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1690 title=_("Start recording?"), \
1691 list=((_("add recording (stop after current event)"), "event"), \
1692 (_("add recording (indefinitely)"), "indefinitely"), \
1693 (_("add recording (enter recording duration)"), "manualduration"), \
1694 (_("add recording (enter recording endtime)"), "manualendtime"), \
1695 (_("don't record"), "no")))
1697 from Tools.ISO639 import LanguageCodes
1699 class InfoBarAudioSelection:
1701 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1703 "audioSelection": (self.audioSelection, _("Audio Options...")),
1706 def audioSelection(self):
1707 from Screens.AudioSelection import AudioSelection
1708 self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self)
1710 def audioSelected(self, ret=None):
1711 print "[infobar::audioSelected]", ret
1713 class InfoBarSubserviceSelection:
1715 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1717 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1720 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1722 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1723 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1725 self["SubserviceQuickzapAction"].setEnabled(False)
1727 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1729 iPlayableService.evUpdatedEventInfo: self.checkSubservicesAvail
1734 def checkSubservicesAvail(self):
1735 service = self.session.nav.getCurrentService()
1736 subservices = service and service.subServices()
1737 if not subservices or subservices.getNumberOfSubservices() == 0:
1738 self["SubserviceQuickzapAction"].setEnabled(False)
1740 def nextSubservice(self):
1741 self.changeSubservice(+1)
1743 def prevSubservice(self):
1744 self.changeSubservice(-1)
1746 def changeSubservice(self, direction):
1747 service = self.session.nav.getCurrentService()
1748 subservices = service and service.subServices()
1749 n = subservices and subservices.getNumberOfSubservices()
1752 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1755 if subservices.getSubservice(idx).toString() == ref.toString():
1760 selection += direction
1765 newservice = subservices.getSubservice(selection)
1766 if newservice.valid():
1769 self.session.nav.playService(newservice, False)
1771 def subserviceSelection(self):
1772 service = self.session.nav.getCurrentService()
1773 subservices = service and service.subServices()
1774 self.bouquets = self.servicelist.getBouquetList()
1775 n = subservices and subservices.getNumberOfSubservices()
1778 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1782 i = subservices.getSubservice(idx)
1783 if i.toString() == ref.toString():
1785 tlist.append((i.getName(), i))
1788 if self.bouquets and len(self.bouquets):
1789 keys = ["red", "blue", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1790 if config.usage.multibouquet.value:
1791 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1793 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1796 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1797 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1800 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys, skin_name = "SubserviceSelection")
1802 def subserviceSelected(self, service):
1804 if not service is None:
1805 if isinstance(service[1], str):
1806 if service[1] == "quickzap":
1807 from Screens.SubservicesQuickzap import SubservicesQuickzap
1808 self.session.open(SubservicesQuickzap, service[2])
1810 self["SubserviceQuickzapAction"].setEnabled(True)
1811 self.session.nav.playService(service[1], False)
1813 def addSubserviceToBouquetCallback(self, service):
1814 if len(service) > 1 and isinstance(service[1], eServiceReference):
1815 self.selectedSubservice = service
1816 if self.bouquets is None:
1819 cnt = len(self.bouquets)
1820 if cnt > 1: # show bouquet list
1821 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1822 elif cnt == 1: # add to only one existing bouquet
1823 self.addSubserviceToBouquet(self.bouquets[0][1])
1824 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1826 def bouquetSelClosed(self, confirmed):
1828 del self.selectedSubservice
1830 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1832 def addSubserviceToBouquet(self, dest):
1833 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1835 self.bsel.close(True)
1837 del self.selectedSubservice
1839 from Components.Sources.HbbtvApplication import HbbtvApplication
1840 gHbbtvApplication = HbbtvApplication()
1841 class InfoBarRedButton:
1843 if not (config.misc.rcused.value == 1):
1844 self["RedButtonActions"] = HelpableActionMap(self, "InfobarRedButtonActions",
1846 "activateRedButton": (self.activateRedButton, _("Red button...")),
1848 self["HbbtvApplication"] = gHbbtvApplication
1850 self["HbbtvApplication"] = Boolean(fixed=0)
1851 self["HbbtvApplication"].name = "" #is this a hack?
1853 self.onHBBTVActivation = [ ]
1854 self.onRedButtonActivation = [ ]
1855 self.onReadyForAIT = [ ]
1856 self.__et = ServiceEventTracker(screen=self, eventmap=
1858 iPlayableService.evHBBTVInfo: self.detectedHbbtvApplication,
1859 iPlayableService.evUpdatedInfo: self.updateInfomation
1862 def updateAIT(self, orgId=0):
1863 for x in self.onReadyForAIT:
1866 except Exception, ErrMsg:
1868 #self.onReadyForAIT.remove(x)
1870 def updateInfomation(self):
1872 self["HbbtvApplication"].setApplicationName("")
1874 except Exception, ErrMsg:
1877 def detectedHbbtvApplication(self):
1878 service = self.session.nav.getCurrentService()
1879 info = service and service.info()
1881 for x in info.getInfoObject(iServiceInformation.sHBBTVUrl):
1884 self.updateAIT(x[3])
1885 self["HbbtvApplication"].setApplicationName(x[1])
1887 except Exception, ErrMsg:
1890 def activateRedButton(self):
1891 service = self.session.nav.getCurrentService()
1892 info = service and service.info()
1893 if info and info.getInfoString(iServiceInformation.sHBBTVUrl) != "":
1894 for x in self.onHBBTVActivation:
1896 elif False: # TODO: other red button services
1897 for x in self.onRedButtonActivation:
1900 class InfoBarAdditionalInfo:
1903 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0 and config.misc.rcused.value == 1)
1904 self["TimeshiftPossible"] = self["RecordingPossible"]
1905 self["ShowTimeshiftOnYellow"] = Boolean(fixed=(not config.misc.rcused.value == 0))
1906 self["ShowAudioOnYellow"] = Boolean(fixed=config.misc.rcused.value == 0)
1907 self["ShowRecordOnRed"] = Boolean(fixed=config.misc.rcused.value == 1)
1908 self["ExtensionsAvailable"] = Boolean(fixed=1)
1910 class InfoBarNotifications:
1912 self.onExecBegin.append(self.checkNotifications)
1913 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1914 self.onClose.append(self.__removeNotification)
1916 def __removeNotification(self):
1917 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1919 def checkNotificationsIfExecing(self):
1921 self.checkNotifications()
1923 def checkNotifications(self):
1924 notifications = Notifications.notifications
1926 n = notifications[0]
1928 del notifications[0]
1931 if n[3].has_key("onSessionOpenCallback"):
1932 n[3]["onSessionOpenCallback"]()
1933 del n[3]["onSessionOpenCallback"]
1936 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1938 dlg = self.session.open(n[1], *n[2], **n[3])
1940 # remember that this notification is currently active
1942 Notifications.current_notifications.append(d)
1943 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1945 def __notificationClosed(self, d):
1946 Notifications.current_notifications.remove(d)
1948 class InfoBarServiceNotifications:
1950 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1952 iPlayableService.evEnd: self.serviceHasEnded
1955 def serviceHasEnded(self):
1956 print "service end!"
1959 self.setSeekState(self.SEEK_STATE_PLAY)
1963 class InfoBarCueSheetSupport:
1969 ENABLE_RESUME_SUPPORT = False
1971 def __init__(self, actionmap = "InfobarCueSheetActions"):
1972 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1974 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1975 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1976 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1980 self.is_closing = False
1981 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1983 iPlayableService.evStart: self.__serviceStarted,
1986 def __serviceStarted(self):
1989 print "new service started! trying to download cuts!"
1990 self.downloadCuesheet()
1992 if self.ENABLE_RESUME_SUPPORT:
1995 for (pts, what) in self.cut_list:
1996 if what == self.CUT_TYPE_LAST:
1999 if last is not None:
2000 self.resume_point = last
2003 if config.usage.on_movie_start.value == "ask":
2004 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?") + "\n" + (_("Resume position at %s") % ("%d:%02d:%02d" % (l/3600, l%3600/60, l%60))), timeout=10)
2005 elif config.usage.on_movie_start.value == "resume":
2006 # TRANSLATORS: The string "Resuming playback" flashes for a moment
2007 # TRANSLATORS: at the start of a movie, when the user has selected
2008 # TRANSLATORS: "Resume from last position" as start behavior.
2009 # TRANSLATORS: The purpose is to notify the user that the movie starts
2010 # TRANSLATORS: in the middle somewhere and not from the beginning.
2011 # TRANSLATORS: (Some translators seem to have interpreted it as a
2012 # TRANSLATORS: question or a choice, but it is a statement.)
2013 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Resuming playback"), timeout=2, type=MessageBox.TYPE_INFO)
2015 def playLastCB(self, answer):
2017 self.doSeek(self.resume_point)
2018 self.hideAfterResume()
2020 def hideAfterResume(self):
2021 if isinstance(self, InfoBarShowHide):
2024 def __getSeekable(self):
2025 service = self.session.nav.getCurrentService()
2028 return service.seek()
2030 def cueGetCurrentPosition(self):
2031 seek = self.__getSeekable()
2034 r = seek.getPlayPosition()
2039 def cueGetEndCutPosition(self):
2042 for cp in self.cut_list:
2043 if cp[1] == self.CUT_TYPE_OUT:
2047 elif cp[1] == self.CUT_TYPE_IN:
2051 def jumpPreviousNextMark(self, cmp, start=False):
2052 current_pos = self.cueGetCurrentPosition()
2053 if current_pos is None:
2055 mark = self.getNearestCutPoint(current_pos, cmp=cmp, start=start)
2056 if mark is not None:
2064 def jumpPreviousMark(self):
2065 # we add 5 seconds, so if the play position is <5s after
2066 # the mark, the mark before will be used
2067 self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
2069 def jumpNextMark(self):
2070 if not self.jumpPreviousNextMark(lambda x: x-90000):
2073 def getNearestCutPoint(self, pts, cmp=abs, start=False):
2080 bestdiff = cmp(0 - pts)
2082 nearest = [0, False]
2083 for cp in self.cut_list:
2084 if beforecut and cp[1] in (self.CUT_TYPE_IN, self.CUT_TYPE_OUT):
2086 if cp[1] == self.CUT_TYPE_IN: # Start is here, disregard previous marks
2087 diff = cmp(cp[0] - pts)
2088 if start and diff >= 0:
2094 if cp[1] == self.CUT_TYPE_IN:
2096 elif cp[1] == self.CUT_TYPE_OUT:
2098 elif cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
2099 diff = cmp(cp[0] - pts)
2100 if instate and diff >= 0 and (nearest is None or bestdiff > diff):
2105 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
2106 current_pos = self.cueGetCurrentPosition()
2107 if current_pos is None:
2108 print "not seekable"
2111 nearest_cutpoint = self.getNearestCutPoint(current_pos)
2113 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
2115 return nearest_cutpoint
2117 self.removeMark(nearest_cutpoint)
2118 elif not onlyremove and not onlyreturn:
2119 self.addMark((current_pos, self.CUT_TYPE_MARK))
2124 def addMark(self, point):
2125 insort(self.cut_list, point)
2126 self.uploadCuesheet()
2127 self.showAfterCuesheetOperation()
2129 def removeMark(self, point):
2130 self.cut_list.remove(point)
2131 self.uploadCuesheet()
2132 self.showAfterCuesheetOperation()
2134 def showAfterCuesheetOperation(self):
2135 if isinstance(self, InfoBarShowHide):
2138 def __getCuesheet(self):
2139 service = self.session.nav.getCurrentService()
2142 return service.cueSheet()
2144 def uploadCuesheet(self):
2145 cue = self.__getCuesheet()
2148 print "upload failed, no cuesheet interface"
2150 cue.setCutList(self.cut_list)
2152 def downloadCuesheet(self):
2153 cue = self.__getCuesheet()
2156 print "download failed, no cuesheet interface"
2159 self.cut_list = cue.getCutList()
2161 class InfoBarSummary(Screen):
2163 <screen position="0,0" size="132,64">
2164 <widget source="global.CurrentTime" render="Label" position="62,46" size="82,18" font="Regular;16" >
2165 <convert type="ClockToText">WithSeconds</convert>
2167 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="82,18" zPosition="1" >
2168 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2169 <convert type="ConditionalShowHide">Blink</convert>
2171 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2172 <convert type="ServiceName">Name</convert>
2174 <widget source="session.Event_Now" render="Progress" position="6,46" size="46,18" borderWidth="1" >
2175 <convert type="EventTime">Progress</convert>
2179 # for picon: (path="piconlcd" will use LCD picons)
2180 # <widget source="session.CurrentService" render="Picon" position="6,0" size="120,64" path="piconlcd" >
2181 # <convert type="ServiceName">Reference</convert>
2184 class InfoBarSummarySupport:
2188 def createSummary(self):
2189 return InfoBarSummary
2191 class InfoBarMoviePlayerSummary(Screen):
2193 <screen position="0,0" size="132,64">
2194 <widget source="global.CurrentTime" render="Label" position="62,46" size="64,18" font="Regular;16" halign="right" >
2195 <convert type="ClockToText">WithSeconds</convert>
2197 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="64,18" zPosition="1" >
2198 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2199 <convert type="ConditionalShowHide">Blink</convert>
2201 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2202 <convert type="ServiceName">Name</convert>
2204 <widget source="session.CurrentService" render="Progress" position="6,46" size="56,18" borderWidth="1" >
2205 <convert type="ServicePosition">Position</convert>
2209 class InfoBarMoviePlayerSummarySupport:
2213 def createSummary(self):
2214 return InfoBarMoviePlayerSummary
2216 class InfoBarTeletextPlugin:
2218 self.teletext_plugin = None
2220 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
2221 self.teletext_plugin = p
2223 if self.teletext_plugin is not None:
2224 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
2226 "startTeletext": (self.startTeletext, _("View teletext..."))
2229 print "no teletext plugin found!"
2231 def startTeletext(self):
2232 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
2234 class InfoBarSubtitleSupport(object):
2236 object.__init__(self)
2237 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
2238 self.subtitle_window.setAnimationMode(0)
2239 self.__subtitles_enabled = False
2241 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2243 iPlayableService.evEnd: self.__serviceStopped,
2244 iPlayableService.evUpdatedInfo: self.__updatedInfo
2246 self.cached_subtitle_checked = False
2247 self.__selected_subtitle = None
2249 def __serviceStopped(self):
2250 self.cached_subtitle_checked = False
2251 if self.__subtitles_enabled:
2252 self.subtitle_window.hide()
2253 self.__subtitles_enabled = False
2254 self.__selected_subtitle = None
2256 def __updatedInfo(self):
2257 if not self.cached_subtitle_checked:
2258 self.cached_subtitle_checked = True
2259 subtitle = self.getCurrentServiceSubtitle()
2260 self.setSelectedSubtitle(subtitle and subtitle.getCachedSubtitle())
2261 if self.__selected_subtitle:
2262 self.setSubtitlesEnable(True)
2264 def getCurrentServiceSubtitle(self):
2265 service = self.session.nav.getCurrentService()
2266 return service and service.subtitle()
2268 def setSubtitlesEnable(self, enable=True):
2269 subtitle = self.getCurrentServiceSubtitle()
2271 if self.__selected_subtitle:
2272 if subtitle and not self.__subtitles_enabled:
2273 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2274 self.subtitle_window.show()
2275 self.__subtitles_enabled = True
2278 subtitle.disableSubtitles(self.subtitle_window.instance)
2279 self.__selected_subtitle = False
2280 self.__subtitles_enabled = False
2281 self.subtitle_window.hide()
2283 def setSelectedSubtitle(self, subtitle):
2284 self.__selected_subtitle = subtitle
2286 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
2287 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
2289 class InfoBarServiceErrorPopupSupport:
2291 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2293 iPlayableService.evTuneFailed: self.__tuneFailed,
2294 iPlayableService.evStart: self.__serviceStarted
2296 self.__serviceStarted()
2298 def __serviceStarted(self):
2299 self.last_error = None
2300 Notifications.RemovePopup(id = "ZapError")
2302 def __tuneFailed(self):
2303 service = self.session.nav.getCurrentService()
2304 info = service and service.info()
2305 error = info and info.getInfo(iServiceInformation.sDVBState)
2307 if error == self.last_error:
2310 self.last_error = error
2313 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2314 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2315 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2316 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2317 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2318 eDVBServicePMTHandler.eventNewProgramInfo: None,
2319 eDVBServicePMTHandler.eventTuned: None,
2320 eDVBServicePMTHandler.eventSOF: None,
2321 eDVBServicePMTHandler.eventEOF: None,
2322 eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
2323 }.get(error) #this returns None when the key not exist in the dict
2325 if error is not None:
2326 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2328 Notifications.RemovePopup(id = "ZapError")