1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import Label
9 from Components.Pixmap import Pixmap
10 from Components.PluginComponent import plugins
11 from Components.ServiceEventTracker import ServiceEventTracker
12 from Components.Sources.CurrentService import CurrentService
13 from Components.Sources.EventInfo import EventInfo
14 from Components.Sources.FrontendStatus import FrontendStatus
15 from Components.Sources.Boolean import Boolean
16 from Components.Sources.Clock import Clock
17 from Components.config import config, ConfigBoolean, ConfigClock
18 from EpgSelection import EPGSelection
19 from Plugins.Plugin import PluginDescriptor
21 from Screen import Screen
22 from Screens.ChoiceBox import ChoiceBox
23 from Screens.Dish import Dish
24 from Screens.EventView import EventViewEPGSelect, EventViewSimple
25 from Screens.InputBox import InputBox
26 from Screens.MessageBox import MessageBox
27 from Screens.MinuteInput import MinuteInput
28 from Screens.TimerSelection import TimerSelection
29 from Screens.PictureInPicture import PictureInPicture
30 from Screens.SubtitleDisplay import SubtitleDisplay
31 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
32 from Screens.SleepTimerEdit import SleepTimerEdit
33 from Screens.TimeDateInput import TimeDateInput
34 from ServiceReference import ServiceReference
36 from Tools import Notifications
37 from Tools.Directories import SCOPE_HDD, resolveFilename
39 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
40 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
42 from time import time, localtime, strftime
43 from os import stat as os_stat
44 from bisect import insort
47 from Menu import MainMenu, mdom
51 self.dishDialog = self.session.instantiateDialog(Dish)
52 self.onLayoutFinish.append(self.dishDialog.show)
54 class InfoBarShowHide:
55 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
63 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
65 "toggleShow": self.toggleShow,
67 }, 1) # lower prio to make it possible to override ok and cancel..
69 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
71 iPlayableService.evStart: self.serviceStarted,
74 self.__state = self.STATE_SHOWN
77 self.hideTimer = eTimer()
78 self.hideTimer.timeout.get().append(self.doTimerHide)
79 self.hideTimer.start(5000, True)
81 self.onShow.append(self.__onShow)
82 self.onHide.append(self.__onHide)
84 def serviceStarted(self):
86 if config.usage.show_infobar_on_zap.value:
90 self.__state = self.STATE_SHOWN
93 def startHideTimer(self):
94 if self.__state == self.STATE_SHOWN and not self.__locked:
95 idx = config.usage.infobar_timeout.index
97 self.hideTimer.start(idx*1000, True)
100 self.__state = self.STATE_HIDDEN
104 self.startHideTimer()
106 def doTimerHide(self):
107 self.hideTimer.stop()
108 if self.__state == self.STATE_SHOWN:
111 def toggleShow(self):
112 if self.__state == self.STATE_SHOWN:
114 self.hideTimer.stop()
115 elif self.__state == self.STATE_HIDDEN:
119 self.__locked = self.__locked + 1
122 self.hideTimer.stop()
124 def unlockShow(self):
125 self.__locked = self.__locked - 1
127 self.startHideTimer()
129 # def startShow(self):
130 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
131 # self.__state = self.STATE_SHOWN
133 # def startHide(self):
134 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
135 # self.__state = self.STATE_HIDDEN
137 class NumberZap(Screen):
144 self.close(int(self["number"].getText()))
146 def keyNumberGlobal(self, number):
147 self.Timer.start(3000, True) #reset timer
148 self.field = self.field + str(number)
149 self["number"].setText(self.field)
150 if len(self.field) >= 4:
153 def __init__(self, session, number):
154 Screen.__init__(self, session)
155 self.field = str(number)
157 self["channel"] = Label(_("Channel:"))
159 self["number"] = Label(self.field)
161 self["actions"] = NumberActionMap( [ "SetupActions" ],
165 "1": self.keyNumberGlobal,
166 "2": self.keyNumberGlobal,
167 "3": self.keyNumberGlobal,
168 "4": self.keyNumberGlobal,
169 "5": self.keyNumberGlobal,
170 "6": self.keyNumberGlobal,
171 "7": self.keyNumberGlobal,
172 "8": self.keyNumberGlobal,
173 "9": self.keyNumberGlobal,
174 "0": self.keyNumberGlobal
177 self.Timer = eTimer()
178 self.Timer.timeout.get().append(self.keyOK)
179 self.Timer.start(3000, True)
181 class InfoBarNumberZap:
182 """ Handles an initial number for NumberZapping """
184 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
186 "1": self.keyNumberGlobal,
187 "2": self.keyNumberGlobal,
188 "3": self.keyNumberGlobal,
189 "4": self.keyNumberGlobal,
190 "5": self.keyNumberGlobal,
191 "6": self.keyNumberGlobal,
192 "7": self.keyNumberGlobal,
193 "8": self.keyNumberGlobal,
194 "9": self.keyNumberGlobal,
195 "0": self.keyNumberGlobal,
198 def keyNumberGlobal(self, number):
199 # print "You pressed number " + str(number)
201 if isinstance(self, InfoBarPiP) and self.pipHandles0Action():
202 self.pipDoHandle0Action()
204 self.servicelist.recallPrevService()
206 self.session.openWithCallback(self.numberEntered, NumberZap, number)
208 def numberEntered(self, retval):
209 # print self.servicelist
211 self.zapToNumber(retval)
213 def searchNumberHelper(self, serviceHandler, num, bouquet):
214 servicelist = serviceHandler.list(bouquet)
215 if not servicelist is None:
217 serviceIterator = servicelist.getNext()
218 if not serviceIterator.valid(): #check end of list
220 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
223 if not num: #found service with searched number ?
224 return serviceIterator, 0
227 def zapToNumber(self, number):
228 bouquet = self.servicelist.bouquet_root
230 serviceHandler = eServiceCenter.getInstance()
231 if not config.usage.multibouquet.value:
232 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
234 bouquetlist = serviceHandler.list(bouquet)
235 if not bouquetlist is None:
237 bouquet = bouquetlist.getNext()
238 if not bouquet.valid(): #check end of list
240 if bouquet.flags & eServiceReference.isDirectory:
241 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
242 if not service is None:
243 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
244 self.servicelist.clearPath()
245 if self.servicelist.bouquet_root != bouquet:
246 self.servicelist.enterPath(self.servicelist.bouquet_root)
247 self.servicelist.enterPath(bouquet)
248 self.servicelist.setCurrentSelection(service) #select the service in servicelist
249 self.servicelist.zap()
251 config.misc.initialchannelselection = ConfigBoolean(default = True)
253 class InfoBarChannelSelection:
254 """ ChannelSelection - handles the channelSelection dialog and the initial
255 channelChange actions which open the channelSelection dialog """
258 self.servicelist = self.session.instantiateDialog(ChannelSelection)
260 if config.misc.initialchannelselection.value:
261 self.onShown.append(self.firstRun)
263 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
265 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
266 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
267 "zapUp": (self.zapUp, _("previous channel")),
268 "zapDown": (self.zapDown, _("next channel")),
269 "historyBack": (self.historyBack, _("previous channel in history")),
270 "historyNext": (self.historyNext, _("next channel in history")),
271 "openServiceList": (self.openServiceList, _("open servicelist")),
274 def showTvChannelList(self, zap=False):
275 self.servicelist.setModeTv()
277 self.servicelist.zap()
278 self.session.execDialog(self.servicelist)
280 def showRadioChannelList(self, zap=False):
281 self.servicelist.setModeRadio()
283 self.servicelist.zap()
284 self.session.execDialog(self.servicelist)
287 self.onShown.remove(self.firstRun)
288 config.misc.initialchannelselection.value = False
289 config.misc.initialchannelselection.save()
290 self.switchChannelDown()
292 def historyBack(self):
293 self.servicelist.historyBack()
295 def historyNext(self):
296 self.servicelist.historyNext()
298 def switchChannelUp(self):
299 self.servicelist.moveUp()
300 self.session.execDialog(self.servicelist)
302 def switchChannelDown(self):
303 self.servicelist.moveDown()
304 self.session.execDialog(self.servicelist)
306 def openServiceList(self):
307 self.session.execDialog(self.servicelist)
310 if self.servicelist.inBouquet():
311 prev = self.servicelist.getCurrentSelection()
313 prev = prev.toString()
315 if config.usage.quickzap_bouquet_change.value:
316 if self.servicelist.atBegin():
317 self.servicelist.prevBouquet()
318 self.servicelist.moveUp()
319 cur = self.servicelist.getCurrentSelection()
320 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
323 self.servicelist.moveUp()
324 self.servicelist.zap()
327 if self.servicelist.inBouquet():
328 prev = self.servicelist.getCurrentSelection()
330 prev = prev.toString()
332 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
333 self.servicelist.nextBouquet()
335 self.servicelist.moveDown()
336 cur = self.servicelist.getCurrentSelection()
337 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
340 self.servicelist.moveDown()
341 self.servicelist.zap()
344 """ Handles a menu action, to open the (main) menu """
346 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
348 "mainMenu": (self.mainMenu, _("Enter main menu...")),
350 self.session.infobar = None
353 print "loading mainmenu XML..."
354 menu = mdom.childNodes[0]
355 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
357 self.session.infobar = self
358 # so we can access the currently active infobar from screens opened from within the mainmenu
359 # at the moment used from the SubserviceSelection
361 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
363 def mainMenuClosed(self, *val):
364 self.session.infobar = None
366 class InfoBarSimpleEventView:
367 """ Opens the Eventview for now/next """
369 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
371 "showEventInfo": (self.openEventView, _("show event details")),
374 def openEventView(self):
376 service = self.session.nav.getCurrentService()
377 ref = self.session.nav.getCurrentlyPlayingServiceReference()
378 info = service.info()
381 self.epglist.append(ptr)
384 self.epglist.append(ptr)
385 if len(self.epglist) > 0:
386 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
388 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
389 if len(self.epglist) > 1:
390 tmp = self.epglist[0]
391 self.epglist[0]=self.epglist[1]
393 setEvent(self.epglist[0])
396 """ EPG - Opens an EPG list when the showEPGList action fires """
398 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
400 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
403 self.is_now_next = False
405 self.bouquetSel = None
406 self.eventView = None
407 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
409 "showEventInfo": (self.openEventView, _("show EPG...")),
410 "showSingleServiceEPG": (self.openSingleServiceEPG, _("show single service EPG...")),
411 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
414 def showEventInfoWhenNotVisible(self):
421 def zapToService(self, service):
422 if not service is None:
423 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
424 self.servicelist.clearPath()
425 if self.servicelist.bouquet_root != self.epg_bouquet:
426 self.servicelist.enterPath(self.servicelist.bouquet_root)
427 self.servicelist.enterPath(self.epg_bouquet)
428 self.servicelist.setCurrentSelection(service) #select the service in servicelist
429 self.servicelist.zap()
431 def getBouquetServices(self, bouquet):
433 servicelist = eServiceCenter.getInstance().list(bouquet)
434 if not servicelist is None:
436 service = servicelist.getNext()
437 if not service.valid(): #check if end of list
439 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
441 services.append(ServiceReference(service))
444 def openBouquetEPG(self, bouquet, withCallback=True):
445 services = self.getBouquetServices(bouquet)
447 self.epg_bouquet = bouquet
449 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
451 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
453 def changeBouquetCB(self, direction, epg):
456 self.bouquetSel.down()
459 bouquet = self.bouquetSel.getCurrent()
460 services = self.getBouquetServices(bouquet)
462 self.epg_bouquet = bouquet
463 epg.setServices(services)
465 def closed(self, ret=False):
466 closedScreen = self.dlg_stack.pop()
467 if self.bouquetSel and closedScreen == self.bouquetSel:
468 self.bouquetSel = None
469 elif self.eventView and closedScreen == self.eventView:
470 self.eventView = None
472 dlgs=len(self.dlg_stack)
474 self.dlg_stack[dlgs-1].close(dlgs > 1)
476 def openMultiServiceEPG(self, withCallback=True):
477 bouquets = self.servicelist.getBouquetList()
482 if cnt > 1: # show bouquet list
484 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
485 self.dlg_stack.append(self.bouquetSel)
487 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
489 self.openBouquetEPG(bouquets[0][1], withCallback)
491 def openSingleServiceEPG(self):
492 ref=self.session.nav.getCurrentlyPlayingServiceReference()
493 self.session.open(EPGSelection, ref)
495 def openSimilarList(self, eventid, refstr):
496 self.session.open(EPGSelection, refstr, None, eventid)
498 def getNowNext(self):
500 service = self.session.nav.getCurrentService()
501 info = service and service.info()
502 ptr = info and info.getEvent(0)
504 self.epglist.append(ptr)
505 ptr = info and info.getEvent(1)
507 self.epglist.append(ptr)
509 def __evEventInfoChanged(self):
510 if self.is_now_next and len(self.dlg_stack) == 1:
512 assert self.eventView
513 if len(self.epglist):
514 self.eventView.setEvent(self.epglist[0])
516 def openEventView(self):
517 ref = self.session.nav.getCurrentlyPlayingServiceReference()
519 if len(self.epglist) == 0:
520 self.is_now_next = False
521 epg = eEPGCache.getInstance()
522 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
524 self.epglist.append(ptr)
525 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
527 self.epglist.append(ptr)
529 self.is_now_next = True
530 if len(self.epglist) > 0:
531 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
532 self.dlg_stack.append(self.eventView)
534 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
535 self.openMultiServiceEPG(False)
537 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
538 if len(self.epglist) > 1:
539 tmp = self.epglist[0]
540 self.epglist[0]=self.epglist[1]
542 setEvent(self.epglist[0])
545 """provides a snr/agc/ber display"""
547 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
550 """provides a current/next event info display"""
552 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
553 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
555 class InfoBarRdsDecoder:
556 """provides RDS and Rass support/display"""
558 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
559 self.rass_interactive = None
561 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
563 iPlayableService.evEnd: self.__serviceStopped,
564 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
567 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
569 "startRassInteractive": self.startRassInteractive
572 self["RdsActions"].setEnabled(False)
574 self.onLayoutFinish.append(self.rds_display.show)
575 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
577 def RassInteractivePossibilityChanged(self, state):
578 self["RdsActions"].setEnabled(state)
580 def RassSlidePicChanged(self):
581 if not self.rass_interactive:
582 service = self.session.nav.getCurrentService()
583 decoder = service and service.rdsDecoder()
585 decoder.showRassSlidePicture()
587 def __serviceStopped(self):
588 if self.rass_interactive is not None:
589 rass_interactive = self.rass_interactive
590 self.rass_interactive = None
591 rass_interactive.close()
593 def startRassInteractive(self):
594 self.rds_display.hide()
595 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
597 def RassInteractiveClosed(self, *val):
598 if self.rass_interactive is not None:
599 self.rass_interactive = None
600 self.RassSlidePicChanged()
601 self.rds_display.show()
603 class InfoBarServiceName:
605 self["CurrentService"] = CurrentService(self.session.nav)
608 """handles actions like seeking, pause"""
610 # ispause, isff, issm
611 SEEK_STATE_PLAY = (0, 0, 0, ">")
612 SEEK_STATE_PAUSE = (1, 0, 0, "||")
613 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
614 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
615 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
616 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
617 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
618 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
620 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
621 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
622 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
623 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
625 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
626 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
627 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
629 SEEK_STATE_EOF = (1, 0, 0, "END")
631 def __init__(self, actionmap = "InfobarSeekActions"):
632 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
634 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
635 iPlayableService.evStart: self.__serviceStarted,
637 iPlayableService.evEOF: self.__evEOF,
638 iPlayableService.evSOF: self.__evSOF,
641 class InfoBarSeekActionMap(HelpableActionMap):
642 def __init__(self, screen, *args, **kwargs):
643 HelpableActionMap.__init__(self, screen, *args, **kwargs)
646 def action(self, contexts, action):
647 print "action:", action
648 if action[:5] == "seek:":
649 time = int(action[5:])
650 self.screen.seekRelative(time * 90000)
651 self.screen.showAfterSeek()
654 return HelpableActionMap.action(self, contexts, action)
656 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
658 "playpauseService": self.playpauseService,
659 "pauseService": (self.pauseService, _("pause")),
660 "unPauseService": (self.unPauseService, _("continue")),
662 "seekFwd": (self.seekFwd, _("skip forward")),
663 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
664 "seekBack": (self.seekBack, _("skip backward")),
665 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
667 "seekFwdDef": (self.seekFwdDef, _("skip forward (self defined)")),
668 "seekBackDef": (self.seekBackDef, _("skip backward (self defined)"))
670 # give them a little more priority to win over color buttons
672 self["SeekActions"].setEnabled(False)
674 self.seekstate = self.SEEK_STATE_PLAY
676 self.seek_flag = True
678 self.onPlayStateChanged = [ ]
680 self.lockedBecauseOfSkipping = False
682 self.__seekableStatusChanged()
684 def showAfterSeek(self):
685 if isinstance(self, InfoBarShowHide):
695 service = self.session.nav.getCurrentService()
699 seek = service.seek()
701 if seek is None or not seek.isCurrentlySeekable():
706 def isSeekable(self):
707 if self.getSeek() is None:
711 def __seekableStatusChanged(self):
712 print "seekable status changed!"
713 if not self.isSeekable():
714 self["SeekActions"].setEnabled(False)
715 print "not seekable, return to play"
716 self.setSeekState(self.SEEK_STATE_PLAY)
718 self["SeekActions"].setEnabled(True)
721 def __serviceStarted(self):
722 self.seekstate = self.SEEK_STATE_PLAY
723 self.__seekableStatusChanged()
725 def setSeekState(self, state):
726 service = self.session.nav.getCurrentService()
731 if not self.isSeekable():
732 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
733 state = self.SEEK_STATE_PLAY
735 pauseable = service.pause()
737 if pauseable is None:
738 print "not pauseable."
739 state = self.SEEK_STATE_PLAY
741 oldstate = self.seekstate
742 self.seekstate = state
745 if oldstate[i] != self.seekstate[i]:
746 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
748 for c in self.onPlayStateChanged:
751 self.checkSkipShowHideLock()
755 def playpauseService(self):
756 if self.seekstate != self.SEEK_STATE_PLAY:
757 self.unPauseService()
761 def pauseService(self):
762 if self.seekstate == self.SEEK_STATE_PAUSE:
763 print "pause, but in fact unpause"
764 self.unPauseService()
766 if self.seekstate == self.SEEK_STATE_PLAY:
767 print "yes, playing."
769 print "no", self.seekstate
771 self.setSeekState(self.SEEK_STATE_PAUSE);
773 def unPauseService(self):
775 if self.seekstate == self.SEEK_STATE_PLAY:
777 self.setSeekState(self.SEEK_STATE_PLAY)
779 def doSeek(self, seektime):
780 print "doseek", seektime
781 service = self.session.nav.getCurrentService()
785 seekable = self.getSeek()
789 seekable.seekTo(90 * seektime)
793 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
794 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
795 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
796 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
797 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
798 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
799 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
800 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
801 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
802 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
803 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
804 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
805 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
806 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
807 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
808 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
810 self.setSeekState(lookup[self.seekstate])
814 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
815 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
816 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
817 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
818 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
819 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
820 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
821 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
822 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
823 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
824 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
825 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
826 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
827 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
828 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
829 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
831 self.setSeekState(lookup[self.seekstate])
833 if self.seekstate == self.SEEK_STATE_PAUSE:
834 seekable = self.getSeek()
835 if seekable is not None:
836 seekable.seekRelative(-1, 3)
838 def seekFwdDef(self):
839 self.seek_flag = False
840 seconds = config.usage.self_defined_seek.value
841 print "Seek", seconds, "seconds self defined forward"
842 seekable = self.getSeek()
843 if seekable is not None:
844 seekable.seekRelative(1, seconds * 90000)
846 def seekBackDef(self):
847 self.seek_flag = False
848 seconds = config.usage.self_defined_seek.value
849 print "Seek", seconds, "seconds self defined backward"
850 seekable = self.getSeek()
851 if seekable is not None:
852 seekable.seekRelative(1, 0 - seconds * 90000)
854 def seekFwdManual(self):
855 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
857 def fwdSeekTo(self, minutes):
858 print "Seek", minutes, "minutes forward"
860 seekable = self.getSeek()
861 if seekable is not None:
862 seekable.seekRelative(1, minutes * 60 * 90000)
864 def seekBackManual(self):
865 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
867 def rwdSeekTo(self, minutes):
869 self.fwdSeekTo(0 - minutes)
871 def checkSkipShowHideLock(self):
872 wantlock = self.seekstate != self.SEEK_STATE_PLAY
874 if config.usage.show_infobar_on_zap.value:
875 if self.lockedBecauseOfSkipping and not wantlock:
877 self.lockedBecauseOfSkipping = False
879 if wantlock and not self.lockedBecauseOfSkipping:
881 self.lockedBecauseOfSkipping = True
884 if self.seekstate == self.SEEK_STATE_EOF:
886 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
887 print "end of stream while seeking back, ignoring."
890 # if we are seeking, we try to end up ~1s before the end, and pause there.
891 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
892 self.setSeekState(self.SEEK_STATE_EOF)
893 self.seekRelativeToEnd(-90000)
895 self.setSeekState(self.SEEK_STATE_EOF)
898 self.setSeekState(self.SEEK_STATE_PLAY)
901 def seekRelative(self, diff):
902 if self.seek_flag == True:
903 seekable = self.getSeek()
904 if seekable is not None:
905 print "seekRelative: res:", seekable.seekRelative(1, diff)
909 self.seek_flag = True
911 def seekRelativeToEnd(self, diff):
912 assert diff <= 0, "diff is expected to be negative!"
914 # might sound like an evil hack, but:
915 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
916 # and we don't get that by passing 0 here (it would seek to begin).
920 # relative-to-end seeking is implemented as absolutes seeks with negative time
921 self.seekAbsolute(diff)
923 def seekAbsolute(self, abs):
924 seekable = self.getSeek()
925 if seekable is not None:
928 from Screens.PVRState import PVRState, TimeshiftState
930 class InfoBarPVRState:
931 def __init__(self, screen=PVRState):
932 self.onPlayStateChanged.append(self.__playStateChanged)
933 self.pvrStateDialog = self.session.instantiateDialog(screen)
934 self.onShow.append(self._mayShow)
935 self.onHide.append(self.pvrStateDialog.hide)
938 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
939 self.pvrStateDialog.show()
941 def __playStateChanged(self, state):
942 playstateString = state[3]
943 self.pvrStateDialog["state"].setText(playstateString)
946 class InfoBarTimeshiftState(InfoBarPVRState):
948 InfoBarPVRState.__init__(self, screen=TimeshiftState)
951 if self.execing and self.timeshift_enabled:
952 self.pvrStateDialog.show()
954 class InfoBarShowMovies:
956 # i don't really like this class.
957 # it calls a not further specified "movie list" on up/down/movieList,
958 # so this is not more than an action map
960 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
962 "movieList": (self.showMovies, _("movie list")),
963 "up": (self.showMovies, _("movie list")),
964 "down": (self.showMovies, _("movie list"))
967 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
971 # Timeshift works the following way:
972 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
973 # - normal playback TUNER unused PLAY enable disable disable
974 # - user presses "yellow" button. FILE record PAUSE enable disable enable
975 # - user presess pause again FILE record PLAY enable disable enable
976 # - user fast forwards FILE record FF enable disable enable
977 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
978 # - user backwards FILE record BACK # !! enable disable enable
982 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
983 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
984 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
985 # - the user can now PVR around
986 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
987 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
989 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
990 # - if the user rewinds, or press pause, timeshift will be activated again
992 # note that a timeshift can be enabled ("recording") and
993 # activated (currently time-shifting).
995 class InfoBarTimeshift:
997 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
999 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1000 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1002 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1004 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1005 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1006 }, prio=-1) # priority over record
1008 self.timeshift_enabled = 0
1009 self.timeshift_state = 0
1010 self.ts_rewind_timer = eTimer()
1011 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1013 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1015 iPlayableService.evStart: self.__serviceStarted,
1016 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1019 def getTimeshift(self):
1020 service = self.session.nav.getCurrentService()
1021 return service and service.timeshift()
1023 def startTimeshift(self):
1024 print "enable timeshift"
1025 ts = self.getTimeshift()
1027 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1028 print "no ts interface"
1031 if self.timeshift_enabled:
1032 print "hu, timeshift already enabled?"
1034 if not ts.startTimeshift():
1035 self.timeshift_enabled = 1
1037 # we remove the "relative time" for now.
1038 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1041 #self.setSeekState(self.SEEK_STATE_PAUSE)
1042 self.activateTimeshiftEnd(False)
1044 # enable the "TimeshiftEnableActions", which will override
1045 # the startTimeshift actions
1046 self.__seekableStatusChanged()
1048 print "timeshift failed"
1050 def stopTimeshift(self):
1051 if not self.timeshift_enabled:
1053 print "disable timeshift"
1054 ts = self.getTimeshift()
1057 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1059 def stopTimeshiftConfirmed(self, confirmed):
1063 ts = self.getTimeshift()
1068 self.timeshift_enabled = 0
1071 self.__seekableStatusChanged()
1073 # activates timeshift, and seeks to (almost) the end
1074 def activateTimeshiftEnd(self, back = True):
1075 ts = self.getTimeshift()
1076 print "activateTimeshiftEnd"
1081 if ts.isTimeshiftActive():
1082 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1086 ts.activateTimeshift() # activate timeshift will automatically pause
1087 self.setSeekState(self.SEEK_STATE_PAUSE)
1088 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1091 self.ts_rewind_timer.start(200, 1)
1093 def rewindService(self):
1094 self.setSeekState(self.SEEK_STATE_BACK_16X)
1096 # same as activateTimeshiftEnd, but pauses afterwards.
1097 def activateTimeshiftEndAndPause(self):
1098 print "activateTimeshiftEndAndPause"
1099 #state = self.seekstate
1100 self.activateTimeshiftEnd(False)
1102 def __seekableStatusChanged(self):
1105 print "self.isSeekable", self.isSeekable()
1106 print "self.timeshift_enabled", self.timeshift_enabled
1108 # when this service is not seekable, but timeshift
1109 # is enabled, this means we can activate
1111 if not self.isSeekable() and self.timeshift_enabled:
1114 print "timeshift activate:", enabled
1115 self["TimeshiftActivateActions"].setEnabled(enabled)
1117 def __serviceStarted(self):
1118 self.timeshift_enabled = False
1119 self.__seekableStatusChanged()
1121 from Screens.PiPSetup import PiPSetup
1123 class InfoBarExtensions:
1124 EXTENSION_SINGLE = 0
1130 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1132 "extensions": (self.showExtensionSelection, _("view extensions...")),
1135 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1136 self.list.append((type, extension, key))
1138 def updateExtension(self, extension, key = None):
1139 self.extensionsList.append(extension)
1141 if self.extensionKeys.has_key(key):
1145 for x in self.availableKeys:
1146 if not self.extensionKeys.has_key(x):
1151 self.extensionKeys[key] = len(self.extensionsList) - 1
1153 def updateExtensions(self):
1154 self.extensionsList = []
1155 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1156 self.extensionKeys = {}
1158 if x[0] == self.EXTENSION_SINGLE:
1159 self.updateExtension(x[1], x[2])
1162 self.updateExtension(y[0], y[1])
1165 def showExtensionSelection(self):
1166 self.updateExtensions()
1167 extensionsList = self.extensionsList[:]
1170 for x in self.availableKeys:
1171 if self.extensionKeys.has_key(x):
1172 entry = self.extensionKeys[x]
1173 extension = self.extensionsList[entry]
1175 name = str(extension[0]())
1176 list.append((extension[0](), extension))
1178 extensionsList.remove(extension)
1180 extensionsList.remove(extension)
1181 for x in extensionsList:
1182 list.append((x[0](), x))
1183 keys += [""] * len(extensionsList)
1184 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1186 def extensionCallback(self, answer):
1187 if answer is not None:
1190 from Tools.BoundFunction import boundFunction
1192 # depends on InfoBarExtensions
1193 from Components.PluginComponent import plugins
1195 class InfoBarPlugins:
1197 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1199 def getPluginName(self, name):
1202 def getPluginList(self):
1204 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1205 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1208 def runPlugin(self, plugin):
1209 plugin(session = self.session, servicelist = self.servicelist)
1211 # depends on InfoBarExtensions
1212 class InfoBarSleepTimer:
1214 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1216 def available(self):
1219 def getSleepTimerName(self):
1220 return _("Sleep Timer")
1222 def showSleepTimerSetup(self):
1223 self.session.open(SleepTimerEdit)
1225 # depends on InfoBarExtensions
1228 self.session.pipshown = False
1230 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1231 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1232 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1234 def available(self):
1238 return self.session.pipshown
1240 def pipHandles0Action(self):
1241 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1243 def getShowHideName(self):
1244 if self.session.pipshown:
1245 return _("Disable Picture in Picture")
1247 return _("Activate Picture in Picture")
1249 def getSwapName(self):
1250 return _("Swap Services")
1252 def getMoveName(self):
1253 return _("Move Picture in Picture")
1256 if self.session.pipshown:
1257 del self.session.pip
1258 self.session.pipshown = False
1260 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1261 self.session.pip.show()
1262 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1263 if self.session.pip.playService(newservice):
1264 self.session.pipshown = True
1265 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1267 self.session.pipshown = False
1268 del self.session.pip
1269 self.session.nav.playService(newservice)
1272 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1273 if self.session.pip.servicePath:
1274 servicepath = self.servicelist.getCurrentServicePath()
1275 ref=servicepath[len(servicepath)-1]
1276 pipref=self.session.pip.getCurrentService()
1277 self.session.pip.playService(swapservice)
1278 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1279 if pipref.toString() != ref.toString(): # is a subservice ?
1280 self.session.nav.stopService() # stop portal
1281 self.session.nav.playService(pipref) # start subservice
1282 self.session.pip.servicePath=servicepath
1285 self.session.open(PiPSetup, pip = self.session.pip)
1287 def pipDoHandle0Action(self):
1288 use = config.usage.pip_zero_button.value
1291 elif "swapstop" == use:
1297 from RecordTimer import parseEvent
1299 class InfoBarInstantRecord:
1300 """Instant Record - handles the instantRecord action in order to
1301 start/stop instant records"""
1303 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1305 "instantRecord": (self.instantRecord, _("Instant Record...")),
1308 self["BlinkingPoint"] = BlinkingPixmapConditional()
1309 self["BlinkingPoint"].hide()
1310 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1312 def stopCurrentRecording(self, entry = -1):
1313 if entry is not None and entry != -1:
1314 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1315 self.recording.remove(self.recording[entry])
1317 def startInstantRecording(self, limitEvent = False):
1318 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1320 # try to get event info
1323 service = self.session.nav.getCurrentService()
1324 epg = eEPGCache.getInstance()
1325 event = epg.lookupEventTime(serviceref, -1, 0)
1327 info = service.info()
1328 ev = info.getEvent(0)
1334 end = time() + 3600 * 10
1335 name = "instant record"
1339 if event is not None:
1340 curEvent = parseEvent(event)
1342 description = curEvent[3]
1343 eventid = curEvent[4]
1348 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1350 data = (begin, end, name, description, eventid)
1352 recording = self.session.nav.recordWithTimer(serviceref, *data)
1353 recording.dontSave = True
1354 self.recording.append(recording)
1356 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1358 def isInstantRecordRunning(self):
1359 print "self.recording:", self.recording
1360 if len(self.recording) > 0:
1361 for x in self.recording:
1366 def recordQuestionCallback(self, answer):
1367 print "pre:\n", self.recording
1369 if answer is None or answer[1] == "no":
1372 recording = self.recording[:]
1374 if not x in self.session.nav.RecordTimer.timer_list:
1375 self.recording.remove(x)
1376 elif x.dontSave and x.isRunning():
1377 list.append((x, False))
1379 if answer[1] == "changeduration":
1380 if len(self.recording) == 1:
1381 self.changeDuration(0)
1383 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1384 elif answer[1] == "changeendtime":
1385 if len(self.recording) == 1:
1388 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1389 elif answer[1] == "stop":
1390 if len(self.recording) == 1:
1391 self.stopCurrentRecording(0)
1393 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1394 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1395 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1396 if answer[1] == "manualduration":
1397 self.changeDuration(len(self.recording)-1)
1398 elif answer[1] == "manualendtime":
1399 self.setEndtime(len(self.recording)-1)
1400 print "after:\n", self.recording
1402 def setEndtime(self, entry):
1403 if entry is not None:
1404 self.selectedEntry = entry
1405 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1406 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1407 dlg.setTitle(_("Please change recording endtime"))
1409 def TimeDateInputClosed(self, ret):
1412 localendtime = localtime(ret[1])
1413 print "stopping recording at", strftime("%c", localendtime)
1414 self.recording[self.selectedEntry].end = ret[1]
1415 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1417 def changeDuration(self, entry):
1418 if entry is not None:
1419 self.selectedEntry = entry
1420 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1422 def inputCallback(self, value):
1423 if value is not None:
1424 print "stopping recording after", int(value), "minutes."
1425 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1426 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1428 def instantRecord(self):
1430 stat = os_stat(resolveFilename(SCOPE_HDD))
1432 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1435 if self.isInstantRecordRunning():
1436 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1437 title=_("A recording is currently running.\nWhat do you want to do?"), \
1438 list=[(_("stop recording"), "stop"), \
1439 (_("change recording (duration)"), "changeduration"), \
1440 (_("change recording (endtime)"), "changeendtime"), \
1441 (_("add recording (indefinitely)"), "indefinitely"), \
1442 (_("add recording (stop after current event)"), "event"), \
1443 (_("add recording (enter recording duration)"), "manualduration"), \
1444 (_("add recording (enter recording endtime)"), "manualendtime"), \
1445 (_("do nothing"), "no")])
1447 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1448 title=_("Start recording?"), \
1449 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1450 (_("add recording (stop after current event)"), "event"), \
1451 (_("add recording (enter recording duration)"), "manualduration"), \
1452 (_("add recording (enter recording endtime)"), "manualendtime"), \
1453 (_("don't record"), "no")])
1455 from Tools.ISO639 import LanguageCodes
1457 class InfoBarAudioSelection:
1459 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1461 "audioSelection": (self.audioSelection, _("Audio Options...")),
1464 def audioSelection(self):
1465 service = self.session.nav.getCurrentService()
1466 audio = service and service.audioTracks()
1467 self.audioTracks = audio
1468 n = audio and audio.getNumberOfTracks() or 0
1469 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1472 self.audioChannel = service.audioChannel()
1475 i = audio.getTrackInfo(x)
1476 language = i.getLanguage()
1477 description = i.getDescription()
1479 if LanguageCodes.has_key(language):
1480 language = LanguageCodes[language][0]
1482 if len(description):
1483 description += " (" + language + ")"
1485 description = language
1487 tlist.append((description, x))
1489 selectedAudio = audio.getCurrentTrack()
1490 tlist.sort(key=lambda x: x[0])
1494 if x[1] != selectedAudio:
1499 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1500 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1502 del self.audioTracks
1504 def audioSelected(self, audio):
1505 if audio is not None:
1506 if isinstance(audio[1], str):
1507 if audio[1] == "mode":
1508 keys = ["red", "green", "yellow"]
1509 selection = self.audioChannel.getCurrentChannel()
1510 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1511 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1513 del self.audioChannel
1514 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1515 self.audioTracks.selectTrack(audio[1])
1517 del self.audioChannel
1518 del self.audioTracks
1520 def modeSelected(self, mode):
1521 if mode is not None:
1522 self.audioChannel.selectChannel(mode[1])
1523 del self.audioChannel
1525 class InfoBarSubserviceSelection:
1527 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1529 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1532 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1534 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1535 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1537 self["SubserviceQuickzapAction"].setEnabled(False)
1539 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1543 def checkSubservicesAvail(self, ev):
1544 if ev == iPlayableService.evUpdatedEventInfo:
1545 service = self.session.nav.getCurrentService()
1546 subservices = service and service.subServices()
1547 if not subservices or subservices.getNumberOfSubservices() == 0:
1548 self["SubserviceQuickzapAction"].setEnabled(False)
1550 def nextSubservice(self):
1551 self.changeSubservice(+1)
1553 def prevSubservice(self):
1554 self.changeSubservice(-1)
1556 def changeSubservice(self, direction):
1557 service = self.session.nav.getCurrentService()
1558 subservices = service and service.subServices()
1559 n = subservices and subservices.getNumberOfSubservices()
1562 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1564 if subservices.getSubservice(x).toString() == ref.toString():
1567 selection += direction
1572 newservice = subservices.getSubservice(selection)
1573 if newservice.valid():
1576 self.session.nav.playService(newservice)
1578 def subserviceSelection(self):
1579 service = self.session.nav.getCurrentService()
1580 subservices = service and service.subServices()
1581 self.bouquets = self.servicelist.getBouquetList()
1582 n = subservices and subservices.getNumberOfSubservices()
1585 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1588 i = subservices.getSubservice(x)
1589 if i.toString() == ref.toString():
1591 tlist.append((i.getName(), i))
1593 if self.bouquets and len(self.bouquets):
1594 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1595 if config.usage.multibouquet.value:
1596 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1598 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1601 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1602 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1605 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1607 def subserviceSelected(self, service):
1609 if not service is None:
1610 if isinstance(service[1], str):
1611 if service[1] == "quickzap":
1612 from Screens.SubservicesQuickzap import SubservicesQuickzap
1613 self.session.open(SubservicesQuickzap, service[2])
1615 self["SubserviceQuickzapAction"].setEnabled(True)
1616 self.session.nav.playService(service[1])
1618 def addSubserviceToBouquetCallback(self, service):
1619 if len(service) > 1 and isinstance(service[1], eServiceReference):
1620 self.selectedSubservice = service
1621 if self.bouquets is None:
1624 cnt = len(self.bouquets)
1625 if cnt > 1: # show bouquet list
1626 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1627 elif cnt == 1: # add to only one existing bouquet
1628 self.addSubserviceToBouquet(self.bouquets[0][1])
1629 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1631 def bouquetSelClosed(self, confirmed):
1633 del self.selectedSubservice
1635 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1637 def addSubserviceToBouquet(self, dest):
1638 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1640 self.bsel.close(True)
1642 del self.selectedSubservice
1644 class InfoBarAdditionalInfo:
1646 self["NimA"] = Pixmap()
1647 self["NimB"] = Pixmap()
1648 self["NimA_Active"] = Pixmap()
1649 self["NimB_Active"] = Pixmap()
1651 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1652 self["TimeshiftPossible"] = self["RecordingPossible"]
1653 self["ExtensionsAvailable"] = Boolean(fixed=1)
1655 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1656 res_mgr = eDVBResourceManager.getInstance()
1658 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1660 def tunerUseMaskChanged(self, mask):
1662 self["NimA_Active"].show()
1664 self["NimA_Active"].hide()
1666 self["NimB_Active"].show()
1668 self["NimB_Active"].hide()
1670 def checkTunerState(self, service):
1671 info = service and service.frontendInfo()
1672 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1673 if feNumber is None:
1683 def gotServiceEvent(self, ev):
1684 service = self.session.nav.getCurrentService()
1685 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1686 self.checkTunerState(service)
1688 class InfoBarNotifications:
1690 self.onExecBegin.append(self.checkNotifications)
1691 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1692 self.onClose.append(self.__removeNotification)
1694 def __removeNotification(self):
1695 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1697 def checkNotificationsIfExecing(self):
1699 self.checkNotifications()
1701 def checkNotifications(self):
1702 if len(Notifications.notifications):
1703 n = Notifications.notifications[0]
1705 Notifications.notifications = Notifications.notifications[1:]
1708 if n[3].has_key("onSessionOpenCallback"):
1709 n[3]["onSessionOpenCallback"]()
1710 del n[3]["onSessionOpenCallback"]
1713 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1715 dlg = self.session.open(n[1], *n[2], **n[3])
1717 # remember that this notification is currently active
1719 Notifications.current_notifications.append(d)
1720 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1722 def __notificationClosed(self, d):
1723 Notifications.current_notifications.remove(d)
1725 class InfoBarServiceNotifications:
1727 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1729 iPlayableService.evEnd: self.serviceHasEnded
1732 def serviceHasEnded(self):
1733 print "service end!"
1736 self.setSeekState(self.SEEK_STATE_PLAY)
1740 class InfoBarCueSheetSupport:
1746 ENABLE_RESUME_SUPPORT = False
1748 def __init__(self, actionmap = "InfobarCueSheetActions"):
1749 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1751 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1752 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1753 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1757 self.is_closing = False
1758 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1760 iPlayableService.evStart: self.__serviceStarted,
1763 def __serviceStarted(self):
1766 print "new service started! trying to download cuts!"
1767 self.downloadCuesheet()
1769 if self.ENABLE_RESUME_SUPPORT:
1772 for (pts, what) in self.cut_list:
1773 if what == self.CUT_TYPE_LAST:
1776 if last is not None:
1777 self.resume_point = last
1778 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1780 def playLastCB(self, answer):
1782 seekable = self.__getSeekable()
1783 if seekable is not None:
1784 seekable.seekTo(self.resume_point)
1785 self.hideAfterResume()
1787 def hideAfterResume(self):
1788 if isinstance(self, InfoBarShowHide):
1791 def __getSeekable(self):
1792 service = self.session.nav.getCurrentService()
1795 return service.seek()
1797 def cueGetCurrentPosition(self):
1798 seek = self.__getSeekable()
1801 r = seek.getPlayPosition()
1806 def jumpPreviousNextMark(self, cmp, alternative=None):
1807 current_pos = self.cueGetCurrentPosition()
1808 if current_pos is None:
1810 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1811 if mark is not None:
1813 elif alternative is not None:
1818 seekable = self.__getSeekable()
1819 if seekable is not None:
1820 seekable.seekTo(pts)
1822 def jumpPreviousMark(self):
1823 # we add 2 seconds, so if the play position is <2s after
1824 # the mark, the mark before will be used
1825 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1827 def jumpNextMark(self):
1828 self.jumpPreviousNextMark(lambda x: x)
1830 def getNearestCutPoint(self, pts, cmp=abs):
1833 for cp in self.cut_list:
1834 diff = cmp(cp[0] - pts)
1835 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1839 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1840 current_pos = self.cueGetCurrentPosition()
1841 if current_pos is None:
1842 print "not seekable"
1845 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1847 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1849 return nearest_cutpoint
1851 self.removeMark(nearest_cutpoint)
1852 elif not onlyremove and not onlyreturn:
1853 self.addMark((current_pos, self.CUT_TYPE_MARK))
1858 def addMark(self, point):
1859 insort(self.cut_list, point)
1860 self.uploadCuesheet()
1861 self.showAfterCuesheetOperation()
1863 def removeMark(self, point):
1864 self.cut_list.remove(point)
1865 self.uploadCuesheet()
1866 self.showAfterCuesheetOperation()
1868 def showAfterCuesheetOperation(self):
1869 if isinstance(self, InfoBarShowHide):
1872 def __getCuesheet(self):
1873 service = self.session.nav.getCurrentService()
1876 return service.cueSheet()
1878 def uploadCuesheet(self):
1879 cue = self.__getCuesheet()
1882 print "upload failed, no cuesheet interface"
1884 cue.setCutList(self.cut_list)
1886 def downloadCuesheet(self):
1887 cue = self.__getCuesheet()
1890 print "download failed, no cuesheet interface"
1893 self.cut_list = cue.getCutList()
1895 class InfoBarSummary(Screen):
1897 <screen position="0,0" size="132,64">
1898 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1899 <convert type="ClockToText">WithSeconds</convert>
1901 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1902 <convert type="ServiceName">Name</convert>
1906 def __init__(self, session, parent):
1907 Screen.__init__(self, session)
1908 self["CurrentService"] = CurrentService(self.session.nav)
1909 self["CurrentTime"] = Clock()
1911 class InfoBarSummarySupport:
1915 def createSummary(self):
1916 return InfoBarSummary
1918 class InfoBarTeletextPlugin:
1920 self.teletext_plugin = None
1922 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1923 self.teletext_plugin = p
1925 if self.teletext_plugin is not None:
1926 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1928 "startTeletext": (self.startTeletext, _("View teletext..."))
1931 print "no teletext plugin found!"
1933 def startTeletext(self):
1934 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1936 class InfoBarSubtitleSupport(object):
1938 object.__init__(self)
1939 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1940 self.__subtitles_enabled = False
1942 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1944 iPlayableService.evEnd: self.__serviceStopped,
1945 iPlayableService.evUpdatedInfo: self.__updatedInfo
1947 self.cached_subtitle_checked = False
1948 self.__selected_subtitle = None
1950 def __serviceStopped(self):
1951 self.subtitle_window.hide()
1952 self.__subtitles_enabled = False
1953 self.cached_subtitle_checked = False
1955 def __updatedInfo(self):
1956 if not self.cached_subtitle_checked:
1957 subtitle = self.getCurrentServiceSubtitle()
1958 self.cached_subtitle_checked = True
1959 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1960 if self.__selected_subtitle:
1961 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1962 self.subtitle_window.show()
1963 self.__subtitles_enabled = True
1965 def getCurrentServiceSubtitle(self):
1966 service = self.session.nav.getCurrentService()
1967 return service and service.subtitle()
1969 def setSubtitlesEnable(self, enable=True):
1970 subtitle = self.getCurrentServiceSubtitle()
1971 if enable and self.__selected_subtitle is not None:
1972 if subtitle and not self.__subtitles_enabled:
1973 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1974 self.subtitle_window.show()
1975 self.__subtitles_enabled = True
1978 subtitle.disableSubtitles(self.subtitle_window.instance)
1979 self.__subtitles_enabled = False
1980 self.subtitle_window.hide()
1982 def setSelectedSubtitle(self, subtitle):
1983 self.__selected_subtitle = subtitle
1985 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1986 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1988 class InfoBarServiceErrorPopupSupport:
1990 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1992 iPlayableService.evTuneFailed: self.__tuneFailed,
1993 iPlayableService.evStart: self.__serviceStarted
1995 self.__serviceStarted()
1997 def __serviceStarted(self):
1998 self.last_error = None
1999 Notifications.RemovePopup(id = "ZapError")
2001 def __tuneFailed(self):
2002 service = self.session.nav.getCurrentService()
2003 info = service and service.info()
2004 error = info and info.getInfo(iServiceInformation.sDVBState)
2006 if error == self.last_error:
2009 self.last_error = error
2012 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2013 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2014 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2015 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2016 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2017 eDVBServicePMTHandler.eventNewProgramInfo: None,
2018 eDVBServicePMTHandler.eventTuned: None,
2019 eDVBServicePMTHandler.eventSOF: None,
2020 eDVBServicePMTHandler.eventEOF: None
2023 error = errors.get(error) #this returns None when the key not exist in the dict
2025 if error is not None:
2026 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2028 Notifications.RemovePopup(id = "ZapError")