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 *
9 from Components.Pixmap import Pixmap, PixmapConditional
10 from Components.PluginComponent import plugins
11 from Components.ProgressBar import *
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.Sources.CurrentService import CurrentService
14 from Components.Sources.EventInfo import EventInfo
15 from Components.Sources.FrontendStatus import FrontendStatus
16 from Components.Sources.Boolean import Boolean
17 from Components.Sources.Clock import Clock
18 from Components.TimerList import TimerEntryComponent
19 from Components.config import config, ConfigBoolean
21 from EpgSelection import EPGSelection
22 from Plugins.Plugin import PluginDescriptor
24 from Screen import Screen
25 from Screens.ChoiceBox import ChoiceBox
26 from Screens.Dish import Dish
27 from Screens.EventView import EventViewEPGSelect, EventViewSimple
28 from Screens.InputBox import InputBox
29 from Screens.MessageBox import MessageBox
30 from Screens.MinuteInput import MinuteInput
31 from Screens.TimerSelection import TimerSelection
32 from Screens.PictureInPicture import PictureInPicture
33 from Screens.SubtitleDisplay import SubtitleDisplay
34 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
35 from Screens.SleepTimerEdit import SleepTimerEdit
36 from ServiceReference import ServiceReference
38 from Tools import Notifications
39 from Tools.Directories import SCOPE_HDD, resolveFilename
41 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
42 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
45 from os import stat as os_stat
46 from bisect import insort
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
69 }, 1) # lower prio to make it possible to override ok and cancel..
71 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
73 iPlayableService.evStart: self.__serviceStarted
76 self.__state = self.STATE_SHOWN
79 self.hideTimer = eTimer()
80 self.hideTimer.timeout.get().append(self.doTimerHide)
81 self.hideTimer.start(5000, True)
83 self.onShow.append(self.__onShow)
84 self.onHide.append(self.__onHide)
86 def __serviceStarted(self):
87 if config.usage.show_infobar_on_zap.value:
91 self.__state = self.STATE_SHOWN
94 def startHideTimer(self):
95 if self.__state == self.STATE_SHOWN and not self.__locked:
96 idx = config.usage.infobar_timeout.index
98 self.hideTimer.start(idx*1000, True)
101 self.__state = self.STATE_HIDDEN
105 self.startHideTimer()
107 def doTimerHide(self):
108 self.hideTimer.stop()
109 if self.__state == self.STATE_SHOWN:
112 def toggleShow(self):
113 if self.__state == self.STATE_SHOWN:
115 self.hideTimer.stop()
116 elif self.__state == self.STATE_HIDDEN:
120 self.__locked = self.__locked + 1
123 self.hideTimer.stop()
125 def unlockShow(self):
126 self.__locked = self.__locked - 1
128 self.startHideTimer()
130 # def startShow(self):
131 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
132 # self.__state = self.STATE_SHOWN
134 # def startHide(self):
135 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
136 # self.__state = self.STATE_HIDDEN
138 class NumberZap(Screen):
145 self.close(int(self["number"].getText()))
147 def keyNumberGlobal(self, number):
148 self.Timer.start(3000, True) #reset timer
149 self.field = self.field + str(number)
150 self["number"].setText(self.field)
151 if len(self.field) >= 4:
154 def __init__(self, session, number):
155 Screen.__init__(self, session)
156 self.field = str(number)
158 self["channel"] = Label(_("Channel:"))
160 self["number"] = Label(self.field)
162 self["actions"] = NumberActionMap( [ "SetupActions" ],
166 "1": self.keyNumberGlobal,
167 "2": self.keyNumberGlobal,
168 "3": self.keyNumberGlobal,
169 "4": self.keyNumberGlobal,
170 "5": self.keyNumberGlobal,
171 "6": self.keyNumberGlobal,
172 "7": self.keyNumberGlobal,
173 "8": self.keyNumberGlobal,
174 "9": self.keyNumberGlobal,
175 "0": self.keyNumberGlobal
178 self.Timer = eTimer()
179 self.Timer.timeout.get().append(self.keyOK)
180 self.Timer.start(3000, True)
182 class InfoBarNumberZap:
183 """ Handles an initial number for NumberZapping """
185 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
187 "1": self.keyNumberGlobal,
188 "2": self.keyNumberGlobal,
189 "3": self.keyNumberGlobal,
190 "4": self.keyNumberGlobal,
191 "5": self.keyNumberGlobal,
192 "6": self.keyNumberGlobal,
193 "7": self.keyNumberGlobal,
194 "8": self.keyNumberGlobal,
195 "9": self.keyNumberGlobal,
196 "0": self.keyNumberGlobal,
199 def keyNumberGlobal(self, number):
200 # print "You pressed number " + str(number)
202 self.servicelist.recallPrevService()
204 self.session.openWithCallback(self.numberEntered, NumberZap, number)
206 def numberEntered(self, retval):
207 # print self.servicelist
209 self.zapToNumber(retval)
211 def searchNumberHelper(self, serviceHandler, num, bouquet):
212 servicelist = serviceHandler.list(bouquet)
213 if not servicelist is None:
215 serviceIterator = servicelist.getNext()
216 if not serviceIterator.valid(): #check end of list
218 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
221 if not num: #found service with searched number ?
222 return serviceIterator, 0
225 def zapToNumber(self, number):
226 bouquet = self.servicelist.bouquet_root
228 serviceHandler = eServiceCenter.getInstance()
229 if not config.usage.multibouquet.value:
230 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
232 bouquetlist = serviceHandler.list(bouquet)
233 if not bouquetlist is None:
235 bouquet = bouquetlist.getNext()
236 if not bouquet.valid(): #check end of list
238 if bouquet.flags & eServiceReference.isDirectory:
239 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
240 if not service is None:
241 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
242 self.servicelist.clearPath()
243 if self.servicelist.bouquet_root != bouquet:
244 self.servicelist.enterPath(self.servicelist.bouquet_root)
245 self.servicelist.enterPath(bouquet)
246 self.servicelist.setCurrentSelection(service) #select the service in servicelist
247 self.servicelist.zap()
249 config.misc.initialchannelselection = ConfigBoolean(default = True)
251 class InfoBarChannelSelection:
252 """ ChannelSelection - handles the channelSelection dialog and the initial
253 channelChange actions which open the channelSelection dialog """
256 self.servicelist = self.session.instantiateDialog(ChannelSelection)
258 if config.misc.initialchannelselection.value:
259 self.onShown.append(self.firstRun)
261 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
263 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
264 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
265 "zapUp": (self.zapUp, _("previous channel")),
266 "zapDown": (self.zapDown, _("next channel")),
267 "historyBack": (self.historyBack, _("previous channel in history")),
268 "historyNext": (self.historyNext, _("next channel in history")),
269 "openServiceList": (self.openServiceList, _("open servicelist")),
272 def showTvChannelList(self, zap=False):
273 self.servicelist.setModeTv()
275 self.servicelist.zap()
276 self.session.execDialog(self.servicelist)
278 def showRadioChannelList(self, zap=False):
279 self.servicelist.setModeRadio()
281 self.servicelist.zap()
282 self.session.execDialog(self.servicelist)
285 self.onShown.remove(self.firstRun)
286 config.misc.initialchannelselection.value = False
287 config.misc.initialchannelselection.save()
288 self.switchChannelDown()
290 def historyBack(self):
291 self.servicelist.historyBack()
293 def historyNext(self):
294 self.servicelist.historyNext()
296 def switchChannelUp(self):
297 self.servicelist.moveUp()
298 self.session.execDialog(self.servicelist)
300 def switchChannelDown(self):
301 self.servicelist.moveDown()
302 self.session.execDialog(self.servicelist)
304 def openServiceList(self):
305 self.session.execDialog(self.servicelist)
308 if self.servicelist.inBouquet():
309 prev = self.servicelist.getCurrentSelection()
311 prev = prev.toString()
313 if config.usage.quickzap_bouquet_change.value:
314 if self.servicelist.atBegin():
315 self.servicelist.prevBouquet()
316 self.servicelist.moveUp()
317 cur = self.servicelist.getCurrentSelection()
318 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
321 self.servicelist.moveUp()
322 self.servicelist.zap()
325 if self.servicelist.inBouquet():
326 prev = self.servicelist.getCurrentSelection()
328 prev = prev.toString()
330 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
331 self.servicelist.nextBouquet()
333 self.servicelist.moveDown()
334 cur = self.servicelist.getCurrentSelection()
335 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
338 self.servicelist.moveDown()
339 self.servicelist.zap()
342 """ Handles a menu action, to open the (main) menu """
344 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
346 "mainMenu": (self.mainMenu, _("Enter main menu...")),
348 self.session.infobar = None
351 print "loading mainmenu XML..."
352 menu = mdom.childNodes[0]
353 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
355 self.session.infobar = self
356 # so we can access the currently active infobar from screens opened from within the mainmenu
357 # at the moment used from the SubserviceSelection
359 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
361 def mainMenuClosed(self, *val):
362 self.session.infobar = None
364 class InfoBarSimpleEventView:
365 """ Opens the Eventview for now/next """
367 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
369 "showEventInfo": (self.openEventView, _("show event details")),
372 def openEventView(self):
374 service = self.session.nav.getCurrentService()
375 ref = self.session.nav.getCurrentlyPlayingServiceReference()
376 info = service.info()
379 self.epglist.append(ptr)
382 self.epglist.append(ptr)
383 if len(self.epglist) > 0:
384 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
386 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
387 if len(self.epglist) > 1:
388 tmp = self.epglist[0]
389 self.epglist[0]=self.epglist[1]
391 setEvent(self.epglist[0])
394 """ EPG - Opens an EPG list when the showEPGList action fires """
396 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
398 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
401 self.is_now_next = False
403 self.bouquetSel = None
404 self.eventView = None
405 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
407 "showEventInfo": (self.openEventView, _("show EPG...")),
410 def zapToService(self, service):
411 if not service is None:
412 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
413 self.servicelist.clearPath()
414 if self.servicelist.bouquet_root != self.epg_bouquet:
415 self.servicelist.enterPath(self.servicelist.bouquet_root)
416 self.servicelist.enterPath(self.epg_bouquet)
417 self.servicelist.setCurrentSelection(service) #select the service in servicelist
418 self.servicelist.zap()
420 def getBouquetServices(self, bouquet):
422 servicelist = eServiceCenter.getInstance().list(bouquet)
423 if not servicelist is None:
425 service = servicelist.getNext()
426 if not service.valid(): #check if end of list
428 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
430 services.append(ServiceReference(service))
433 def openBouquetEPG(self, bouquet, withCallback=True):
434 services = self.getBouquetServices(bouquet)
436 self.epg_bouquet = bouquet
438 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
440 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
442 def changeBouquetCB(self, direction, epg):
445 self.bouquetSel.down()
448 bouquet = self.bouquetSel.getCurrent()
449 services = self.getBouquetServices(bouquet)
451 self.epg_bouquet = bouquet
452 epg.setServices(services)
454 def closed(self, ret=False):
455 closedScreen = self.dlg_stack.pop()
456 if self.bouquetSel and closedScreen == self.bouquetSel:
457 self.bouquetSel = None
458 elif self.eventView and closedScreen == self.eventView:
459 self.eventView = None
461 dlgs=len(self.dlg_stack)
463 self.dlg_stack[dlgs-1].close(dlgs > 1)
465 def openMultiServiceEPG(self, withCallback=True):
466 bouquets = self.servicelist.getBouquetList()
471 if cnt > 1: # show bouquet list
473 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
474 self.dlg_stack.append(self.bouquetSel)
476 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
478 self.openBouquetEPG(bouquets[0][1], withCallback)
480 def openSingleServiceEPG(self):
481 ref=self.session.nav.getCurrentlyPlayingServiceReference()
482 self.session.open(EPGSelection, ref)
484 def openSimilarList(self, eventid, refstr):
485 self.session.open(EPGSelection, refstr, None, eventid)
487 def getNowNext(self):
489 service = self.session.nav.getCurrentService()
490 info = service and service.info()
491 ptr = info and info.getEvent(0)
493 self.epglist.append(ptr)
494 ptr = info and info.getEvent(1)
496 self.epglist.append(ptr)
498 def __evEventInfoChanged(self):
499 if self.is_now_next and len(self.dlg_stack) == 1:
501 assert self.eventView
502 if len(self.epglist):
503 self.eventView.setEvent(self.epglist[0])
505 def openEventView(self):
506 ref = self.session.nav.getCurrentlyPlayingServiceReference()
508 if len(self.epglist) == 0:
509 self.is_now_next = False
510 epg = eEPGCache.getInstance()
511 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
513 self.epglist.append(ptr)
514 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
516 self.epglist.append(ptr)
518 self.is_now_next = True
519 if len(self.epglist) > 0:
520 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
521 self.dlg_stack.append(self.eventView)
523 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
524 self.openMultiServiceEPG(False)
526 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
527 if len(self.epglist) > 1:
528 tmp = self.epglist[0]
529 self.epglist[0]=self.epglist[1]
531 setEvent(self.epglist[0])
534 """provides a snr/agc/ber display"""
536 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
539 """provides a current/next event info display"""
541 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
542 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
544 class InfoBarRdsDecoder:
545 """provides RDS and Rass support/display"""
547 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
548 self.rass_interactive = None
550 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
552 iPlayableService.evEnd: self.__serviceStopped,
553 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
556 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
558 "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
561 self["RdsActions"].setEnabled(False)
563 self.onLayoutFinish.append(self.rds_display.show)
564 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
566 def RassInteractivePossibilityChanged(self, state):
567 self["RdsActions"].setEnabled(state)
569 def RassSlidePicChanged(self):
570 if not self.rass_interactive:
571 service = self.session.nav.getCurrentService()
572 decoder = service and service.rdsDecoder()
574 decoder.showRassSlidePicture()
576 def __serviceStopped(self):
577 if self.rass_interactive is not None:
578 rass_interactive = self.rass_interactive
579 self.rass_interactive = None
580 rass_interactive.close()
582 def startRassInteractive(self):
583 self.rds_display.hide()
584 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
586 def RassInteractiveClosed(self, *val):
587 if self.rass_interactive is not None:
588 self.rass_interactive = None
589 self.RassSlidePicChanged()
590 self.rds_display.show()
592 class InfoBarServiceName:
594 self["CurrentService"] = CurrentService(self.session.nav)
597 """handles actions like seeking, pause"""
599 # ispause, isff, issm
600 SEEK_STATE_PLAY = (0, 0, 0, ">")
601 SEEK_STATE_PAUSE = (1, 0, 0, "||")
602 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
603 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
604 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
605 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
606 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
607 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
609 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
610 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
611 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
612 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
614 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
615 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
616 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
619 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
621 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
622 iPlayableService.evStart: self.__serviceStarted,
624 iPlayableService.evEOF: self.__evEOF,
625 iPlayableService.evSOF: self.__evSOF,
628 class InfoBarSeekActionMap(HelpableActionMap):
629 def __init__(self, screen, *args, **kwargs):
630 HelpableActionMap.__init__(self, screen, *args, **kwargs)
633 def action(self, contexts, action):
634 if action[:5] == "seek:":
635 time = int(action[5:])
636 self.screen.seekRelative(time * 90000)
639 return HelpableActionMap.action(self, contexts, action)
641 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
643 "playpauseService": (self.playpauseService, _("pause")),
644 "pauseService": (self.pauseService, _("pause")),
645 "unPauseService": (self.unPauseService, _("continue")),
647 "seekFwd": (self.seekFwd, _("skip forward")),
648 "seekFwdDown": self.seekFwdDown,
649 "seekFwdUp": self.seekFwdUp,
650 "seekBack": (self.seekBack, _("skip backward")),
651 "seekBackDown": self.seekBackDown,
652 "seekBackUp": self.seekBackUp,
654 # give them a little more priority to win over color buttons
656 self["SeekActions"].setEnabled(False)
658 self.seekstate = self.SEEK_STATE_PLAY
659 self.onClose.append(self.delTimer)
661 self.fwdtimer = False
662 self.fwdKeyTimer = eTimer()
663 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
665 self.rwdtimer = False
666 self.rwdKeyTimer = eTimer()
667 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
669 self.onPlayStateChanged = [ ]
671 self.lockedBecauseOfSkipping = False
684 service = self.session.nav.getCurrentService()
688 seek = service.seek()
690 if seek is None or not seek.isCurrentlySeekable():
695 def isSeekable(self):
696 if self.getSeek() is None:
700 def __seekableStatusChanged(self):
701 print "seekable status changed!"
702 if not self.isSeekable():
703 self["SeekActions"].setEnabled(False)
704 print "not seekable, return to play"
705 self.setSeekState(self.SEEK_STATE_PLAY)
707 self["SeekActions"].setEnabled(True)
710 def __serviceStarted(self):
711 self.seekstate = self.SEEK_STATE_PLAY
713 def setSeekState(self, state):
714 service = self.session.nav.getCurrentService()
719 if not self.isSeekable():
720 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
721 state = self.SEEK_STATE_PLAY
723 pauseable = service.pause()
725 if pauseable is None:
726 print "not pauseable."
727 state = self.SEEK_STATE_PLAY
729 oldstate = self.seekstate
730 self.seekstate = state
733 if oldstate[i] != self.seekstate[i]:
734 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
736 for c in self.onPlayStateChanged:
739 self.checkSkipShowHideLock()
743 def playpauseService(self):
744 if self.seekstate != self.SEEK_STATE_PLAY:
745 self.unPauseService()
749 def pauseService(self):
750 if self.seekstate == self.SEEK_STATE_PAUSE:
751 print "pause, but in fact unpause"
752 self.unPauseService()
754 if self.seekstate == self.SEEK_STATE_PLAY:
755 print "yes, playing."
757 print "no", self.seekstate
759 self.setSeekState(self.SEEK_STATE_PAUSE);
761 def unPauseService(self):
763 if self.seekstate == self.SEEK_STATE_PLAY:
765 self.setSeekState(self.SEEK_STATE_PLAY)
767 def doSeek(self, seektime):
768 print "doseek", seektime
769 service = self.session.nav.getCurrentService()
773 seekable = self.getSeek()
777 seekable.seekTo(90 * seektime)
779 def seekFwdDown(self):
780 print "start fwd timer"
782 self.fwdKeyTimer.start(1000)
784 def seekBackDown(self):
785 print "start rewind timer"
787 self.rwdKeyTimer.start(1000)
792 self.fwdKeyTimer.stop()
793 self.fwdtimer = False
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_32X,
803 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
804 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
805 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
806 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
807 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
808 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
809 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
810 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
811 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
812 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
814 self.setSeekState(lookup[self.seekstate])
816 def seekBackUp(self):
819 self.rwdKeyTimer.stop()
820 self.rwdtimer = False
825 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
826 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
827 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
828 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
829 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
830 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
831 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
832 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
833 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
834 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
835 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
836 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
837 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
838 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
839 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
841 self.setSeekState(lookup[self.seekstate])
843 if self.seekstate == self.SEEK_STATE_PAUSE:
844 seekable = self.getSeek()
845 if seekable is not None:
846 seekable.seekRelative(-1, 3)
848 def fwdTimerFire(self):
849 print "Display seek fwd"
850 self.fwdKeyTimer.stop()
851 self.fwdtimer = False
852 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
854 def fwdSeekTo(self, minutes):
855 print "Seek", minutes, "minutes forward"
857 seekable = self.getSeek()
858 if seekable is not None:
859 seekable.seekRelative(1, minutes * 60 * 90000)
861 def rwdTimerFire(self):
863 self.rwdKeyTimer.stop()
864 self.rwdtimer = False
865 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
867 def rwdSeekTo(self, minutes):
869 self.fwdSeekTo(0 - minutes)
871 def checkSkipShowHideLock(self):
872 wantlock = self.seekstate != self.SEEK_STATE_PLAY
874 if config.usage.show_infobar_on_zap.value:
875 if self.lockedBecauseOfSkipping and not wantlock:
877 self.lockedBecauseOfSkipping = False
879 if wantlock and not self.lockedBecauseOfSkipping:
881 self.lockedBecauseOfSkipping = True
884 if self.seekstate != self.SEEK_STATE_PLAY:
885 self.setSeekState(self.SEEK_STATE_PAUSE)
887 #self.getSeek().seekRelative(1, -90000)
888 self.setSeekState(self.SEEK_STATE_PLAY)
890 self.setSeekState(self.SEEK_STATE_PAUSE)
893 self.setSeekState(self.SEEK_STATE_PLAY)
896 def seekRelative(self, diff):
897 seekable = self.getSeek()
898 if seekable is not None:
899 seekable.seekRelative(1, diff)
901 def seekAbsolute(self, abs):
902 seekable = self.getSeek()
903 if seekable is not None:
906 from Screens.PVRState import PVRState, TimeshiftState
908 class InfoBarPVRState:
909 def __init__(self, screen=PVRState):
910 self.onPlayStateChanged.append(self.__playStateChanged)
911 self.pvrStateDialog = self.session.instantiateDialog(screen)
912 self.onShow.append(self._mayShow)
913 self.onHide.append(self.pvrStateDialog.hide)
916 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
917 self.pvrStateDialog.show()
919 def __playStateChanged(self, state):
920 playstateString = state[3]
921 self.pvrStateDialog["state"].setText(playstateString)
924 class InfoBarTimeshiftState(InfoBarPVRState):
926 InfoBarPVRState.__init__(self, screen=TimeshiftState)
929 if self.execing and self.timeshift_enabled:
930 self.pvrStateDialog.show()
932 class InfoBarShowMovies:
934 # i don't really like this class.
935 # it calls a not further specified "movie list" on up/down/movieList,
936 # so this is not more than an action map
938 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
940 "movieList": (self.showMovies, "movie list"),
941 "up": (self.showMovies, "movie list"),
942 "down": (self.showMovies, "movie list")
945 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
949 # Timeshift works the following way:
950 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
951 # - normal playback TUNER unused PLAY enable disable disable
952 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
953 # - user presess pause again FILE record PLAY enable disable enable
954 # - user fast forwards FILE record FF enable disable enable
955 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
956 # - user backwards FILE record BACK # !! enable disable enable
960 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
961 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
962 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
963 # - the user can now PVR around
964 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
965 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
967 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
968 # - if the user rewinds, or press pause, timeshift will be activated again
970 # note that a timeshift can be enabled ("recording") and
971 # activated (currently time-shifting).
973 class InfoBarTimeshift:
975 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
977 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
978 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
980 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
982 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
983 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
984 }, prio=-1) # priority over record
986 self.timeshift_enabled = 0
987 self.timeshift_state = 0
988 self.ts_pause_timer = eTimer()
989 self.ts_pause_timer.timeout.get().append(self.pauseService)
991 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
993 iPlayableService.evStart: self.__serviceStarted,
994 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
997 def getTimeshift(self):
998 service = self.session.nav.getCurrentService()
999 return service and service.timeshift()
1001 def startTimeshift(self):
1002 print "enable timeshift"
1003 ts = self.getTimeshift()
1005 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1006 print "no ts interface"
1009 if self.timeshift_enabled:
1010 print "hu, timeshift already enabled?"
1012 if not ts.startTimeshift():
1013 self.timeshift_enabled = 1
1015 # we remove the "relative time" for now.
1016 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1019 self.setSeekState(self.SEEK_STATE_PAUSE)
1021 # enable the "TimeshiftEnableActions", which will override
1022 # the startTimeshift actions
1023 self.__seekableStatusChanged()
1025 print "timeshift failed"
1027 def stopTimeshift(self):
1028 if not self.timeshift_enabled:
1030 print "disable timeshift"
1031 ts = self.getTimeshift()
1034 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1036 def stopTimeshiftConfirmed(self, confirmed):
1040 ts = self.getTimeshift()
1045 self.timeshift_enabled = 0
1048 self.__seekableStatusChanged()
1050 # activates timeshift, and seeks to (almost) the end
1051 def activateTimeshiftEnd(self):
1052 ts = self.getTimeshift()
1057 if ts.isTimeshiftActive():
1058 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1061 self.setSeekState(self.SEEK_STATE_PLAY)
1062 ts.activateTimeshift()
1063 self.seekRelative(0)
1065 # same as activateTimeshiftEnd, but pauses afterwards.
1066 def activateTimeshiftEndAndPause(self):
1067 state = self.seekstate
1068 self.activateTimeshiftEnd()
1070 # well, this is "andPause", but it could be pressed from pause,
1071 # when pausing on the (fake-)"live" picture, so an un-pause
1074 print "now, pauseService"
1075 if state == self.SEEK_STATE_PLAY:
1076 print "is PLAYING, start pause timer"
1077 self.ts_pause_timer.start(200, 1)
1080 self.unPauseService()
1082 def __seekableStatusChanged(self):
1085 print "self.isSeekable", self.isSeekable()
1086 print "self.timeshift_enabled", self.timeshift_enabled
1088 # when this service is not seekable, but timeshift
1089 # is enabled, this means we can activate
1091 if not self.isSeekable() and self.timeshift_enabled:
1094 print "timeshift activate:", enabled
1095 self["TimeshiftActivateActions"].setEnabled(enabled)
1097 def __serviceStarted(self):
1098 self.timeshift_enabled = False
1099 self.__seekableStatusChanged()
1101 from Screens.PiPSetup import PiPSetup
1103 class InfoBarExtensions:
1104 EXTENSION_SINGLE = 0
1110 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1112 "extensions": (self.showExtensionSelection, _("view extensions...")),
1115 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1116 self.list.append((type, extension, key))
1118 def updateExtension(self, extension, key = None):
1119 self.extensionsList.append(extension)
1121 if self.extensionKeys.has_key(key):
1125 for x in self.availableKeys:
1126 if not self.extensionKeys.has_key(x):
1131 self.extensionKeys[key] = len(self.extensionsList) - 1
1133 def updateExtensions(self):
1134 self.extensionsList = []
1135 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1136 self.extensionKeys = {}
1138 if x[0] == self.EXTENSION_SINGLE:
1139 self.updateExtension(x[1], x[2])
1142 self.updateExtension(y[0], y[1])
1145 def showExtensionSelection(self):
1146 self.updateExtensions()
1147 extensionsList = self.extensionsList[:]
1150 for x in self.availableKeys:
1151 if self.extensionKeys.has_key(x):
1152 entry = self.extensionKeys[x]
1153 extension = self.extensionsList[entry]
1155 name = str(extension[0]())
1156 list.append((extension[0](), extension))
1158 extensionsList.remove(extension)
1160 extensionsList.remove(extension)
1161 for x in extensionsList:
1162 list.append((x[0](), x))
1163 keys += [""] * len(extensionsList)
1164 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1166 def extensionCallback(self, answer):
1167 if answer is not None:
1170 from Tools.BoundFunction import boundFunction
1172 # depends on InfoBarExtensions
1173 from Components.PluginComponent import plugins
1175 class InfoBarPlugins:
1177 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1179 def getPluginName(self, name):
1182 def getPluginList(self):
1184 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1185 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1188 def runPlugin(self, plugin):
1189 plugin(session = self.session)
1191 # depends on InfoBarExtensions
1192 class InfoBarSleepTimer:
1194 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1196 def available(self):
1199 def getSleepTimerName(self):
1200 return _("Sleep Timer")
1202 def showSleepTimerSetup(self):
1203 self.session.open(SleepTimerEdit)
1205 # depends on InfoBarExtensions
1208 self.session.pipshown = False
1210 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1211 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1212 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1214 def available(self):
1218 return self.session.pipshown
1220 def getShowHideName(self):
1221 if self.session.pipshown:
1222 return _("Disable Picture in Picture")
1224 return _("Activate Picture in Picture")
1226 def getSwapName(self):
1227 return _("Swap Services")
1229 def getMoveName(self):
1230 return _("Move Picture in Picture")
1233 if self.session.pipshown:
1234 del self.session.pip
1235 self.session.pipshown = False
1237 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1238 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1239 if self.session.pip.playService(newservice):
1240 self.session.pipshown = True
1241 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1243 self.session.pipshown = False
1244 del self.session.pip
1245 self.session.nav.playService(newservice)
1248 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1249 if self.session.pip.servicePath:
1250 servicepath = self.servicelist.getCurrentServicePath()
1251 ref=servicepath[len(servicepath)-1]
1252 pipref=self.session.pip.getCurrentService()
1253 self.session.pip.playService(swapservice)
1254 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1255 if pipref.toString() != ref.toString(): # is a subservice ?
1256 self.session.nav.stopService() # stop portal
1257 self.session.nav.playService(pipref) # start subservice
1258 self.session.pip.servicePath=servicepath
1261 self.session.open(PiPSetup, pip = self.session.pip)
1263 from RecordTimer import parseEvent
1265 class InfoBarInstantRecord:
1266 """Instant Record - handles the instantRecord action in order to
1267 start/stop instant records"""
1269 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1271 "instantRecord": (self.instantRecord, _("Instant Record...")),
1274 self["BlinkingPoint"] = BlinkingPixmapConditional()
1275 self["BlinkingPoint"].hide()
1276 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1278 def stopCurrentRecording(self, entry = -1):
1279 if entry is not None and entry != -1:
1280 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1281 self.recording.remove(self.recording[entry])
1283 def startInstantRecording(self, limitEvent = False):
1284 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1286 # try to get event info
1289 service = self.session.nav.getCurrentService()
1290 epg = eEPGCache.getInstance()
1291 event = epg.lookupEventTime(serviceref, -1, 0)
1293 info = service.info()
1294 ev = info.getEvent(0)
1300 end = time() + 3600 * 10
1301 name = "instant record"
1305 if event is not None:
1306 curEvent = parseEvent(event)
1308 description = curEvent[3]
1309 eventid = curEvent[4]
1314 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1316 data = (begin, end, name, description, eventid)
1318 recording = self.session.nav.recordWithTimer(serviceref, *data)
1319 recording.dontSave = True
1320 self.recording.append(recording)
1322 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1324 def isInstantRecordRunning(self):
1325 print "self.recording:", self.recording
1326 if len(self.recording) > 0:
1327 for x in self.recording:
1332 def recordQuestionCallback(self, answer):
1333 print "pre:\n", self.recording
1335 if answer is None or answer[1] == "no":
1338 recording = self.recording[:]
1340 if not x in self.session.nav.RecordTimer.timer_list:
1341 self.recording.remove(x)
1342 elif x.dontSave and x.isRunning():
1343 list.append(TimerEntryComponent(x, False))
1345 if answer[1] == "changeduration":
1346 if len(self.recording) == 1:
1347 self.changeDuration(0)
1349 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1350 elif answer[1] == "stop":
1351 if len(self.recording) == 1:
1352 self.stopCurrentRecording(0)
1354 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1355 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1357 if answer[1] == "event":
1359 if answer[1] == "manualduration":
1360 self.selectedEntry = len(self.recording)
1361 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1362 self.startInstantRecording(limitEvent = limitEvent)
1364 print "after:\n", self.recording
1366 def changeDuration(self, entry):
1367 if entry is not None:
1368 self.selectedEntry = entry
1369 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1371 def inputCallback(self, value):
1372 if value is not None:
1373 print "stopping recording after", int(value), "minutes."
1374 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1375 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1377 def instantRecord(self):
1379 stat = os_stat(resolveFilename(SCOPE_HDD))
1381 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1384 if self.isInstantRecordRunning():
1385 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1386 title=_("A recording is currently running.\nWhat do you want to do?"), \
1387 list=[(_("stop recording"), "stop"), \
1388 (_("change recording (duration)"), "changeduration"), \
1389 (_("add recording (indefinitely)"), "indefinitely"), \
1390 (_("add recording (stop after current event)"), "event"), \
1391 (_("add recording (enter recording duration)"), "manualduration"), \
1392 (_("do nothing"), "no")])
1394 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1395 title=_("Start recording?"), \
1396 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1397 (_("add recording (stop after current event)"), "event"), \
1398 (_("add recording (enter recording duration)"), "manualduration"), \
1399 (_("don't record"), "no")])
1401 from Tools.ISO639 import LanguageCodes
1403 class InfoBarAudioSelection:
1405 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1407 "audioSelection": (self.audioSelection, _("Audio Options...")),
1410 def audioSelection(self):
1411 service = self.session.nav.getCurrentService()
1412 audio = service and service.audioTracks()
1413 self.audioTracks = audio
1414 n = audio and audio.getNumberOfTracks() or 0
1415 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1417 print "tlist:", tlist
1419 self.audioChannel = service.audioChannel()
1422 i = audio.getTrackInfo(x)
1423 language = i.getLanguage()
1424 description = i.getDescription()
1426 if LanguageCodes.has_key(language):
1427 language = LanguageCodes[language][0]
1429 if len(description):
1430 description += " (" + language + ")"
1432 description = language
1434 tlist.append((description, x))
1436 selectedAudio = tlist[0][1]
1437 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1441 if x[1] != selectedAudio:
1446 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1447 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1449 del self.audioTracks
1451 def audioSelected(self, audio):
1452 if audio is not None:
1453 if isinstance(audio[1], str):
1454 if audio[1] == "mode":
1455 keys = ["red", "green", "yellow"]
1456 selection = self.audioChannel.getCurrentChannel()
1457 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1458 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1460 del self.audioChannel
1461 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1462 self.audioTracks.selectTrack(audio[1])
1464 del self.audioChannel
1465 del self.audioTracks
1467 def modeSelected(self, mode):
1468 if mode is not None:
1469 self.audioChannel.selectChannel(mode[1])
1470 del self.audioChannel
1472 class InfoBarSubserviceSelection:
1474 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1476 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1479 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1481 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1482 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1484 self["SubserviceQuickzapAction"].setEnabled(False)
1486 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1490 def checkSubservicesAvail(self, ev):
1491 if ev == iPlayableService.evUpdatedEventInfo:
1492 service = self.session.nav.getCurrentService()
1493 subservices = service and service.subServices()
1494 if not subservices or subservices.getNumberOfSubservices() == 0:
1495 self["SubserviceQuickzapAction"].setEnabled(False)
1497 def nextSubservice(self):
1498 self.changeSubservice(+1)
1500 def prevSubservice(self):
1501 self.changeSubservice(-1)
1503 def changeSubservice(self, direction):
1504 service = self.session.nav.getCurrentService()
1505 subservices = service and service.subServices()
1506 n = subservices and subservices.getNumberOfSubservices()
1509 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1511 if subservices.getSubservice(x).toString() == ref.toString():
1514 selection += direction
1519 newservice = subservices.getSubservice(selection)
1520 if newservice.valid():
1523 self.session.nav.playService(newservice)
1525 def subserviceSelection(self):
1526 service = self.session.nav.getCurrentService()
1527 subservices = service and service.subServices()
1528 self.bouquets = self.servicelist.getBouquetList()
1529 n = subservices and subservices.getNumberOfSubservices()
1532 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1535 i = subservices.getSubservice(x)
1536 if i.toString() == ref.toString():
1538 tlist.append((i.getName(), i))
1540 if self.bouquets and len(self.bouquets):
1541 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1542 if config.usage.multibouquet.value:
1543 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1545 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1548 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1549 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1552 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1554 def subserviceSelected(self, service):
1556 if not service is None:
1557 if isinstance(service[1], str):
1558 if service[1] == "quickzap":
1559 from Screens.SubservicesQuickzap import SubservicesQuickzap
1560 self.session.open(SubservicesQuickzap, service[2])
1562 self["SubserviceQuickzapAction"].setEnabled(True)
1563 self.session.nav.playService(service[1])
1565 def addSubserviceToBouquetCallback(self, service):
1566 if len(service) > 1 and isinstance(service[1], eServiceReference):
1567 self.selectedSubservice = service
1568 if self.bouquets is None:
1571 cnt = len(self.bouquets)
1572 if cnt > 1: # show bouquet list
1573 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1574 elif cnt == 1: # add to only one existing bouquet
1575 self.addSubserviceToBouquet(self.bouquets[0][1])
1576 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1578 def bouquetSelClosed(self, confirmed):
1580 del self.selectedSubservice
1582 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1584 def addSubserviceToBouquet(self, dest):
1585 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1587 self.bsel.close(True)
1589 del self.selectedSubservice
1591 class InfoBarAdditionalInfo:
1593 self["NimA"] = Pixmap()
1594 self["NimB"] = Pixmap()
1595 self["NimA_Active"] = Pixmap()
1596 self["NimB_Active"] = Pixmap()
1598 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1599 self["TimeshiftPossible"] = self["RecordingPossible"]
1600 self["ExtensionsAvailable"] = Boolean(fixed=1)
1602 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1603 res_mgr = eDVBResourceManager.getInstance()
1605 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1607 def tunerUseMaskChanged(self, mask):
1609 self["NimA_Active"].show()
1611 self["NimA_Active"].hide()
1613 self["NimB_Active"].show()
1615 self["NimB_Active"].hide()
1617 def checkTunerState(self, service):
1618 info = service and service.frontendInfo()
1619 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1620 if feNumber is None:
1630 def gotServiceEvent(self, ev):
1631 service = self.session.nav.getCurrentService()
1632 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1633 self.checkTunerState(service)
1635 class InfoBarNotifications:
1637 self.onExecBegin.append(self.checkNotifications)
1638 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1639 self.onClose.append(self.__removeNotification)
1641 def __removeNotification(self):
1642 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1644 def checkNotificationsIfExecing(self):
1646 self.checkNotifications()
1648 def checkNotifications(self):
1649 if len(Notifications.notifications):
1650 n = Notifications.notifications[0]
1652 Notifications.notifications = Notifications.notifications[1:]
1655 if n[3].has_key("onSessionOpenCallback"):
1656 n[3]["onSessionOpenCallback"]()
1657 del n[3]["onSessionOpenCallback"]
1660 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1662 dlg = self.session.open(n[1], *n[2], **n[3])
1664 # remember that this notification is currently active
1666 Notifications.current_notifications.append(d)
1667 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1669 def __notificationClosed(self, d):
1670 Notifications.current_notifications.remove(d)
1672 class InfoBarServiceNotifications:
1674 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1676 iPlayableService.evEnd: self.serviceHasEnded
1679 def serviceHasEnded(self):
1680 print "service end!"
1683 self.setSeekState(self.SEEK_STATE_PLAY)
1687 class InfoBarCueSheetSupport:
1693 ENABLE_RESUME_SUPPORT = False
1696 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1698 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1699 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1700 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1704 self.is_closing = False
1705 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1707 iPlayableService.evStart: self.__serviceStarted,
1710 def __serviceStarted(self):
1713 print "new service started! trying to download cuts!"
1714 self.downloadCuesheet()
1716 if self.ENABLE_RESUME_SUPPORT:
1719 for (pts, what) in self.cut_list:
1720 if what == self.CUT_TYPE_LAST:
1723 if last is not None:
1724 self.resume_point = last
1725 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1727 def playLastCB(self, answer):
1729 seekable = self.__getSeekable()
1730 if seekable is not None:
1731 seekable.seekTo(self.resume_point)
1733 def __getSeekable(self):
1734 service = self.session.nav.getCurrentService()
1737 return service.seek()
1739 def cueGetCurrentPosition(self):
1740 seek = self.__getSeekable()
1743 r = seek.getPlayPosition()
1748 def jumpPreviousNextMark(self, cmp, alternative=None):
1749 current_pos = self.cueGetCurrentPosition()
1750 if current_pos is None:
1752 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1753 if mark is not None:
1755 elif alternative is not None:
1760 seekable = self.__getSeekable()
1761 if seekable is not None:
1762 seekable.seekTo(pts)
1764 def jumpPreviousMark(self):
1765 # we add 2 seconds, so if the play position is <2s after
1766 # the mark, the mark before will be used
1767 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1769 def jumpNextMark(self):
1770 self.jumpPreviousNextMark(lambda x: x)
1772 def getNearestCutPoint(self, pts, cmp=abs):
1775 for cp in self.cut_list:
1776 diff = cmp(cp[0] - pts)
1777 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1781 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1782 current_pos = self.cueGetCurrentPosition()
1783 if current_pos is None:
1784 print "not seekable"
1787 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1789 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1791 return nearest_cutpoint
1793 self.removeMark(nearest_cutpoint)
1794 elif not onlyremove and not onlyreturn:
1795 self.addMark((current_pos, self.CUT_TYPE_MARK))
1800 def addMark(self, point):
1801 insort(self.cut_list, point)
1802 self.uploadCuesheet()
1804 def removeMark(self, point):
1805 self.cut_list.remove(point)
1806 self.uploadCuesheet()
1808 def __getCuesheet(self):
1809 service = self.session.nav.getCurrentService()
1812 return service.cueSheet()
1814 def uploadCuesheet(self):
1815 cue = self.__getCuesheet()
1818 print "upload failed, no cuesheet interface"
1820 cue.setCutList(self.cut_list)
1822 def downloadCuesheet(self):
1823 cue = self.__getCuesheet()
1826 print "upload failed, no cuesheet interface"
1828 self.cut_list = cue.getCutList()
1830 class InfoBarSummary(Screen):
1832 <screen position="0,0" size="132,64">
1833 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1834 <convert type="ClockToText">WithSeconds</convert>
1836 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1837 <convert type="ServiceName">Name</convert>
1841 def __init__(self, session, parent):
1842 Screen.__init__(self, session)
1843 self["CurrentService"] = CurrentService(self.session.nav)
1844 self["CurrentTime"] = Clock()
1846 class InfoBarSummarySupport:
1850 def createSummary(self):
1851 return InfoBarSummary
1853 class InfoBarTeletextPlugin:
1855 self.teletext_plugin = None
1857 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1858 self.teletext_plugin = p
1860 if self.teletext_plugin is not None:
1861 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1863 "startTeletext": (self.startTeletext, _("View teletext..."))
1866 print "no teletext plugin found!"
1868 def startTeletext(self):
1869 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1871 class InfoBarSubtitleSupport(object):
1873 object.__init__(self)
1874 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1875 self.__subtitles_enabled = False
1877 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1879 iPlayableService.evEnd: self.__serviceStopped,
1880 iPlayableService.evUpdatedInfo: self.__updatedInfo
1882 self.cached_subtitle_checked = False
1884 def __serviceStopped(self):
1885 self.subtitle_window.hide()
1886 self.__subtitles_enabled = False
1887 self.cached_subtitle_checked = False
1889 def __updatedInfo(self):
1890 if not self.cached_subtitle_checked:
1891 subtitle = self.getCurrentServiceSubtitle()
1892 self.cached_subtitle_checked = True
1894 self.__selected_subtitle = subtitle.getCachedSubtitle()
1895 if self.__selected_subtitle:
1896 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1897 self.subtitle_window.show()
1898 self.__subtitles_enabled = True
1900 def getCurrentServiceSubtitle(self):
1901 service = self.session.nav.getCurrentService()
1902 return service and service.subtitle()
1904 def setSubtitlesEnable(self, enable=True):
1905 subtitle = self.getCurrentServiceSubtitle()
1906 if enable and self.__selected_subtitle is not None:
1907 if subtitle and not self.__subtitles_enabled:
1908 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1909 self.subtitle_window.show()
1910 self.__subtitles_enabled = True
1913 subtitle.disableSubtitles(self.subtitle_window.instance)
1914 self.__subtitles_enabled = False
1915 self.subtitle_window.hide()
1917 def setSelectedSubtitle(self, subtitle):
1918 self.__selected_subtitle = subtitle
1920 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1921 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1923 class InfoBarServiceErrorPopupSupport:
1925 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1927 iPlayableService.evTuneFailed: self.__tuneFailed,
1928 iPlayableService.evStart: self.__serviceStarted
1930 self.__serviceStarted()
1932 def __serviceStarted(self):
1933 self.last_error = None
1934 Notifications.RemovePopup(id = "ZapError")
1936 def __tuneFailed(self):
1937 service = self.session.nav.getCurrentService()
1938 info = service and service.info()
1939 error = info and info.getInfo(iServiceInformation.sDVBState)
1941 if error == self.last_error:
1944 self.last_error = error
1947 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1948 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1949 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1950 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1951 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1952 eDVBServicePMTHandler.eventNewProgramInfo: None,
1953 eDVBServicePMTHandler.eventTuned: None,
1954 eDVBServicePMTHandler.eventSOF: None,
1955 eDVBServicePMTHandler.eventEOF: None
1958 error = errors.get(error) #this returns None when the key not exist in the dict
1960 if error is not None:
1961 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1963 Notifications.RemovePopup(id = "ZapError")