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 if config.usage.show_infobar_on_skip.value:
652 self.screen.showAfterSeek()
655 return HelpableActionMap.action(self, contexts, action)
657 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
659 "playpauseService": self.playpauseService,
660 "pauseService": (self.pauseService, _("pause")),
661 "unPauseService": (self.unPauseService, _("continue")),
663 "seekFwd": (self.seekFwd, _("skip forward")),
664 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
665 "seekBack": (self.seekBack, _("skip backward")),
666 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
668 "seekFwdDef": (self.seekFwdDef, _("skip forward (self defined)")),
669 "seekBackDef": (self.seekBackDef, _("skip backward (self defined)"))
671 # give them a little more priority to win over color buttons
673 self["SeekActions"].setEnabled(False)
675 self.seekstate = self.SEEK_STATE_PLAY
677 self.seek_flag = True
679 self.onPlayStateChanged = [ ]
681 self.lockedBecauseOfSkipping = False
683 self.__seekableStatusChanged()
685 def showAfterSeek(self):
686 if isinstance(self, InfoBarShowHide):
696 service = self.session.nav.getCurrentService()
700 seek = service.seek()
702 if seek is None or not seek.isCurrentlySeekable():
707 def isSeekable(self):
708 if self.getSeek() is None:
712 def __seekableStatusChanged(self):
713 print "seekable status changed!"
714 if not self.isSeekable():
715 self["SeekActions"].setEnabled(False)
716 print "not seekable, return to play"
717 self.setSeekState(self.SEEK_STATE_PLAY)
719 self["SeekActions"].setEnabled(True)
722 def __serviceStarted(self):
723 self.seekstate = self.SEEK_STATE_PLAY
724 self.__seekableStatusChanged()
726 def setSeekState(self, state):
727 service = self.session.nav.getCurrentService()
732 if not self.isSeekable():
733 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
734 state = self.SEEK_STATE_PLAY
736 pauseable = service.pause()
738 if pauseable is None:
739 print "not pauseable."
740 state = self.SEEK_STATE_PLAY
742 oldstate = self.seekstate
743 self.seekstate = state
746 if oldstate[i] != self.seekstate[i]:
747 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
749 for c in self.onPlayStateChanged:
752 self.checkSkipShowHideLock()
756 def playpauseService(self):
757 if self.seekstate != self.SEEK_STATE_PLAY:
758 self.unPauseService()
762 def pauseService(self):
763 if self.seekstate == self.SEEK_STATE_PAUSE:
764 print "pause, but in fact unpause"
765 self.unPauseService()
767 if self.seekstate == self.SEEK_STATE_PLAY:
768 print "yes, playing."
770 print "no", self.seekstate
772 self.setSeekState(self.SEEK_STATE_PAUSE);
774 def unPauseService(self):
776 if self.seekstate == self.SEEK_STATE_PLAY:
778 self.setSeekState(self.SEEK_STATE_PLAY)
780 def doSeek(self, seektime):
781 print "doseek", seektime
782 service = self.session.nav.getCurrentService()
786 seekable = self.getSeek()
790 seekable.seekTo(90 * seektime)
794 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
795 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
796 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
797 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
798 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
799 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
800 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
801 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
802 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
803 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
804 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
805 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
806 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
807 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
808 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
809 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
811 self.setSeekState(lookup[self.seekstate])
815 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
816 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
817 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
818 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
819 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
820 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
821 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
822 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
823 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
824 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
825 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
826 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
827 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
828 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
829 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
830 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
832 self.setSeekState(lookup[self.seekstate])
834 if self.seekstate == self.SEEK_STATE_PAUSE:
835 seekable = self.getSeek()
836 if seekable is not None:
837 seekable.seekRelative(-1, 3)
839 def seekFwdDef(self):
840 self.seek_flag = False
841 seconds = config.usage.self_defined_seek.value
842 print "Seek", seconds, "seconds self defined forward"
843 seekable = self.getSeek()
844 if seekable is not None:
845 seekable.seekRelative(1, seconds * 90000)
847 def seekBackDef(self):
848 self.seek_flag = False
849 seconds = config.usage.self_defined_seek.value
850 print "Seek", seconds, "seconds self defined backward"
851 seekable = self.getSeek()
852 if seekable is not None:
853 seekable.seekRelative(1, 0 - seconds * 90000)
855 def seekFwdManual(self):
856 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
858 def fwdSeekTo(self, minutes):
859 print "Seek", minutes, "minutes forward"
861 seekable = self.getSeek()
862 if seekable is not None:
863 seekable.seekRelative(1, minutes * 60 * 90000)
865 def seekBackManual(self):
866 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
868 def rwdSeekTo(self, minutes):
870 self.fwdSeekTo(0 - minutes)
872 def checkSkipShowHideLock(self):
873 wantlock = self.seekstate != self.SEEK_STATE_PLAY
875 if config.usage.show_infobar_on_skip.value:
876 if self.lockedBecauseOfSkipping and not wantlock:
878 self.lockedBecauseOfSkipping = False
880 if wantlock and not self.lockedBecauseOfSkipping:
882 self.lockedBecauseOfSkipping = True
885 if self.seekstate == self.SEEK_STATE_EOF:
887 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
888 print "end of stream while seeking back, ignoring."
891 # if we are seeking, we try to end up ~1s before the end, and pause there.
892 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
893 self.setSeekState(self.SEEK_STATE_EOF)
894 self.seekRelativeToEnd(-90000)
896 self.setSeekState(self.SEEK_STATE_EOF)
899 self.setSeekState(self.SEEK_STATE_PLAY)
902 def seekRelative(self, diff):
903 if self.seek_flag == True:
904 seekable = self.getSeek()
905 if seekable is not None:
906 print "seekRelative: res:", seekable.seekRelative(1, diff)
910 self.seek_flag = True
912 def seekRelativeToEnd(self, diff):
913 assert diff <= 0, "diff is expected to be negative!"
915 # might sound like an evil hack, but:
916 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
917 # and we don't get that by passing 0 here (it would seek to begin).
921 # relative-to-end seeking is implemented as absolutes seeks with negative time
922 self.seekAbsolute(diff)
924 def seekAbsolute(self, abs):
925 seekable = self.getSeek()
926 if seekable is not None:
929 from Screens.PVRState import PVRState, TimeshiftState
931 class InfoBarPVRState:
932 def __init__(self, screen=PVRState):
933 self.onPlayStateChanged.append(self.__playStateChanged)
934 self.pvrStateDialog = self.session.instantiateDialog(screen)
935 self.onShow.append(self._mayShow)
936 self.onHide.append(self.pvrStateDialog.hide)
939 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
940 self.pvrStateDialog.show()
942 def __playStateChanged(self, state):
943 playstateString = state[3]
944 self.pvrStateDialog["state"].setText(playstateString)
947 class InfoBarTimeshiftState(InfoBarPVRState):
949 InfoBarPVRState.__init__(self, screen=TimeshiftState)
952 if self.execing and self.timeshift_enabled:
953 self.pvrStateDialog.show()
955 class InfoBarShowMovies:
957 # i don't really like this class.
958 # it calls a not further specified "movie list" on up/down/movieList,
959 # so this is not more than an action map
961 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
963 "movieList": (self.showMovies, _("movie list")),
964 "up": (self.showMovies, _("movie list")),
965 "down": (self.showMovies, _("movie list"))
968 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
972 # Timeshift works the following way:
973 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
974 # - normal playback TUNER unused PLAY enable disable disable
975 # - user presses "yellow" button. FILE record PAUSE enable disable enable
976 # - user presess pause again FILE record PLAY enable disable enable
977 # - user fast forwards FILE record FF enable disable enable
978 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
979 # - user backwards FILE record BACK # !! enable disable enable
983 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
984 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
985 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
986 # - the user can now PVR around
987 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
988 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
990 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
991 # - if the user rewinds, or press pause, timeshift will be activated again
993 # note that a timeshift can be enabled ("recording") and
994 # activated (currently time-shifting).
996 class InfoBarTimeshift:
998 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1000 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1001 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1003 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1005 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1006 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1007 }, prio=-1) # priority over record
1009 self.timeshift_enabled = 0
1010 self.timeshift_state = 0
1011 self.ts_rewind_timer = eTimer()
1012 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1014 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1016 iPlayableService.evStart: self.__serviceStarted,
1017 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1020 def getTimeshift(self):
1021 service = self.session.nav.getCurrentService()
1022 return service and service.timeshift()
1024 def startTimeshift(self):
1025 print "enable timeshift"
1026 ts = self.getTimeshift()
1028 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1029 print "no ts interface"
1032 if self.timeshift_enabled:
1033 print "hu, timeshift already enabled?"
1035 if not ts.startTimeshift():
1036 self.timeshift_enabled = 1
1038 # we remove the "relative time" for now.
1039 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1042 #self.setSeekState(self.SEEK_STATE_PAUSE)
1043 self.activateTimeshiftEnd(False)
1045 # enable the "TimeshiftEnableActions", which will override
1046 # the startTimeshift actions
1047 self.__seekableStatusChanged()
1049 print "timeshift failed"
1051 def stopTimeshift(self):
1052 if not self.timeshift_enabled:
1054 print "disable timeshift"
1055 ts = self.getTimeshift()
1058 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1060 def stopTimeshiftConfirmed(self, confirmed):
1064 ts = self.getTimeshift()
1069 self.timeshift_enabled = 0
1072 self.__seekableStatusChanged()
1074 # activates timeshift, and seeks to (almost) the end
1075 def activateTimeshiftEnd(self, back = True):
1076 ts = self.getTimeshift()
1077 print "activateTimeshiftEnd"
1082 if ts.isTimeshiftActive():
1083 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1087 ts.activateTimeshift() # activate timeshift will automatically pause
1088 self.setSeekState(self.SEEK_STATE_PAUSE)
1089 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1092 self.ts_rewind_timer.start(200, 1)
1094 def rewindService(self):
1095 self.setSeekState(self.SEEK_STATE_BACK_16X)
1097 # same as activateTimeshiftEnd, but pauses afterwards.
1098 def activateTimeshiftEndAndPause(self):
1099 print "activateTimeshiftEndAndPause"
1100 #state = self.seekstate
1101 self.activateTimeshiftEnd(False)
1103 def __seekableStatusChanged(self):
1106 print "self.isSeekable", self.isSeekable()
1107 print "self.timeshift_enabled", self.timeshift_enabled
1109 # when this service is not seekable, but timeshift
1110 # is enabled, this means we can activate
1112 if not self.isSeekable() and self.timeshift_enabled:
1115 print "timeshift activate:", enabled
1116 self["TimeshiftActivateActions"].setEnabled(enabled)
1118 def __serviceStarted(self):
1119 self.timeshift_enabled = False
1120 self.__seekableStatusChanged()
1122 from Screens.PiPSetup import PiPSetup
1124 class InfoBarExtensions:
1125 EXTENSION_SINGLE = 0
1131 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1133 "extensions": (self.showExtensionSelection, _("view extensions...")),
1136 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1137 self.list.append((type, extension, key))
1139 def updateExtension(self, extension, key = None):
1140 self.extensionsList.append(extension)
1142 if self.extensionKeys.has_key(key):
1146 for x in self.availableKeys:
1147 if not self.extensionKeys.has_key(x):
1152 self.extensionKeys[key] = len(self.extensionsList) - 1
1154 def updateExtensions(self):
1155 self.extensionsList = []
1156 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1157 self.extensionKeys = {}
1159 if x[0] == self.EXTENSION_SINGLE:
1160 self.updateExtension(x[1], x[2])
1163 self.updateExtension(y[0], y[1])
1166 def showExtensionSelection(self):
1167 self.updateExtensions()
1168 extensionsList = self.extensionsList[:]
1171 for x in self.availableKeys:
1172 if self.extensionKeys.has_key(x):
1173 entry = self.extensionKeys[x]
1174 extension = self.extensionsList[entry]
1176 name = str(extension[0]())
1177 list.append((extension[0](), extension))
1179 extensionsList.remove(extension)
1181 extensionsList.remove(extension)
1182 for x in extensionsList:
1183 list.append((x[0](), x))
1184 keys += [""] * len(extensionsList)
1185 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1187 def extensionCallback(self, answer):
1188 if answer is not None:
1191 from Tools.BoundFunction import boundFunction
1193 # depends on InfoBarExtensions
1194 from Components.PluginComponent import plugins
1196 class InfoBarPlugins:
1198 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1200 def getPluginName(self, name):
1203 def getPluginList(self):
1205 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1206 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1209 def runPlugin(self, plugin):
1210 plugin(session = self.session, servicelist = self.servicelist)
1212 # depends on InfoBarExtensions
1213 class InfoBarSleepTimer:
1215 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1217 def available(self):
1220 def getSleepTimerName(self):
1221 return _("Sleep Timer")
1223 def showSleepTimerSetup(self):
1224 self.session.open(SleepTimerEdit)
1226 # depends on InfoBarExtensions
1229 self.session.pipshown = False
1231 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1232 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1233 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1235 def available(self):
1239 return self.session.pipshown
1241 def pipHandles0Action(self):
1242 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1244 def getShowHideName(self):
1245 if self.session.pipshown:
1246 return _("Disable Picture in Picture")
1248 return _("Activate Picture in Picture")
1250 def getSwapName(self):
1251 return _("Swap Services")
1253 def getMoveName(self):
1254 return _("Move Picture in Picture")
1257 if self.session.pipshown:
1258 del self.session.pip
1259 self.session.pipshown = False
1261 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1262 self.session.pip.show()
1263 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1264 if self.session.pip.playService(newservice):
1265 self.session.pipshown = True
1266 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1268 self.session.pipshown = False
1269 del self.session.pip
1270 self.session.nav.playService(newservice)
1273 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1274 if self.session.pip.servicePath:
1275 servicepath = self.servicelist.getCurrentServicePath()
1276 ref=servicepath[len(servicepath)-1]
1277 pipref=self.session.pip.getCurrentService()
1278 self.session.pip.playService(swapservice)
1279 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1280 if pipref.toString() != ref.toString(): # is a subservice ?
1281 self.session.nav.stopService() # stop portal
1282 self.session.nav.playService(pipref) # start subservice
1283 self.session.pip.servicePath=servicepath
1286 self.session.open(PiPSetup, pip = self.session.pip)
1288 def pipDoHandle0Action(self):
1289 use = config.usage.pip_zero_button.value
1292 elif "swapstop" == use:
1298 from RecordTimer import parseEvent
1300 class InfoBarInstantRecord:
1301 """Instant Record - handles the instantRecord action in order to
1302 start/stop instant records"""
1304 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1306 "instantRecord": (self.instantRecord, _("Instant Record...")),
1309 self["BlinkingPoint"] = BlinkingPixmapConditional()
1310 self["BlinkingPoint"].hide()
1311 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1313 def stopCurrentRecording(self, entry = -1):
1314 if entry is not None and entry != -1:
1315 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1316 self.recording.remove(self.recording[entry])
1318 def startInstantRecording(self, limitEvent = False):
1319 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1321 # try to get event info
1324 service = self.session.nav.getCurrentService()
1325 epg = eEPGCache.getInstance()
1326 event = epg.lookupEventTime(serviceref, -1, 0)
1328 info = service.info()
1329 ev = info.getEvent(0)
1335 end = time() + 3600 * 10
1336 name = "instant record"
1340 if event is not None:
1341 curEvent = parseEvent(event)
1343 description = curEvent[3]
1344 eventid = curEvent[4]
1349 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1351 data = (begin, end, name, description, eventid)
1353 recording = self.session.nav.recordWithTimer(serviceref, *data)
1354 recording.dontSave = True
1355 self.recording.append(recording)
1357 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1359 def isInstantRecordRunning(self):
1360 print "self.recording:", self.recording
1361 if len(self.recording) > 0:
1362 for x in self.recording:
1367 def recordQuestionCallback(self, answer):
1368 print "pre:\n", self.recording
1370 if answer is None or answer[1] == "no":
1373 recording = self.recording[:]
1375 if not x in self.session.nav.RecordTimer.timer_list:
1376 self.recording.remove(x)
1377 elif x.dontSave and x.isRunning():
1378 list.append((x, False))
1380 if answer[1] == "changeduration":
1381 if len(self.recording) == 1:
1382 self.changeDuration(0)
1384 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1385 elif answer[1] == "changeendtime":
1386 if len(self.recording) == 1:
1389 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1390 elif answer[1] == "stop":
1391 if len(self.recording) == 1:
1392 self.stopCurrentRecording(0)
1394 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1395 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1396 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1397 if answer[1] == "manualduration":
1398 self.changeDuration(len(self.recording)-1)
1399 elif answer[1] == "manualendtime":
1400 self.setEndtime(len(self.recording)-1)
1401 print "after:\n", self.recording
1403 def setEndtime(self, entry):
1404 if entry is not None:
1405 self.selectedEntry = entry
1406 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1407 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1408 dlg.setTitle(_("Please change recording endtime"))
1410 def TimeDateInputClosed(self, ret):
1413 localendtime = localtime(ret[1])
1414 print "stopping recording at", strftime("%c", localendtime)
1415 self.recording[self.selectedEntry].end = ret[1]
1416 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1418 def changeDuration(self, entry):
1419 if entry is not None:
1420 self.selectedEntry = entry
1421 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1423 def inputCallback(self, value):
1424 if value is not None:
1425 print "stopping recording after", int(value), "minutes."
1426 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1427 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1429 def instantRecord(self):
1431 stat = os_stat(resolveFilename(SCOPE_HDD))
1433 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1436 if self.isInstantRecordRunning():
1437 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1438 title=_("A recording is currently running.\nWhat do you want to do?"), \
1439 list=[(_("stop recording"), "stop"), \
1440 (_("change recording (duration)"), "changeduration"), \
1441 (_("change recording (endtime)"), "changeendtime"), \
1442 (_("add recording (indefinitely)"), "indefinitely"), \
1443 (_("add recording (stop after current event)"), "event"), \
1444 (_("add recording (enter recording duration)"), "manualduration"), \
1445 (_("add recording (enter recording endtime)"), "manualendtime"), \
1446 (_("do nothing"), "no")])
1448 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1449 title=_("Start recording?"), \
1450 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1451 (_("add recording (stop after current event)"), "event"), \
1452 (_("add recording (enter recording duration)"), "manualduration"), \
1453 (_("add recording (enter recording endtime)"), "manualendtime"), \
1454 (_("don't record"), "no")])
1456 from Tools.ISO639 import LanguageCodes
1458 class InfoBarAudioSelection:
1460 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1462 "audioSelection": (self.audioSelection, _("Audio Options...")),
1465 def audioSelection(self):
1466 service = self.session.nav.getCurrentService()
1467 audio = service and service.audioTracks()
1468 self.audioTracks = audio
1469 n = audio and audio.getNumberOfTracks() or 0
1470 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1473 self.audioChannel = service.audioChannel()
1476 i = audio.getTrackInfo(x)
1477 language = i.getLanguage()
1478 description = i.getDescription()
1480 if LanguageCodes.has_key(language):
1481 language = LanguageCodes[language][0]
1483 if len(description):
1484 description += " (" + language + ")"
1486 description = language
1488 tlist.append((description, x))
1490 selectedAudio = audio.getCurrentTrack()
1491 tlist.sort(key=lambda x: x[0])
1495 if x[1] != selectedAudio:
1500 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1501 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1503 del self.audioTracks
1505 def audioSelected(self, audio):
1506 if audio is not None:
1507 if isinstance(audio[1], str):
1508 if audio[1] == "mode":
1509 keys = ["red", "green", "yellow"]
1510 selection = self.audioChannel.getCurrentChannel()
1511 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1512 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1514 del self.audioChannel
1515 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1516 self.audioTracks.selectTrack(audio[1])
1518 del self.audioChannel
1519 del self.audioTracks
1521 def modeSelected(self, mode):
1522 if mode is not None:
1523 self.audioChannel.selectChannel(mode[1])
1524 del self.audioChannel
1526 class InfoBarSubserviceSelection:
1528 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1530 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1533 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1535 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1536 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1538 self["SubserviceQuickzapAction"].setEnabled(False)
1540 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1544 def checkSubservicesAvail(self, ev):
1545 if ev == iPlayableService.evUpdatedEventInfo:
1546 service = self.session.nav.getCurrentService()
1547 subservices = service and service.subServices()
1548 if not subservices or subservices.getNumberOfSubservices() == 0:
1549 self["SubserviceQuickzapAction"].setEnabled(False)
1551 def nextSubservice(self):
1552 self.changeSubservice(+1)
1554 def prevSubservice(self):
1555 self.changeSubservice(-1)
1557 def changeSubservice(self, direction):
1558 service = self.session.nav.getCurrentService()
1559 subservices = service and service.subServices()
1560 n = subservices and subservices.getNumberOfSubservices()
1563 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1565 if subservices.getSubservice(x).toString() == ref.toString():
1568 selection += direction
1573 newservice = subservices.getSubservice(selection)
1574 if newservice.valid():
1577 self.session.nav.playService(newservice)
1579 def subserviceSelection(self):
1580 service = self.session.nav.getCurrentService()
1581 subservices = service and service.subServices()
1582 self.bouquets = self.servicelist.getBouquetList()
1583 n = subservices and subservices.getNumberOfSubservices()
1586 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1589 i = subservices.getSubservice(x)
1590 if i.toString() == ref.toString():
1592 tlist.append((i.getName(), i))
1594 if self.bouquets and len(self.bouquets):
1595 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1596 if config.usage.multibouquet.value:
1597 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1599 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1602 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1603 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1606 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1608 def subserviceSelected(self, service):
1610 if not service is None:
1611 if isinstance(service[1], str):
1612 if service[1] == "quickzap":
1613 from Screens.SubservicesQuickzap import SubservicesQuickzap
1614 self.session.open(SubservicesQuickzap, service[2])
1616 self["SubserviceQuickzapAction"].setEnabled(True)
1617 self.session.nav.playService(service[1])
1619 def addSubserviceToBouquetCallback(self, service):
1620 if len(service) > 1 and isinstance(service[1], eServiceReference):
1621 self.selectedSubservice = service
1622 if self.bouquets is None:
1625 cnt = len(self.bouquets)
1626 if cnt > 1: # show bouquet list
1627 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1628 elif cnt == 1: # add to only one existing bouquet
1629 self.addSubserviceToBouquet(self.bouquets[0][1])
1630 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1632 def bouquetSelClosed(self, confirmed):
1634 del self.selectedSubservice
1636 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1638 def addSubserviceToBouquet(self, dest):
1639 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1641 self.bsel.close(True)
1643 del self.selectedSubservice
1645 class InfoBarAdditionalInfo:
1647 self["NimA"] = Pixmap()
1648 self["NimB"] = Pixmap()
1649 self["NimA_Active"] = Pixmap()
1650 self["NimB_Active"] = Pixmap()
1652 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1653 self["TimeshiftPossible"] = self["RecordingPossible"]
1654 self["ExtensionsAvailable"] = Boolean(fixed=1)
1656 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1657 res_mgr = eDVBResourceManager.getInstance()
1659 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1661 def tunerUseMaskChanged(self, mask):
1663 self["NimA_Active"].show()
1665 self["NimA_Active"].hide()
1667 self["NimB_Active"].show()
1669 self["NimB_Active"].hide()
1671 def checkTunerState(self, service):
1672 info = service and service.frontendInfo()
1673 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1674 if feNumber is None:
1684 def gotServiceEvent(self, ev):
1685 service = self.session.nav.getCurrentService()
1686 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1687 self.checkTunerState(service)
1689 class InfoBarNotifications:
1691 self.onExecBegin.append(self.checkNotifications)
1692 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1693 self.onClose.append(self.__removeNotification)
1695 def __removeNotification(self):
1696 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1698 def checkNotificationsIfExecing(self):
1700 self.checkNotifications()
1702 def checkNotifications(self):
1703 if len(Notifications.notifications):
1704 n = Notifications.notifications[0]
1706 Notifications.notifications = Notifications.notifications[1:]
1709 if n[3].has_key("onSessionOpenCallback"):
1710 n[3]["onSessionOpenCallback"]()
1711 del n[3]["onSessionOpenCallback"]
1714 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1716 dlg = self.session.open(n[1], *n[2], **n[3])
1718 # remember that this notification is currently active
1720 Notifications.current_notifications.append(d)
1721 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1723 def __notificationClosed(self, d):
1724 Notifications.current_notifications.remove(d)
1726 class InfoBarServiceNotifications:
1728 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1730 iPlayableService.evEnd: self.serviceHasEnded
1733 def serviceHasEnded(self):
1734 print "service end!"
1737 self.setSeekState(self.SEEK_STATE_PLAY)
1741 class InfoBarCueSheetSupport:
1747 ENABLE_RESUME_SUPPORT = False
1749 def __init__(self, actionmap = "InfobarCueSheetActions"):
1750 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1752 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1753 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1754 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1758 self.is_closing = False
1759 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1761 iPlayableService.evStart: self.__serviceStarted,
1764 def __serviceStarted(self):
1767 print "new service started! trying to download cuts!"
1768 self.downloadCuesheet()
1770 if self.ENABLE_RESUME_SUPPORT:
1773 for (pts, what) in self.cut_list:
1774 if what == self.CUT_TYPE_LAST:
1777 if last is not None:
1778 self.resume_point = last
1779 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1781 def playLastCB(self, answer):
1783 seekable = self.__getSeekable()
1784 if seekable is not None:
1785 seekable.seekTo(self.resume_point)
1786 self.hideAfterResume()
1788 def hideAfterResume(self):
1789 if isinstance(self, InfoBarShowHide):
1792 def __getSeekable(self):
1793 service = self.session.nav.getCurrentService()
1796 return service.seek()
1798 def cueGetCurrentPosition(self):
1799 seek = self.__getSeekable()
1802 r = seek.getPlayPosition()
1807 def jumpPreviousNextMark(self, cmp, alternative=None):
1808 current_pos = self.cueGetCurrentPosition()
1809 if current_pos is None:
1811 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1812 if mark is not None:
1814 elif alternative is not None:
1819 seekable = self.__getSeekable()
1820 if seekable is not None:
1821 seekable.seekTo(pts)
1823 def jumpPreviousMark(self):
1824 # we add 2 seconds, so if the play position is <2s after
1825 # the mark, the mark before will be used
1826 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1828 def jumpNextMark(self):
1829 self.jumpPreviousNextMark(lambda x: x)
1831 def getNearestCutPoint(self, pts, cmp=abs):
1834 for cp in self.cut_list:
1835 diff = cmp(cp[0] - pts)
1836 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1840 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1841 current_pos = self.cueGetCurrentPosition()
1842 if current_pos is None:
1843 print "not seekable"
1846 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1848 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1850 return nearest_cutpoint
1852 self.removeMark(nearest_cutpoint)
1853 elif not onlyremove and not onlyreturn:
1854 self.addMark((current_pos, self.CUT_TYPE_MARK))
1859 def addMark(self, point):
1860 insort(self.cut_list, point)
1861 self.uploadCuesheet()
1862 self.showAfterCuesheetOperation()
1864 def removeMark(self, point):
1865 self.cut_list.remove(point)
1866 self.uploadCuesheet()
1867 self.showAfterCuesheetOperation()
1869 def showAfterCuesheetOperation(self):
1870 if isinstance(self, InfoBarShowHide):
1873 def __getCuesheet(self):
1874 service = self.session.nav.getCurrentService()
1877 return service.cueSheet()
1879 def uploadCuesheet(self):
1880 cue = self.__getCuesheet()
1883 print "upload failed, no cuesheet interface"
1885 cue.setCutList(self.cut_list)
1887 def downloadCuesheet(self):
1888 cue = self.__getCuesheet()
1891 print "download failed, no cuesheet interface"
1894 self.cut_list = cue.getCutList()
1896 class InfoBarSummary(Screen):
1898 <screen position="0,0" size="132,64">
1899 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1900 <convert type="ClockToText">WithSeconds</convert>
1902 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1903 <convert type="ServiceName">Name</convert>
1907 def __init__(self, session, parent):
1908 Screen.__init__(self, session)
1909 self["CurrentService"] = CurrentService(self.session.nav)
1910 self["CurrentTime"] = Clock()
1912 class InfoBarSummarySupport:
1916 def createSummary(self):
1917 return InfoBarSummary
1919 class InfoBarTeletextPlugin:
1921 self.teletext_plugin = None
1923 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1924 self.teletext_plugin = p
1926 if self.teletext_plugin is not None:
1927 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1929 "startTeletext": (self.startTeletext, _("View teletext..."))
1932 print "no teletext plugin found!"
1934 def startTeletext(self):
1935 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1937 class InfoBarSubtitleSupport(object):
1939 object.__init__(self)
1940 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1941 self.__subtitles_enabled = False
1943 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1945 iPlayableService.evEnd: self.__serviceStopped,
1946 iPlayableService.evUpdatedInfo: self.__updatedInfo
1948 self.cached_subtitle_checked = False
1949 self.__selected_subtitle = None
1951 def __serviceStopped(self):
1952 self.subtitle_window.hide()
1953 self.__subtitles_enabled = False
1954 self.cached_subtitle_checked = False
1956 def __updatedInfo(self):
1957 if not self.cached_subtitle_checked:
1958 subtitle = self.getCurrentServiceSubtitle()
1959 self.cached_subtitle_checked = True
1960 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1961 if self.__selected_subtitle:
1962 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1963 self.subtitle_window.show()
1964 self.__subtitles_enabled = True
1966 def getCurrentServiceSubtitle(self):
1967 service = self.session.nav.getCurrentService()
1968 return service and service.subtitle()
1970 def setSubtitlesEnable(self, enable=True):
1971 subtitle = self.getCurrentServiceSubtitle()
1972 if enable and self.__selected_subtitle is not None:
1973 if subtitle and not self.__subtitles_enabled:
1974 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1975 self.subtitle_window.show()
1976 self.__subtitles_enabled = True
1979 subtitle.disableSubtitles(self.subtitle_window.instance)
1980 self.__subtitles_enabled = False
1981 self.subtitle_window.hide()
1983 def setSelectedSubtitle(self, subtitle):
1984 self.__selected_subtitle = subtitle
1986 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1987 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1989 class InfoBarServiceErrorPopupSupport:
1991 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1993 iPlayableService.evTuneFailed: self.__tuneFailed,
1994 iPlayableService.evStart: self.__serviceStarted
1996 self.__serviceStarted()
1998 def __serviceStarted(self):
1999 self.last_error = None
2000 Notifications.RemovePopup(id = "ZapError")
2002 def __tuneFailed(self):
2003 service = self.session.nav.getCurrentService()
2004 info = service and service.info()
2005 error = info and info.getInfo(iServiceInformation.sDVBState)
2007 if error == self.last_error:
2010 self.last_error = error
2013 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2014 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2015 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2016 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2017 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2018 eDVBServicePMTHandler.eventNewProgramInfo: None,
2019 eDVBServicePMTHandler.eventTuned: None,
2020 eDVBServicePMTHandler.eventSOF: None,
2021 eDVBServicePMTHandler.eventEOF: None
2024 error = errors.get(error) #this returns None when the key not exist in the dict
2026 if error is not None:
2027 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2029 Notifications.RemovePopup(id = "ZapError")