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_16X = (0, 16, 0, ">> 16x")
617 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
618 SEEK_STATE_FF_48X = (0, 48, 0, ">> 48x")
619 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
620 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
622 SEEK_STATE_BACK_8X = (0, -8, 0, "<< 8x")
623 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
624 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
625 SEEK_STATE_BACK_48X = (0, -48, 0, "<< 48x")
626 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
627 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
629 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
630 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
631 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
633 SEEK_STATE_EOF = (1, 0, 0, "END")
635 def __init__(self, actionmap = "InfobarSeekActions"):
636 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
638 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
639 iPlayableService.evStart: self.__serviceStarted,
641 iPlayableService.evEOF: self.__evEOF,
642 iPlayableService.evSOF: self.__evSOF,
645 class InfoBarSeekActionMap(HelpableActionMap):
646 def __init__(self, screen, *args, **kwargs):
647 HelpableActionMap.__init__(self, screen, *args, **kwargs)
650 def action(self, contexts, action):
651 print "action:", action
652 if action[:5] == "seek:":
653 time = int(action[5:])
654 self.screen.seekRelative(time * 90000)
655 if config.usage.show_infobar_on_skip.value:
656 self.screen.showAfterSeek()
659 return HelpableActionMap.action(self, contexts, action)
661 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
663 "playpauseService": self.playpauseService,
664 "pauseService": (self.pauseService, _("pause")),
665 "unPauseService": (self.unPauseService, _("continue")),
667 "seekFwd": (self.seekFwd, _("skip forward")),
668 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
669 "seekBack": (self.seekBack, _("skip backward")),
670 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
672 "seekFwdDef": (self.seekFwdDef, _("skip forward (self defined)")),
673 "seekBackDef": (self.seekBackDef, _("skip backward (self defined)"))
675 # give them a little more priority to win over color buttons
677 self["SeekActions"].setEnabled(False)
679 self.seekstate = self.SEEK_STATE_PLAY
681 self.seek_flag = True
683 self.onPlayStateChanged = [ ]
685 self.lockedBecauseOfSkipping = False
687 self.__seekableStatusChanged()
689 def showAfterSeek(self):
690 if isinstance(self, InfoBarShowHide):
700 service = self.session.nav.getCurrentService()
704 seek = service.seek()
706 if seek is None or not seek.isCurrentlySeekable():
711 def isSeekable(self):
712 if self.getSeek() is None:
716 def __seekableStatusChanged(self):
717 print "seekable status changed!"
718 if not self.isSeekable():
719 self["SeekActions"].setEnabled(False)
720 print "not seekable, return to play"
721 self.setSeekState(self.SEEK_STATE_PLAY)
723 self["SeekActions"].setEnabled(True)
726 def __serviceStarted(self):
727 self.seekstate = self.SEEK_STATE_PLAY
728 self.__seekableStatusChanged()
730 def setSeekState(self, state):
731 service = self.session.nav.getCurrentService()
736 if not self.isSeekable():
737 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
738 state = self.SEEK_STATE_PLAY
740 pauseable = service.pause()
742 if pauseable is None:
743 print "not pauseable."
744 state = self.SEEK_STATE_PLAY
746 oldstate = self.seekstate
747 self.seekstate = state
750 if oldstate[i] != self.seekstate[i]:
751 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
753 for c in self.onPlayStateChanged:
756 self.checkSkipShowHideLock()
760 def playpauseService(self):
761 if self.seekstate != self.SEEK_STATE_PLAY:
762 self.unPauseService()
766 def pauseService(self):
767 if self.seekstate == self.SEEK_STATE_PAUSE:
768 print "pause, but in fact unpause"
769 self.unPauseService()
771 if self.seekstate == self.SEEK_STATE_PLAY:
772 print "yes, playing."
774 print "no", self.seekstate
776 self.setSeekState(self.SEEK_STATE_PAUSE);
778 def unPauseService(self):
780 if self.seekstate == self.SEEK_STATE_PLAY:
782 self.setSeekState(self.SEEK_STATE_PLAY)
784 def doSeek(self, seektime):
785 print "doseek", seektime
786 service = self.session.nav.getCurrentService()
790 seekable = self.getSeek()
794 seekable.seekTo(90 * seektime)
798 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
799 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
800 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
801 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
802 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_16X,
803 self.SEEK_STATE_FF_16X: self.SEEK_STATE_FF_32X,
804 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_48X,
805 self.SEEK_STATE_FF_48X: self.SEEK_STATE_FF_64X,
806 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
807 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
808 self.SEEK_STATE_BACK_8X: self.SEEK_STATE_PLAY,
809 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_8X,
810 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
811 self.SEEK_STATE_BACK_48X: self.SEEK_STATE_BACK_32X,
812 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_48X,
813 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
814 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
815 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
816 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
817 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
819 self.setSeekState(lookup[self.seekstate])
823 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_8X,
824 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
825 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
826 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
827 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
828 self.SEEK_STATE_FF_16X: self.SEEK_STATE_FF_8X,
829 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_16X,
830 self.SEEK_STATE_FF_48X: self.SEEK_STATE_FF_32X,
831 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_48X,
832 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
833 self.SEEK_STATE_BACK_8X: self.SEEK_STATE_BACK_16X,
834 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
835 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_48X,
836 self.SEEK_STATE_BACK_48X: self.SEEK_STATE_BACK_64X,
837 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
838 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
839 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
840 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
841 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
842 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_8X,
844 self.setSeekState(lookup[self.seekstate])
846 if self.seekstate == self.SEEK_STATE_PAUSE:
847 seekable = self.getSeek()
848 if seekable is not None:
849 seekable.seekRelative(-1, 3)
851 def seekFwdDef(self):
852 self.seek_flag = False
853 seconds = config.usage.self_defined_seek.value
854 print "Seek", seconds, "seconds self defined forward"
855 seekable = self.getSeek()
856 if seekable is not None:
857 seekable.seekRelative(1, seconds * 90000)
859 def seekBackDef(self):
860 self.seek_flag = False
861 seconds = config.usage.self_defined_seek.value
862 print "Seek", seconds, "seconds self defined backward"
863 seekable = self.getSeek()
864 if seekable is not None:
865 seekable.seekRelative(1, 0 - seconds * 90000)
867 def seekFwdManual(self):
868 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
870 def fwdSeekTo(self, minutes):
871 print "Seek", minutes, "minutes forward"
873 seekable = self.getSeek()
874 if seekable is not None:
875 seekable.seekRelative(1, minutes * 60 * 90000)
877 def seekBackManual(self):
878 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
880 def rwdSeekTo(self, minutes):
882 self.fwdSeekTo(0 - minutes)
884 def checkSkipShowHideLock(self):
885 wantlock = self.seekstate != self.SEEK_STATE_PLAY
887 if config.usage.show_infobar_on_skip.value:
888 if self.lockedBecauseOfSkipping and not wantlock:
890 self.lockedBecauseOfSkipping = False
892 if wantlock and not self.lockedBecauseOfSkipping:
894 self.lockedBecauseOfSkipping = True
897 if self.seekstate == self.SEEK_STATE_EOF:
899 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
900 print "end of stream while seeking back, ignoring."
903 # if we are seeking, we try to end up ~1s before the end, and pause there.
904 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
905 self.setSeekState(self.SEEK_STATE_EOF)
906 self.seekRelativeToEnd(-90000)
908 self.setSeekState(self.SEEK_STATE_EOF)
911 self.setSeekState(self.SEEK_STATE_PLAY)
914 def seekRelative(self, diff):
915 if self.seek_flag == True:
916 seekable = self.getSeek()
917 if seekable is not None:
918 print "seekRelative: res:", seekable.seekRelative(1, diff)
922 self.seek_flag = True
924 def seekRelativeToEnd(self, diff):
925 assert diff <= 0, "diff is expected to be negative!"
927 # might sound like an evil hack, but:
928 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
929 # and we don't get that by passing 0 here (it would seek to begin).
933 # relative-to-end seeking is implemented as absolutes seeks with negative time
934 self.seekAbsolute(diff)
936 def seekAbsolute(self, abs):
937 seekable = self.getSeek()
938 if seekable is not None:
941 from Screens.PVRState import PVRState, TimeshiftState
943 class InfoBarPVRState:
944 def __init__(self, screen=PVRState):
945 self.onPlayStateChanged.append(self.__playStateChanged)
946 self.pvrStateDialog = self.session.instantiateDialog(screen)
947 self.onShow.append(self._mayShow)
948 self.onHide.append(self.pvrStateDialog.hide)
951 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
952 self.pvrStateDialog.show()
954 def __playStateChanged(self, state):
955 playstateString = state[3]
956 self.pvrStateDialog["state"].setText(playstateString)
959 class InfoBarTimeshiftState(InfoBarPVRState):
961 InfoBarPVRState.__init__(self, screen=TimeshiftState)
964 if self.execing and self.timeshift_enabled:
965 self.pvrStateDialog.show()
967 class InfoBarShowMovies:
969 # i don't really like this class.
970 # it calls a not further specified "movie list" on up/down/movieList,
971 # so this is not more than an action map
973 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
975 "movieList": (self.showMovies, _("movie list")),
976 "up": (self.showMovies, _("movie list")),
977 "down": (self.showMovies, _("movie list"))
980 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
984 # Timeshift works the following way:
985 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
986 # - normal playback TUNER unused PLAY enable disable disable
987 # - user presses "yellow" button. FILE record PAUSE enable disable enable
988 # - user presess pause again FILE record PLAY enable disable enable
989 # - user fast forwards FILE record FF enable disable enable
990 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
991 # - user backwards FILE record BACK # !! enable disable enable
995 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
996 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
997 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
998 # - the user can now PVR around
999 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1000 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1002 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1003 # - if the user rewinds, or press pause, timeshift will be activated again
1005 # note that a timeshift can be enabled ("recording") and
1006 # activated (currently time-shifting).
1008 class InfoBarTimeshift:
1010 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1012 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1013 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1015 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1017 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1018 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1019 }, prio=-1) # priority over record
1021 self.timeshift_enabled = 0
1022 self.timeshift_state = 0
1023 self.ts_rewind_timer = eTimer()
1024 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1026 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1028 iPlayableService.evStart: self.__serviceStarted,
1029 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1032 def getTimeshift(self):
1033 service = self.session.nav.getCurrentService()
1034 return service and service.timeshift()
1036 def startTimeshift(self):
1037 print "enable timeshift"
1038 ts = self.getTimeshift()
1040 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1041 print "no ts interface"
1044 if self.timeshift_enabled:
1045 print "hu, timeshift already enabled?"
1047 if not ts.startTimeshift():
1048 self.timeshift_enabled = 1
1050 # we remove the "relative time" for now.
1051 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1054 #self.setSeekState(self.SEEK_STATE_PAUSE)
1055 self.activateTimeshiftEnd(False)
1057 # enable the "TimeshiftEnableActions", which will override
1058 # the startTimeshift actions
1059 self.__seekableStatusChanged()
1061 print "timeshift failed"
1063 def stopTimeshift(self):
1064 if not self.timeshift_enabled:
1066 print "disable timeshift"
1067 ts = self.getTimeshift()
1070 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1072 def stopTimeshiftConfirmed(self, confirmed):
1076 ts = self.getTimeshift()
1081 self.timeshift_enabled = 0
1084 self.__seekableStatusChanged()
1086 # activates timeshift, and seeks to (almost) the end
1087 def activateTimeshiftEnd(self, back = True):
1088 ts = self.getTimeshift()
1089 print "activateTimeshiftEnd"
1094 if ts.isTimeshiftActive():
1095 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1099 ts.activateTimeshift() # activate timeshift will automatically pause
1100 self.setSeekState(self.SEEK_STATE_PAUSE)
1101 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1104 self.ts_rewind_timer.start(200, 1)
1106 def rewindService(self):
1107 self.setSeekState(self.SEEK_STATE_BACK_16X)
1109 # same as activateTimeshiftEnd, but pauses afterwards.
1110 def activateTimeshiftEndAndPause(self):
1111 print "activateTimeshiftEndAndPause"
1112 #state = self.seekstate
1113 self.activateTimeshiftEnd(False)
1115 def __seekableStatusChanged(self):
1118 print "self.isSeekable", self.isSeekable()
1119 print "self.timeshift_enabled", self.timeshift_enabled
1121 # when this service is not seekable, but timeshift
1122 # is enabled, this means we can activate
1124 if not self.isSeekable() and self.timeshift_enabled:
1127 print "timeshift activate:", enabled
1128 self["TimeshiftActivateActions"].setEnabled(enabled)
1130 def __serviceStarted(self):
1131 self.timeshift_enabled = False
1132 self.__seekableStatusChanged()
1134 from Screens.PiPSetup import PiPSetup
1136 class InfoBarExtensions:
1137 EXTENSION_SINGLE = 0
1143 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1145 "extensions": (self.showExtensionSelection, _("view extensions...")),
1148 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1149 self.list.append((type, extension, key))
1151 def updateExtension(self, extension, key = None):
1152 self.extensionsList.append(extension)
1154 if self.extensionKeys.has_key(key):
1158 for x in self.availableKeys:
1159 if not self.extensionKeys.has_key(x):
1164 self.extensionKeys[key] = len(self.extensionsList) - 1
1166 def updateExtensions(self):
1167 self.extensionsList = []
1168 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1169 self.extensionKeys = {}
1171 if x[0] == self.EXTENSION_SINGLE:
1172 self.updateExtension(x[1], x[2])
1175 self.updateExtension(y[0], y[1])
1178 def showExtensionSelection(self):
1179 self.updateExtensions()
1180 extensionsList = self.extensionsList[:]
1183 for x in self.availableKeys:
1184 if self.extensionKeys.has_key(x):
1185 entry = self.extensionKeys[x]
1186 extension = self.extensionsList[entry]
1188 name = str(extension[0]())
1189 list.append((extension[0](), extension))
1191 extensionsList.remove(extension)
1193 extensionsList.remove(extension)
1194 for x in extensionsList:
1195 list.append((x[0](), x))
1196 keys += [""] * len(extensionsList)
1197 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1199 def extensionCallback(self, answer):
1200 if answer is not None:
1203 from Tools.BoundFunction import boundFunction
1205 # depends on InfoBarExtensions
1206 from Components.PluginComponent import plugins
1208 class InfoBarPlugins:
1210 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1212 def getPluginName(self, name):
1215 def getPluginList(self):
1217 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1218 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1221 def runPlugin(self, plugin):
1222 plugin(session = self.session, servicelist = self.servicelist)
1224 # depends on InfoBarExtensions
1225 class InfoBarSleepTimer:
1227 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1229 def available(self):
1232 def getSleepTimerName(self):
1233 return _("Sleep Timer")
1235 def showSleepTimerSetup(self):
1236 self.session.open(SleepTimerEdit)
1238 # depends on InfoBarExtensions
1241 self.session.pipshown = False
1243 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1244 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1245 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1247 def available(self):
1251 return self.session.pipshown
1253 def pipHandles0Action(self):
1254 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1256 def getShowHideName(self):
1257 if self.session.pipshown:
1258 return _("Disable Picture in Picture")
1260 return _("Activate Picture in Picture")
1262 def getSwapName(self):
1263 return _("Swap Services")
1265 def getMoveName(self):
1266 return _("Move Picture in Picture")
1269 if self.session.pipshown:
1270 del self.session.pip
1271 self.session.pipshown = False
1273 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1274 self.session.pip.show()
1275 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1276 if self.session.pip.playService(newservice):
1277 self.session.pipshown = True
1278 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1280 self.session.pipshown = False
1281 del self.session.pip
1282 self.session.nav.playService(newservice)
1285 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1286 if self.session.pip.servicePath:
1287 servicepath = self.servicelist.getCurrentServicePath()
1288 ref=servicepath[len(servicepath)-1]
1289 pipref=self.session.pip.getCurrentService()
1290 self.session.pip.playService(swapservice)
1291 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1292 if pipref.toString() != ref.toString(): # is a subservice ?
1293 self.session.nav.stopService() # stop portal
1294 self.session.nav.playService(pipref) # start subservice
1295 self.session.pip.servicePath=servicepath
1298 self.session.open(PiPSetup, pip = self.session.pip)
1300 def pipDoHandle0Action(self):
1301 use = config.usage.pip_zero_button.value
1304 elif "swapstop" == use:
1310 from RecordTimer import parseEvent
1312 class InfoBarInstantRecord:
1313 """Instant Record - handles the instantRecord action in order to
1314 start/stop instant records"""
1316 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1318 "instantRecord": (self.instantRecord, _("Instant Record...")),
1321 self["BlinkingPoint"] = BlinkingPixmapConditional()
1322 self["BlinkingPoint"].hide()
1323 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1325 def stopCurrentRecording(self, entry = -1):
1326 if entry is not None and entry != -1:
1327 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1328 self.recording.remove(self.recording[entry])
1330 def startInstantRecording(self, limitEvent = False):
1331 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1333 # try to get event info
1336 service = self.session.nav.getCurrentService()
1337 epg = eEPGCache.getInstance()
1338 event = epg.lookupEventTime(serviceref, -1, 0)
1340 info = service.info()
1341 ev = info.getEvent(0)
1347 end = time() + 3600 * 10
1348 name = "instant record"
1352 if event is not None:
1353 curEvent = parseEvent(event)
1355 description = curEvent[3]
1356 eventid = curEvent[4]
1361 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1363 data = (begin, end, name, description, eventid)
1365 recording = self.session.nav.recordWithTimer(serviceref, *data)
1366 recording.dontSave = True
1367 self.recording.append(recording)
1369 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1371 def isInstantRecordRunning(self):
1372 print "self.recording:", self.recording
1373 if len(self.recording) > 0:
1374 for x in self.recording:
1379 def recordQuestionCallback(self, answer):
1380 print "pre:\n", self.recording
1382 if answer is None or answer[1] == "no":
1385 recording = self.recording[:]
1387 if not x in self.session.nav.RecordTimer.timer_list:
1388 self.recording.remove(x)
1389 elif x.dontSave and x.isRunning():
1390 list.append((x, False))
1392 if answer[1] == "changeduration":
1393 if len(self.recording) == 1:
1394 self.changeDuration(0)
1396 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1397 elif answer[1] == "changeendtime":
1398 if len(self.recording) == 1:
1401 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1402 elif answer[1] == "stop":
1403 if len(self.recording) == 1:
1404 self.stopCurrentRecording(0)
1406 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1407 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1408 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1409 if answer[1] == "manualduration":
1410 self.changeDuration(len(self.recording)-1)
1411 elif answer[1] == "manualendtime":
1412 self.setEndtime(len(self.recording)-1)
1413 print "after:\n", self.recording
1415 def setEndtime(self, entry):
1416 if entry is not None:
1417 self.selectedEntry = entry
1418 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1419 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1420 dlg.setTitle(_("Please change recording endtime"))
1422 def TimeDateInputClosed(self, ret):
1425 localendtime = localtime(ret[1])
1426 print "stopping recording at", strftime("%c", localendtime)
1427 self.recording[self.selectedEntry].end = ret[1]
1428 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1430 def changeDuration(self, entry):
1431 if entry is not None:
1432 self.selectedEntry = entry
1433 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1435 def inputCallback(self, value):
1436 if value is not None:
1437 print "stopping recording after", int(value), "minutes."
1438 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1439 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1441 def instantRecord(self):
1443 stat = os_stat(resolveFilename(SCOPE_HDD))
1445 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1448 if self.isInstantRecordRunning():
1449 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1450 title=_("A recording is currently running.\nWhat do you want to do?"), \
1451 list=[(_("stop recording"), "stop"), \
1452 (_("change recording (duration)"), "changeduration"), \
1453 (_("change recording (endtime)"), "changeendtime"), \
1454 (_("add recording (indefinitely)"), "indefinitely"), \
1455 (_("add recording (stop after current event)"), "event"), \
1456 (_("add recording (enter recording duration)"), "manualduration"), \
1457 (_("add recording (enter recording endtime)"), "manualendtime"), \
1458 (_("do nothing"), "no")])
1460 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1461 title=_("Start recording?"), \
1462 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1463 (_("add recording (stop after current event)"), "event"), \
1464 (_("add recording (enter recording duration)"), "manualduration"), \
1465 (_("add recording (enter recording endtime)"), "manualendtime"), \
1466 (_("don't record"), "no")])
1468 from Tools.ISO639 import LanguageCodes
1470 class InfoBarAudioSelection:
1472 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1474 "audioSelection": (self.audioSelection, _("Audio Options...")),
1477 def audioSelection(self):
1478 service = self.session.nav.getCurrentService()
1479 audio = service and service.audioTracks()
1480 self.audioTracks = audio
1481 n = audio and audio.getNumberOfTracks() or 0
1482 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1485 self.audioChannel = service.audioChannel()
1488 i = audio.getTrackInfo(x)
1489 language = i.getLanguage()
1490 description = i.getDescription()
1492 if LanguageCodes.has_key(language):
1493 language = LanguageCodes[language][0]
1495 if len(description):
1496 description += " (" + language + ")"
1498 description = language
1500 tlist.append((description, x))
1502 selectedAudio = audio.getCurrentTrack()
1503 tlist.sort(key=lambda x: x[0])
1507 if x[1] != selectedAudio:
1512 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1513 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1515 del self.audioTracks
1517 def audioSelected(self, audio):
1518 if audio is not None:
1519 if isinstance(audio[1], str):
1520 if audio[1] == "mode":
1521 keys = ["red", "green", "yellow"]
1522 selection = self.audioChannel.getCurrentChannel()
1523 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1524 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1526 del self.audioChannel
1527 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1528 self.audioTracks.selectTrack(audio[1])
1530 del self.audioChannel
1531 del self.audioTracks
1533 def modeSelected(self, mode):
1534 if mode is not None:
1535 self.audioChannel.selectChannel(mode[1])
1536 del self.audioChannel
1538 class InfoBarSubserviceSelection:
1540 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1542 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1545 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1547 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1548 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1550 self["SubserviceQuickzapAction"].setEnabled(False)
1552 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1556 def checkSubservicesAvail(self, ev):
1557 if ev == iPlayableService.evUpdatedEventInfo:
1558 service = self.session.nav.getCurrentService()
1559 subservices = service and service.subServices()
1560 if not subservices or subservices.getNumberOfSubservices() == 0:
1561 self["SubserviceQuickzapAction"].setEnabled(False)
1563 def nextSubservice(self):
1564 self.changeSubservice(+1)
1566 def prevSubservice(self):
1567 self.changeSubservice(-1)
1569 def changeSubservice(self, direction):
1570 service = self.session.nav.getCurrentService()
1571 subservices = service and service.subServices()
1572 n = subservices and subservices.getNumberOfSubservices()
1575 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1577 if subservices.getSubservice(x).toString() == ref.toString():
1580 selection += direction
1585 newservice = subservices.getSubservice(selection)
1586 if newservice.valid():
1589 self.session.nav.playService(newservice)
1591 def subserviceSelection(self):
1592 service = self.session.nav.getCurrentService()
1593 subservices = service and service.subServices()
1594 self.bouquets = self.servicelist.getBouquetList()
1595 n = subservices and subservices.getNumberOfSubservices()
1598 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1601 i = subservices.getSubservice(x)
1602 if i.toString() == ref.toString():
1604 tlist.append((i.getName(), i))
1606 if self.bouquets and len(self.bouquets):
1607 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1608 if config.usage.multibouquet.value:
1609 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1611 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1614 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1615 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1618 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1620 def subserviceSelected(self, service):
1622 if not service is None:
1623 if isinstance(service[1], str):
1624 if service[1] == "quickzap":
1625 from Screens.SubservicesQuickzap import SubservicesQuickzap
1626 self.session.open(SubservicesQuickzap, service[2])
1628 self["SubserviceQuickzapAction"].setEnabled(True)
1629 self.session.nav.playService(service[1])
1631 def addSubserviceToBouquetCallback(self, service):
1632 if len(service) > 1 and isinstance(service[1], eServiceReference):
1633 self.selectedSubservice = service
1634 if self.bouquets is None:
1637 cnt = len(self.bouquets)
1638 if cnt > 1: # show bouquet list
1639 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1640 elif cnt == 1: # add to only one existing bouquet
1641 self.addSubserviceToBouquet(self.bouquets[0][1])
1642 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1644 def bouquetSelClosed(self, confirmed):
1646 del self.selectedSubservice
1648 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1650 def addSubserviceToBouquet(self, dest):
1651 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1653 self.bsel.close(True)
1655 del self.selectedSubservice
1657 class InfoBarAdditionalInfo:
1659 self["NimA"] = Pixmap()
1660 self["NimB"] = Pixmap()
1661 self["NimA_Active"] = Pixmap()
1662 self["NimB_Active"] = Pixmap()
1664 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1665 self["TimeshiftPossible"] = self["RecordingPossible"]
1666 self["ExtensionsAvailable"] = Boolean(fixed=1)
1668 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1669 res_mgr = eDVBResourceManager.getInstance()
1671 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1673 def tunerUseMaskChanged(self, mask):
1675 self["NimA_Active"].show()
1677 self["NimA_Active"].hide()
1679 self["NimB_Active"].show()
1681 self["NimB_Active"].hide()
1683 def checkTunerState(self, service):
1684 info = service and service.frontendInfo()
1685 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1686 if feNumber is None:
1696 def gotServiceEvent(self, ev):
1697 service = self.session.nav.getCurrentService()
1698 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1699 self.checkTunerState(service)
1701 class InfoBarNotifications:
1703 self.onExecBegin.append(self.checkNotifications)
1704 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1705 self.onClose.append(self.__removeNotification)
1707 def __removeNotification(self):
1708 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1710 def checkNotificationsIfExecing(self):
1712 self.checkNotifications()
1714 def checkNotifications(self):
1715 if len(Notifications.notifications):
1716 n = Notifications.notifications[0]
1718 Notifications.notifications = Notifications.notifications[1:]
1721 if n[3].has_key("onSessionOpenCallback"):
1722 n[3]["onSessionOpenCallback"]()
1723 del n[3]["onSessionOpenCallback"]
1726 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1728 dlg = self.session.open(n[1], *n[2], **n[3])
1730 # remember that this notification is currently active
1732 Notifications.current_notifications.append(d)
1733 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1735 def __notificationClosed(self, d):
1736 Notifications.current_notifications.remove(d)
1738 class InfoBarServiceNotifications:
1740 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1742 iPlayableService.evEnd: self.serviceHasEnded
1745 def serviceHasEnded(self):
1746 print "service end!"
1749 self.setSeekState(self.SEEK_STATE_PLAY)
1753 class InfoBarCueSheetSupport:
1759 ENABLE_RESUME_SUPPORT = False
1761 def __init__(self, actionmap = "InfobarCueSheetActions"):
1762 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1764 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1765 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1766 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1770 self.is_closing = False
1771 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1773 iPlayableService.evStart: self.__serviceStarted,
1776 def __serviceStarted(self):
1779 print "new service started! trying to download cuts!"
1780 self.downloadCuesheet()
1782 if self.ENABLE_RESUME_SUPPORT:
1785 for (pts, what) in self.cut_list:
1786 if what == self.CUT_TYPE_LAST:
1789 if last is not None:
1790 self.resume_point = last
1791 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1793 def playLastCB(self, answer):
1795 seekable = self.__getSeekable()
1796 if seekable is not None:
1797 seekable.seekTo(self.resume_point)
1798 self.hideAfterResume()
1800 def hideAfterResume(self):
1801 if isinstance(self, InfoBarShowHide):
1804 def __getSeekable(self):
1805 service = self.session.nav.getCurrentService()
1808 return service.seek()
1810 def cueGetCurrentPosition(self):
1811 seek = self.__getSeekable()
1814 r = seek.getPlayPosition()
1819 def jumpPreviousNextMark(self, cmp, alternative=None):
1820 current_pos = self.cueGetCurrentPosition()
1821 if current_pos is None:
1823 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1824 if mark is not None:
1826 elif alternative is not None:
1831 seekable = self.__getSeekable()
1832 if seekable is not None:
1833 seekable.seekTo(pts)
1835 def jumpPreviousMark(self):
1836 # we add 2 seconds, so if the play position is <2s after
1837 # the mark, the mark before will be used
1838 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1840 def jumpNextMark(self):
1841 self.jumpPreviousNextMark(lambda x: x)
1843 def getNearestCutPoint(self, pts, cmp=abs):
1846 for cp in self.cut_list:
1847 diff = cmp(cp[0] - pts)
1848 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1852 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1853 current_pos = self.cueGetCurrentPosition()
1854 if current_pos is None:
1855 print "not seekable"
1858 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1860 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1862 return nearest_cutpoint
1864 self.removeMark(nearest_cutpoint)
1865 elif not onlyremove and not onlyreturn:
1866 self.addMark((current_pos, self.CUT_TYPE_MARK))
1871 def addMark(self, point):
1872 insort(self.cut_list, point)
1873 self.uploadCuesheet()
1874 self.showAfterCuesheetOperation()
1876 def removeMark(self, point):
1877 self.cut_list.remove(point)
1878 self.uploadCuesheet()
1879 self.showAfterCuesheetOperation()
1881 def showAfterCuesheetOperation(self):
1882 if isinstance(self, InfoBarShowHide):
1885 def __getCuesheet(self):
1886 service = self.session.nav.getCurrentService()
1889 return service.cueSheet()
1891 def uploadCuesheet(self):
1892 cue = self.__getCuesheet()
1895 print "upload failed, no cuesheet interface"
1897 cue.setCutList(self.cut_list)
1899 def downloadCuesheet(self):
1900 cue = self.__getCuesheet()
1903 print "download failed, no cuesheet interface"
1906 self.cut_list = cue.getCutList()
1908 class InfoBarSummary(Screen):
1910 <screen position="0,0" size="132,64">
1911 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1912 <convert type="ClockToText">WithSeconds</convert>
1914 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1915 <convert type="ServiceName">Name</convert>
1919 def __init__(self, session, parent):
1920 Screen.__init__(self, session)
1921 self["CurrentService"] = CurrentService(self.session.nav)
1922 self["CurrentTime"] = Clock()
1924 class InfoBarSummarySupport:
1928 def createSummary(self):
1929 return InfoBarSummary
1931 class InfoBarTeletextPlugin:
1933 self.teletext_plugin = None
1935 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1936 self.teletext_plugin = p
1938 if self.teletext_plugin is not None:
1939 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1941 "startTeletext": (self.startTeletext, _("View teletext..."))
1944 print "no teletext plugin found!"
1946 def startTeletext(self):
1947 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1949 class InfoBarSubtitleSupport(object):
1951 object.__init__(self)
1952 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1953 self.__subtitles_enabled = False
1955 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1957 iPlayableService.evEnd: self.__serviceStopped,
1958 iPlayableService.evUpdatedInfo: self.__updatedInfo
1960 self.cached_subtitle_checked = False
1961 self.__selected_subtitle = None
1963 def __serviceStopped(self):
1964 self.subtitle_window.hide()
1965 self.__subtitles_enabled = False
1966 self.cached_subtitle_checked = False
1968 def __updatedInfo(self):
1969 if not self.cached_subtitle_checked:
1970 subtitle = self.getCurrentServiceSubtitle()
1971 self.cached_subtitle_checked = True
1972 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1973 if self.__selected_subtitle:
1974 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1975 self.subtitle_window.show()
1976 self.__subtitles_enabled = True
1978 def getCurrentServiceSubtitle(self):
1979 service = self.session.nav.getCurrentService()
1980 return service and service.subtitle()
1982 def setSubtitlesEnable(self, enable=True):
1983 subtitle = self.getCurrentServiceSubtitle()
1984 if enable and self.__selected_subtitle is not None:
1985 if subtitle and not self.__subtitles_enabled:
1986 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1987 self.subtitle_window.show()
1988 self.__subtitles_enabled = True
1991 subtitle.disableSubtitles(self.subtitle_window.instance)
1992 self.__subtitles_enabled = False
1993 self.subtitle_window.hide()
1995 def setSelectedSubtitle(self, subtitle):
1996 self.__selected_subtitle = subtitle
1998 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1999 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
2001 class InfoBarServiceErrorPopupSupport:
2003 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2005 iPlayableService.evTuneFailed: self.__tuneFailed,
2006 iPlayableService.evStart: self.__serviceStarted
2008 self.__serviceStarted()
2010 def __serviceStarted(self):
2011 self.last_error = None
2012 Notifications.RemovePopup(id = "ZapError")
2014 def __tuneFailed(self):
2015 service = self.session.nav.getCurrentService()
2016 info = service and service.info()
2017 error = info and info.getInfo(iServiceInformation.sDVBState)
2019 if error == self.last_error:
2022 self.last_error = error
2025 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2026 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2027 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2028 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2029 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2030 eDVBServicePMTHandler.eventNewProgramInfo: None,
2031 eDVBServicePMTHandler.eventTuned: None,
2032 eDVBServicePMTHandler.eventSOF: None,
2033 eDVBServicePMTHandler.eventEOF: None
2036 error = errors.get(error) #this returns None when the key not exist in the dict
2038 if error is not None:
2039 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2041 Notifications.RemovePopup(id = "ZapError")