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.TimerList import TimerEntryComponent
18 from Components.config import config, ConfigBoolean, ConfigClock
19 from EpgSelection import EPGSelection
20 from Plugins.Plugin import PluginDescriptor
22 from Screen import Screen
23 from Screens.ChoiceBox import ChoiceBox
24 from Screens.Dish import Dish
25 from Screens.EventView import EventViewEPGSelect, EventViewSimple
26 from Screens.InputBox import InputBox
27 from Screens.MessageBox import MessageBox
28 from Screens.MinuteInput import MinuteInput
29 from Screens.TimerSelection import TimerSelection
30 from Screens.PictureInPicture import PictureInPicture
31 from Screens.SubtitleDisplay import SubtitleDisplay
32 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
33 from Screens.SleepTimerEdit import SleepTimerEdit
34 from Screens.TimeDateInput import TimeDateInput
35 from ServiceReference import ServiceReference
37 from Tools import Notifications
38 from Tools.Directories import SCOPE_HDD, resolveFilename
40 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
41 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
43 from time import time, localtime, strftime
44 from os import stat as os_stat
45 from bisect import insort
48 from Menu import MainMenu, mdom
52 self.dishDialog = self.session.instantiateDialog(Dish)
53 self.onLayoutFinish.append(self.dishDialog.show)
55 class InfoBarShowHide:
56 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
64 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
66 "toggleShow": self.toggleShow,
68 }, 1) # lower prio to make it possible to override ok and cancel..
70 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
72 iPlayableService.evStart: self.serviceStarted,
75 self.__state = self.STATE_SHOWN
78 self.hideTimer = eTimer()
79 self.hideTimer.timeout.get().append(self.doTimerHide)
80 self.hideTimer.start(5000, True)
82 self.onShow.append(self.__onShow)
83 self.onHide.append(self.__onHide)
85 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...")),
408 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
411 def showEventInfoWhenNotVisible(self):
418 def zapToService(self, service):
419 if not service is None:
420 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
421 self.servicelist.clearPath()
422 if self.servicelist.bouquet_root != self.epg_bouquet:
423 self.servicelist.enterPath(self.servicelist.bouquet_root)
424 self.servicelist.enterPath(self.epg_bouquet)
425 self.servicelist.setCurrentSelection(service) #select the service in servicelist
426 self.servicelist.zap()
428 def getBouquetServices(self, bouquet):
430 servicelist = eServiceCenter.getInstance().list(bouquet)
431 if not servicelist is None:
433 service = servicelist.getNext()
434 if not service.valid(): #check if end of list
436 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
438 services.append(ServiceReference(service))
441 def openBouquetEPG(self, bouquet, withCallback=True):
442 services = self.getBouquetServices(bouquet)
444 self.epg_bouquet = bouquet
446 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
448 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
450 def changeBouquetCB(self, direction, epg):
453 self.bouquetSel.down()
456 bouquet = self.bouquetSel.getCurrent()
457 services = self.getBouquetServices(bouquet)
459 self.epg_bouquet = bouquet
460 epg.setServices(services)
462 def closed(self, ret=False):
463 closedScreen = self.dlg_stack.pop()
464 if self.bouquetSel and closedScreen == self.bouquetSel:
465 self.bouquetSel = None
466 elif self.eventView and closedScreen == self.eventView:
467 self.eventView = None
469 dlgs=len(self.dlg_stack)
471 self.dlg_stack[dlgs-1].close(dlgs > 1)
473 def openMultiServiceEPG(self, withCallback=True):
474 bouquets = self.servicelist.getBouquetList()
479 if cnt > 1: # show bouquet list
481 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
482 self.dlg_stack.append(self.bouquetSel)
484 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
486 self.openBouquetEPG(bouquets[0][1], withCallback)
488 def openSingleServiceEPG(self):
489 ref=self.session.nav.getCurrentlyPlayingServiceReference()
490 self.session.open(EPGSelection, ref)
492 def openSimilarList(self, eventid, refstr):
493 self.session.open(EPGSelection, refstr, None, eventid)
495 def getNowNext(self):
497 service = self.session.nav.getCurrentService()
498 info = service and service.info()
499 ptr = info and info.getEvent(0)
501 self.epglist.append(ptr)
502 ptr = info and info.getEvent(1)
504 self.epglist.append(ptr)
506 def __evEventInfoChanged(self):
507 if self.is_now_next and len(self.dlg_stack) == 1:
509 assert self.eventView
510 if len(self.epglist):
511 self.eventView.setEvent(self.epglist[0])
513 def openEventView(self):
514 ref = self.session.nav.getCurrentlyPlayingServiceReference()
516 if len(self.epglist) == 0:
517 self.is_now_next = False
518 epg = eEPGCache.getInstance()
519 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
521 self.epglist.append(ptr)
522 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
524 self.epglist.append(ptr)
526 self.is_now_next = True
527 if len(self.epglist) > 0:
528 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
529 self.dlg_stack.append(self.eventView)
531 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
532 self.openMultiServiceEPG(False)
534 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
535 if len(self.epglist) > 1:
536 tmp = self.epglist[0]
537 self.epglist[0]=self.epglist[1]
539 setEvent(self.epglist[0])
542 """provides a snr/agc/ber display"""
544 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
547 """provides a current/next event info display"""
549 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
550 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
552 class InfoBarRdsDecoder:
553 """provides RDS and Rass support/display"""
555 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
556 self.rass_interactive = None
558 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
560 iPlayableService.evEnd: self.__serviceStopped,
561 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
564 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
566 "startRassInteractive": self.startRassInteractive
569 self["RdsActions"].setEnabled(False)
571 self.onLayoutFinish.append(self.rds_display.show)
572 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
574 def RassInteractivePossibilityChanged(self, state):
575 self["RdsActions"].setEnabled(state)
577 def RassSlidePicChanged(self):
578 if not self.rass_interactive:
579 service = self.session.nav.getCurrentService()
580 decoder = service and service.rdsDecoder()
582 decoder.showRassSlidePicture()
584 def __serviceStopped(self):
585 if self.rass_interactive is not None:
586 rass_interactive = self.rass_interactive
587 self.rass_interactive = None
588 rass_interactive.close()
590 def startRassInteractive(self):
591 self.rds_display.hide()
592 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
594 def RassInteractiveClosed(self, *val):
595 if self.rass_interactive is not None:
596 self.rass_interactive = None
597 self.RassSlidePicChanged()
598 self.rds_display.show()
600 class InfoBarServiceName:
602 self["CurrentService"] = CurrentService(self.session.nav)
605 """handles actions like seeking, pause"""
607 # ispause, isff, issm
608 SEEK_STATE_PLAY = (0, 0, 0, ">")
609 SEEK_STATE_PAUSE = (1, 0, 0, "||")
610 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
611 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
612 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
613 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
614 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
615 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
617 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
618 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
619 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
620 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
622 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
623 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
624 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
626 SEEK_STATE_EOF = (1, 0, 0, "END")
628 def __init__(self, actionmap = "InfobarSeekActions"):
629 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
631 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
632 iPlayableService.evStart: self.__serviceStarted,
634 iPlayableService.evEOF: self.__evEOF,
635 iPlayableService.evSOF: self.__evSOF,
638 class InfoBarSeekActionMap(HelpableActionMap):
639 def __init__(self, screen, *args, **kwargs):
640 HelpableActionMap.__init__(self, screen, *args, **kwargs)
643 def action(self, contexts, action):
644 print "action:", action
645 if action[:5] == "seek:":
646 time = int(action[5:])
647 self.screen.seekRelative(time * 90000)
648 self.screen.showAfterSeek()
651 return HelpableActionMap.action(self, contexts, action)
653 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
655 "playpauseService": self.playpauseService,
656 "pauseService": (self.pauseService, _("pause")),
657 "unPauseService": (self.unPauseService, _("continue")),
659 "seekFwd": (self.seekFwd, _("skip forward")),
660 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
661 "seekBack": (self.seekBack, _("skip backward")),
662 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
664 "seekFwdDef": (self.seekFwdDef, _("skip forward (self defined)")),
665 "seekBackDef": (self.seekBackDef, _("skip backward (self defined)"))
667 # give them a little more priority to win over color buttons
669 self["SeekActions"].setEnabled(False)
671 self.seekstate = self.SEEK_STATE_PLAY
673 self.seek_flag = True
675 self.onPlayStateChanged = [ ]
677 self.lockedBecauseOfSkipping = False
679 self.__seekableStatusChanged()
681 def showAfterSeek(self):
682 if isinstance(self, InfoBarShowHide):
692 service = self.session.nav.getCurrentService()
696 seek = service.seek()
698 if seek is None or not seek.isCurrentlySeekable():
703 def isSeekable(self):
704 if self.getSeek() is None:
708 def __seekableStatusChanged(self):
709 print "seekable status changed!"
710 if not self.isSeekable():
711 self["SeekActions"].setEnabled(False)
712 print "not seekable, return to play"
713 self.setSeekState(self.SEEK_STATE_PLAY)
715 self["SeekActions"].setEnabled(True)
718 def __serviceStarted(self):
719 self.seekstate = self.SEEK_STATE_PLAY
720 self.__seekableStatusChanged()
722 def setSeekState(self, state):
723 service = self.session.nav.getCurrentService()
728 if not self.isSeekable():
729 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
730 state = self.SEEK_STATE_PLAY
732 pauseable = service.pause()
734 if pauseable is None:
735 print "not pauseable."
736 state = self.SEEK_STATE_PLAY
738 oldstate = self.seekstate
739 self.seekstate = state
742 if oldstate[i] != self.seekstate[i]:
743 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
745 for c in self.onPlayStateChanged:
748 self.checkSkipShowHideLock()
752 def playpauseService(self):
753 if self.seekstate != self.SEEK_STATE_PLAY:
754 self.unPauseService()
758 def pauseService(self):
759 if self.seekstate == self.SEEK_STATE_PAUSE:
760 print "pause, but in fact unpause"
761 self.unPauseService()
763 if self.seekstate == self.SEEK_STATE_PLAY:
764 print "yes, playing."
766 print "no", self.seekstate
768 self.setSeekState(self.SEEK_STATE_PAUSE);
770 def unPauseService(self):
772 if self.seekstate == self.SEEK_STATE_PLAY:
774 self.setSeekState(self.SEEK_STATE_PLAY)
776 def doSeek(self, seektime):
777 print "doseek", seektime
778 service = self.session.nav.getCurrentService()
782 seekable = self.getSeek()
786 seekable.seekTo(90 * seektime)
790 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
791 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
792 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
793 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
794 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
795 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
796 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
797 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
798 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
799 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
800 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
801 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
802 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
803 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
804 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
805 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
807 self.setSeekState(lookup[self.seekstate])
811 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
812 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
813 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
814 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
815 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
816 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
817 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
818 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
819 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
820 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
821 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
822 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
823 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
824 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
825 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
826 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
828 self.setSeekState(lookup[self.seekstate])
830 if self.seekstate == self.SEEK_STATE_PAUSE:
831 seekable = self.getSeek()
832 if seekable is not None:
833 seekable.seekRelative(-1, 3)
835 def seekFwdDef(self):
836 self.seek_flag = False
837 seconds = config.usage.self_defined_seek.value
838 print "Seek", seconds, "seconds self defined forward"
839 seekable = self.getSeek()
840 if seekable is not None:
841 seekable.seekRelative(1, seconds * 90000)
843 def seekBackDef(self):
844 self.seek_flag = False
845 seconds = config.usage.self_defined_seek.value
846 print "Seek", seconds, "seconds self defined backward"
847 seekable = self.getSeek()
848 if seekable is not None:
849 seekable.seekRelative(1, 0 - seconds * 90000)
851 def seekFwdManual(self):
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 seekBackManual(self):
862 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
864 def rwdSeekTo(self, minutes):
866 self.fwdSeekTo(0 - minutes)
868 def checkSkipShowHideLock(self):
869 wantlock = self.seekstate != self.SEEK_STATE_PLAY
871 if config.usage.show_infobar_on_zap.value:
872 if self.lockedBecauseOfSkipping and not wantlock:
874 self.lockedBecauseOfSkipping = False
876 if wantlock and not self.lockedBecauseOfSkipping:
878 self.lockedBecauseOfSkipping = True
881 if self.seekstate == self.SEEK_STATE_EOF:
883 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
884 print "end of stream while seeking back, ignoring."
887 # if we are seeking, we try to end up ~1s before the end, and pause there.
888 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
889 self.setSeekState(self.SEEK_STATE_EOF)
890 self.seekRelativeToEnd(-90000)
892 self.setSeekState(self.SEEK_STATE_EOF)
895 self.setSeekState(self.SEEK_STATE_PLAY)
898 def seekRelative(self, diff):
899 if self.seek_flag == True:
900 seekable = self.getSeek()
901 if seekable is not None:
902 print "seekRelative: res:", seekable.seekRelative(1, diff)
906 self.seek_flag = True
908 def seekRelativeToEnd(self, diff):
909 assert diff <= 0, "diff is expected to be negative!"
911 # might sound like an evil hack, but:
912 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
913 # and we don't get that by passing 0 here (it would seek to begin).
917 # relative-to-end seeking is implemented as absolutes seeks with negative time
918 self.seekAbsolute(diff)
920 def seekAbsolute(self, abs):
921 seekable = self.getSeek()
922 if seekable is not None:
925 from Screens.PVRState import PVRState, TimeshiftState
927 class InfoBarPVRState:
928 def __init__(self, screen=PVRState):
929 self.onPlayStateChanged.append(self.__playStateChanged)
930 self.pvrStateDialog = self.session.instantiateDialog(screen)
931 self.onShow.append(self._mayShow)
932 self.onHide.append(self.pvrStateDialog.hide)
935 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
936 self.pvrStateDialog.show()
938 def __playStateChanged(self, state):
939 playstateString = state[3]
940 self.pvrStateDialog["state"].setText(playstateString)
943 class InfoBarTimeshiftState(InfoBarPVRState):
945 InfoBarPVRState.__init__(self, screen=TimeshiftState)
948 if self.execing and self.timeshift_enabled:
949 self.pvrStateDialog.show()
951 class InfoBarShowMovies:
953 # i don't really like this class.
954 # it calls a not further specified "movie list" on up/down/movieList,
955 # so this is not more than an action map
957 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
959 "movieList": (self.showMovies, _("movie list")),
960 "up": (self.showMovies, _("movie list")),
961 "down": (self.showMovies, _("movie list"))
964 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
968 # Timeshift works the following way:
969 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
970 # - normal playback TUNER unused PLAY enable disable disable
971 # - user presses "yellow" button. FILE record PAUSE enable disable enable
972 # - user presess pause again FILE record PLAY enable disable enable
973 # - user fast forwards FILE record FF enable disable enable
974 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
975 # - user backwards FILE record BACK # !! enable disable enable
979 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
980 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
981 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
982 # - the user can now PVR around
983 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
984 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
986 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
987 # - if the user rewinds, or press pause, timeshift will be activated again
989 # note that a timeshift can be enabled ("recording") and
990 # activated (currently time-shifting).
992 class InfoBarTimeshift:
994 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
996 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
997 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
999 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1001 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1002 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1003 }, prio=-1) # priority over record
1005 self.timeshift_enabled = 0
1006 self.timeshift_state = 0
1007 self.ts_rewind_timer = eTimer()
1008 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1010 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1012 iPlayableService.evStart: self.__serviceStarted,
1013 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1016 def getTimeshift(self):
1017 service = self.session.nav.getCurrentService()
1018 return service and service.timeshift()
1020 def startTimeshift(self):
1021 print "enable timeshift"
1022 ts = self.getTimeshift()
1024 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1025 print "no ts interface"
1028 if self.timeshift_enabled:
1029 print "hu, timeshift already enabled?"
1031 if not ts.startTimeshift():
1032 self.timeshift_enabled = 1
1034 # we remove the "relative time" for now.
1035 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1038 #self.setSeekState(self.SEEK_STATE_PAUSE)
1039 self.activateTimeshiftEnd(False)
1041 # enable the "TimeshiftEnableActions", which will override
1042 # the startTimeshift actions
1043 self.__seekableStatusChanged()
1045 print "timeshift failed"
1047 def stopTimeshift(self):
1048 if not self.timeshift_enabled:
1050 print "disable timeshift"
1051 ts = self.getTimeshift()
1054 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1056 def stopTimeshiftConfirmed(self, confirmed):
1060 ts = self.getTimeshift()
1065 self.timeshift_enabled = 0
1068 self.__seekableStatusChanged()
1070 # activates timeshift, and seeks to (almost) the end
1071 def activateTimeshiftEnd(self, back = True):
1072 ts = self.getTimeshift()
1073 print "activateTimeshiftEnd"
1078 if ts.isTimeshiftActive():
1079 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1083 ts.activateTimeshift() # activate timeshift will automatically pause
1084 self.setSeekState(self.SEEK_STATE_PAUSE)
1085 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1088 self.ts_rewind_timer.start(200, 1)
1090 def rewindService(self):
1091 self.setSeekState(self.SEEK_STATE_BACK_16X)
1093 # same as activateTimeshiftEnd, but pauses afterwards.
1094 def activateTimeshiftEndAndPause(self):
1095 print "activateTimeshiftEndAndPause"
1096 #state = self.seekstate
1097 self.activateTimeshiftEnd(False)
1099 def __seekableStatusChanged(self):
1102 print "self.isSeekable", self.isSeekable()
1103 print "self.timeshift_enabled", self.timeshift_enabled
1105 # when this service is not seekable, but timeshift
1106 # is enabled, this means we can activate
1108 if not self.isSeekable() and self.timeshift_enabled:
1111 print "timeshift activate:", enabled
1112 self["TimeshiftActivateActions"].setEnabled(enabled)
1114 def __serviceStarted(self):
1115 self.timeshift_enabled = False
1116 self.__seekableStatusChanged()
1118 from Screens.PiPSetup import PiPSetup
1120 class InfoBarExtensions:
1121 EXTENSION_SINGLE = 0
1127 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1129 "extensions": (self.showExtensionSelection, _("view extensions...")),
1132 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1133 self.list.append((type, extension, key))
1135 def updateExtension(self, extension, key = None):
1136 self.extensionsList.append(extension)
1138 if self.extensionKeys.has_key(key):
1142 for x in self.availableKeys:
1143 if not self.extensionKeys.has_key(x):
1148 self.extensionKeys[key] = len(self.extensionsList) - 1
1150 def updateExtensions(self):
1151 self.extensionsList = []
1152 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1153 self.extensionKeys = {}
1155 if x[0] == self.EXTENSION_SINGLE:
1156 self.updateExtension(x[1], x[2])
1159 self.updateExtension(y[0], y[1])
1162 def showExtensionSelection(self):
1163 self.updateExtensions()
1164 extensionsList = self.extensionsList[:]
1167 for x in self.availableKeys:
1168 if self.extensionKeys.has_key(x):
1169 entry = self.extensionKeys[x]
1170 extension = self.extensionsList[entry]
1172 name = str(extension[0]())
1173 list.append((extension[0](), extension))
1175 extensionsList.remove(extension)
1177 extensionsList.remove(extension)
1178 for x in extensionsList:
1179 list.append((x[0](), x))
1180 keys += [""] * len(extensionsList)
1181 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1183 def extensionCallback(self, answer):
1184 if answer is not None:
1187 from Tools.BoundFunction import boundFunction
1189 # depends on InfoBarExtensions
1190 from Components.PluginComponent import plugins
1192 class InfoBarPlugins:
1194 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1196 def getPluginName(self, name):
1199 def getPluginList(self):
1201 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1202 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1205 def runPlugin(self, plugin):
1206 plugin(session = self.session)
1208 # depends on InfoBarExtensions
1209 class InfoBarSleepTimer:
1211 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1213 def available(self):
1216 def getSleepTimerName(self):
1217 return _("Sleep Timer")
1219 def showSleepTimerSetup(self):
1220 self.session.open(SleepTimerEdit)
1222 # depends on InfoBarExtensions
1225 self.session.pipshown = False
1227 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1228 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1229 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1231 def available(self):
1235 return self.session.pipshown
1237 def getShowHideName(self):
1238 if self.session.pipshown:
1239 return _("Disable Picture in Picture")
1241 return _("Activate Picture in Picture")
1243 def getSwapName(self):
1244 return _("Swap Services")
1246 def getMoveName(self):
1247 return _("Move Picture in Picture")
1250 if self.session.pipshown:
1251 del self.session.pip
1252 self.session.pipshown = False
1254 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1255 self.session.pip.show()
1256 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1257 if self.session.pip.playService(newservice):
1258 self.session.pipshown = True
1259 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1261 self.session.pipshown = False
1262 del self.session.pip
1263 self.session.nav.playService(newservice)
1266 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1267 if self.session.pip.servicePath:
1268 servicepath = self.servicelist.getCurrentServicePath()
1269 ref=servicepath[len(servicepath)-1]
1270 pipref=self.session.pip.getCurrentService()
1271 self.session.pip.playService(swapservice)
1272 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1273 if pipref.toString() != ref.toString(): # is a subservice ?
1274 self.session.nav.stopService() # stop portal
1275 self.session.nav.playService(pipref) # start subservice
1276 self.session.pip.servicePath=servicepath
1279 self.session.open(PiPSetup, pip = self.session.pip)
1281 from RecordTimer import parseEvent
1283 class InfoBarInstantRecord:
1284 """Instant Record - handles the instantRecord action in order to
1285 start/stop instant records"""
1287 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1289 "instantRecord": (self.instantRecord, _("Instant Record...")),
1292 self["BlinkingPoint"] = BlinkingPixmapConditional()
1293 self["BlinkingPoint"].hide()
1294 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1296 def stopCurrentRecording(self, entry = -1):
1297 if entry is not None and entry != -1:
1298 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1299 self.recording.remove(self.recording[entry])
1301 def startInstantRecording(self, limitEvent = False):
1302 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1304 # try to get event info
1307 service = self.session.nav.getCurrentService()
1308 epg = eEPGCache.getInstance()
1309 event = epg.lookupEventTime(serviceref, -1, 0)
1311 info = service.info()
1312 ev = info.getEvent(0)
1318 end = time() + 3600 * 10
1319 name = "instant record"
1323 if event is not None:
1324 curEvent = parseEvent(event)
1326 description = curEvent[3]
1327 eventid = curEvent[4]
1332 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1334 data = (begin, end, name, description, eventid)
1336 recording = self.session.nav.recordWithTimer(serviceref, *data)
1337 recording.dontSave = True
1338 self.recording.append(recording)
1340 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1342 def isInstantRecordRunning(self):
1343 print "self.recording:", self.recording
1344 if len(self.recording) > 0:
1345 for x in self.recording:
1350 def recordQuestionCallback(self, answer):
1351 print "pre:\n", self.recording
1353 if answer is None or answer[1] == "no":
1356 recording = self.recording[:]
1358 if not x in self.session.nav.RecordTimer.timer_list:
1359 self.recording.remove(x)
1360 elif x.dontSave and x.isRunning():
1361 list.append(TimerEntryComponent(x, False))
1363 if answer[1] == "changeduration":
1364 if len(self.recording) == 1:
1365 self.changeDuration(0)
1367 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1368 elif answer[1] == "changeendtime":
1369 if len(self.recording) == 1:
1372 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1373 elif answer[1] == "stop":
1374 if len(self.recording) == 1:
1375 self.stopCurrentRecording(0)
1377 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1378 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1379 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1380 if answer[1] == "manualduration":
1381 self.changeDuration(len(self.recording)-1)
1382 elif answer[1] == "manualendtime":
1383 self.setEndtime(len(self.recording)-1)
1384 print "after:\n", self.recording
1386 def setEndtime(self, entry):
1387 if entry is not None:
1388 self.selectedEntry = entry
1389 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1390 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1391 dlg.setTitle(_("Please change recording endtime"))
1393 def TimeDateInputClosed(self, ret):
1396 localendtime = localtime(ret[1])
1397 print "stopping recording at", strftime("%c", localendtime)
1398 self.recording[self.selectedEntry].end = ret[1]
1399 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1401 def changeDuration(self, entry):
1402 if entry is not None:
1403 self.selectedEntry = entry
1404 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1406 def inputCallback(self, value):
1407 if value is not None:
1408 print "stopping recording after", int(value), "minutes."
1409 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1410 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1412 def instantRecord(self):
1414 stat = os_stat(resolveFilename(SCOPE_HDD))
1416 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1419 if self.isInstantRecordRunning():
1420 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1421 title=_("A recording is currently running.\nWhat do you want to do?"), \
1422 list=[(_("stop recording"), "stop"), \
1423 (_("change recording (duration)"), "changeduration"), \
1424 (_("change recording (endtime)"), "changeendtime"), \
1425 (_("add recording (indefinitely)"), "indefinitely"), \
1426 (_("add recording (stop after current event)"), "event"), \
1427 (_("add recording (enter recording duration)"), "manualduration"), \
1428 (_("add recording (enter recording endtime)"), "manualendtime"), \
1429 (_("do nothing"), "no")])
1431 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1432 title=_("Start recording?"), \
1433 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1434 (_("add recording (stop after current event)"), "event"), \
1435 (_("add recording (enter recording duration)"), "manualduration"), \
1436 (_("add recording (enter recording endtime)"), "manualendtime"), \
1437 (_("don't record"), "no")])
1439 from Tools.ISO639 import LanguageCodes
1441 class InfoBarAudioSelection:
1443 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1445 "audioSelection": (self.audioSelection, _("Audio Options...")),
1448 def audioSelection(self):
1449 service = self.session.nav.getCurrentService()
1450 audio = service and service.audioTracks()
1451 self.audioTracks = audio
1452 n = audio and audio.getNumberOfTracks() or 0
1453 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1455 print "tlist:", tlist
1457 self.audioChannel = service.audioChannel()
1460 i = audio.getTrackInfo(x)
1461 language = i.getLanguage()
1462 description = i.getDescription()
1464 if LanguageCodes.has_key(language):
1465 language = LanguageCodes[language][0]
1467 if len(description):
1468 description += " (" + language + ")"
1470 description = language
1472 tlist.append((description, x))
1474 selectedAudio = tlist[0][1]
1475 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1479 if x[1] != selectedAudio:
1484 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1485 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1487 del self.audioTracks
1489 def audioSelected(self, audio):
1490 if audio is not None:
1491 if isinstance(audio[1], str):
1492 if audio[1] == "mode":
1493 keys = ["red", "green", "yellow"]
1494 selection = self.audioChannel.getCurrentChannel()
1495 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1496 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1498 del self.audioChannel
1499 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1500 self.audioTracks.selectTrack(audio[1])
1502 del self.audioChannel
1503 del self.audioTracks
1505 def modeSelected(self, mode):
1506 if mode is not None:
1507 self.audioChannel.selectChannel(mode[1])
1508 del self.audioChannel
1510 class InfoBarSubserviceSelection:
1512 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1514 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1517 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1519 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1520 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1522 self["SubserviceQuickzapAction"].setEnabled(False)
1524 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1528 def checkSubservicesAvail(self, ev):
1529 if ev == iPlayableService.evUpdatedEventInfo:
1530 service = self.session.nav.getCurrentService()
1531 subservices = service and service.subServices()
1532 if not subservices or subservices.getNumberOfSubservices() == 0:
1533 self["SubserviceQuickzapAction"].setEnabled(False)
1535 def nextSubservice(self):
1536 self.changeSubservice(+1)
1538 def prevSubservice(self):
1539 self.changeSubservice(-1)
1541 def changeSubservice(self, direction):
1542 service = self.session.nav.getCurrentService()
1543 subservices = service and service.subServices()
1544 n = subservices and subservices.getNumberOfSubservices()
1547 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1549 if subservices.getSubservice(x).toString() == ref.toString():
1552 selection += direction
1557 newservice = subservices.getSubservice(selection)
1558 if newservice.valid():
1561 self.session.nav.playService(newservice)
1563 def subserviceSelection(self):
1564 service = self.session.nav.getCurrentService()
1565 subservices = service and service.subServices()
1566 self.bouquets = self.servicelist.getBouquetList()
1567 n = subservices and subservices.getNumberOfSubservices()
1570 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1573 i = subservices.getSubservice(x)
1574 if i.toString() == ref.toString():
1576 tlist.append((i.getName(), i))
1578 if self.bouquets and len(self.bouquets):
1579 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1580 if config.usage.multibouquet.value:
1581 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1583 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1586 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1587 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1590 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1592 def subserviceSelected(self, service):
1594 if not service is None:
1595 if isinstance(service[1], str):
1596 if service[1] == "quickzap":
1597 from Screens.SubservicesQuickzap import SubservicesQuickzap
1598 self.session.open(SubservicesQuickzap, service[2])
1600 self["SubserviceQuickzapAction"].setEnabled(True)
1601 self.session.nav.playService(service[1])
1603 def addSubserviceToBouquetCallback(self, service):
1604 if len(service) > 1 and isinstance(service[1], eServiceReference):
1605 self.selectedSubservice = service
1606 if self.bouquets is None:
1609 cnt = len(self.bouquets)
1610 if cnt > 1: # show bouquet list
1611 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1612 elif cnt == 1: # add to only one existing bouquet
1613 self.addSubserviceToBouquet(self.bouquets[0][1])
1614 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1616 def bouquetSelClosed(self, confirmed):
1618 del self.selectedSubservice
1620 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1622 def addSubserviceToBouquet(self, dest):
1623 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1625 self.bsel.close(True)
1627 del self.selectedSubservice
1629 class InfoBarAdditionalInfo:
1631 self["NimA"] = Pixmap()
1632 self["NimB"] = Pixmap()
1633 self["NimA_Active"] = Pixmap()
1634 self["NimB_Active"] = Pixmap()
1636 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1637 self["TimeshiftPossible"] = self["RecordingPossible"]
1638 self["ExtensionsAvailable"] = Boolean(fixed=1)
1640 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1641 res_mgr = eDVBResourceManager.getInstance()
1643 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1645 def tunerUseMaskChanged(self, mask):
1647 self["NimA_Active"].show()
1649 self["NimA_Active"].hide()
1651 self["NimB_Active"].show()
1653 self["NimB_Active"].hide()
1655 def checkTunerState(self, service):
1656 info = service and service.frontendInfo()
1657 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1658 if feNumber is None:
1668 def gotServiceEvent(self, ev):
1669 service = self.session.nav.getCurrentService()
1670 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1671 self.checkTunerState(service)
1673 class InfoBarNotifications:
1675 self.onExecBegin.append(self.checkNotifications)
1676 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1677 self.onClose.append(self.__removeNotification)
1679 def __removeNotification(self):
1680 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1682 def checkNotificationsIfExecing(self):
1684 self.checkNotifications()
1686 def checkNotifications(self):
1687 if len(Notifications.notifications):
1688 n = Notifications.notifications[0]
1690 Notifications.notifications = Notifications.notifications[1:]
1693 if n[3].has_key("onSessionOpenCallback"):
1694 n[3]["onSessionOpenCallback"]()
1695 del n[3]["onSessionOpenCallback"]
1698 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1700 dlg = self.session.open(n[1], *n[2], **n[3])
1702 # remember that this notification is currently active
1704 Notifications.current_notifications.append(d)
1705 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1707 def __notificationClosed(self, d):
1708 Notifications.current_notifications.remove(d)
1710 class InfoBarServiceNotifications:
1712 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1714 iPlayableService.evEnd: self.serviceHasEnded
1717 def serviceHasEnded(self):
1718 print "service end!"
1721 self.setSeekState(self.SEEK_STATE_PLAY)
1725 class InfoBarCueSheetSupport:
1731 ENABLE_RESUME_SUPPORT = False
1733 def __init__(self, actionmap = "InfobarCueSheetActions"):
1734 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1736 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1737 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1738 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1742 self.is_closing = False
1743 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1745 iPlayableService.evStart: self.__serviceStarted,
1748 def __serviceStarted(self):
1751 print "new service started! trying to download cuts!"
1752 self.downloadCuesheet()
1754 if self.ENABLE_RESUME_SUPPORT:
1757 for (pts, what) in self.cut_list:
1758 if what == self.CUT_TYPE_LAST:
1761 if last is not None:
1762 self.resume_point = last
1763 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1765 def playLastCB(self, answer):
1767 seekable = self.__getSeekable()
1768 if seekable is not None:
1769 seekable.seekTo(self.resume_point)
1770 self.hideAfterResume()
1772 def hideAfterResume(self):
1773 if isinstance(self, InfoBarShowHide):
1776 def __getSeekable(self):
1777 service = self.session.nav.getCurrentService()
1780 return service.seek()
1782 def cueGetCurrentPosition(self):
1783 seek = self.__getSeekable()
1786 r = seek.getPlayPosition()
1791 def jumpPreviousNextMark(self, cmp, alternative=None):
1792 current_pos = self.cueGetCurrentPosition()
1793 if current_pos is None:
1795 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1796 if mark is not None:
1798 elif alternative is not None:
1803 seekable = self.__getSeekable()
1804 if seekable is not None:
1805 seekable.seekTo(pts)
1807 def jumpPreviousMark(self):
1808 # we add 2 seconds, so if the play position is <2s after
1809 # the mark, the mark before will be used
1810 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1812 def jumpNextMark(self):
1813 self.jumpPreviousNextMark(lambda x: x)
1815 def getNearestCutPoint(self, pts, cmp=abs):
1818 for cp in self.cut_list:
1819 diff = cmp(cp[0] - pts)
1820 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1824 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1825 current_pos = self.cueGetCurrentPosition()
1826 if current_pos is None:
1827 print "not seekable"
1830 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1832 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1834 return nearest_cutpoint
1836 self.removeMark(nearest_cutpoint)
1837 elif not onlyremove and not onlyreturn:
1838 self.addMark((current_pos, self.CUT_TYPE_MARK))
1843 def addMark(self, point):
1844 insort(self.cut_list, point)
1845 self.uploadCuesheet()
1846 self.showAfterCuesheetOperation()
1848 def removeMark(self, point):
1849 self.cut_list.remove(point)
1850 self.uploadCuesheet()
1851 self.showAfterCuesheetOperation()
1853 def showAfterCuesheetOperation(self):
1854 if isinstance(self, InfoBarShowHide):
1857 def __getCuesheet(self):
1858 service = self.session.nav.getCurrentService()
1861 return service.cueSheet()
1863 def uploadCuesheet(self):
1864 cue = self.__getCuesheet()
1867 print "upload failed, no cuesheet interface"
1869 cue.setCutList(self.cut_list)
1871 def downloadCuesheet(self):
1872 cue = self.__getCuesheet()
1875 print "download failed, no cuesheet interface"
1878 self.cut_list = cue.getCutList()
1880 class InfoBarSummary(Screen):
1882 <screen position="0,0" size="132,64">
1883 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1884 <convert type="ClockToText">WithSeconds</convert>
1886 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1887 <convert type="ServiceName">Name</convert>
1891 def __init__(self, session, parent):
1892 Screen.__init__(self, session)
1893 self["CurrentService"] = CurrentService(self.session.nav)
1894 self["CurrentTime"] = Clock()
1896 class InfoBarSummarySupport:
1900 def createSummary(self):
1901 return InfoBarSummary
1903 class InfoBarTeletextPlugin:
1905 self.teletext_plugin = None
1907 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1908 self.teletext_plugin = p
1910 if self.teletext_plugin is not None:
1911 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1913 "startTeletext": (self.startTeletext, _("View teletext..."))
1916 print "no teletext plugin found!"
1918 def startTeletext(self):
1919 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1921 class InfoBarSubtitleSupport(object):
1923 object.__init__(self)
1924 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1925 self.__subtitles_enabled = False
1927 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1929 iPlayableService.evEnd: self.__serviceStopped,
1930 iPlayableService.evUpdatedInfo: self.__updatedInfo
1932 self.cached_subtitle_checked = False
1933 self.__selected_subtitle = None
1935 def __serviceStopped(self):
1936 self.subtitle_window.hide()
1937 self.__subtitles_enabled = False
1938 self.cached_subtitle_checked = False
1940 def __updatedInfo(self):
1941 if not self.cached_subtitle_checked:
1942 subtitle = self.getCurrentServiceSubtitle()
1943 self.cached_subtitle_checked = True
1944 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1945 if self.__selected_subtitle:
1946 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1947 self.subtitle_window.show()
1948 self.__subtitles_enabled = True
1950 def getCurrentServiceSubtitle(self):
1951 service = self.session.nav.getCurrentService()
1952 return service and service.subtitle()
1954 def setSubtitlesEnable(self, enable=True):
1955 subtitle = self.getCurrentServiceSubtitle()
1956 if enable and self.__selected_subtitle is not None:
1957 if subtitle and not self.__subtitles_enabled:
1958 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1959 self.subtitle_window.show()
1960 self.__subtitles_enabled = True
1963 subtitle.disableSubtitles(self.subtitle_window.instance)
1964 self.__subtitles_enabled = False
1965 self.subtitle_window.hide()
1967 def setSelectedSubtitle(self, subtitle):
1968 self.__selected_subtitle = subtitle
1970 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1971 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1973 class InfoBarServiceErrorPopupSupport:
1975 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1977 iPlayableService.evTuneFailed: self.__tuneFailed,
1978 iPlayableService.evStart: self.__serviceStarted
1980 self.__serviceStarted()
1982 def __serviceStarted(self):
1983 self.last_error = None
1984 Notifications.RemovePopup(id = "ZapError")
1986 def __tuneFailed(self):
1987 service = self.session.nav.getCurrentService()
1988 info = service and service.info()
1989 error = info and info.getInfo(iServiceInformation.sDVBState)
1991 if error == self.last_error:
1994 self.last_error = error
1997 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1998 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1999 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2000 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2001 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2002 eDVBServicePMTHandler.eventNewProgramInfo: None,
2003 eDVBServicePMTHandler.eventTuned: None,
2004 eDVBServicePMTHandler.eventSOF: None,
2005 eDVBServicePMTHandler.eventEOF: None
2008 error = errors.get(error) #this returns None when the key not exist in the dict
2010 if error is not None:
2011 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2013 Notifications.RemovePopup(id = "ZapError")