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.RadioText import RadioText
16 from Components.Sources.FrontendStatus import FrontendStatus
17 from Components.Sources.Boolean import Boolean
18 from Components.Sources.Clock import Clock
19 from Components.TimerList import TimerEntryComponent
20 from Components.config import config, ConfigBoolean
22 from EpgSelection import EPGSelection
23 from Plugins.Plugin import PluginDescriptor
25 from Screen import Screen
26 from Screens.ChoiceBox import ChoiceBox
27 from Screens.Dish import Dish
28 from Screens.EventView import EventViewEPGSelect, EventViewSimple
29 from Screens.InputBox import InputBox
30 from Screens.MessageBox import MessageBox
31 from Screens.MinuteInput import MinuteInput
32 from Screens.TimerSelection import TimerSelection
33 from Screens.PictureInPicture import PictureInPicture
34 from Screens.SubtitleDisplay import SubtitleDisplay
35 from Screens.SleepTimerEdit import SleepTimerEdit
36 from ServiceReference import ServiceReference
38 from Tools import Notifications
39 from Tools.Directories import *
41 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
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,
71 self.__state = self.STATE_SHOWN
74 self.onExecBegin.append(self.show)
76 self.hideTimer = eTimer()
77 self.hideTimer.timeout.get().append(self.doTimerHide)
78 self.hideTimer.start(5000, True)
80 self.onShow.append(self.__onShow)
81 self.onHide.append(self.__onHide)
84 self.__state = self.STATE_SHOWN
87 def startHideTimer(self):
88 if self.__state == self.STATE_SHOWN and not self.__locked:
89 idx = config.usage.infobar_timeout.index
91 self.hideTimer.start(idx*1000, True)
94 self.__state = self.STATE_HIDDEN
100 def doTimerHide(self):
101 self.hideTimer.stop()
102 if self.__state == self.STATE_SHOWN:
105 def toggleShow(self):
106 if self.__state == self.STATE_SHOWN:
108 self.hideTimer.stop()
109 elif self.__state == self.STATE_HIDDEN:
113 self.__locked = self.__locked + 1
116 self.hideTimer.stop()
118 def unlockShow(self):
119 self.__locked = self.__locked - 1
121 self.startHideTimer()
123 # def startShow(self):
124 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
125 # self.__state = self.STATE_SHOWN
127 # def startHide(self):
128 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
129 # self.__state = self.STATE_HIDDEN
131 class NumberZap(Screen):
138 self.close(int(self["number"].getText()))
140 def keyNumberGlobal(self, number):
141 self.Timer.start(3000, True) #reset timer
142 self.field = self.field + str(number)
143 self["number"].setText(self.field)
144 if len(self.field) >= 4:
147 def __init__(self, session, number):
148 Screen.__init__(self, session)
149 self.field = str(number)
151 self["channel"] = Label(_("Channel:"))
153 self["number"] = Label(self.field)
155 self["actions"] = NumberActionMap( [ "SetupActions" ],
159 "1": self.keyNumberGlobal,
160 "2": self.keyNumberGlobal,
161 "3": self.keyNumberGlobal,
162 "4": self.keyNumberGlobal,
163 "5": self.keyNumberGlobal,
164 "6": self.keyNumberGlobal,
165 "7": self.keyNumberGlobal,
166 "8": self.keyNumberGlobal,
167 "9": self.keyNumberGlobal,
168 "0": self.keyNumberGlobal
171 self.Timer = eTimer()
172 self.Timer.timeout.get().append(self.keyOK)
173 self.Timer.start(3000, True)
175 class InfoBarNumberZap:
176 """ Handles an initial number for NumberZapping """
178 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
180 "1": self.keyNumberGlobal,
181 "2": self.keyNumberGlobal,
182 "3": self.keyNumberGlobal,
183 "4": self.keyNumberGlobal,
184 "5": self.keyNumberGlobal,
185 "6": self.keyNumberGlobal,
186 "7": self.keyNumberGlobal,
187 "8": self.keyNumberGlobal,
188 "9": self.keyNumberGlobal,
189 "0": self.keyNumberGlobal,
192 def keyNumberGlobal(self, number):
193 # print "You pressed number " + str(number)
195 self.servicelist.recallPrevService()
196 if config.usage.show_infobar_on_zap.value:
199 self.session.openWithCallback(self.numberEntered, NumberZap, number)
201 def numberEntered(self, retval):
202 # print self.servicelist
204 self.zapToNumber(retval)
206 def searchNumberHelper(self, serviceHandler, num, bouquet):
207 servicelist = serviceHandler.list(bouquet)
208 if not servicelist is None:
210 serviceIterator = servicelist.getNext()
211 if not serviceIterator.valid(): #check end of list
213 if serviceIterator.flags: #assume normal dvb service have no flags set
216 if not num: #found service with searched number ?
217 return serviceIterator, 0
220 def zapToNumber(self, number):
221 bouquet = self.servicelist.bouquet_root
223 serviceHandler = eServiceCenter.getInstance()
224 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
225 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
227 bouquetlist = serviceHandler.list(bouquet)
228 if not bouquetlist is None:
230 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
231 if not bouquet.valid(): #check end of list
233 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
235 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
236 if not service is None:
237 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
238 self.servicelist.clearPath()
239 if self.servicelist.bouquet_root != bouquet:
240 self.servicelist.enterPath(self.servicelist.bouquet_root)
241 self.servicelist.enterPath(bouquet)
242 self.servicelist.setCurrentSelection(service) #select the service in servicelist
243 self.servicelist.zap()
245 config.misc.initialchannelselection = ConfigBoolean(default = True)
247 class InfoBarChannelSelection:
248 """ ChannelSelection - handles the channelSelection dialog and the initial
249 channelChange actions which open the channelSelection dialog """
252 self.servicelist = self.session.instantiateDialog(ChannelSelection)
254 if config.misc.initialchannelselection.value:
255 self.onShown.append(self.firstRun)
257 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
259 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
260 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
261 "zapUp": (self.zapUp, _("previous channel")),
262 "zapDown": (self.zapDown, _("next channel")),
263 "historyBack": (self.historyBack, _("previous channel in history")),
264 "historyNext": (self.historyNext, _("next channel in history")),
265 "openServiceList": (self.openServiceList, _("open servicelist")),
268 def showTvChannelList(self, zap=False):
269 self.servicelist.setModeTv()
271 self.servicelist.zap()
272 self.session.execDialog(self.servicelist)
274 def showRadioChannelList(self, zap=False):
275 self.servicelist.setModeRadio()
277 self.servicelist.zap()
278 self.session.execDialog(self.servicelist)
281 self.onShown.remove(self.firstRun)
282 config.misc.initialchannelselection.value = False
283 config.misc.initialchannelselection.save()
284 self.switchChannelDown()
286 def historyBack(self):
287 self.servicelist.historyBack()
289 def historyNext(self):
290 self.servicelist.historyNext()
292 def switchChannelUp(self):
293 self.servicelist.moveUp()
294 self.session.execDialog(self.servicelist)
296 def switchChannelDown(self):
297 self.servicelist.moveDown()
298 self.session.execDialog(self.servicelist)
300 def openServiceList(self):
301 self.session.execDialog(self.servicelist)
304 if self.servicelist.inBouquet():
305 prev = self.servicelist.getCurrentSelection()
307 prev = prev.toString()
309 if config.usage.quickzap_bouquet_change.value:
310 if self.servicelist.atBegin():
311 self.servicelist.prevBouquet()
312 self.servicelist.moveUp()
313 cur = self.servicelist.getCurrentSelection()
314 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
317 self.servicelist.moveUp()
318 self.servicelist.zap()
319 if config.usage.show_infobar_on_zap.value:
323 if self.servicelist.inBouquet():
324 prev = self.servicelist.getCurrentSelection()
326 prev = prev.toString()
328 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
329 self.servicelist.nextBouquet()
331 self.servicelist.moveDown()
332 cur = self.servicelist.getCurrentSelection()
333 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
336 self.servicelist.moveDown()
337 self.servicelist.zap()
338 if config.usage.show_infobar_on_zap.value:
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: #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 InfoBarRadioText:
545 """provides radio (RDS) text info display"""
547 self["RadioText"] = RadioText(self.session.nav)
549 class InfoBarServiceName:
551 self["CurrentService"] = CurrentService(self.session.nav)
554 """handles actions like seeking, pause"""
556 # ispause, isff, issm
557 SEEK_STATE_PLAY = (0, 0, 0, ">")
558 SEEK_STATE_PAUSE = (1, 0, 0, "||")
559 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
560 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
561 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
562 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
563 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
564 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
566 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
567 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
568 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
569 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
571 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
572 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
573 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
576 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
578 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
579 iPlayableService.evStart: self.__serviceStarted,
581 iPlayableService.evEOF: self.__evEOF,
582 iPlayableService.evSOF: self.__evSOF,
585 class InfoBarSeekActionMap(HelpableActionMap):
586 def __init__(self, screen, *args, **kwargs):
587 HelpableActionMap.__init__(self, screen, *args, **kwargs)
590 def action(self, contexts, action):
591 if action[:5] == "seek:":
592 time = int(action[5:])
593 self.screen.seekRelative(time * 90000)
596 return HelpableActionMap.action(self, contexts, action)
598 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
600 "pauseService": (self.pauseService, _("pause")),
601 "unPauseService": (self.unPauseService, _("continue")),
603 "seekFwd": (self.seekFwd, _("skip forward")),
604 "seekFwdDown": self.seekFwdDown,
605 "seekFwdUp": self.seekFwdUp,
606 "seekBack": (self.seekBack, _("skip backward")),
607 "seekBackDown": self.seekBackDown,
608 "seekBackUp": self.seekBackUp,
610 # give them a little more priority to win over color buttons
612 self.seekstate = self.SEEK_STATE_PLAY
613 self.onClose.append(self.delTimer)
615 self.fwdtimer = False
616 self.fwdKeyTimer = eTimer()
617 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
619 self.rwdtimer = False
620 self.rwdKeyTimer = eTimer()
621 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
623 self.onPlayStateChanged = [ ]
625 self.lockedBecauseOfSkipping = False
638 service = self.session.nav.getCurrentService()
642 seek = service.seek()
644 if seek is None or not seek.isCurrentlySeekable():
649 def isSeekable(self):
650 if self.getSeek() is None:
654 def __seekableStatusChanged(self):
655 print "seekable status changed!"
656 if not self.isSeekable():
657 self["SeekActions"].setEnabled(False)
658 print "not seekable, return to play"
659 self.setSeekState(self.SEEK_STATE_PLAY)
661 self["SeekActions"].setEnabled(True)
664 def __serviceStarted(self):
665 self.seekstate = self.SEEK_STATE_PLAY
667 def setSeekState(self, state):
668 service = self.session.nav.getCurrentService()
673 if not self.isSeekable():
674 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
675 state = self.SEEK_STATE_PLAY
677 pauseable = service.pause()
679 if pauseable is None:
680 print "not pauseable."
681 state = self.SEEK_STATE_PLAY
683 oldstate = self.seekstate
684 self.seekstate = state
687 if oldstate[i] != self.seekstate[i]:
688 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
690 for c in self.onPlayStateChanged:
693 self.checkSkipShowHideLock()
697 def pauseService(self):
698 if self.seekstate == self.SEEK_STATE_PAUSE:
699 print "pause, but in fact unpause"
700 self.unPauseService()
702 if self.seekstate == self.SEEK_STATE_PLAY:
703 print "yes, playing."
705 print "no", self.seekstate
707 self.setSeekState(self.SEEK_STATE_PAUSE);
709 def unPauseService(self):
711 if self.seekstate == self.SEEK_STATE_PLAY:
713 self.setSeekState(self.SEEK_STATE_PLAY)
715 def doSeek(self, seektime):
716 print "doseek", seektime
717 service = self.session.nav.getCurrentService()
721 seekable = self.getSeek()
725 seekable.seekTo(90 * seektime)
727 def seekFwdDown(self):
728 print "start fwd timer"
730 self.fwdKeyTimer.start(1000)
732 def seekBackDown(self):
733 print "start rewind timer"
735 self.rwdKeyTimer.start(1000)
740 self.fwdKeyTimer.stop()
741 self.fwdtimer = False
746 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
747 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
748 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
749 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
750 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
751 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
752 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
753 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
754 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
755 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
756 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
757 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
758 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
759 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
760 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
762 self.setSeekState(lookup[self.seekstate])
764 def seekBackUp(self):
767 self.rwdKeyTimer.stop()
768 self.rwdtimer = False
773 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
774 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
775 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
776 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
777 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
778 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
779 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
780 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
781 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
782 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
783 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
784 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
785 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
786 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
787 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
789 self.setSeekState(lookup[self.seekstate])
791 if self.seekstate == self.SEEK_STATE_PAUSE:
792 seekable = self.getSeek()
793 if seekable is not None:
794 seekable.seekRelative(-1, 3)
796 def fwdTimerFire(self):
797 print "Display seek fwd"
798 self.fwdKeyTimer.stop()
799 self.fwdtimer = False
800 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
802 def fwdSeekTo(self, minutes):
803 print "Seek", minutes, "minutes forward"
805 seekable = self.getSeek()
806 if seekable is not None:
807 seekable.seekRelative(1, minutes * 60 * 90000)
809 def rwdTimerFire(self):
811 self.rwdKeyTimer.stop()
812 self.rwdtimer = False
813 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
815 def rwdSeekTo(self, minutes):
817 self.fwdSeekTo(0 - minutes)
819 def checkSkipShowHideLock(self):
820 wantlock = self.seekstate != self.SEEK_STATE_PLAY
822 if config.usage.show_infobar_on_zap.value:
823 if self.lockedBecauseOfSkipping and not wantlock:
825 self.lockedBecauseOfSkipping = False
827 if wantlock and not self.lockedBecauseOfSkipping:
829 self.lockedBecauseOfSkipping = True
832 if self.seekstate != self.SEEK_STATE_PLAY:
833 self.setSeekState(self.SEEK_STATE_PAUSE)
835 #self.getSeek().seekRelative(1, -90000)
836 self.setSeekState(self.SEEK_STATE_PLAY)
838 self.setSeekState(self.SEEK_STATE_PAUSE)
841 self.setSeekState(self.SEEK_STATE_PLAY)
844 def seekRelative(self, diff):
845 seekable = self.getSeek()
846 if seekable is not None:
847 seekable.seekRelative(1, diff)
849 def seekAbsolute(self, abs):
850 seekable = self.getSeek()
851 if seekable is not None:
854 from Screens.PVRState import PVRState, TimeshiftState
856 class InfoBarPVRState:
857 def __init__(self, screen=PVRState):
858 self.onPlayStateChanged.append(self.__playStateChanged)
859 self.pvrStateDialog = self.session.instantiateDialog(screen)
860 self.onShow.append(self.__mayShow)
861 self.onHide.append(self.pvrStateDialog.hide)
864 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
865 self.pvrStateDialog.show()
867 def __playStateChanged(self, state):
868 playstateString = state[3]
869 self.pvrStateDialog["state"].setText(playstateString)
872 class InfoBarTimeshiftState(InfoBarPVRState):
874 InfoBarPVRState.__init__(self, screen=TimeshiftState)
876 class InfoBarShowMovies:
878 # i don't really like this class.
879 # it calls a not further specified "movie list" on up/down/movieList,
880 # so this is not more than an action map
882 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
884 "movieList": (self.showMovies, "movie list"),
885 "up": (self.showMovies, "movie list"),
886 "down": (self.showMovies, "movie list")
889 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
893 # Timeshift works the following way:
894 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
895 # - normal playback TUNER unused PLAY enable disable disable
896 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
897 # - user presess pause again FILE record PLAY enable disable enable
898 # - user fast forwards FILE record FF enable disable enable
899 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
900 # - user backwards FILE record BACK # !! enable disable enable
904 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
905 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
906 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
907 # - the user can now PVR around
908 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
909 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
911 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
912 # - if the user rewinds, or press pause, timeshift will be activated again
914 # note that a timeshift can be enabled ("recording") and
915 # activated (currently time-shifting).
917 class InfoBarTimeshift:
919 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
921 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
922 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
924 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
926 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
927 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
928 }, prio=-1) # priority over record
930 self.timeshift_enabled = 0
931 self.timeshift_state = 0
932 self.ts_pause_timer = eTimer()
933 self.ts_pause_timer.timeout.get().append(self.pauseService)
935 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
937 iPlayableService.evStart: self.__serviceStarted,
938 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
941 def getTimeshift(self):
942 service = self.session.nav.getCurrentService()
943 return service and service.timeshift()
945 def startTimeshift(self):
946 print "enable timeshift"
947 ts = self.getTimeshift()
949 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
950 print "no ts interface"
953 if self.timeshift_enabled:
954 print "hu, timeshift already enabled?"
956 if not ts.startTimeshift():
958 self.timeshift_enabled = 1
960 # we remove the "relative time" for now.
961 #self.pvrStateDialog["timeshift"].setRelative(time.time())
964 self.setSeekState(self.SEEK_STATE_PAUSE)
966 # enable the "TimeshiftEnableActions", which will override
967 # the startTimeshift actions
968 self.__seekableStatusChanged()
970 print "timeshift failed"
972 def stopTimeshift(self):
973 if not self.timeshift_enabled:
975 print "disable timeshift"
976 ts = self.getTimeshift()
979 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
981 def stopTimeshiftConfirmed(self, confirmed):
985 ts = self.getTimeshift()
990 self.timeshift_enabled = 0
993 self.__seekableStatusChanged()
995 # activates timeshift, and seeks to (almost) the end
996 def activateTimeshiftEnd(self):
997 ts = self.getTimeshift()
1002 if ts.isTimeshiftActive():
1003 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1006 self.setSeekState(self.SEEK_STATE_PLAY)
1007 ts.activateTimeshift()
1008 self.seekRelative(0)
1010 # same as activateTimeshiftEnd, but pauses afterwards.
1011 def activateTimeshiftEndAndPause(self):
1012 state = self.seekstate
1013 self.activateTimeshiftEnd()
1015 # well, this is "andPause", but it could be pressed from pause,
1016 # when pausing on the (fake-)"live" picture, so an un-pause
1019 print "now, pauseService"
1020 if state == self.SEEK_STATE_PLAY:
1021 print "is PLAYING, start pause timer"
1022 self.ts_pause_timer.start(200, 1)
1025 self.unPauseService()
1027 def __seekableStatusChanged(self):
1030 print "self.isSeekable", self.isSeekable()
1031 print "self.timeshift_enabled", self.timeshift_enabled
1033 # when this service is not seekable, but timeshift
1034 # is enabled, this means we can activate
1036 if not self.isSeekable() and self.timeshift_enabled:
1039 print "timeshift activate:", enabled
1040 self["TimeshiftActivateActions"].setEnabled(enabled)
1042 def __serviceStarted(self):
1043 self.timeshift_enabled = False
1044 self.__seekableStatusChanged()
1046 from Screens.PiPSetup import PiPSetup
1048 class InfoBarExtensions:
1049 EXTENSION_SINGLE = 0
1055 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1057 "extensions": (self.showExtensionSelection, _("view extensions...")),
1060 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1061 self.list.append((type, extension, key))
1063 def updateExtension(self, extension, key = None):
1064 self.extensionsList.append(extension)
1066 if self.extensionKeys.has_key(key):
1070 for x in self.availableKeys:
1071 if not self.extensionKeys.has_key(x):
1076 self.extensionKeys[key] = len(self.extensionsList) - 1
1078 def updateExtensions(self):
1079 self.extensionsList = []
1080 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1081 self.extensionKeys = {}
1083 if x[0] == self.EXTENSION_SINGLE:
1084 self.updateExtension(x[1], x[2])
1087 self.updateExtension(y[0], y[1])
1090 def showExtensionSelection(self):
1091 self.updateExtensions()
1092 extensionsList = self.extensionsList[:]
1095 for x in self.availableKeys:
1096 if self.extensionKeys.has_key(x):
1097 entry = self.extensionKeys[x]
1098 extension = self.extensionsList[entry]
1100 name = str(extension[0]())
1101 list.append((extension[0](), extension))
1103 extensionsList.remove(extension)
1105 extensionsList.remove(extension)
1106 for x in extensionsList:
1107 list.append((x[0](), x))
1108 keys += [""] * len(extensionsList)
1109 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1111 def extensionCallback(self, answer):
1112 if answer is not None:
1115 from Tools.BoundFunction import boundFunction
1117 # depends on InfoBarExtensions
1118 from Components.PluginComponent import plugins
1120 class InfoBarPlugins:
1122 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1124 def getPluginName(self, name):
1127 def getPluginList(self):
1129 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1130 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1133 def runPlugin(self, plugin):
1134 plugin(session = self.session)
1136 # depends on InfoBarExtensions
1137 class InfoBarSleepTimer:
1139 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1141 def available(self):
1144 def getSleepTimerName(self):
1145 return _("Sleep Timer")
1147 def showSleepTimerSetup(self):
1148 self.session.open(SleepTimerEdit)
1150 # depends on InfoBarExtensions
1153 self.session.pipshown = False
1155 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1156 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1157 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1159 def available(self):
1163 return self.session.pipshown
1165 def getShowHideName(self):
1166 if self.session.pipshown:
1167 return _("Disable Picture in Picture")
1169 return _("Activate Picture in Picture")
1171 def getSwapName(self):
1172 return _("Swap Services")
1174 def getMoveName(self):
1175 return _("Move Picture in Picture")
1178 if self.session.pipshown:
1179 del self.session.pip
1180 self.session.pipshown = False
1182 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1183 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1184 if self.session.pip.playService(newservice):
1185 self.session.pipshown = True
1186 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1188 self.session.pipshown = False
1189 del self.session.pip
1190 self.session.nav.playService(newservice)
1193 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1194 if self.session.pip.servicePath:
1195 servicepath = self.servicelist.getCurrentServicePath()
1196 ref=servicepath[len(servicepath)-1]
1197 pipref=self.session.pip.getCurrentService()
1198 self.session.pip.playService(swapservice)
1199 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1200 if pipref.toString() != ref.toString(): # is a subservice ?
1201 self.session.nav.stopService() # stop portal
1202 self.session.nav.playService(pipref) # start subservice
1203 self.session.pip.servicePath=servicepath
1206 self.session.open(PiPSetup, pip = self.session.pip)
1208 from RecordTimer import parseEvent
1210 class InfoBarInstantRecord:
1211 """Instant Record - handles the instantRecord action in order to
1212 start/stop instant records"""
1214 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1216 "instantRecord": (self.instantRecord, _("Instant Record...")),
1219 self["BlinkingPoint"] = BlinkingPixmapConditional()
1220 self["BlinkingPoint"].hide()
1221 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1223 def stopCurrentRecording(self, entry = -1):
1224 if entry is not None and entry != -1:
1225 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1226 self.recording.remove(self.recording[entry])
1228 def startInstantRecording(self, limitEvent = False):
1229 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1231 # try to get event info
1234 service = self.session.nav.getCurrentService()
1235 epg = eEPGCache.getInstance()
1236 event = epg.lookupEventTime(serviceref, -1, 0)
1238 info = service.info()
1239 ev = info.getEvent(0)
1245 end = time.time() + 3600 * 10
1246 name = "instant record"
1250 if event is not None:
1251 curEvent = parseEvent(event)
1253 description = curEvent[3]
1254 eventid = curEvent[4]
1259 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1261 data = (begin, end, name, description, eventid)
1263 recording = self.session.nav.recordWithTimer(serviceref, *data)
1264 recording.dontSave = True
1265 self.recording.append(recording)
1267 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1269 def isInstantRecordRunning(self):
1270 print "self.recording:", self.recording
1271 if len(self.recording) > 0:
1272 for x in self.recording:
1277 def recordQuestionCallback(self, answer):
1278 print "pre:\n", self.recording
1280 if answer is None or answer[1] == "no":
1283 recording = self.recording[:]
1285 if not x in self.session.nav.RecordTimer.timer_list:
1286 self.recording.remove(x)
1287 elif x.dontSave and x.isRunning():
1288 list.append(TimerEntryComponent(x, False))
1290 if answer[1] == "changeduration":
1291 if len(self.recording) == 1:
1292 self.changeDuration(0)
1294 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1295 elif answer[1] == "stop":
1296 if len(self.recording) == 1:
1297 self.stopCurrentRecording(0)
1299 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1300 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1302 if answer[1] == "event":
1304 if answer[1] == "manualduration":
1305 self.selectedEntry = len(self.recording)
1306 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1307 self.startInstantRecording(limitEvent = limitEvent)
1309 print "after:\n", self.recording
1311 def changeDuration(self, entry):
1312 if entry is not None:
1313 self.selectedEntry = entry
1314 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1316 def inputCallback(self, value):
1317 if value is not None:
1318 print "stopping recording after", int(value), "minutes."
1319 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1320 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1322 def instantRecord(self):
1324 stat = os.stat(resolveFilename(SCOPE_HDD))
1326 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1329 if self.isInstantRecordRunning():
1330 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("A recording is currently running.\nWhat do you want to do?"), list=[(_("stop recording"), "stop"), (_("change recording (duration)"), "changeduration"), (_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"), (_("do nothing"), "no")])
1332 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Start recording?"), list=[(_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"),(_("don't record"), "no")])
1334 from Tools.ISO639 import LanguageCodes
1336 class InfoBarAudioSelection:
1338 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1340 "audioSelection": (self.audioSelection, _("Audio Options...")),
1343 def audioSelection(self):
1344 service = self.session.nav.getCurrentService()
1345 audio = service and service.audioTracks()
1346 self.audioTracks = audio
1347 n = audio and audio.getNumberOfTracks() or 0
1348 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1350 print "tlist:", tlist
1352 self.audioChannel = service.audioChannel()
1355 i = audio.getTrackInfo(x)
1356 language = i.getLanguage()
1357 description = i.getDescription()
1359 if LanguageCodes.has_key(language):
1360 language = LanguageCodes[language][0]
1362 if len(description):
1363 description += " (" + language + ")"
1365 description = language
1367 tlist.append((description, x))
1369 selectedAudio = tlist[0][1]
1370 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1374 if x[1] != selectedAudio:
1379 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1380 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1382 del self.audioTracks
1384 def audioSelected(self, audio):
1385 if audio is not None:
1386 if isinstance(audio[1], str):
1387 if audio[1] == "mode":
1388 keys = ["red", "green", "yellow"]
1389 selection = self.audioChannel.getCurrentChannel()
1390 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1391 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1393 del self.audioChannel
1394 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1395 self.audioTracks.selectTrack(audio[1])
1397 del self.audioChannel
1398 del self.audioTracks
1400 def modeSelected(self, mode):
1401 if mode is not None:
1402 self.audioChannel.selectChannel(mode[1])
1403 del self.audioChannel
1405 class InfoBarSubserviceSelection:
1407 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1409 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1412 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1414 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1415 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1417 self["SubserviceQuickzapAction"].setEnabled(False)
1419 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1421 def checkSubservicesAvail(self, ev):
1422 if ev == iPlayableService.evUpdatedEventInfo:
1423 service = self.session.nav.getCurrentService()
1424 subservices = service and service.subServices()
1425 if not subservices or subservices.getNumberOfSubservices() == 0:
1426 self["SubserviceQuickzapAction"].setEnabled(False)
1428 def nextSubservice(self):
1429 self.changeSubservice(+1)
1431 def prevSubservice(self):
1432 self.changeSubservice(-1)
1434 def changeSubservice(self, direction):
1435 service = self.session.nav.getCurrentService()
1436 subservices = service and service.subServices()
1437 n = subservices and subservices.getNumberOfSubservices()
1440 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1442 if subservices.getSubservice(x).toString() == ref.toString():
1445 selection += direction
1450 newservice = subservices.getSubservice(selection)
1451 if newservice.valid():
1454 if config.usage.show_infobar_on_zap.value:
1456 self.session.nav.playService(newservice)
1458 def subserviceSelection(self):
1459 service = self.session.nav.getCurrentService()
1460 subservices = service and service.subServices()
1462 n = subservices and subservices.getNumberOfSubservices()
1465 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1468 i = subservices.getSubservice(x)
1469 if i.toString() == ref.toString():
1471 tlist.append((i.getName(), i))
1473 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1475 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1477 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1479 def subserviceSelected(self, service):
1480 if not service is None:
1481 if isinstance(service[1], str):
1482 if service[1] == "quickzap":
1483 from Screens.SubservicesQuickzap import SubservicesQuickzap
1484 self.session.open(SubservicesQuickzap, service[2])
1486 self["SubserviceQuickzapAction"].setEnabled(True)
1487 if config.usage.show_infobar_on_zap.value:
1489 self.session.nav.playService(service[1])
1491 class InfoBarAdditionalInfo:
1493 self["NimA"] = Pixmap()
1494 self["NimB"] = Pixmap()
1495 self["NimA_Active"] = Pixmap()
1496 self["NimB_Active"] = Pixmap()
1498 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1499 self["TimeshiftPossible"] = self["RecordingPossible"]
1500 self["ExtensionsAvailable"] = Boolean(fixed=1)
1502 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1503 res_mgr = eDVBResourceManagerPtr()
1504 if eDVBResourceManager.getInstance(res_mgr) == 0:
1505 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1507 def tunerUseMaskChanged(self, mask):
1509 self["NimA_Active"].show()
1511 self["NimA_Active"].hide()
1513 self["NimB_Active"].show()
1515 self["NimB_Active"].hide()
1517 def checkTunerState(self, service):
1518 info = service.frontendInfo()
1519 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1520 if feNumber is None:
1530 def gotServiceEvent(self, ev):
1531 service = self.session.nav.getCurrentService()
1532 if ev == iPlayableService.evStart:
1533 self.checkTunerState(service)
1535 class InfoBarNotifications:
1537 self.onExecBegin.append(self.checkNotifications)
1538 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1539 self.onClose.append(self.__removeNotification)
1541 def __removeNotification(self):
1542 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1544 def checkNotificationsIfExecing(self):
1546 self.checkNotifications()
1548 def checkNotifications(self):
1549 if len(Notifications.notifications):
1550 n = Notifications.notifications[0]
1551 Notifications.notifications = Notifications.notifications[1:]
1554 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1556 self.session.open(n[1], *n[2], **n[3])
1558 class InfoBarServiceNotifications:
1560 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1562 iPlayableService.evEnd: self.serviceHasEnded
1565 def serviceHasEnded(self):
1566 print "service end!"
1569 self.setSeekState(self.SEEK_STATE_PLAY)
1573 class InfoBarCueSheetSupport:
1579 ENABLE_RESUME_SUPPORT = False
1582 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1584 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1585 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1586 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1590 self.is_closing = False
1591 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1593 iPlayableService.evStart: self.__serviceStarted,
1596 def __serviceStarted(self):
1599 print "new service started! trying to download cuts!"
1600 self.downloadCuesheet()
1602 if self.ENABLE_RESUME_SUPPORT:
1605 for (pts, what) in self.cut_list:
1606 if what == self.CUT_TYPE_LAST:
1609 if last is not None:
1610 self.resume_point = last
1611 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1613 def playLastCB(self, answer):
1615 seekable = self.__getSeekable()
1616 if seekable is not None:
1617 seekable.seekTo(self.resume_point)
1619 def __getSeekable(self):
1620 service = self.session.nav.getCurrentService()
1623 return service.seek()
1625 def cueGetCurrentPosition(self):
1626 seek = self.__getSeekable()
1629 r = seek.getPlayPosition()
1634 def jumpPreviousNextMark(self, cmp, alternative=None):
1635 current_pos = self.cueGetCurrentPosition()
1636 if current_pos is None:
1638 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1639 if mark is not None:
1641 elif alternative is not None:
1646 seekable = self.__getSeekable()
1647 if seekable is not None:
1648 seekable.seekTo(pts)
1650 def jumpPreviousMark(self):
1651 # we add 2 seconds, so if the play position is <2s after
1652 # the mark, the mark before will be used
1653 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1655 def jumpNextMark(self):
1656 self.jumpPreviousNextMark(lambda x: x)
1658 def getNearestCutPoint(self, pts, cmp=abs):
1661 for cp in self.cut_list:
1662 diff = cmp(cp[0] - pts)
1663 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1667 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1668 current_pos = self.cueGetCurrentPosition()
1669 if current_pos is None:
1670 print "not seekable"
1673 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1675 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1677 return nearest_cutpoint
1679 self.removeMark(nearest_cutpoint)
1680 elif not onlyremove and not onlyreturn:
1681 self.addMark((current_pos, self.CUT_TYPE_MARK))
1686 def addMark(self, point):
1687 bisect.insort(self.cut_list, point)
1688 self.uploadCuesheet()
1690 def removeMark(self, point):
1691 self.cut_list.remove(point)
1692 self.uploadCuesheet()
1694 def __getCuesheet(self):
1695 service = self.session.nav.getCurrentService()
1698 return service.cueSheet()
1700 def uploadCuesheet(self):
1701 cue = self.__getCuesheet()
1704 print "upload failed, no cuesheet interface"
1706 cue.setCutList(self.cut_list)
1708 def downloadCuesheet(self):
1709 cue = self.__getCuesheet()
1712 print "upload failed, no cuesheet interface"
1714 self.cut_list = cue.getCutList()
1716 class InfoBarSummary(Screen):
1718 <screen position="0,0" size="132,64">
1719 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1720 <convert type="ClockToText">WithSeconds</convert>
1722 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1723 <convert type="ServiceName">Name</convert>
1727 def __init__(self, session, parent):
1728 Screen.__init__(self, session)
1729 self["CurrentService"] = CurrentService(self.session.nav)
1730 self["CurrentTime"] = Clock()
1732 class InfoBarSummarySupport:
1736 def createSummary(self):
1737 return InfoBarSummary
1739 class InfoBarTeletextPlugin:
1741 self.teletext_plugin = None
1743 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1744 self.teletext_plugin = p
1746 if self.teletext_plugin is not None:
1747 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1749 "startTeletext": (self.startTeletext, _("View teletext..."))
1752 print "no teletext plugin found!"
1754 def startTeletext(self):
1755 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1757 class InfoBarSubtitleSupport(object):
1759 object.__init__(self)
1760 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1761 self.__subtitles_enabled = False
1763 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1765 iPlayableService.evEnd: self.__serviceStopped,
1766 iPlayableService.evUpdatedInfo: self.__updatedInfo
1768 self.cached_subtitle_checked = False
1770 def __serviceStopped(self):
1771 self.subtitle_window.hide()
1772 self.__subtitles_enabled = False
1773 self.cached_subtitle_checked = False
1775 def __updatedInfo(self):
1776 if not self.cached_subtitle_checked:
1777 subtitle = self.getCurrentServiceSubtitle()
1778 self.cached_subtitle_checked = True
1780 self.__selected_subtitle = subtitle.getCachedSubtitle()
1781 if self.__selected_subtitle:
1782 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1783 self.subtitle_window.show()
1784 self.__subtitles_enabled = True
1786 def getCurrentServiceSubtitle(self):
1787 service = self.session.nav.getCurrentService()
1788 return service and service.subtitle()
1790 def setSubtitlesEnable(self, enable=True):
1791 subtitle = self.getCurrentServiceSubtitle()
1792 if enable and self.__selected_subtitle is not None:
1793 if subtitle and not self.__subtitles_enabled:
1794 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1795 self.subtitle_window.show()
1796 self.__subtitles_enabled = True
1799 subtitle.disableSubtitles(self.subtitle_window.instance)
1800 self.__subtitles_enabled = False
1801 self.subtitle_window.hide()
1803 def setSelectedSubtitle(self, subtitle):
1804 self.__selected_subtitle = subtitle
1806 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1807 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)