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 if self.selected_subtitle != subtitles:
1150 print "enable subtitles", subtitles
1151 self.subtitles_enabled = False
1152 self.selected_subtitle = subtitles
1153 self.subtitles_enabled = True
1155 def subtitlesEnabled(self):
1156 return self.subtitles_enabled
1158 def disableSubtitles(self):
1159 self.subtitles_enabled = False
1161 # depends on InfoBarExtensions
1164 self.session.pipshown = False
1166 self.addExtension((self.getShowHideName, self.showPiP, self.available), "red")
1167 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1168 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1170 def available(self):
1174 return self.session.pipshown
1176 def getShowHideName(self):
1177 if self.session.pipshown:
1178 return _("Disable Picture in Picture")
1180 return _("Activate Picture in Picture")
1182 def getSwapName(self):
1183 return _("Swap Services")
1185 def getMoveName(self):
1186 return _("Move Picture in Picture")
1189 if self.session.pipshown:
1190 del self.session.pip
1191 self.session.pipshown = False
1193 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1194 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1195 if self.session.pip.playService(newservice):
1196 self.session.pipshown = True
1197 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1199 self.session.pipshown = False
1200 del self.session.pip
1201 self.session.nav.playService(newservice)
1204 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1205 if self.session.pip.servicePath:
1206 servicepath = self.servicelist.getCurrentServicePath()
1207 ref=servicepath[len(servicepath)-1]
1208 pipref=self.session.pip.getCurrentService()
1209 self.session.pip.playService(swapservice)
1210 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1211 if pipref.toString() != ref.toString(): # is a subservice ?
1212 self.session.nav.stopService() # stop portal
1213 self.session.nav.playService(pipref) # start subservice
1214 self.session.pip.servicePath=servicepath
1217 self.session.open(PiPSetup, pip = self.session.pip)
1219 from RecordTimer import parseEvent
1221 class InfoBarInstantRecord:
1222 """Instant Record - handles the instantRecord action in order to
1223 start/stop instant records"""
1225 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1227 "instantRecord": (self.instantRecord, _("Instant Record...")),
1230 self["BlinkingPoint"] = BlinkingPixmapConditional()
1231 self["BlinkingPoint"].hide()
1232 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1234 def stopCurrentRecording(self, entry = -1):
1235 if entry is not None and entry != -1:
1236 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1237 self.recording.remove(self.recording[entry])
1239 def startInstantRecording(self, limitEvent = False):
1240 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1242 # try to get event info
1245 service = self.session.nav.getCurrentService()
1246 epg = eEPGCache.getInstance()
1247 event = epg.lookupEventTime(serviceref, -1, 0)
1249 info = service.info()
1250 ev = info.getEvent(0)
1256 end = time.time() + 3600 * 10
1257 name = "instant record"
1261 if event is not None:
1262 curEvent = parseEvent(event)
1264 description = curEvent[3]
1265 eventid = curEvent[4]
1270 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1272 data = (begin, end, name, description, eventid)
1274 recording = self.session.nav.recordWithTimer(serviceref, *data)
1275 recording.dontSave = True
1276 self.recording.append(recording)
1278 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1280 def isInstantRecordRunning(self):
1281 print "self.recording:", self.recording
1282 if len(self.recording) > 0:
1283 for x in self.recording:
1288 def recordQuestionCallback(self, answer):
1289 print "pre:\n", self.recording
1291 if answer is None or answer[1] == "no":
1294 recording = self.recording[:]
1296 if not x in self.session.nav.RecordTimer.timer_list:
1297 self.recording.remove(x)
1298 elif x.dontSave and x.isRunning():
1299 list.append(TimerEntryComponent(x, False))
1301 if answer[1] == "changeduration":
1302 if len(self.recording) == 1:
1303 self.changeDuration(0)
1305 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1306 elif answer[1] == "stop":
1307 if len(self.recording) == 1:
1308 self.stopCurrentRecording(0)
1310 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1311 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1313 if answer[1] == "event":
1315 if answer[1] == "manualduration":
1316 self.selectedEntry = len(self.recording)
1317 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1318 self.startInstantRecording(limitEvent = limitEvent)
1320 print "after:\n", self.recording
1322 def changeDuration(self, entry):
1323 if entry is not None:
1324 self.selectedEntry = entry
1325 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1327 def inputCallback(self, value):
1328 if value is not None:
1329 print "stopping recording after", int(value), "minutes."
1330 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1331 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1333 def instantRecord(self):
1335 stat = os.stat(resolveFilename(SCOPE_HDD))
1337 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1340 if self.isInstantRecordRunning():
1341 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")])
1343 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")])
1345 from Tools.ISO639 import LanguageCodes
1347 class InfoBarAudioSelection:
1349 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1351 "audioSelection": (self.audioSelection, _("Audio Options...")),
1354 def audioSelection(self):
1355 service = self.session.nav.getCurrentService()
1356 audio = service and service.audioTracks()
1357 self.audioTracks = audio
1358 n = audio and audio.getNumberOfTracks() or 0
1359 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1361 print "tlist:", tlist
1363 self.audioChannel = service.audioChannel()
1366 i = audio.getTrackInfo(x)
1367 language = i.getLanguage()
1368 description = i.getDescription()
1370 if len(language) == 3:
1371 if language in LanguageCodes:
1372 language = LanguageCodes[language][0]
1374 if len(description):
1375 description += " (" + language + ")"
1377 description = language
1379 tlist.append((description, x))
1381 selectedAudio = tlist[0][1]
1382 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1386 if x[1] != selectedAudio:
1391 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1392 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1394 del self.audioTracks
1396 def audioSelected(self, audio):
1397 if audio is not None:
1398 if isinstance(audio[1], str):
1399 if audio[1] == "mode":
1400 keys = ["red", "green", "yellow"]
1401 selection = self.audioChannel.getCurrentChannel()
1402 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1403 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1405 del self.audioChannel
1406 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1407 self.audioTracks.selectTrack(audio[1])
1409 del self.audioChannel
1410 del self.audioTracks
1412 def modeSelected(self, mode):
1413 if mode is not None:
1414 self.audioChannel.selectChannel(mode[1])
1415 del self.audioChannel
1417 class InfoBarSubserviceSelection:
1419 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1421 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1424 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1426 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1427 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1429 self["SubserviceQuickzapAction"].setEnabled(False)
1431 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1433 def checkSubservicesAvail(self, ev):
1434 if ev == iPlayableService.evUpdatedEventInfo:
1435 service = self.session.nav.getCurrentService()
1436 subservices = service and service.subServices()
1437 if not subservices or subservices.getNumberOfSubservices() == 0:
1438 self["SubserviceQuickzapAction"].setEnabled(False)
1440 def nextSubservice(self):
1441 self.changeSubservice(+1)
1443 def prevSubservice(self):
1444 self.changeSubservice(-1)
1446 def changeSubservice(self, direction):
1447 service = self.session.nav.getCurrentService()
1448 subservices = service and service.subServices()
1449 n = subservices and subservices.getNumberOfSubservices()
1452 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1454 if subservices.getSubservice(x).toString() == ref.toString():
1457 selection += direction
1462 newservice = subservices.getSubservice(selection)
1463 if newservice.valid():
1466 if config.usage.show_infobar_on_zap.value:
1468 self.session.nav.playService(newservice)
1470 def subserviceSelection(self):
1471 service = self.session.nav.getCurrentService()
1472 subservices = service and service.subServices()
1474 n = subservices and subservices.getNumberOfSubservices()
1477 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1480 i = subservices.getSubservice(x)
1481 if i.toString() == ref.toString():
1483 tlist.append((i.getName(), i))
1485 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1487 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1489 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1491 def subserviceSelected(self, service):
1492 if not service is None:
1493 if isinstance(service[1], str):
1494 if service[1] == "quickzap":
1495 from Screens.SubservicesQuickzap import SubservicesQuickzap
1496 self.session.open(SubservicesQuickzap, service[2])
1498 self["SubserviceQuickzapAction"].setEnabled(True)
1499 if config.usage.show_infobar_on_zap.value:
1501 self.session.nav.playService(service[1])
1503 class InfoBarAdditionalInfo:
1505 self["NimA"] = Pixmap()
1506 self["NimB"] = Pixmap()
1507 self["NimA_Active"] = Pixmap()
1508 self["NimB_Active"] = Pixmap()
1510 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1511 self["TimeshiftPossible"] = self["RecordingPossible"]
1512 self["ExtensionsAvailable"] = Boolean(fixed=1)
1514 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1515 res_mgr = eDVBResourceManagerPtr()
1516 if eDVBResourceManager.getInstance(res_mgr) == 0:
1517 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1519 def tunerUseMaskChanged(self, mask):
1521 self["NimA_Active"].show()
1523 self["NimA_Active"].hide()
1525 self["NimB_Active"].show()
1527 self["NimB_Active"].hide()
1529 def checkTunerState(self, service):
1530 info = service.frontendInfo()
1531 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1532 if feNumber is None:
1542 def gotServiceEvent(self, ev):
1543 service = self.session.nav.getCurrentService()
1544 if ev == iPlayableService.evStart:
1545 self.checkTunerState(service)
1547 class InfoBarNotifications:
1549 self.onExecBegin.append(self.checkNotifications)
1550 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1551 self.onClose.append(self.__removeNotification)
1553 def __removeNotification(self):
1554 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1556 def checkNotificationsIfExecing(self):
1558 self.checkNotifications()
1560 def checkNotifications(self):
1561 if len(Notifications.notifications):
1562 n = Notifications.notifications[0]
1563 Notifications.notifications = Notifications.notifications[1:]
1566 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1568 self.session.open(n[1], *n[2], **n[3])
1570 class InfoBarServiceNotifications:
1572 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1574 iPlayableService.evEnd: self.serviceHasEnded
1577 def serviceHasEnded(self):
1578 print "service end!"
1581 self.setSeekState(self.SEEK_STATE_PLAY)
1585 class InfoBarCueSheetSupport:
1591 ENABLE_RESUME_SUPPORT = False
1594 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1596 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1597 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1598 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1602 self.is_closing = False
1603 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1605 iPlayableService.evStart: self.__serviceStarted,
1608 def __serviceStarted(self):
1611 print "new service started! trying to download cuts!"
1612 self.downloadCuesheet()
1614 if self.ENABLE_RESUME_SUPPORT:
1617 for (pts, what) in self.cut_list:
1618 if what == self.CUT_TYPE_LAST:
1621 if last is not None:
1622 self.resume_point = last
1623 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1625 def playLastCB(self, answer):
1627 seekable = self.__getSeekable()
1628 if seekable is not None:
1629 seekable.seekTo(self.resume_point)
1631 def __getSeekable(self):
1632 service = self.session.nav.getCurrentService()
1635 return service.seek()
1637 def cueGetCurrentPosition(self):
1638 seek = self.__getSeekable()
1641 r = seek.getPlayPosition()
1646 def jumpPreviousNextMark(self, cmp, alternative=None):
1647 current_pos = self.cueGetCurrentPosition()
1648 if current_pos is None:
1650 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1651 if mark is not None:
1653 elif alternative is not None:
1658 seekable = self.__getSeekable()
1659 if seekable is not None:
1660 seekable.seekTo(pts)
1662 def jumpPreviousMark(self):
1663 # we add 2 seconds, so if the play position is <2s after
1664 # the mark, the mark before will be used
1665 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1667 def jumpNextMark(self):
1668 self.jumpPreviousNextMark(lambda x: x)
1670 def getNearestCutPoint(self, pts, cmp=abs):
1673 for cp in self.cut_list:
1674 diff = cmp(cp[0] - pts)
1675 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1679 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1680 current_pos = self.cueGetCurrentPosition()
1681 if current_pos is None:
1682 print "not seekable"
1685 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1687 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1689 return nearest_cutpoint
1691 self.removeMark(nearest_cutpoint)
1692 elif not onlyremove and not onlyreturn:
1693 self.addMark((current_pos, self.CUT_TYPE_MARK))
1698 def addMark(self, point):
1699 bisect.insort(self.cut_list, point)
1700 self.uploadCuesheet()
1702 def removeMark(self, point):
1703 self.cut_list.remove(point)
1704 self.uploadCuesheet()
1706 def __getCuesheet(self):
1707 service = self.session.nav.getCurrentService()
1710 return service.cueSheet()
1712 def uploadCuesheet(self):
1713 cue = self.__getCuesheet()
1716 print "upload failed, no cuesheet interface"
1718 cue.setCutList(self.cut_list)
1720 def downloadCuesheet(self):
1721 cue = self.__getCuesheet()
1724 print "upload failed, no cuesheet interface"
1726 self.cut_list = cue.getCutList()
1728 class InfoBarSummary(Screen):
1730 <screen position="0,0" size="132,64">
1731 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1732 <convert type="ClockToText">WithSeconds</convert>
1734 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1735 <convert type="ServiceName">Name</convert>
1739 def __init__(self, session, parent):
1740 Screen.__init__(self, session)
1741 self["CurrentService"] = CurrentService(self.session.nav)
1742 self["CurrentTime"] = Clock()
1744 class InfoBarSummarySupport:
1748 def createSummary(self):
1749 return InfoBarSummary
1751 class InfoBarTeletextPlugin:
1753 self.teletext_plugin = None
1755 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1756 self.teletext_plugin = p
1758 if self.teletext_plugin is not None:
1759 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1761 "startTeletext": (self.startTeletext, _("View teletext..."))
1764 print "no teletext plugin found!"
1766 def startTeletext(self):
1767 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1769 class InfoBarSubtitleSupport(object):
1771 object.__init__(self)
1772 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1773 self.__subtitles_enabled = False
1775 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1777 iPlayableService.evStart: self.__serviceStarted,
1780 def __serviceStarted(self):
1781 # reenable if it was enabled
1782 r = self.__subtitles_enabled
1783 self.__subtitles_enabled = False
1784 self.__selected_subtitle = None
1785 self.setSubtitlesEnable(r)
1787 def getCurrentServiceSubtitle(self):
1788 service = self.session.nav.getCurrentService()
1789 return service and service.subtitle()
1791 def setSubtitlesEnable(self, enable=True):
1792 subtitle = self.getCurrentServiceSubtitle()
1793 if enable and self.__selected_subtitle is not None:
1794 if subtitle and not self.__subtitles_enabled:
1795 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1796 self.subtitle_window.show()
1797 self.__subtitles_enabled = True
1800 subtitle.disableSubtitles(self.subtitle_window.instance)
1802 self.subtitle_window.hide()
1803 self.__subtitles_enabled = False
1805 def setSelectedSubtitle(self, subtitle):
1806 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1808 self.__selected_subtitle = subtitle
1809 self.__serviceStarted()
1811 self.__selected_subtitle = subtitle
1813 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1814 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)