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, system as os_system
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, _("Pause/Continue")),
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,
1208 iPlayableService.evUser+3: self.__lowDiskspaceMessage
1211 def getTimeshift(self):
1212 service = self.session.nav.getCurrentService()
1213 return service and service.timeshift()
1215 def startTimeshift(self):
1216 print "enable timeshift"
1217 ts = self.getTimeshift()
1219 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1220 print "no ts interface"
1223 if self.timeshift_enabled:
1224 print "hu, timeshift already enabled?"
1226 if not ts.startTimeshift():
1227 self.timeshift_enabled = 1
1229 # we remove the "relative time" for now.
1230 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1233 #self.setSeekState(self.SEEK_STATE_PAUSE)
1234 self.activateTimeshiftEnd(False)
1236 # enable the "TimeshiftEnableActions", which will override
1237 # the startTimeshift actions
1238 self.__seekableStatusChanged()
1240 print "timeshift failed"
1242 def stopTimeshift(self):
1243 if not self.timeshift_enabled:
1245 print "disable timeshift"
1246 ts = self.getTimeshift()
1249 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1251 def stopTimeshiftConfirmed(self, confirmed):
1255 ts = self.getTimeshift()
1260 self.timeshift_enabled = 0
1263 self.__seekableStatusChanged()
1265 # activates timeshift, and seeks to (almost) the end
1266 def activateTimeshiftEnd(self, back = True):
1267 ts = self.getTimeshift()
1268 print "activateTimeshiftEnd"
1273 if ts.isTimeshiftActive():
1274 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1278 ts.activateTimeshift() # activate timeshift will automatically pause
1279 self.setSeekState(self.SEEK_STATE_PAUSE)
1282 self.ts_rewind_timer.start(200, 1)
1284 def rewindService(self):
1285 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1287 # same as activateTimeshiftEnd, but pauses afterwards.
1288 def activateTimeshiftEndAndPause(self):
1289 print "activateTimeshiftEndAndPause"
1290 #state = self.seekstate
1291 self.activateTimeshiftEnd(False)
1293 def __seekableStatusChanged(self):
1296 # print "self.isSeekable", self.isSeekable()
1297 # print "self.timeshift_enabled", self.timeshift_enabled
1299 # when this service is not seekable, but timeshift
1300 # is enabled, this means we can activate
1302 if not self.isSeekable() and self.timeshift_enabled:
1305 # print "timeshift activate:", enabled
1306 self["TimeshiftActivateActions"].setEnabled(enabled)
1308 def __serviceStarted(self):
1309 self.timeshift_enabled = False
1310 self.__seekableStatusChanged()
1312 def __lowDiskspaceMessage(self):
1313 Notifications.AddPopup(text = _("Write error. Not enough space for writing.\n"), type = MessageBox.TYPE_ERROR, timeout = 0, id = "DiskFullMessage")
1315 from Screens.PiPSetup import PiPSetup
1317 class InfoBarExtensions:
1318 EXTENSION_SINGLE = 0
1324 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1326 "extensions": (self.showExtensionSelection, _("view extensions...")),
1327 }, 1) # lower priority
1329 for p in plugins.getPlugins(PluginDescriptor.WHERE_EXTENSIONSINGLE):
1332 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1333 self.list.append((type, extension, key))
1335 def updateExtension(self, extension, key = None):
1336 self.extensionsList.append(extension)
1338 if self.extensionKeys.has_key(key):
1342 for x in self.availableKeys:
1343 if not self.extensionKeys.has_key(x):
1348 self.extensionKeys[key] = len(self.extensionsList) - 1
1350 def updateExtensions(self):
1351 self.extensionsList = []
1352 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1353 self.extensionKeys = {}
1355 if x[0] == self.EXTENSION_SINGLE:
1356 self.updateExtension(x[1], x[2])
1359 self.updateExtension(y[0], y[1])
1362 def showExtensionSelection(self):
1363 self.updateExtensions()
1364 extensionsList = self.extensionsList[:]
1367 for x in self.availableKeys:
1368 if self.extensionKeys.has_key(x):
1369 entry = self.extensionKeys[x]
1370 extension = self.extensionsList[entry]
1372 name = str(extension[0]())
1373 list.append((extension[0](), extension))
1375 extensionsList.remove(extension)
1377 extensionsList.remove(extension)
1378 list.extend([(x[0](), x) for x in extensionsList])
1380 keys += [""] * len(extensionsList)
1381 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys, skin_name = "ExtensionsList")
1383 def extensionCallback(self, answer):
1384 if answer is not None:
1387 from Tools.BoundFunction import boundFunction
1390 # depends on InfoBarExtensions
1392 class InfoBarPlugins:
1394 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1396 def getPluginName(self, name):
1399 def getPluginList(self):
1401 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1402 args = inspect.getargspec(p.__call__)[0]
1403 if len(args) == 1 or len(args) == 2 and isinstance(self, InfoBarChannelSelection):
1404 l.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name))
1405 l.sort(key = lambda e: e[2]) # sort by name
1408 def runPlugin(self, plugin):
1409 if isinstance(self, InfoBarChannelSelection):
1410 plugin(session = self.session, servicelist = self.servicelist)
1412 plugin(session = self.session)
1414 from Components.Task import job_manager
1415 class InfoBarJobman:
1417 self.addExtension(extension = self.getJobList, type = InfoBarExtensions.EXTENSION_LIST)
1419 def getJobList(self):
1420 return [((boundFunction(self.getJobName, job), boundFunction(self.showJobView, job), lambda: True), None) for job in job_manager.getPendingJobs()]
1422 def getJobName(self, job):
1423 return "%s: %s (%d%%)" % (job.getStatustext(), job.name, int(100*job.progress/float(job.end)))
1425 def showJobView(self, job):
1426 from Screens.TaskView import JobView
1427 job_manager.in_background = False
1428 self.session.openWithCallback(self.JobViewCB, JobView, job)
1430 def JobViewCB(self, in_background):
1431 job_manager.in_background = in_background
1433 # depends on InfoBarExtensions
1437 self.session.pipshown
1439 self.session.pipshown = False
1440 if SystemInfo.get("NumVideoDecoders", 1) > 1:
1442 self.addExtension((self.getShowHideName, self.showPiP, lambda: True), "blue")
1443 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1444 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1446 self.addExtension((self.getShowHideName, self.showPiP, self.pipShown), "blue")
1447 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1450 return self.session.pipshown
1452 def pipHandles0Action(self):
1453 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1455 def getShowHideName(self):
1456 if self.session.pipshown:
1457 return _("Disable Picture in Picture")
1459 return _("Activate Picture in Picture")
1461 def getSwapName(self):
1462 return _("Swap Services")
1464 def getMoveName(self):
1465 return _("Move Picture in Picture")
1468 if self.session.pipshown:
1469 del self.session.pip
1470 self.session.pipshown = False
1472 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1473 self.session.pip.setAnimationMode(0)
1474 self.session.pip.show()
1475 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1476 if self.session.pip.playService(newservice):
1477 self.session.pipshown = True
1478 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1480 self.session.pipshown = False
1481 del self.session.pip
1482 self.session.nav.playService(newservice)
1485 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1486 if self.session.pip.servicePath:
1487 servicepath = self.servicelist.getCurrentServicePath()
1488 ref=servicepath[len(servicepath)-1]
1489 pipref=self.session.pip.getCurrentService()
1490 self.session.pip.playService(swapservice)
1491 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1492 if pipref.toString() != ref.toString(): # is a subservice ?
1493 self.session.nav.stopService() # stop portal
1494 self.session.nav.playService(pipref) # start subservice
1495 self.session.pip.servicePath=servicepath
1498 self.session.open(PiPSetup, pip = self.session.pip)
1500 def pipDoHandle0Action(self):
1501 use = config.usage.pip_zero_button.value
1504 elif "swapstop" == use:
1510 from RecordTimer import parseEvent, RecordTimerEntry
1512 class InfoBarInstantRecord:
1513 """Instant Record - handles the instantRecord action in order to
1514 start/stop instant records"""
1516 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1518 "instantRecord": (self.instantRecord, _("Instant Record...")),
1522 def stopCurrentRecording(self, entry = -1):
1523 if entry is not None and entry != -1:
1524 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1525 self.recording.remove(self.recording[entry])
1527 def startInstantRecording(self, limitEvent = False):
1528 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1530 # try to get event info
1533 service = self.session.nav.getCurrentService()
1534 epg = eEPGCache.getInstance()
1535 event = epg.lookupEventTime(serviceref, -1, 0)
1537 info = service.info()
1538 ev = info.getEvent(0)
1544 end = begin + 3600 # dummy
1545 name = "instant record"
1549 if event is not None:
1550 curEvent = parseEvent(event)
1552 description = curEvent[3]
1553 eventid = curEvent[4]
1558 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1560 if isinstance(serviceref, eServiceReference):
1561 serviceref = ServiceReference(serviceref)
1563 recording = RecordTimerEntry(serviceref, begin, end, name, description, eventid, dirname = preferredInstantRecordPath())
1564 recording.dontSave = True
1566 if event is None or limitEvent == False:
1567 recording.autoincrease = True
1568 recording.setAutoincreaseEnd()
1570 simulTimerList = self.session.nav.RecordTimer.record(recording)
1572 if simulTimerList is None: # no conflict
1573 self.recording.append(recording)
1575 if len(simulTimerList) > 1: # with other recording
1576 name = simulTimerList[1].name
1577 name_date = ' '.join((name, strftime('%c', localtime(simulTimerList[1].begin))))
1578 print "[TIMER] conflicts with", name_date
1579 recording.autoincrease = True # start with max available length, then increment
1580 if recording.setAutoincreaseEnd():
1581 self.session.nav.RecordTimer.record(recording)
1582 self.recording.append(recording)
1583 self.session.open(MessageBox, _("Record time limited due to conflicting timer %s") % name_date, MessageBox.TYPE_INFO)
1585 self.session.open(MessageBox, _("Couldn't record due to conflicting timer %s") % name, MessageBox.TYPE_INFO)
1587 self.session.open(MessageBox, _("Couldn't record due to invalid service %s") % serviceref, MessageBox.TYPE_INFO)
1588 recording.autoincrease = False
1590 def isInstantRecordRunning(self):
1591 print "self.recording:", self.recording
1593 for x in self.recording:
1598 def recordQuestionCallback(self, answer):
1599 print "pre:\n", self.recording
1601 if answer is None or answer[1] == "no":
1604 recording = self.recording[:]
1606 if not x in self.session.nav.RecordTimer.timer_list:
1607 self.recording.remove(x)
1608 elif x.dontSave and x.isRunning():
1609 list.append((x, False))
1611 if answer[1] == "changeduration":
1612 if len(self.recording) == 1:
1613 self.changeDuration(0)
1615 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1616 elif answer[1] == "changeendtime":
1617 if len(self.recording) == 1:
1620 self.session.openWithCallback(self.setEndtime, TimerSelection, list)
1621 elif answer[1] == "stop":
1622 if len(self.recording) == 1:
1623 self.stopCurrentRecording(0)
1625 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1626 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1627 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1628 if answer[1] == "manualduration":
1629 self.changeDuration(len(self.recording)-1)
1630 elif answer[1] == "manualendtime":
1631 self.setEndtime(len(self.recording)-1)
1632 print "after:\n", self.recording
1634 def setEndtime(self, entry):
1635 if entry is not None and entry >= 0:
1636 self.selectedEntry = entry
1637 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1638 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1639 dlg.setTitle(_("Please change recording endtime"))
1641 def TimeDateInputClosed(self, ret):
1644 localendtime = localtime(ret[1])
1645 print "stopping recording at", strftime("%c", localendtime)
1646 if self.recording[self.selectedEntry].end != ret[1]:
1647 self.recording[self.selectedEntry].autoincrease = False
1648 self.recording[self.selectedEntry].end = ret[1]
1649 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1651 def changeDuration(self, entry):
1652 if entry is not None and entry >= 0:
1653 self.selectedEntry = entry
1654 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1656 def inputCallback(self, value):
1657 if value is not None:
1658 print "stopping recording after", int(value), "minutes."
1659 entry = self.recording[self.selectedEntry]
1661 entry.autoincrease = False
1662 entry.end = int(time()) + 60 * int(value)
1663 self.session.nav.RecordTimer.timeChanged(entry)
1665 def instantRecord(self):
1666 dir = preferredInstantRecordPath()
1667 if not dir or not fileExists(dir, 'w'):
1668 dir = defaultMoviePath()
1670 if not fileExists("/hdd", 0):
1671 print "not found /hdd"
1672 os_system("ln -s /media/hdd /hdd")
1677 # XXX: this message is a little odd as we might be recording to a remote device
1678 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1681 if self.isInstantRecordRunning():
1682 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1683 title=_("A recording is currently running.\nWhat do you want to do?"), \
1684 list=((_("stop recording"), "stop"), \
1685 (_("add recording (stop after current event)"), "event"), \
1686 (_("add recording (indefinitely)"), "indefinitely"), \
1687 (_("add recording (enter recording duration)"), "manualduration"), \
1688 (_("add recording (enter recording endtime)"), "manualendtime"), \
1689 (_("change recording (duration)"), "changeduration"), \
1690 (_("change recording (endtime)"), "changeendtime"), \
1691 (_("do nothing"), "no")))
1693 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1694 title=_("Start recording?"), \
1695 list=((_("add recording (stop after current event)"), "event"), \
1696 (_("add recording (indefinitely)"), "indefinitely"), \
1697 (_("add recording (enter recording duration)"), "manualduration"), \
1698 (_("add recording (enter recording endtime)"), "manualendtime"), \
1699 (_("don't record"), "no")))
1701 from Tools.ISO639 import LanguageCodes
1703 class InfoBarAudioSelection:
1705 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1707 "audioSelection": (self.audioSelection, _("Audio Options...")),
1710 def audioSelection(self):
1711 from Screens.AudioSelection import AudioSelection
1712 self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self)
1714 def audioSelected(self, ret=None):
1715 print "[infobar::audioSelected]", ret
1717 class InfoBarSubserviceSelection:
1719 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1721 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1724 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1726 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1727 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1729 self["SubserviceQuickzapAction"].setEnabled(False)
1731 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1733 iPlayableService.evUpdatedEventInfo: self.checkSubservicesAvail
1738 def checkSubservicesAvail(self):
1739 service = self.session.nav.getCurrentService()
1740 subservices = service and service.subServices()
1741 if not subservices or subservices.getNumberOfSubservices() == 0:
1742 self["SubserviceQuickzapAction"].setEnabled(False)
1744 def nextSubservice(self):
1745 self.changeSubservice(+1)
1747 def prevSubservice(self):
1748 self.changeSubservice(-1)
1750 def changeSubservice(self, direction):
1751 service = self.session.nav.getCurrentService()
1752 subservices = service and service.subServices()
1753 n = subservices and subservices.getNumberOfSubservices()
1756 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1759 if subservices.getSubservice(idx).toString() == ref.toString():
1764 selection += direction
1769 newservice = subservices.getSubservice(selection)
1770 if newservice.valid():
1773 self.session.nav.playService(newservice, False)
1775 def subserviceSelection(self):
1776 service = self.session.nav.getCurrentService()
1777 subservices = service and service.subServices()
1778 self.bouquets = self.servicelist.getBouquetList()
1779 n = subservices and subservices.getNumberOfSubservices()
1782 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1786 i = subservices.getSubservice(idx)
1787 if i.toString() == ref.toString():
1789 tlist.append((i.getName(), i))
1792 if self.bouquets and len(self.bouquets):
1793 keys = ["red", "blue", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1794 if config.usage.multibouquet.value:
1795 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1797 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1800 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1801 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1804 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys, skin_name = "SubserviceSelection")
1806 def subserviceSelected(self, service):
1808 if not service is None:
1809 if isinstance(service[1], str):
1810 if service[1] == "quickzap":
1811 from Screens.SubservicesQuickzap import SubservicesQuickzap
1812 self.session.open(SubservicesQuickzap, service[2])
1814 self["SubserviceQuickzapAction"].setEnabled(True)
1815 self.session.nav.playService(service[1], False)
1817 def addSubserviceToBouquetCallback(self, service):
1818 if len(service) > 1 and isinstance(service[1], eServiceReference):
1819 self.selectedSubservice = service
1820 if self.bouquets is None:
1823 cnt = len(self.bouquets)
1824 if cnt > 1: # show bouquet list
1825 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1826 elif cnt == 1: # add to only one existing bouquet
1827 self.addSubserviceToBouquet(self.bouquets[0][1])
1828 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1830 def bouquetSelClosed(self, confirmed):
1832 del self.selectedSubservice
1834 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1836 def addSubserviceToBouquet(self, dest):
1837 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1839 self.bsel.close(True)
1841 del self.selectedSubservice
1843 from Components.Sources.HbbtvApplication import HbbtvApplication
1844 gHbbtvApplication = HbbtvApplication()
1845 class InfoBarRedButton:
1847 if not (config.misc.rcused.value == 1):
1848 self["RedButtonActions"] = HelpableActionMap(self, "InfobarRedButtonActions",
1850 "activateRedButton": (self.activateRedButton, _("Red button...")),
1852 self["HbbtvApplication"] = gHbbtvApplication
1854 self["HbbtvApplication"] = Boolean(fixed=0)
1855 self["HbbtvApplication"].name = "" #is this a hack?
1857 self.onHBBTVActivation = [ ]
1858 self.onRedButtonActivation = [ ]
1859 self.onReadyForAIT = [ ]
1860 self.__et = ServiceEventTracker(screen=self, eventmap=
1862 iPlayableService.evHBBTVInfo: self.detectedHbbtvApplication,
1863 iPlayableService.evUpdatedInfo: self.updateInfomation
1866 def updateAIT(self, orgId=0):
1867 for x in self.onReadyForAIT:
1870 except Exception, ErrMsg:
1872 #self.onReadyForAIT.remove(x)
1874 def updateInfomation(self):
1876 self["HbbtvApplication"].setApplicationName("")
1878 except Exception, ErrMsg:
1881 def detectedHbbtvApplication(self):
1882 service = self.session.nav.getCurrentService()
1883 info = service and service.info()
1885 for x in info.getInfoObject(iServiceInformation.sHBBTVUrl):
1888 self.updateAIT(x[3])
1889 self["HbbtvApplication"].setApplicationName(x[1])
1891 except Exception, ErrMsg:
1894 def activateRedButton(self):
1895 service = self.session.nav.getCurrentService()
1896 info = service and service.info()
1897 if info and info.getInfoString(iServiceInformation.sHBBTVUrl) != "":
1898 for x in self.onHBBTVActivation:
1900 elif False: # TODO: other red button services
1901 for x in self.onRedButtonActivation:
1904 class InfoBarAdditionalInfo:
1907 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0 and config.misc.rcused.value == 1)
1908 self["TimeshiftPossible"] = self["RecordingPossible"]
1909 self["ShowTimeshiftOnYellow"] = Boolean(fixed=(not config.misc.rcused.value == 0))
1910 self["ShowAudioOnYellow"] = Boolean(fixed=config.misc.rcused.value == 0)
1911 self["ShowRecordOnRed"] = Boolean(fixed=config.misc.rcused.value == 1)
1912 self["ExtensionsAvailable"] = Boolean(fixed=1)
1914 class InfoBarNotifications:
1916 self.onExecBegin.append(self.checkNotifications)
1917 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1918 self.onClose.append(self.__removeNotification)
1920 def __removeNotification(self):
1921 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1923 def checkNotificationsIfExecing(self):
1925 self.checkNotifications()
1927 def checkNotifications(self):
1928 notifications = Notifications.notifications
1930 n = notifications[0]
1932 del notifications[0]
1935 if n[3].has_key("onSessionOpenCallback"):
1936 n[3]["onSessionOpenCallback"]()
1937 del n[3]["onSessionOpenCallback"]
1940 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1942 dlg = self.session.open(n[1], *n[2], **n[3])
1944 # remember that this notification is currently active
1946 Notifications.current_notifications.append(d)
1947 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1949 def __notificationClosed(self, d):
1950 Notifications.current_notifications.remove(d)
1952 class InfoBarServiceNotifications:
1954 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1956 iPlayableService.evEnd: self.serviceHasEnded
1959 def serviceHasEnded(self):
1960 print "service end!"
1963 self.setSeekState(self.SEEK_STATE_PLAY)
1967 class InfoBarCueSheetSupport:
1973 ENABLE_RESUME_SUPPORT = False
1975 def __init__(self, actionmap = "InfobarCueSheetActions"):
1976 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1978 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1979 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1980 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1984 self.is_closing = False
1985 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1987 iPlayableService.evStart: self.__serviceStarted,
1990 def __serviceStarted(self):
1993 print "new service started! trying to download cuts!"
1994 self.downloadCuesheet()
1996 if self.ENABLE_RESUME_SUPPORT:
1999 for (pts, what) in self.cut_list:
2000 if what == self.CUT_TYPE_LAST:
2003 if last is not None:
2004 self.resume_point = last
2007 if config.usage.on_movie_start.value == "ask":
2008 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)
2009 elif config.usage.on_movie_start.value == "resume":
2010 # TRANSLATORS: The string "Resuming playback" flashes for a moment
2011 # TRANSLATORS: at the start of a movie, when the user has selected
2012 # TRANSLATORS: "Resume from last position" as start behavior.
2013 # TRANSLATORS: The purpose is to notify the user that the movie starts
2014 # TRANSLATORS: in the middle somewhere and not from the beginning.
2015 # TRANSLATORS: (Some translators seem to have interpreted it as a
2016 # TRANSLATORS: question or a choice, but it is a statement.)
2017 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Resuming playback"), timeout=2, type=MessageBox.TYPE_INFO)
2019 def playLastCB(self, answer):
2021 self.doSeek(self.resume_point)
2022 self.hideAfterResume()
2024 def hideAfterResume(self):
2025 if isinstance(self, InfoBarShowHide):
2028 def __getSeekable(self):
2029 service = self.session.nav.getCurrentService()
2032 return service.seek()
2034 def cueGetCurrentPosition(self):
2035 seek = self.__getSeekable()
2038 r = seek.getPlayPosition()
2043 def cueGetEndCutPosition(self):
2046 for cp in self.cut_list:
2047 if cp[1] == self.CUT_TYPE_OUT:
2051 elif cp[1] == self.CUT_TYPE_IN:
2055 def jumpPreviousNextMark(self, cmp, start=False):
2056 current_pos = self.cueGetCurrentPosition()
2057 if current_pos is None:
2059 mark = self.getNearestCutPoint(current_pos, cmp=cmp, start=start)
2060 if mark is not None:
2068 def jumpPreviousMark(self):
2069 # we add 5 seconds, so if the play position is <5s after
2070 # the mark, the mark before will be used
2071 self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
2073 def jumpNextMark(self):
2074 if not self.jumpPreviousNextMark(lambda x: x-90000):
2077 def getNearestCutPoint(self, pts, cmp=abs, start=False):
2084 bestdiff = cmp(0 - pts)
2086 nearest = [0, False]
2087 for cp in self.cut_list:
2088 if beforecut and cp[1] in (self.CUT_TYPE_IN, self.CUT_TYPE_OUT):
2090 if cp[1] == self.CUT_TYPE_IN: # Start is here, disregard previous marks
2091 diff = cmp(cp[0] - pts)
2092 if start and diff >= 0:
2098 if cp[1] == self.CUT_TYPE_IN:
2100 elif cp[1] == self.CUT_TYPE_OUT:
2102 elif cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
2103 diff = cmp(cp[0] - pts)
2104 if instate and diff >= 0 and (nearest is None or bestdiff > diff):
2109 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
2110 current_pos = self.cueGetCurrentPosition()
2111 if current_pos is None:
2112 print "not seekable"
2115 nearest_cutpoint = self.getNearestCutPoint(current_pos)
2117 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
2119 return nearest_cutpoint
2121 self.removeMark(nearest_cutpoint)
2122 elif not onlyremove and not onlyreturn:
2123 self.addMark((current_pos, self.CUT_TYPE_MARK))
2128 def addMark(self, point):
2129 insort(self.cut_list, point)
2130 self.uploadCuesheet()
2131 self.showAfterCuesheetOperation()
2133 def removeMark(self, point):
2134 self.cut_list.remove(point)
2135 self.uploadCuesheet()
2136 self.showAfterCuesheetOperation()
2138 def showAfterCuesheetOperation(self):
2139 if isinstance(self, InfoBarShowHide):
2142 def __getCuesheet(self):
2143 service = self.session.nav.getCurrentService()
2146 return service.cueSheet()
2148 def uploadCuesheet(self):
2149 cue = self.__getCuesheet()
2152 print "upload failed, no cuesheet interface"
2154 cue.setCutList(self.cut_list)
2156 def downloadCuesheet(self):
2157 cue = self.__getCuesheet()
2160 print "download failed, no cuesheet interface"
2163 self.cut_list = cue.getCutList()
2165 class InfoBarSummary(Screen):
2167 <screen position="0,0" size="132,64">
2168 <widget source="global.CurrentTime" render="Label" position="62,46" size="82,18" font="Regular;16" >
2169 <convert type="ClockToText">WithSeconds</convert>
2171 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="82,18" zPosition="1" >
2172 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2173 <convert type="ConditionalShowHide">Blink</convert>
2175 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2176 <convert type="ServiceName">Name</convert>
2178 <widget source="session.Event_Now" render="Progress" position="6,46" size="46,18" borderWidth="1" >
2179 <convert type="EventTime">Progress</convert>
2183 # for picon: (path="piconlcd" will use LCD picons)
2184 # <widget source="session.CurrentService" render="Picon" position="6,0" size="120,64" path="piconlcd" >
2185 # <convert type="ServiceName">Reference</convert>
2188 class InfoBarSummarySupport:
2192 def createSummary(self):
2193 return InfoBarSummary
2195 class InfoBarMoviePlayerSummary(Screen):
2197 <screen position="0,0" size="132,64">
2198 <widget source="global.CurrentTime" render="Label" position="62,46" size="64,18" font="Regular;16" halign="right" >
2199 <convert type="ClockToText">WithSeconds</convert>
2201 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="64,18" zPosition="1" >
2202 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2203 <convert type="ConditionalShowHide">Blink</convert>
2205 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2206 <convert type="ServiceName">Name</convert>
2208 <widget source="session.CurrentService" render="Progress" position="6,46" size="56,18" borderWidth="1" >
2209 <convert type="ServicePosition">Position</convert>
2213 class InfoBarMoviePlayerSummarySupport:
2217 def createSummary(self):
2218 return InfoBarMoviePlayerSummary
2220 class InfoBarTeletextPlugin:
2222 self.teletext_plugin = None
2224 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
2225 self.teletext_plugin = p
2227 if self.teletext_plugin is not None:
2228 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
2230 "startTeletext": (self.startTeletext, _("View teletext..."))
2233 print "no teletext plugin found!"
2235 def startTeletext(self):
2236 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
2238 class InfoBarSubtitleSupport(object):
2240 object.__init__(self)
2241 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
2242 self.subtitle_window.setAnimationMode(0)
2243 self.__subtitles_enabled = False
2245 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2247 iPlayableService.evEnd: self.__serviceStopped,
2248 iPlayableService.evUpdatedInfo: self.__updatedInfo
2250 self.cached_subtitle_checked = False
2251 self.__selected_subtitle = None
2253 def __serviceStopped(self):
2254 self.cached_subtitle_checked = False
2255 if self.__subtitles_enabled:
2256 self.subtitle_window.hide()
2257 self.__subtitles_enabled = False
2258 self.__selected_subtitle = None
2260 def __updatedInfo(self):
2261 if not self.__selected_subtitle:
2262 subtitle = self.getCurrentServiceSubtitle()
2263 self.setSelectedSubtitle(subtitle and subtitle.getCachedSubtitle())
2264 if self.__selected_subtitle:
2265 self.setSubtitlesEnable(True)
2267 def getCurrentServiceSubtitle(self):
2268 service = self.session.nav.getCurrentService()
2269 return service and service.subtitle()
2271 def setSubtitlesEnable(self, enable=True):
2272 subtitle = self.getCurrentServiceSubtitle()
2274 if self.__selected_subtitle:
2275 if subtitle and not self.__subtitles_enabled:
2276 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2277 self.subtitle_window.show()
2278 self.__subtitles_enabled = True
2281 subtitle.disableSubtitles(self.subtitle_window.instance)
2282 self.__selected_subtitle = None
2283 self.__subtitles_enabled = False
2284 self.subtitle_window.hide()
2286 def setSelectedSubtitle(self, subtitle):
2287 self.__selected_subtitle = subtitle
2289 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
2290 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
2292 class InfoBarServiceErrorPopupSupport:
2294 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2296 iPlayableService.evTuneFailed: self.__tuneFailed,
2297 iPlayableService.evStart: self.__serviceStarted
2299 self.__serviceStarted()
2301 def __serviceStarted(self):
2302 self.last_error = None
2303 Notifications.RemovePopup(id = "ZapError")
2305 def __tuneFailed(self):
2306 service = self.session.nav.getCurrentService()
2307 info = service and service.info()
2308 error = info and info.getInfo(iServiceInformation.sDVBState)
2310 if error == self.last_error:
2313 self.last_error = error
2316 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2317 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2318 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2319 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2320 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2321 eDVBServicePMTHandler.eventNewProgramInfo: None,
2322 eDVBServicePMTHandler.eventTuned: None,
2323 eDVBServicePMTHandler.eventSOF: None,
2324 eDVBServicePMTHandler.eventEOF: None,
2325 eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
2326 }.get(error) #this returns None when the key not exist in the dict
2328 if error is not None:
2329 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2331 Notifications.RemovePopup(id = "ZapError")