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 ServiceReference import ServiceReference
37 from Tools import Notifications
38 from Tools.Directories import *
40 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
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,
70 self.__state = self.STATE_SHOWN
73 self.onExecBegin.append(self.show)
75 self.hideTimer = eTimer()
76 self.hideTimer.timeout.get().append(self.doTimerHide)
77 self.hideTimer.start(5000, True)
79 self.onShow.append(self.__onShow)
80 self.onHide.append(self.__onHide)
83 self.__state = self.STATE_SHOWN
86 def startHideTimer(self):
87 if self.__state == self.STATE_SHOWN and not self.__locked:
88 idx = config.usage.infobar_timeout.index
90 self.hideTimer.start(idx*1000, True)
93 self.__state = self.STATE_HIDDEN
99 def doTimerHide(self):
100 self.hideTimer.stop()
101 if self.__state == self.STATE_SHOWN:
104 def toggleShow(self):
105 if self.__state == self.STATE_SHOWN:
107 self.hideTimer.stop()
108 elif self.__state == self.STATE_HIDDEN:
112 self.__locked = self.__locked + 1
115 self.hideTimer.stop()
117 def unlockShow(self):
118 self.__locked = self.__locked - 1
120 self.startHideTimer()
122 # def startShow(self):
123 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
124 # self.__state = self.STATE_SHOWN
126 # def startHide(self):
127 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
128 # self.__state = self.STATE_HIDDEN
130 class NumberZap(Screen):
137 self.close(int(self["number"].getText()))
139 def keyNumberGlobal(self, number):
140 self.Timer.start(3000, True) #reset timer
141 self.field = self.field + str(number)
142 self["number"].setText(self.field)
143 if len(self.field) >= 4:
146 def __init__(self, session, number):
147 Screen.__init__(self, session)
148 self.field = str(number)
150 self["channel"] = Label(_("Channel:"))
152 self["number"] = Label(self.field)
154 self["actions"] = NumberActionMap( [ "SetupActions" ],
158 "1": self.keyNumberGlobal,
159 "2": self.keyNumberGlobal,
160 "3": self.keyNumberGlobal,
161 "4": self.keyNumberGlobal,
162 "5": self.keyNumberGlobal,
163 "6": self.keyNumberGlobal,
164 "7": self.keyNumberGlobal,
165 "8": self.keyNumberGlobal,
166 "9": self.keyNumberGlobal,
167 "0": self.keyNumberGlobal
170 self.Timer = eTimer()
171 self.Timer.timeout.get().append(self.keyOK)
172 self.Timer.start(3000, True)
174 class InfoBarNumberZap:
175 """ Handles an initial number for NumberZapping """
177 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
179 "1": self.keyNumberGlobal,
180 "2": self.keyNumberGlobal,
181 "3": self.keyNumberGlobal,
182 "4": self.keyNumberGlobal,
183 "5": self.keyNumberGlobal,
184 "6": self.keyNumberGlobal,
185 "7": self.keyNumberGlobal,
186 "8": self.keyNumberGlobal,
187 "9": self.keyNumberGlobal,
188 "0": self.keyNumberGlobal,
191 def keyNumberGlobal(self, number):
192 # print "You pressed number " + str(number)
194 self.servicelist.recallPrevService()
195 if config.usage.show_infobar_on_zap.value:
198 self.session.openWithCallback(self.numberEntered, NumberZap, number)
200 def numberEntered(self, retval):
201 # print self.servicelist
203 self.zapToNumber(retval)
205 def searchNumberHelper(self, serviceHandler, num, bouquet):
206 servicelist = serviceHandler.list(bouquet)
207 if not servicelist is None:
209 serviceIterator = servicelist.getNext()
210 if not serviceIterator.valid(): #check end of list
212 if serviceIterator.flags: #assume normal dvb service have no flags set
215 if not num: #found service with searched number ?
216 return serviceIterator, 0
219 def zapToNumber(self, number):
220 bouquet = self.servicelist.bouquet_root
222 serviceHandler = eServiceCenter.getInstance()
223 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
224 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
226 bouquetlist = serviceHandler.list(bouquet)
227 if not bouquetlist is None:
229 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
230 if not bouquet.valid(): #check end of list
232 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
234 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
235 if not service is None:
236 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
237 self.servicelist.clearPath()
238 if self.servicelist.bouquet_root != bouquet:
239 self.servicelist.enterPath(self.servicelist.bouquet_root)
240 self.servicelist.enterPath(bouquet)
241 self.servicelist.setCurrentSelection(service) #select the service in servicelist
242 self.servicelist.zap()
244 config.misc.initialchannelselection = ConfigBoolean(default = True)
246 class InfoBarChannelSelection:
247 """ ChannelSelection - handles the channelSelection dialog and the initial
248 channelChange actions which open the channelSelection dialog """
251 self.servicelist = self.session.instantiateDialog(ChannelSelection)
253 if config.misc.initialchannelselection.value:
254 self.onShown.append(self.firstRun)
256 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
258 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
259 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
260 "zapUp": (self.zapUp, _("previous channel")),
261 "zapDown": (self.zapDown, _("next channel")),
262 "historyBack": (self.historyBack, _("previous channel in history")),
263 "historyNext": (self.historyNext, _("next channel in history")),
264 "openServiceList": (self.openServiceList, _("open servicelist")),
267 def showTvChannelList(self, zap=False):
268 self.servicelist.setModeTv()
270 self.servicelist.zap()
271 self.session.execDialog(self.servicelist)
273 def showRadioChannelList(self, zap=False):
274 self.servicelist.setModeRadio()
276 self.servicelist.zap()
277 self.session.execDialog(self.servicelist)
280 self.onShown.remove(self.firstRun)
281 config.misc.initialchannelselection.value = False
282 config.misc.initialchannelselection.save()
283 self.switchChannelDown()
285 def historyBack(self):
286 self.servicelist.historyBack()
288 def historyNext(self):
289 self.servicelist.historyNext()
291 def switchChannelUp(self):
292 self.servicelist.moveUp()
293 self.session.execDialog(self.servicelist)
295 def switchChannelDown(self):
296 self.servicelist.moveDown()
297 self.session.execDialog(self.servicelist)
299 def openServiceList(self):
300 self.session.execDialog(self.servicelist)
303 if self.servicelist.inBouquet():
304 prev = self.servicelist.getCurrentSelection()
306 prev = prev.toString()
308 if config.usage.quickzap_bouquet_change.value:
309 if self.servicelist.atBegin():
310 self.servicelist.prevBouquet()
311 self.servicelist.moveUp()
312 cur = self.servicelist.getCurrentSelection()
313 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
316 self.servicelist.moveUp()
317 self.servicelist.zap()
318 if config.usage.show_infobar_on_zap.value:
322 if self.servicelist.inBouquet():
323 prev = self.servicelist.getCurrentSelection()
325 prev = prev.toString()
327 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
328 self.servicelist.nextBouquet()
330 self.servicelist.moveDown()
331 cur = self.servicelist.getCurrentSelection()
332 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
335 self.servicelist.moveDown()
336 self.servicelist.zap()
337 if config.usage.show_infobar_on_zap.value:
341 """ Handles a menu action, to open the (main) menu """
343 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
345 "mainMenu": (self.mainMenu, _("Enter main menu...")),
349 print "loading mainmenu XML..."
350 menu = mdom.childNodes[0]
351 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
352 self.session.open(MainMenu, menu, menu.childNodes)
354 class InfoBarSimpleEventView:
355 """ Opens the Eventview for now/next """
357 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
359 "showEventInfo": (self.openEventView, _("show event details")),
362 def openEventView(self):
364 service = self.session.nav.getCurrentService()
365 ref = self.session.nav.getCurrentlyPlayingServiceReference()
366 info = service.info()
369 self.epglist.append(ptr)
372 self.epglist.append(ptr)
373 if len(self.epglist) > 0:
374 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
376 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
377 if len(self.epglist) > 1:
378 tmp = self.epglist[0]
379 self.epglist[0]=self.epglist[1]
381 setEvent(self.epglist[0])
384 """ EPG - Opens an EPG list when the showEPGList action fires """
386 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
388 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
391 self.is_now_next = False
393 self.bouquetSel = None
394 self.eventView = None
395 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
397 "showEventInfo": (self.openEventView, _("show EPG...")),
400 def zapToService(self, service):
401 if not service is None:
402 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
403 self.servicelist.clearPath()
404 if self.servicelist.bouquet_root != self.epg_bouquet:
405 self.servicelist.enterPath(self.servicelist.bouquet_root)
406 self.servicelist.enterPath(self.epg_bouquet)
407 self.servicelist.setCurrentSelection(service) #select the service in servicelist
408 self.servicelist.zap()
410 def getBouquetServices(self, bouquet):
412 servicelist = eServiceCenter.getInstance().list(bouquet)
413 if not servicelist is None:
415 service = servicelist.getNext()
416 if not service.valid(): #check if end of list
418 if service.flags: #ignore non playable services
420 services.append(ServiceReference(service))
423 def openBouquetEPG(self, bouquet, withCallback=True):
424 services = self.getBouquetServices(bouquet)
426 self.epg_bouquet = bouquet
428 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
430 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
432 def changeBouquetCB(self, direction, epg):
435 self.bouquetSel.down()
438 bouquet = self.bouquetSel.getCurrent()
439 services = self.getBouquetServices(bouquet)
441 self.epg_bouquet = bouquet
442 epg.setServices(services)
444 def closed(self, ret=False):
445 closedScreen = self.dlg_stack.pop()
446 if self.bouquetSel and closedScreen == self.bouquetSel:
447 self.bouquetSel = None
448 elif self.eventView and closedScreen == self.eventView:
449 self.eventView = None
451 dlgs=len(self.dlg_stack)
453 self.dlg_stack[dlgs-1].close(dlgs > 1)
455 def openMultiServiceEPG(self, withCallback=True):
456 bouquets = self.servicelist.getBouquetList()
461 if cnt > 1: # show bouquet list
463 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
464 self.dlg_stack.append(self.bouquetSel)
466 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
468 self.openBouquetEPG(bouquets[0][1], withCallback)
470 def openSingleServiceEPG(self):
471 ref=self.session.nav.getCurrentlyPlayingServiceReference()
472 self.session.open(EPGSelection, ref)
474 def openSimilarList(self, eventid, refstr):
475 self.session.open(EPGSelection, refstr, None, eventid)
477 def getNowNext(self):
479 service = self.session.nav.getCurrentService()
480 info = service and service.info()
481 ptr = info and info.getEvent(0)
483 self.epglist.append(ptr)
484 ptr = info and info.getEvent(1)
486 self.epglist.append(ptr)
488 def __evEventInfoChanged(self):
489 if self.is_now_next and len(self.dlg_stack) == 1:
491 assert self.eventView
492 if len(self.epglist):
493 self.eventView.setEvent(self.epglist[0])
495 def openEventView(self):
496 ref = self.session.nav.getCurrentlyPlayingServiceReference()
498 if len(self.epglist) == 0:
499 self.is_now_next = False
500 epg = eEPGCache.getInstance()
501 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
503 self.epglist.append(ptr)
504 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
506 self.epglist.append(ptr)
508 self.is_now_next = True
509 if len(self.epglist) > 0:
510 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
511 self.dlg_stack.append(self.eventView)
513 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
514 self.openMultiServiceEPG(False)
516 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
517 if len(self.epglist) > 1:
518 tmp = self.epglist[0]
519 self.epglist[0]=self.epglist[1]
521 setEvent(self.epglist[0])
524 """provides a snr/agc/ber display"""
526 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
529 """provides a current/next event info display"""
531 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
532 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
534 class InfoBarRadioText:
535 """provides radio (RDS) text info display"""
537 self["RadioText"] = RadioText(self.session.nav)
539 class InfoBarServiceName:
541 self["CurrentService"] = CurrentService(self.session.nav)
544 """handles actions like seeking, pause"""
546 # ispause, isff, issm
547 SEEK_STATE_PLAY = (0, 0, 0, ">")
548 SEEK_STATE_PAUSE = (1, 0, 0, "||")
549 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
550 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
551 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
552 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
553 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
554 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
556 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
557 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
558 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
559 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
561 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
562 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
563 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
566 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
568 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
569 iPlayableService.evStart: self.__serviceStarted,
571 iPlayableService.evEOF: self.__evEOF,
572 iPlayableService.evSOF: self.__evSOF,
575 class InfoBarSeekActionMap(HelpableActionMap):
576 def __init__(self, screen, *args, **kwargs):
577 HelpableActionMap.__init__(self, screen, *args, **kwargs)
580 def action(self, contexts, action):
581 if action[:5] == "seek:":
582 time = int(action[5:])
583 self.screen.seekRelative(time * 90000)
586 return HelpableActionMap.action(self, contexts, action)
588 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
590 "pauseService": (self.pauseService, _("pause")),
591 "unPauseService": (self.unPauseService, _("continue")),
593 "seekFwd": (self.seekFwd, _("skip forward")),
594 "seekFwdDown": self.seekFwdDown,
595 "seekFwdUp": self.seekFwdUp,
596 "seekBack": (self.seekBack, _("skip backward")),
597 "seekBackDown": self.seekBackDown,
598 "seekBackUp": self.seekBackUp,
600 # give them a little more priority to win over color buttons
602 self.seekstate = self.SEEK_STATE_PLAY
603 self.onClose.append(self.delTimer)
605 self.fwdtimer = False
606 self.fwdKeyTimer = eTimer()
607 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
609 self.rwdtimer = False
610 self.rwdKeyTimer = eTimer()
611 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
613 self.onPlayStateChanged = [ ]
615 self.lockedBecauseOfSkipping = False
628 service = self.session.nav.getCurrentService()
632 seek = service.seek()
634 if seek is None or not seek.isCurrentlySeekable():
639 def isSeekable(self):
640 if self.getSeek() is None:
644 def __seekableStatusChanged(self):
645 print "seekable status changed!"
646 if not self.isSeekable():
647 self["SeekActions"].setEnabled(False)
648 print "not seekable, return to play"
649 self.setSeekState(self.SEEK_STATE_PLAY)
651 self["SeekActions"].setEnabled(True)
654 def __serviceStarted(self):
655 self.seekstate = self.SEEK_STATE_PLAY
657 def setSeekState(self, state):
658 service = self.session.nav.getCurrentService()
663 if not self.isSeekable():
664 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
665 state = self.SEEK_STATE_PLAY
667 pauseable = service.pause()
669 if pauseable is None:
670 print "not pauseable."
671 state = self.SEEK_STATE_PLAY
673 oldstate = self.seekstate
674 self.seekstate = state
677 if oldstate[i] != self.seekstate[i]:
678 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
680 for c in self.onPlayStateChanged:
683 self.checkSkipShowHideLock()
687 def pauseService(self):
688 if self.seekstate == self.SEEK_STATE_PAUSE:
689 print "pause, but in fact unpause"
690 self.unPauseService()
692 if self.seekstate == self.SEEK_STATE_PLAY:
693 print "yes, playing."
695 print "no", self.seekstate
697 self.setSeekState(self.SEEK_STATE_PAUSE);
699 def unPauseService(self):
701 if self.seekstate == self.SEEK_STATE_PLAY:
703 self.setSeekState(self.SEEK_STATE_PLAY)
705 def doSeek(self, seektime):
706 print "doseek", seektime
707 service = self.session.nav.getCurrentService()
711 seekable = self.getSeek()
715 seekable.seekTo(90 * seektime)
717 def seekFwdDown(self):
718 print "start fwd timer"
720 self.fwdKeyTimer.start(1000)
722 def seekBackDown(self):
723 print "start rewind timer"
725 self.rwdKeyTimer.start(1000)
730 self.fwdKeyTimer.stop()
731 self.fwdtimer = False
736 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
737 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
738 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
739 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
740 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
741 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
742 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
743 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
744 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
745 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
746 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
747 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
748 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
749 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
750 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
752 self.setSeekState(lookup[self.seekstate])
754 def seekBackUp(self):
757 self.rwdKeyTimer.stop()
758 self.rwdtimer = False
763 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
764 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
765 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
766 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
767 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
768 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
769 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
770 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
771 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
772 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
773 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
774 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
775 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
776 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
777 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
779 self.setSeekState(lookup[self.seekstate])
781 if self.seekstate == self.SEEK_STATE_PAUSE:
782 seekable = self.getSeek()
783 if seekable is not None:
784 seekable.seekRelative(-1, 3)
786 def fwdTimerFire(self):
787 print "Display seek fwd"
788 self.fwdKeyTimer.stop()
789 self.fwdtimer = False
790 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
792 def fwdSeekTo(self, minutes):
793 print "Seek", minutes, "minutes forward"
795 seekable = self.getSeek()
796 if seekable is not None:
797 seekable.seekRelative(1, minutes * 60 * 90000)
799 def rwdTimerFire(self):
801 self.rwdKeyTimer.stop()
802 self.rwdtimer = False
803 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
805 def rwdSeekTo(self, minutes):
807 self.fwdSeekTo(0 - minutes)
809 def checkSkipShowHideLock(self):
810 wantlock = self.seekstate != self.SEEK_STATE_PLAY
812 if config.usage.show_infobar_on_zap.value:
813 if self.lockedBecauseOfSkipping and not wantlock:
815 self.lockedBecauseOfSkipping = False
817 if wantlock and not self.lockedBecauseOfSkipping:
819 self.lockedBecauseOfSkipping = True
822 if self.seekstate != self.SEEK_STATE_PLAY:
823 self.setSeekState(self.SEEK_STATE_PAUSE)
825 #self.getSeek().seekRelative(1, -90000)
826 self.setSeekState(self.SEEK_STATE_PLAY)
828 self.setSeekState(self.SEEK_STATE_PAUSE)
831 self.setSeekState(self.SEEK_STATE_PLAY)
834 def seekRelative(self, diff):
835 seekable = self.getSeek()
836 if seekable is not None:
837 seekable.seekRelative(1, diff)
839 def seekAbsolute(self, abs):
840 seekable = self.getSeek()
841 if seekable is not None:
844 from Screens.PVRState import PVRState, TimeshiftState
846 class InfoBarPVRState:
847 def __init__(self, screen=PVRState):
848 self.onPlayStateChanged.append(self.__playStateChanged)
849 self.pvrStateDialog = self.session.instantiateDialog(screen)
850 self.onShow.append(self.__mayShow)
851 self.onHide.append(self.pvrStateDialog.hide)
854 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
855 self.pvrStateDialog.show()
857 def __playStateChanged(self, state):
858 playstateString = state[3]
859 self.pvrStateDialog["state"].setText(playstateString)
862 class InfoBarTimeshiftState(InfoBarPVRState):
864 InfoBarPVRState.__init__(self, screen=TimeshiftState)
866 class InfoBarShowMovies:
868 # i don't really like this class.
869 # it calls a not further specified "movie list" on up/down/movieList,
870 # so this is not more than an action map
872 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
874 "movieList": (self.showMovies, "movie list"),
875 "up": (self.showMovies, "movie list"),
876 "down": (self.showMovies, "movie list")
879 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
883 # Timeshift works the following way:
884 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
885 # - normal playback TUNER unused PLAY enable disable disable
886 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
887 # - user presess pause again FILE record PLAY enable disable enable
888 # - user fast forwards FILE record FF enable disable enable
889 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
890 # - user backwards FILE record BACK # !! enable disable enable
894 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
895 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
896 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
897 # - the user can now PVR around
898 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
899 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
901 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
902 # - if the user rewinds, or press pause, timeshift will be activated again
904 # note that a timeshift can be enabled ("recording") and
905 # activated (currently time-shifting).
907 class InfoBarTimeshift:
909 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
911 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
912 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
914 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
916 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
917 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
918 }, prio=-1) # priority over record
920 self.timeshift_enabled = 0
921 self.timeshift_state = 0
922 self.ts_pause_timer = eTimer()
923 self.ts_pause_timer.timeout.get().append(self.pauseService)
925 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
927 iPlayableService.evStart: self.__serviceStarted,
928 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
931 def getTimeshift(self):
932 service = self.session.nav.getCurrentService()
933 return service and service.timeshift()
935 def startTimeshift(self):
936 print "enable timeshift"
937 ts = self.getTimeshift()
939 # self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
940 # print "no ts interface"
943 if self.timeshift_enabled:
944 print "hu, timeshift already enabled?"
946 if not ts.startTimeshift():
948 self.timeshift_enabled = 1
950 # we remove the "relative time" for now.
951 #self.pvrStateDialog["timeshift"].setRelative(time.time())
954 self.setSeekState(self.SEEK_STATE_PAUSE)
956 # enable the "TimeshiftEnableActions", which will override
957 # the startTimeshift actions
958 self.__seekableStatusChanged()
960 print "timeshift failed"
962 def stopTimeshift(self):
963 if not self.timeshift_enabled:
965 print "disable timeshift"
966 ts = self.getTimeshift()
969 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
971 def stopTimeshiftConfirmed(self, confirmed):
975 ts = self.getTimeshift()
980 self.timeshift_enabled = 0
983 self.__seekableStatusChanged()
985 # activates timeshift, and seeks to (almost) the end
986 def activateTimeshiftEnd(self):
987 ts = self.getTimeshift()
992 if ts.isTimeshiftActive():
993 print "!! activate timeshift called - but shouldn't this be a normal pause?"
996 self.setSeekState(self.SEEK_STATE_PLAY)
997 ts.activateTimeshift()
1000 # same as activateTimeshiftEnd, but pauses afterwards.
1001 def activateTimeshiftEndAndPause(self):
1002 state = self.seekstate
1003 self.activateTimeshiftEnd()
1005 # well, this is "andPause", but it could be pressed from pause,
1006 # when pausing on the (fake-)"live" picture, so an un-pause
1009 print "now, pauseService"
1010 if state == self.SEEK_STATE_PLAY:
1011 print "is PLAYING, start pause timer"
1012 self.ts_pause_timer.start(200, 1)
1015 self.unPauseService()
1017 def __seekableStatusChanged(self):
1020 print "self.isSeekable", self.isSeekable()
1021 print "self.timeshift_enabled", self.timeshift_enabled
1023 # when this service is not seekable, but timeshift
1024 # is enabled, this means we can activate
1026 if not self.isSeekable() and self.timeshift_enabled:
1029 print "timeshift activate:", enabled
1030 self["TimeshiftActivateActions"].setEnabled(enabled)
1032 def __serviceStarted(self):
1033 self.timeshift_enabled = False
1034 self.__seekableStatusChanged()
1036 from Screens.PiPSetup import PiPSetup
1038 class InfoBarExtensions:
1039 EXTENSION_SINGLE = 0
1045 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1047 "extensions": (self.showExtensionSelection, _("view extensions...")),
1050 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1051 self.list.append((type, extension, key))
1053 def updateExtension(self, extension, key = None):
1054 self.extensionsList.append(extension)
1056 if self.extensionKeys.has_key(key):
1060 for x in self.availableKeys:
1061 if not self.extensionKeys.has_key(x):
1066 self.extensionKeys[key] = len(self.extensionsList) - 1
1068 def updateExtensions(self):
1069 self.extensionsList = []
1070 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1071 self.extensionKeys = {}
1073 if x[0] == self.EXTENSION_SINGLE:
1074 self.updateExtension(x[1], x[2])
1077 self.updateExtension(y[0], y[1])
1080 def showExtensionSelection(self):
1081 self.updateExtensions()
1082 extensionsList = self.extensionsList[:]
1085 for x in self.availableKeys:
1086 if self.extensionKeys.has_key(x):
1087 entry = self.extensionKeys[x]
1088 extension = self.extensionsList[entry]
1090 name = str(extension[0]())
1091 list.append((extension[0](), extension))
1093 extensionsList.remove(extension)
1095 extensionsList.remove(extension)
1096 for x in extensionsList:
1097 list.append((x[0](), x))
1098 keys += [""] * len(extensionsList)
1099 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1101 def extensionCallback(self, answer):
1102 if answer is not None:
1105 from Tools.BoundFunction import boundFunction
1107 # depends on InfoBarExtensions
1108 from Components.PluginComponent import plugins
1110 class InfoBarPlugins:
1112 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1115 def getPluginName(self, name):
1118 def getPluginList(self):
1120 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1121 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1124 def runPlugin(self, plugin):
1125 plugin(session = self.session)
1127 # depends on InfoBarExtensions and InfoBarSubtitleSupport
1128 class InfoBarSubtitles:
1130 self.addExtension((self.getDisableSubtitleName, self.disableSubtitles, self.subtitlesEnabled), "4")
1131 self.addExtension(extension = self.getSubtitleList, type = InfoBarExtensions.EXTENSION_LIST)
1133 def getDisableSubtitleName(self):
1134 return _("Disable subtitles")
1136 def getSubtitleList(self):
1138 s = self.getCurrentServiceSubtitle()
1139 l = s and s.getSubtitleList() or [ ]
1142 list.append(((boundFunction(self.getSubtitleEntryName, x[0]), boundFunction(self.enableSubtitle, x[1]), lambda: True), None))
1145 def getSubtitleEntryName(self, name):
1146 return "Enable Subtitles: " + name
1148 def enableSubtitle(self, subtitles):
1149 print "enable subitles", subtitles
1150 self.selected_subtitle = subtitles
1151 self.subtitles_enabled = True
1153 def subtitlesEnabled(self):
1154 return self.subtitles_enabled
1156 def disableSubtitles(self):
1157 self.subtitles_enabled = False
1159 # depends on InfoBarExtensions
1162 self.session.pipshown = False
1164 self.addExtension((self.getShowHideName, self.showPiP, self.available), "red")
1165 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1166 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1168 def available(self):
1172 return self.session.pipshown
1174 def getShowHideName(self):
1175 if self.session.pipshown:
1176 return _("Disable Picture in Picture")
1178 return _("Activate Picture in Picture")
1180 def getSwapName(self):
1181 return _("Swap Services")
1183 def getMoveName(self):
1184 return _("Move Picture in Picture")
1187 if self.session.pipshown:
1188 del self.session.pip
1189 self.session.pipshown = False
1191 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1192 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1193 if self.session.pip.playService(newservice):
1194 self.session.pipshown = True
1195 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1197 self.session.pipshown = False
1198 del self.session.pip
1199 self.session.nav.playService(newservice)
1202 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1203 if self.session.pip.servicePath:
1204 servicepath = self.servicelist.getCurrentServicePath()
1205 ref=servicepath[len(servicepath)-1]
1206 pipref=self.session.pip.getCurrentService()
1207 self.session.pip.playService(swapservice)
1208 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1209 if pipref.toString() != ref.toString(): # is a subservice ?
1210 self.session.nav.stopService() # stop portal
1211 self.session.nav.playService(pipref) # start subservice
1212 self.session.pip.servicePath=servicepath
1215 self.session.open(PiPSetup, pip = self.session.pip)
1217 from RecordTimer import parseEvent
1219 class InfoBarInstantRecord:
1220 """Instant Record - handles the instantRecord action in order to
1221 start/stop instant records"""
1223 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1225 "instantRecord": (self.instantRecord, _("Instant Record...")),
1228 self["BlinkingPoint"] = BlinkingPixmapConditional()
1229 self["BlinkingPoint"].hide()
1230 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1232 def stopCurrentRecording(self, entry = -1):
1233 if entry is not None and entry != -1:
1234 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1235 self.recording.remove(self.recording[entry])
1237 def startInstantRecording(self, limitEvent = False):
1238 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1240 # try to get event info
1243 service = self.session.nav.getCurrentService()
1244 epg = eEPGCache.getInstance()
1245 event = epg.lookupEventTime(serviceref, -1, 0)
1247 info = service.info()
1248 ev = info.getEvent(0)
1254 end = time.time() + 3600 * 10
1255 name = "instant record"
1259 if event is not None:
1260 curEvent = parseEvent(event)
1262 description = curEvent[3]
1263 eventid = curEvent[4]
1268 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1270 data = (begin, end, name, description, eventid)
1272 recording = self.session.nav.recordWithTimer(serviceref, *data)
1273 recording.dontSave = True
1274 self.recording.append(recording)
1276 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1278 def isInstantRecordRunning(self):
1279 print "self.recording:", self.recording
1280 if len(self.recording) > 0:
1281 for x in self.recording:
1286 def recordQuestionCallback(self, answer):
1287 print "pre:\n", self.recording
1289 if answer is None or answer[1] == "no":
1292 recording = self.recording[:]
1294 if not x in self.session.nav.RecordTimer.timer_list:
1295 self.recording.remove(x)
1296 elif x.dontSave and x.isRunning():
1297 list.append(TimerEntryComponent(x, False))
1299 if answer[1] == "changeduration":
1300 if len(self.recording) == 1:
1301 self.changeDuration(0)
1303 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1304 elif answer[1] == "stop":
1305 if len(self.recording) == 1:
1306 self.stopCurrentRecording(0)
1308 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1309 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1311 if answer[1] == "event":
1313 if answer[1] == "manualduration":
1314 self.selectedEntry = len(self.recording)
1315 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1316 self.startInstantRecording(limitEvent = limitEvent)
1318 print "after:\n", self.recording
1320 def changeDuration(self, entry):
1321 if entry is not None:
1322 self.selectedEntry = entry
1323 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1325 def inputCallback(self, value):
1326 if value is not None:
1327 print "stopping recording after", int(value), "minutes."
1328 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1329 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1331 def instantRecord(self):
1333 stat = os.stat(resolveFilename(SCOPE_HDD))
1335 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1338 if self.isInstantRecordRunning():
1339 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")])
1341 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")])
1343 from Tools.ISO639 import LanguageCodes
1345 class InfoBarAudioSelection:
1347 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1349 "audioSelection": (self.audioSelection, _("Audio Options...")),
1352 def audioSelection(self):
1353 service = self.session.nav.getCurrentService()
1354 audio = service and service.audioTracks()
1355 self.audioTracks = audio
1356 n = audio and audio.getNumberOfTracks() or 0
1357 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1359 print "tlist:", tlist
1361 self.audioChannel = service.audioChannel()
1364 i = audio.getTrackInfo(x)
1365 language = i.getLanguage()
1366 description = i.getDescription()
1368 if len(language) == 3:
1369 if language in LanguageCodes:
1370 language = LanguageCodes[language][0]
1372 if len(description):
1373 description += " (" + language + ")"
1375 description = language
1377 tlist.append((description, x))
1379 selectedAudio = tlist[0][1]
1380 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1384 if x[1] != selectedAudio:
1389 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1390 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1392 del self.audioTracks
1394 def audioSelected(self, audio):
1395 if audio is not None:
1396 if isinstance(audio[1], str):
1397 if audio[1] == "mode":
1398 keys = ["red", "green", "yellow"]
1399 selection = self.audioChannel.getCurrentChannel()
1400 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1401 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1403 del self.audioChannel
1404 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1405 self.audioTracks.selectTrack(audio[1])
1407 del self.audioChannel
1408 del self.audioTracks
1410 def modeSelected(self, mode):
1411 if mode is not None:
1412 self.audioChannel.selectChannel(mode[1])
1413 del self.audioChannel
1415 class InfoBarSubserviceSelection:
1417 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1419 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1422 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1424 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1425 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1427 self["SubserviceQuickzapAction"].setEnabled(False)
1429 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1431 def checkSubservicesAvail(self, ev):
1432 if ev == iPlayableService.evUpdatedEventInfo:
1433 service = self.session.nav.getCurrentService()
1434 subservices = service and service.subServices()
1435 if not subservices or subservices.getNumberOfSubservices() == 0:
1436 self["SubserviceQuickzapAction"].setEnabled(False)
1438 def nextSubservice(self):
1439 self.changeSubservice(+1)
1441 def prevSubservice(self):
1442 self.changeSubservice(-1)
1444 def changeSubservice(self, direction):
1445 service = self.session.nav.getCurrentService()
1446 subservices = service and service.subServices()
1447 n = subservices and subservices.getNumberOfSubservices()
1450 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1452 if subservices.getSubservice(x).toString() == ref.toString():
1455 selection += direction
1460 newservice = subservices.getSubservice(selection)
1461 if newservice.valid():
1464 if config.usage.show_infobar_on_zap.value:
1466 self.session.nav.playService(newservice)
1468 def subserviceSelection(self):
1469 service = self.session.nav.getCurrentService()
1470 subservices = service and service.subServices()
1472 n = subservices and subservices.getNumberOfSubservices()
1475 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1478 i = subservices.getSubservice(x)
1479 if i.toString() == ref.toString():
1481 tlist.append((i.getName(), i))
1483 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1485 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1487 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1489 def subserviceSelected(self, service):
1490 if not service is None:
1491 if isinstance(service[1], str):
1492 if service[1] == "quickzap":
1493 from Screens.SubservicesQuickzap import SubservicesQuickzap
1494 self.session.open(SubservicesQuickzap, service[2])
1496 self["SubserviceQuickzapAction"].setEnabled(True)
1497 if config.usage.show_infobar_on_zap.value:
1499 self.session.nav.playService(service[1])
1501 class InfoBarAdditionalInfo:
1503 self["NimA"] = Pixmap()
1504 self["NimB"] = Pixmap()
1505 self["NimA_Active"] = Pixmap()
1506 self["NimB_Active"] = Pixmap()
1508 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1509 self["TimeshiftPossible"] = self["RecordingPossible"]
1510 self["ExtensionsAvailable"] = Boolean(fixed=1)
1512 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1513 res_mgr = eDVBResourceManagerPtr()
1514 if eDVBResourceManager.getInstance(res_mgr) == 0:
1515 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1517 def tunerUseMaskChanged(self, mask):
1519 self["NimA_Active"].show()
1521 self["NimA_Active"].hide()
1523 self["NimB_Active"].show()
1525 self["NimB_Active"].hide()
1527 def checkTunerState(self, service):
1528 info = service.frontendInfo()
1529 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1530 if feNumber is None:
1540 def gotServiceEvent(self, ev):
1541 service = self.session.nav.getCurrentService()
1542 if ev == iPlayableService.evStart:
1543 self.checkTunerState(service)
1545 class InfoBarNotifications:
1547 self.onExecBegin.append(self.checkNotifications)
1548 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1549 self.onClose.append(self.__removeNotification)
1551 def __removeNotification(self):
1552 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1554 def checkNotificationsIfExecing(self):
1556 self.checkNotifications()
1558 def checkNotifications(self):
1559 if len(Notifications.notifications):
1560 n = Notifications.notifications[0]
1561 Notifications.notifications = Notifications.notifications[1:]
1564 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1566 self.session.open(n[1], *n[2], **n[3])
1568 class InfoBarServiceNotifications:
1570 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1572 iPlayableService.evEnd: self.serviceHasEnded
1575 def serviceHasEnded(self):
1576 print "service end!"
1579 self.setSeekState(self.SEEK_STATE_PLAY)
1583 class InfoBarCueSheetSupport:
1589 ENABLE_RESUME_SUPPORT = False
1592 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1594 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1595 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1596 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1600 self.is_closing = False
1601 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1603 iPlayableService.evStart: self.__serviceStarted,
1606 def __serviceStarted(self):
1609 print "new service started! trying to download cuts!"
1610 self.downloadCuesheet()
1612 if self.ENABLE_RESUME_SUPPORT:
1615 for (pts, what) in self.cut_list:
1616 if what == self.CUT_TYPE_LAST:
1619 if last is not None:
1620 self.resume_point = last
1621 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1623 def playLastCB(self, answer):
1625 seekable = self.__getSeekable()
1626 if seekable is not None:
1627 seekable.seekTo(self.resume_point)
1629 def __getSeekable(self):
1630 service = self.session.nav.getCurrentService()
1633 return service.seek()
1635 def cueGetCurrentPosition(self):
1636 seek = self.__getSeekable()
1639 r = seek.getPlayPosition()
1644 def jumpPreviousNextMark(self, cmp, alternative=None):
1645 current_pos = self.cueGetCurrentPosition()
1646 if current_pos is None:
1648 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1649 if mark is not None:
1651 elif alternative is not None:
1656 seekable = self.__getSeekable()
1657 if seekable is not None:
1658 seekable.seekTo(pts)
1660 def jumpPreviousMark(self):
1661 # we add 2 seconds, so if the play position is <2s after
1662 # the mark, the mark before will be used
1663 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1665 def jumpNextMark(self):
1666 self.jumpPreviousNextMark(lambda x: x)
1668 def getNearestCutPoint(self, pts, cmp=abs):
1671 for cp in self.cut_list:
1672 diff = cmp(cp[0] - pts)
1673 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1677 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1678 current_pos = self.cueGetCurrentPosition()
1679 if current_pos is None:
1680 print "not seekable"
1683 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1685 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1687 return nearest_cutpoint
1689 self.removeMark(nearest_cutpoint)
1690 elif not onlyremove and not onlyreturn:
1691 self.addMark((current_pos, self.CUT_TYPE_MARK))
1696 def addMark(self, point):
1697 bisect.insort(self.cut_list, point)
1698 self.uploadCuesheet()
1700 def removeMark(self, point):
1701 self.cut_list.remove(point)
1702 self.uploadCuesheet()
1704 def __getCuesheet(self):
1705 service = self.session.nav.getCurrentService()
1708 return service.cueSheet()
1710 def uploadCuesheet(self):
1711 cue = self.__getCuesheet()
1714 print "upload failed, no cuesheet interface"
1716 cue.setCutList(self.cut_list)
1718 def downloadCuesheet(self):
1719 cue = self.__getCuesheet()
1722 print "upload failed, no cuesheet interface"
1724 self.cut_list = cue.getCutList()
1726 class InfoBarSummary(Screen):
1728 <screen position="0,0" size="132,64">
1729 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1730 <convert type="ClockToText">WithSeconds</convert>
1732 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1733 <convert type="ServiceName">Name</convert>
1737 def __init__(self, session, parent):
1738 Screen.__init__(self, session)
1739 self["CurrentService"] = CurrentService(self.session.nav)
1740 self["CurrentTime"] = Clock()
1742 class InfoBarSummarySupport:
1746 def createSummary(self):
1747 return InfoBarSummary
1749 class InfoBarTeletextPlugin:
1751 self.teletext_plugin = None
1753 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1754 self.teletext_plugin = p
1756 if self.teletext_plugin is not None:
1757 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1759 "startTeletext": (self.startTeletext, _("View teletext..."))
1762 print "no teletext plugin found!"
1764 def startTeletext(self):
1765 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1767 class InfoBarSubtitleSupport(object):
1769 object.__init__(self)
1770 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1771 self.__subtitles_enabled = False
1773 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1775 iPlayableService.evStart: self.__serviceStarted,
1778 def __serviceStarted(self):
1779 # reenable if it was enabled
1780 r = self.__subtitles_enabled
1781 self.__subtitles_enabled = False
1782 self.__selected_subtitle = None
1783 self.setSubtitlesEnable(r)
1785 def getCurrentServiceSubtitle(self):
1786 service = self.session.nav.getCurrentService()
1787 return service and service.subtitle()
1789 def setSubtitlesEnable(self, enable=True):
1790 subtitle = self.getCurrentServiceSubtitle()
1791 if enable and self.__selected_subtitle:
1792 if subtitle and not self.__subtitles_enabled:
1793 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1794 self.subtitle_window.show()
1795 self.__subtitles_enabled = True
1798 subtitle.disableSubtitles(self.subtitle_window.instance)
1800 self.subtitle_window.hide()
1801 self.__subtitles_enabled = False
1803 def setSelectedSubtitle(self, subtitle):
1804 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1806 self.__selected_subtitle = subtitle
1807 self.__serviceStarted()
1809 self.__selected_subtitle = subtitle
1811 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1812 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)