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 self.hideTimer.start(5000, True)
91 self.__state = self.STATE_HIDDEN
97 def doTimerHide(self):
99 if self.__state == self.STATE_SHOWN:
102 def toggleShow(self):
103 if self.__state == self.STATE_SHOWN:
105 self.hideTimer.stop()
106 elif self.__state == self.STATE_HIDDEN:
110 self.__locked = self.__locked + 1
113 self.hideTimer.stop()
115 def unlockShow(self):
116 self.__locked = self.__locked - 1
118 self.startHideTimer()
120 # def startShow(self):
121 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
122 # self.__state = self.STATE_SHOWN
124 # def startHide(self):
125 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
126 # self.__state = self.STATE_HIDDEN
128 class NumberZap(Screen):
135 self.close(int(self["number"].getText()))
137 def keyNumberGlobal(self, number):
138 self.Timer.start(3000, True) #reset timer
139 self.field = self.field + str(number)
140 self["number"].setText(self.field)
141 if len(self.field) >= 4:
144 def __init__(self, session, number):
145 Screen.__init__(self, session)
146 self.field = str(number)
148 self["channel"] = Label(_("Channel:"))
150 self["number"] = Label(self.field)
152 self["actions"] = NumberActionMap( [ "SetupActions" ],
156 "1": self.keyNumberGlobal,
157 "2": self.keyNumberGlobal,
158 "3": self.keyNumberGlobal,
159 "4": self.keyNumberGlobal,
160 "5": self.keyNumberGlobal,
161 "6": self.keyNumberGlobal,
162 "7": self.keyNumberGlobal,
163 "8": self.keyNumberGlobal,
164 "9": self.keyNumberGlobal,
165 "0": self.keyNumberGlobal
168 self.Timer = eTimer()
169 self.Timer.timeout.get().append(self.keyOK)
170 self.Timer.start(3000, True)
172 class InfoBarNumberZap:
173 """ Handles an initial number for NumberZapping """
175 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
177 "1": self.keyNumberGlobal,
178 "2": self.keyNumberGlobal,
179 "3": self.keyNumberGlobal,
180 "4": self.keyNumberGlobal,
181 "5": self.keyNumberGlobal,
182 "6": self.keyNumberGlobal,
183 "7": self.keyNumberGlobal,
184 "8": self.keyNumberGlobal,
185 "9": self.keyNumberGlobal,
186 "0": self.keyNumberGlobal,
189 def keyNumberGlobal(self, number):
190 # print "You pressed number " + str(number)
192 self.servicelist.recallPrevService()
195 self.session.openWithCallback(self.numberEntered, NumberZap, number)
197 def numberEntered(self, retval):
198 # print self.servicelist
200 self.zapToNumber(retval)
202 def searchNumberHelper(self, serviceHandler, num, bouquet):
203 servicelist = serviceHandler.list(bouquet)
204 if not servicelist is None:
206 serviceIterator = servicelist.getNext()
207 if not serviceIterator.valid(): #check end of list
209 if serviceIterator.flags: #assume normal dvb service have no flags set
212 if not num: #found service with searched number ?
213 return serviceIterator, 0
216 def zapToNumber(self, number):
217 bouquet = self.servicelist.bouquet_root
219 serviceHandler = eServiceCenter.getInstance()
220 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
221 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
223 bouquetlist = serviceHandler.list(bouquet)
224 if not bouquetlist is None:
226 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
227 if not bouquet.valid(): #check end of list
229 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
231 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
232 if not service is None:
233 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
234 self.servicelist.clearPath()
235 if self.servicelist.bouquet_root != bouquet:
236 self.servicelist.enterPath(self.servicelist.bouquet_root)
237 self.servicelist.enterPath(bouquet)
238 self.servicelist.setCurrentSelection(service) #select the service in servicelist
239 self.servicelist.zap()
241 config.misc.initialchannelselection = ConfigBoolean(default = True)
243 class InfoBarChannelSelection:
244 """ ChannelSelection - handles the channelSelection dialog and the initial
245 channelChange actions which open the channelSelection dialog """
248 self.servicelist = self.session.instantiateDialog(ChannelSelection)
250 if config.misc.initialchannelselection.value:
251 self.onShown.append(self.firstRun)
253 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
255 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
256 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
257 "zapUp": (self.zapUp, _("previous channel")),
258 "zapDown": (self.zapDown, _("next channel")),
259 "historyBack": (self.historyBack, _("previous channel in history")),
260 "historyNext": (self.historyNext, _("next channel in history")),
261 "openServiceList": (self.openServiceList, _("open servicelist")),
264 def showTvChannelList(self, zap=False):
265 self.servicelist.setModeTv()
267 self.servicelist.zap()
268 self.session.execDialog(self.servicelist)
270 def showRadioChannelList(self, zap=False):
271 self.servicelist.setModeRadio()
273 self.servicelist.zap()
274 self.session.execDialog(self.servicelist)
277 self.onShown.remove(self.firstRun)
278 config.misc.initialchannelselection.value = False
279 config.misc.initialchannelselection.save()
280 self.switchChannelDown()
282 def historyBack(self):
283 self.servicelist.historyBack()
285 def historyNext(self):
286 self.servicelist.historyNext()
288 def switchChannelUp(self):
289 self.servicelist.moveUp()
290 self.session.execDialog(self.servicelist)
292 def switchChannelDown(self):
293 self.servicelist.moveDown()
294 self.session.execDialog(self.servicelist)
296 def openServiceList(self):
297 self.session.execDialog(self.servicelist)
300 if self.servicelist.inBouquet():
301 prev = self.servicelist.getCurrentSelection()
303 prev = prev.toString()
305 if config.usage.quickzap_bouquet_change.value:
306 if self.servicelist.atBegin():
307 self.servicelist.prevBouquet()
308 self.servicelist.moveUp()
309 cur = self.servicelist.getCurrentSelection()
310 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
313 self.servicelist.moveUp()
314 self.servicelist.zap()
318 if self.servicelist.inBouquet():
319 prev = self.servicelist.getCurrentSelection()
321 prev = prev.toString()
323 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
324 self.servicelist.nextBouquet()
326 self.servicelist.moveDown()
327 cur = self.servicelist.getCurrentSelection()
328 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
331 self.servicelist.moveDown()
332 self.servicelist.zap()
336 """ Handles a menu action, to open the (main) menu """
338 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
340 "mainMenu": (self.mainMenu, _("Enter main menu...")),
344 print "loading mainmenu XML..."
345 menu = mdom.childNodes[0]
346 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
347 self.session.open(MainMenu, menu, menu.childNodes)
349 class InfoBarSimpleEventView:
350 """ Opens the Eventview for now/next """
352 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
354 "showEventInfo": (self.openEventView, _("show event details")),
357 def openEventView(self):
359 service = self.session.nav.getCurrentService()
360 ref = self.session.nav.getCurrentlyPlayingServiceReference()
361 info = service.info()
364 self.epglist.append(ptr)
367 self.epglist.append(ptr)
368 if len(self.epglist) > 0:
369 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
371 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
372 if len(self.epglist) > 1:
373 tmp = self.epglist[0]
374 self.epglist[0]=self.epglist[1]
376 setEvent(self.epglist[0])
379 """ EPG - Opens an EPG list when the showEPGList action fires """
381 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
383 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
386 self.is_now_next = False
388 self.bouquetSel = None
389 self.eventView = None
390 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
392 "showEventInfo": (self.openEventView, _("show EPG...")),
395 def zapToService(self, service):
396 if not service is None:
397 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
398 self.servicelist.clearPath()
399 if self.servicelist.bouquet_root != self.epg_bouquet:
400 self.servicelist.enterPath(self.servicelist.bouquet_root)
401 self.servicelist.enterPath(self.epg_bouquet)
402 self.servicelist.setCurrentSelection(service) #select the service in servicelist
403 self.servicelist.zap()
405 def getBouquetServices(self, bouquet):
407 servicelist = eServiceCenter.getInstance().list(bouquet)
408 if not servicelist is None:
410 service = servicelist.getNext()
411 if not service.valid(): #check if end of list
413 if service.flags: #ignore non playable services
415 services.append(ServiceReference(service))
418 def openBouquetEPG(self, bouquet, withCallback=True):
419 services = self.getBouquetServices(bouquet)
421 self.epg_bouquet = bouquet
423 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
425 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
427 def changeBouquetCB(self, direction, epg):
430 self.bouquetSel.down()
433 bouquet = self.bouquetSel.getCurrent()
434 services = self.getBouquetServices(bouquet)
436 self.epg_bouquet = bouquet
437 epg.setServices(services)
439 def closed(self, ret=False):
440 closedScreen = self.dlg_stack.pop()
441 if self.bouquetSel and closedScreen == self.bouquetSel:
442 self.bouquetSel = None
443 elif self.eventView and closedScreen == self.eventView:
444 self.eventView = None
446 dlgs=len(self.dlg_stack)
448 self.dlg_stack[dlgs-1].close(dlgs > 1)
450 def openMultiServiceEPG(self, withCallback=True):
451 bouquets = self.servicelist.getBouquetList()
456 if cnt > 1: # show bouquet list
458 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
459 self.dlg_stack.append(self.bouquetSel)
461 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
463 self.openBouquetEPG(bouquets[0][1], withCallback)
465 def openSingleServiceEPG(self):
466 ref=self.session.nav.getCurrentlyPlayingServiceReference()
467 self.session.open(EPGSelection, ref)
469 def openSimilarList(self, eventid, refstr):
470 self.session.open(EPGSelection, refstr, None, eventid)
472 def getNowNext(self):
474 service = self.session.nav.getCurrentService()
475 info = service and service.info()
476 ptr = info and info.getEvent(0)
478 self.epglist.append(ptr)
479 ptr = info and info.getEvent(1)
481 self.epglist.append(ptr)
483 def __evEventInfoChanged(self):
484 if self.is_now_next and len(self.dlg_stack) == 1:
486 assert self.eventView
487 if len(self.epglist):
488 self.eventView.setEvent(self.epglist[0])
490 def openEventView(self):
491 ref = self.session.nav.getCurrentlyPlayingServiceReference()
493 if len(self.epglist) == 0:
494 self.is_now_next = False
495 epg = eEPGCache.getInstance()
496 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
498 self.epglist.append(ptr)
499 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
501 self.epglist.append(ptr)
503 self.is_now_next = True
504 if len(self.epglist) > 0:
505 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
506 self.dlg_stack.append(self.eventView)
508 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
509 self.openMultiServiceEPG(False)
511 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
512 if len(self.epglist) > 1:
513 tmp = self.epglist[0]
514 self.epglist[0]=self.epglist[1]
516 setEvent(self.epglist[0])
519 """provides a snr/agc/ber display"""
521 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
524 """provides a current/next event info display"""
526 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
527 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
529 class InfoBarRadioText:
530 """provides radio (RDS) text info display"""
532 self["RadioText"] = RadioText(self.session.nav)
534 class InfoBarServiceName:
536 self["CurrentService"] = CurrentService(self.session.nav)
539 """handles actions like seeking, pause"""
541 # ispause, isff, issm
542 SEEK_STATE_PLAY = (0, 0, 0, ">")
543 SEEK_STATE_PAUSE = (1, 0, 0, "||")
544 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
545 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
546 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
547 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
548 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
549 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
551 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
552 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
553 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
554 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
556 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
557 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
558 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
561 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
563 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
564 iPlayableService.evStart: self.__serviceStarted,
566 iPlayableService.evEOF: self.__evEOF,
567 iPlayableService.evSOF: self.__evSOF,
570 class InfoBarSeekActionMap(HelpableActionMap):
571 def __init__(self, screen, *args, **kwargs):
572 HelpableActionMap.__init__(self, screen, *args, **kwargs)
575 def action(self, contexts, action):
576 if action[:5] == "seek:":
577 time = int(action[5:])
578 self.screen.seekRelative(time * 90000)
581 return HelpableActionMap.action(self, contexts, action)
583 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
585 "pauseService": (self.pauseService, _("pause")),
586 "unPauseService": (self.unPauseService, _("continue")),
588 "seekFwd": (self.seekFwd, _("skip forward")),
589 "seekFwdDown": self.seekFwdDown,
590 "seekFwdUp": self.seekFwdUp,
591 "seekBack": (self.seekBack, _("skip backward")),
592 "seekBackDown": self.seekBackDown,
593 "seekBackUp": self.seekBackUp,
595 # give them a little more priority to win over color buttons
597 self.seekstate = self.SEEK_STATE_PLAY
598 self.onClose.append(self.delTimer)
600 self.fwdtimer = False
601 self.fwdKeyTimer = eTimer()
602 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
604 self.rwdtimer = False
605 self.rwdKeyTimer = eTimer()
606 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
608 self.onPlayStateChanged = [ ]
610 self.lockedBecauseOfSkipping = False
623 service = self.session.nav.getCurrentService()
627 seek = service.seek()
629 if seek is None or not seek.isCurrentlySeekable():
634 def isSeekable(self):
635 if self.getSeek() is None:
639 def __seekableStatusChanged(self):
640 print "seekable status changed!"
641 if not self.isSeekable():
642 self["SeekActions"].setEnabled(False)
643 print "not seekable, return to play"
644 self.setSeekState(self.SEEK_STATE_PLAY)
646 self["SeekActions"].setEnabled(True)
649 def __serviceStarted(self):
650 self.seekstate = self.SEEK_STATE_PLAY
652 def setSeekState(self, state):
653 service = self.session.nav.getCurrentService()
658 if not self.isSeekable():
659 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
660 state = self.SEEK_STATE_PLAY
662 pauseable = service.pause()
664 if pauseable is None:
665 print "not pauseable."
666 state = self.SEEK_STATE_PLAY
668 oldstate = self.seekstate
669 self.seekstate = state
672 if oldstate[i] != self.seekstate[i]:
673 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
675 for c in self.onPlayStateChanged:
678 self.checkSkipShowHideLock()
682 def pauseService(self):
683 if self.seekstate == self.SEEK_STATE_PAUSE:
684 print "pause, but in fact unpause"
685 self.unPauseService()
687 if self.seekstate == self.SEEK_STATE_PLAY:
688 print "yes, playing."
690 print "no", self.seekstate
692 self.setSeekState(self.SEEK_STATE_PAUSE);
694 def unPauseService(self):
696 if self.seekstate == self.SEEK_STATE_PLAY:
698 self.setSeekState(self.SEEK_STATE_PLAY)
700 def doSeek(self, seektime):
701 print "doseek", seektime
702 service = self.session.nav.getCurrentService()
706 seekable = self.getSeek()
710 seekable.seekTo(90 * seektime)
712 def seekFwdDown(self):
713 print "start fwd timer"
715 self.fwdKeyTimer.start(1000)
717 def seekBackDown(self):
718 print "start rewind timer"
720 self.rwdKeyTimer.start(1000)
725 self.fwdKeyTimer.stop()
726 self.fwdtimer = False
731 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
732 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
733 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
734 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
735 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
736 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
737 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
738 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
739 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
740 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
741 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
742 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
743 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
744 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
745 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
747 self.setSeekState(lookup[self.seekstate])
749 def seekBackUp(self):
752 self.rwdKeyTimer.stop()
753 self.rwdtimer = False
758 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
759 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
760 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
761 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
762 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
763 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
764 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
765 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
766 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
767 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
768 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
769 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
770 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
771 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
772 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
774 self.setSeekState(lookup[self.seekstate])
776 if self.seekstate == self.SEEK_STATE_PAUSE:
777 seekable = self.getSeek()
778 if seekable is not None:
779 seekable.seekRelative(-1, 3)
781 def fwdTimerFire(self):
782 print "Display seek fwd"
783 self.fwdKeyTimer.stop()
784 self.fwdtimer = False
785 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
787 def fwdSeekTo(self, minutes):
788 print "Seek", minutes, "minutes forward"
790 seekable = self.getSeek()
791 if seekable is not None:
792 seekable.seekRelative(1, minutes * 60 * 90000)
794 def rwdTimerFire(self):
796 self.rwdKeyTimer.stop()
797 self.rwdtimer = False
798 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
800 def rwdSeekTo(self, minutes):
802 self.fwdSeekTo(0 - minutes)
804 def checkSkipShowHideLock(self):
805 wantlock = self.seekstate != self.SEEK_STATE_PLAY
807 if self.lockedBecauseOfSkipping and not wantlock:
809 self.lockedBecauseOfSkipping = False
811 if wantlock and not self.lockedBecauseOfSkipping:
813 self.lockedBecauseOfSkipping = True
816 if self.seekstate != self.SEEK_STATE_PLAY:
817 self.setSeekState(self.SEEK_STATE_PAUSE)
819 #self.getSeek().seekRelative(1, -90000)
820 self.setSeekState(self.SEEK_STATE_PLAY)
822 self.setSeekState(self.SEEK_STATE_PAUSE)
825 self.setSeekState(self.SEEK_STATE_PLAY)
828 def seekRelative(self, diff):
829 seekable = self.getSeek()
830 if seekable is not None:
831 seekable.seekRelative(1, diff)
833 def seekAbsolute(self, abs):
834 seekable = self.getSeek()
835 if seekable is not None:
838 from Screens.PVRState import PVRState, TimeshiftState
840 class InfoBarPVRState:
841 def __init__(self, screen=PVRState):
842 self.onPlayStateChanged.append(self.__playStateChanged)
843 self.pvrStateDialog = self.session.instantiateDialog(screen)
844 self.onShow.append(self.__mayShow)
845 self.onHide.append(self.pvrStateDialog.hide)
848 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
849 self.pvrStateDialog.show()
851 def __playStateChanged(self, state):
852 playstateString = state[3]
853 self.pvrStateDialog["state"].setText(playstateString)
856 class InfoBarTimeshiftState(InfoBarPVRState):
858 InfoBarPVRState.__init__(self, screen=TimeshiftState)
860 class InfoBarShowMovies:
862 # i don't really like this class.
863 # it calls a not further specified "movie list" on up/down/movieList,
864 # so this is not more than an action map
866 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
868 "movieList": (self.showMovies, "movie list"),
869 "up": (self.showMovies, "movie list"),
870 "down": (self.showMovies, "movie list")
873 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
877 # Timeshift works the following way:
878 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
879 # - normal playback TUNER unused PLAY enable disable disable
880 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
881 # - user presess pause again FILE record PLAY enable disable enable
882 # - user fast forwards FILE record FF enable disable enable
883 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
884 # - user backwards FILE record BACK # !! enable disable enable
888 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
889 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
890 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
891 # - the user can now PVR around
892 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
893 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
895 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
896 # - if the user rewinds, or press pause, timeshift will be activated again
898 # note that a timeshift can be enabled ("recording") and
899 # activated (currently time-shifting).
901 class InfoBarTimeshift:
903 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
905 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
906 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
908 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
910 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
911 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
912 }, prio=-1) # priority over record
914 self.timeshift_enabled = 0
915 self.timeshift_state = 0
916 self.ts_pause_timer = eTimer()
917 self.ts_pause_timer.timeout.get().append(self.pauseService)
919 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
921 iPlayableService.evStart: self.__serviceStarted,
922 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
925 def getTimeshift(self):
926 service = self.session.nav.getCurrentService()
927 return service and service.timeshift()
929 def startTimeshift(self):
930 print "enable timeshift"
931 ts = self.getTimeshift()
933 # self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
934 # print "no ts interface"
937 if self.timeshift_enabled:
938 print "hu, timeshift already enabled?"
940 if not ts.startTimeshift():
942 self.timeshift_enabled = 1
944 # we remove the "relative time" for now.
945 #self.pvrStateDialog["timeshift"].setRelative(time.time())
948 self.setSeekState(self.SEEK_STATE_PAUSE)
950 # enable the "TimeshiftEnableActions", which will override
951 # the startTimeshift actions
952 self.__seekableStatusChanged()
954 print "timeshift failed"
956 def stopTimeshift(self):
957 if not self.timeshift_enabled:
959 print "disable timeshift"
960 ts = self.getTimeshift()
963 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
965 def stopTimeshiftConfirmed(self, confirmed):
969 ts = self.getTimeshift()
974 self.timeshift_enabled = 0
977 self.__seekableStatusChanged()
979 # activates timeshift, and seeks to (almost) the end
980 def activateTimeshiftEnd(self):
981 ts = self.getTimeshift()
986 if ts.isTimeshiftActive():
987 print "!! activate timeshift called - but shouldn't this be a normal pause?"
990 self.setSeekState(self.SEEK_STATE_PLAY)
991 ts.activateTimeshift()
994 # same as activateTimeshiftEnd, but pauses afterwards.
995 def activateTimeshiftEndAndPause(self):
996 state = self.seekstate
997 self.activateTimeshiftEnd()
999 # well, this is "andPause", but it could be pressed from pause,
1000 # when pausing on the (fake-)"live" picture, so an un-pause
1003 print "now, pauseService"
1004 if state == self.SEEK_STATE_PLAY:
1005 print "is PLAYING, start pause timer"
1006 self.ts_pause_timer.start(200, 1)
1009 self.unPauseService()
1011 def __seekableStatusChanged(self):
1014 print "self.isSeekable", self.isSeekable()
1015 print "self.timeshift_enabled", self.timeshift_enabled
1017 # when this service is not seekable, but timeshift
1018 # is enabled, this means we can activate
1020 if not self.isSeekable() and self.timeshift_enabled:
1023 print "timeshift activate:", enabled
1024 self["TimeshiftActivateActions"].setEnabled(enabled)
1026 def __serviceStarted(self):
1027 self.timeshift_enabled = False
1028 self.__seekableStatusChanged()
1030 from Screens.PiPSetup import PiPSetup
1032 class InfoBarExtensions:
1033 EXTENSION_SINGLE = 0
1039 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1041 "extensions": (self.showExtensionSelection, _("view extensions...")),
1044 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1045 self.list.append((type, extension, key))
1047 def updateExtension(self, extension, key = None):
1048 self.extensionsList.append(extension)
1050 if self.extensionKeys.has_key(key):
1054 for x in self.availableKeys:
1055 if not self.extensionKeys.has_key(x):
1060 self.extensionKeys[key] = len(self.extensionsList) - 1
1062 def updateExtensions(self):
1063 self.extensionsList = []
1064 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1065 self.extensionKeys = {}
1067 if x[0] == self.EXTENSION_SINGLE:
1068 self.updateExtension(x[1], x[2])
1071 self.updateExtension(y[0], y[1])
1074 def showExtensionSelection(self):
1075 self.updateExtensions()
1076 extensionsList = self.extensionsList[:]
1079 for x in self.availableKeys:
1080 if self.extensionKeys.has_key(x):
1081 entry = self.extensionKeys[x]
1082 extension = self.extensionsList[entry]
1084 name = str(extension[0]())
1085 list.append((extension[0](), extension))
1087 extensionsList.remove(extension)
1089 extensionsList.remove(extension)
1090 for x in extensionsList:
1091 list.append((x[0](), x))
1092 keys += [""] * len(extensionsList)
1093 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1095 def extensionCallback(self, answer):
1096 if answer is not None:
1099 from Tools.BoundFunction import boundFunction
1101 # depends on InfoBarExtensions
1102 from Components.PluginComponent import plugins
1104 class InfoBarPlugins:
1106 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1109 def getPluginName(self, name):
1112 def getPluginList(self):
1114 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1115 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1118 def runPlugin(self, plugin):
1119 plugin(session = self.session)
1121 # depends on InfoBarExtensions and InfoBarSubtitleSupport
1122 class InfoBarSubtitles:
1124 self.addExtension((self.getDisableSubtitleName, self.disableSubtitles, self.subtitlesEnabled), "4")
1125 self.addExtension(extension = self.getSubtitleList, type = InfoBarExtensions.EXTENSION_LIST)
1127 def getDisableSubtitleName(self):
1128 return _("Disable subtitles")
1130 def getSubtitleList(self):
1132 s = self.getCurrentServiceSubtitle()
1133 l = s and s.getSubtitleList() or [ ]
1136 list.append(((boundFunction(self.getSubtitleEntryName, x[0]), boundFunction(self.enableSubtitle, x[1]), lambda: True), None))
1139 def getSubtitleEntryName(self, name):
1140 return "Enable Subtitles: " + name
1142 def enableSubtitle(self, subtitles):
1143 print "enable subitles", subtitles
1144 self.selected_subtitle = subtitles
1145 self.subtitles_enabled = True
1147 def subtitlesEnabled(self):
1148 return self.subtitles_enabled
1150 def disableSubtitles(self):
1151 self.subtitles_enabled = False
1153 # depends on InfoBarExtensions
1156 self.session.pipshown = False
1158 self.addExtension((self.getShowHideName, self.showPiP, self.available), "1")
1159 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "2")
1160 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "3")
1163 def available(self):
1167 return self.session.pipshown
1169 def getShowHideName(self):
1170 if self.session.pipshown:
1171 return _("Disable Picture in Picture")
1173 return _("Activate Picture in Picture")
1175 def getSwapName(self):
1176 return _("Swap Services")
1178 def getMoveName(self):
1179 return _("Move Picture in Picture")
1182 if self.session.pipshown:
1183 del self.session.pip
1184 self.session.pipshown = False
1186 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1187 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1188 if self.session.pip.playService(newservice):
1189 self.session.pipshown = True
1190 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1192 self.session.pipshown = False
1193 del self.session.pip
1194 self.session.nav.playService(newservice)
1197 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1198 if self.session.pip.servicePath:
1199 servicepath = self.servicelist.getCurrentServicePath()
1200 ref=servicepath[len(servicepath)-1]
1201 pipref=self.session.pip.getCurrentService()
1202 self.session.pip.playService(swapservice)
1203 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1204 if pipref.toString() != ref.toString(): # is a subservice ?
1205 self.session.nav.stopService() # stop portal
1206 self.session.nav.playService(pipref) # start subservice
1207 self.session.pip.servicePath=servicepath
1210 self.session.open(PiPSetup, pip = self.session.pip)
1212 from RecordTimer import parseEvent
1214 class InfoBarInstantRecord:
1215 """Instant Record - handles the instantRecord action in order to
1216 start/stop instant records"""
1218 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1220 "instantRecord": (self.instantRecord, _("Instant Record...")),
1223 self["BlinkingPoint"] = BlinkingPixmapConditional()
1224 self["BlinkingPoint"].hide()
1225 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1227 def stopCurrentRecording(self, entry = -1):
1228 if entry is not None and entry != -1:
1229 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1230 self.recording.remove(self.recording[entry])
1232 def startInstantRecording(self, limitEvent = False):
1233 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1235 # try to get event info
1238 service = self.session.nav.getCurrentService()
1239 epg = eEPGCache.getInstance()
1240 event = epg.lookupEventTime(serviceref, -1, 0)
1242 info = service.info()
1243 ev = info.getEvent(0)
1249 end = time.time() + 3600 * 10
1250 name = "instant record"
1254 if event is not None:
1255 curEvent = parseEvent(event)
1257 description = curEvent[3]
1258 eventid = curEvent[4]
1263 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1265 data = (begin, end, name, description, eventid)
1267 recording = self.session.nav.recordWithTimer(serviceref, *data)
1268 recording.dontSave = True
1269 self.recording.append(recording)
1271 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1273 def isInstantRecordRunning(self):
1274 print "self.recording:", self.recording
1275 if len(self.recording) > 0:
1276 for x in self.recording:
1281 def recordQuestionCallback(self, answer):
1282 print "pre:\n", self.recording
1284 if answer is None or answer[1] == "no":
1287 recording = self.recording[:]
1289 if not x in self.session.nav.RecordTimer.timer_list:
1290 self.recording.remove(x)
1291 elif x.dontSave and x.isRunning():
1292 list.append(TimerEntryComponent(x, False))
1294 if answer[1] == "changeduration":
1295 if len(self.recording) == 1:
1296 self.changeDuration(0)
1298 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1299 elif answer[1] == "stop":
1300 if len(self.recording) == 1:
1301 self.stopCurrentRecording(0)
1303 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1304 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1306 if answer[1] == "event":
1308 if answer[1] == "manualduration":
1309 self.selectedEntry = len(self.recording)
1310 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1311 self.startInstantRecording(limitEvent = limitEvent)
1313 print "after:\n", self.recording
1315 def changeDuration(self, entry):
1316 if entry is not None:
1317 self.selectedEntry = entry
1318 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1320 def inputCallback(self, value):
1321 if value is not None:
1322 print "stopping recording after", int(value), "minutes."
1323 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1324 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1326 def instantRecord(self):
1328 stat = os.stat(resolveFilename(SCOPE_HDD))
1330 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1333 if self.isInstantRecordRunning():
1334 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")])
1336 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")])
1338 from Tools.ISO639 import LanguageCodes
1340 class InfoBarAudioSelection:
1342 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1344 "audioSelection": (self.audioSelection, _("Audio Options...")),
1347 def audioSelection(self):
1348 service = self.session.nav.getCurrentService()
1349 audio = service and service.audioTracks()
1350 self.audioTracks = audio
1351 n = audio and audio.getNumberOfTracks() or 0
1352 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1354 print "tlist:", tlist
1356 self.audioChannel = service.audioChannel()
1359 i = audio.getTrackInfo(x)
1360 language = i.getLanguage()
1361 description = i.getDescription()
1363 if len(language) == 3:
1364 if language in LanguageCodes:
1365 language = LanguageCodes[language][0]
1367 if len(description):
1368 description += " (" + language + ")"
1370 description = language
1372 tlist.append((description, x))
1374 selectedAudio = tlist[0][1]
1375 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1379 if x[1] != selectedAudio:
1384 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1385 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1387 del self.audioTracks
1389 def audioSelected(self, audio):
1390 if audio is not None:
1391 if isinstance(audio[1], str):
1392 if audio[1] == "mode":
1393 keys = ["red", "green", "yellow"]
1394 selection = self.audioChannel.getCurrentChannel()
1395 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1396 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1398 del self.audioChannel
1399 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1400 self.audioTracks.selectTrack(audio[1])
1402 del self.audioChannel
1403 del self.audioTracks
1405 def modeSelected(self, mode):
1406 if mode is not None:
1407 self.audioChannel.selectChannel(mode[1])
1408 del self.audioChannel
1410 class InfoBarSubserviceSelection:
1412 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1414 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1417 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1419 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1420 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1422 self["SubserviceQuickzapAction"].setEnabled(False)
1424 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1426 def checkSubservicesAvail(self, ev):
1427 if ev == iPlayableService.evUpdatedEventInfo:
1428 service = self.session.nav.getCurrentService()
1429 subservices = service and service.subServices()
1430 if not subservices or subservices.getNumberOfSubservices() == 0:
1431 self["SubserviceQuickzapAction"].setEnabled(False)
1433 def nextSubservice(self):
1434 self.changeSubservice(+1)
1436 def prevSubservice(self):
1437 self.changeSubservice(-1)
1439 def changeSubservice(self, direction):
1440 service = self.session.nav.getCurrentService()
1441 subservices = service and service.subServices()
1442 n = subservices and subservices.getNumberOfSubservices()
1445 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1447 if subservices.getSubservice(x).toString() == ref.toString():
1450 selection += direction
1455 newservice = subservices.getSubservice(selection)
1456 if newservice.valid():
1460 self.session.nav.playService(newservice)
1462 def subserviceSelection(self):
1463 service = self.session.nav.getCurrentService()
1464 subservices = service and service.subServices()
1466 n = subservices and subservices.getNumberOfSubservices()
1469 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1472 i = subservices.getSubservice(x)
1473 if i.toString() == ref.toString():
1475 tlist.append((i.getName(), i))
1477 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1479 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1481 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1483 def subserviceSelected(self, service):
1484 if not service is None:
1485 if isinstance(service[1], str):
1486 if service[1] == "quickzap":
1487 from Screens.SubservicesQuickzap import SubservicesQuickzap
1488 self.session.open(SubservicesQuickzap, service[2])
1490 self["SubserviceQuickzapAction"].setEnabled(True)
1492 self.session.nav.playService(service[1])
1494 class InfoBarAdditionalInfo:
1496 self["NimA"] = Pixmap()
1497 self["NimB"] = Pixmap()
1498 self["NimA_Active"] = Pixmap()
1499 self["NimB_Active"] = Pixmap()
1501 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1502 self["TimeshiftPossible"] = self["RecordingPossible"]
1503 self["ExtensionsAvailable"] = Boolean(fixed=1)
1505 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1506 res_mgr = eDVBResourceManagerPtr()
1507 if eDVBResourceManager.getInstance(res_mgr) == 0:
1508 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1510 def tunerUseMaskChanged(self, mask):
1512 self["NimA_Active"].show()
1514 self["NimA_Active"].hide()
1516 self["NimB_Active"].show()
1518 self["NimB_Active"].hide()
1520 def checkTunerState(self, service):
1521 info = service.frontendInfo()
1522 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1523 if feNumber is None:
1533 def gotServiceEvent(self, ev):
1534 service = self.session.nav.getCurrentService()
1535 if ev == iPlayableService.evStart:
1536 self.checkTunerState(service)
1538 class InfoBarNotifications:
1540 self.onExecBegin.append(self.checkNotifications)
1541 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1542 self.onClose.append(self.__removeNotification)
1544 def __removeNotification(self):
1545 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1547 def checkNotificationsIfExecing(self):
1549 self.checkNotifications()
1551 def checkNotifications(self):
1552 if len(Notifications.notifications):
1553 n = Notifications.notifications[0]
1554 Notifications.notifications = Notifications.notifications[1:]
1557 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1559 self.session.open(n[1], *n[2], **n[3])
1561 class InfoBarServiceNotifications:
1563 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1565 iPlayableService.evEnd: self.serviceHasEnded
1568 def serviceHasEnded(self):
1569 print "service end!"
1572 self.setSeekState(self.SEEK_STATE_PLAY)
1576 class InfoBarCueSheetSupport:
1582 ENABLE_RESUME_SUPPORT = False
1585 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1587 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1588 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1589 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1593 self.is_closing = False
1594 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1596 iPlayableService.evStart: self.__serviceStarted,
1599 def __serviceStarted(self):
1602 print "new service started! trying to download cuts!"
1603 self.downloadCuesheet()
1605 if self.ENABLE_RESUME_SUPPORT:
1608 for (pts, what) in self.cut_list:
1609 if what == self.CUT_TYPE_LAST:
1612 if last is not None:
1613 self.resume_point = last
1614 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1616 def playLastCB(self, answer):
1618 seekable = self.__getSeekable()
1619 if seekable is not None:
1620 seekable.seekTo(self.resume_point)
1622 def __getSeekable(self):
1623 service = self.session.nav.getCurrentService()
1626 return service.seek()
1628 def cueGetCurrentPosition(self):
1629 seek = self.__getSeekable()
1632 r = seek.getPlayPosition()
1637 def jumpPreviousNextMark(self, cmp, alternative=None):
1638 current_pos = self.cueGetCurrentPosition()
1639 if current_pos is None:
1641 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1642 if mark is not None:
1644 elif alternative is not None:
1649 seekable = self.__getSeekable()
1650 if seekable is not None:
1651 seekable.seekTo(pts)
1653 def jumpPreviousMark(self):
1654 # we add 2 seconds, so if the play position is <2s after
1655 # the mark, the mark before will be used
1656 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1658 def jumpNextMark(self):
1659 self.jumpPreviousNextMark(lambda x: x)
1661 def getNearestCutPoint(self, pts, cmp=abs):
1664 for cp in self.cut_list:
1665 diff = cmp(cp[0] - pts)
1666 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1670 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1671 current_pos = self.cueGetCurrentPosition()
1672 if current_pos is None:
1673 print "not seekable"
1676 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1678 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1680 return nearest_cutpoint
1682 self.removeMark(nearest_cutpoint)
1683 elif not onlyremove and not onlyreturn:
1684 self.addMark((current_pos, self.CUT_TYPE_MARK))
1689 def addMark(self, point):
1690 bisect.insort(self.cut_list, point)
1691 self.uploadCuesheet()
1693 def removeMark(self, point):
1694 self.cut_list.remove(point)
1695 self.uploadCuesheet()
1697 def __getCuesheet(self):
1698 service = self.session.nav.getCurrentService()
1701 return service.cueSheet()
1703 def uploadCuesheet(self):
1704 cue = self.__getCuesheet()
1707 print "upload failed, no cuesheet interface"
1709 cue.setCutList(self.cut_list)
1711 def downloadCuesheet(self):
1712 cue = self.__getCuesheet()
1715 print "upload failed, no cuesheet interface"
1717 self.cut_list = cue.getCutList()
1719 class InfoBarSummary(Screen):
1721 <screen position="0,0" size="132,64">
1722 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1723 <convert type="ClockToText">WithSeconds</convert>
1725 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1726 <convert type="ServiceName">Name</convert>
1730 def __init__(self, session, parent):
1731 Screen.__init__(self, session)
1732 self["CurrentService"] = CurrentService(self.session.nav)
1733 self["CurrentTime"] = Clock()
1735 class InfoBarSummarySupport:
1739 def createSummary(self):
1740 return InfoBarSummary
1742 class InfoBarTeletextPlugin:
1744 self.teletext_plugin = None
1746 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1747 self.teletext_plugin = p
1749 if self.teletext_plugin is not None:
1750 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1752 "startTeletext": (self.startTeletext, _("View teletext..."))
1755 print "no teletext plugin found!"
1757 def startTeletext(self):
1758 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1760 class InfoBarSubtitleSupport(object):
1762 object.__init__(self)
1763 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1764 self.__subtitles_enabled = False
1766 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1768 iPlayableService.evStart: self.__serviceStarted,
1771 def __serviceStarted(self):
1772 # reenable if it was enabled
1773 r = self.__subtitles_enabled
1774 self.__subtitles_enabled = False
1775 self.__selected_subtitle = None
1776 self.setSubtitlesEnable(r)
1778 def getCurrentServiceSubtitle(self):
1779 service = self.session.nav.getCurrentService()
1780 return service and service.subtitle()
1782 def setSubtitlesEnable(self, enable=True):
1783 subtitle = self.getCurrentServiceSubtitle()
1784 if enable and self.__selected_subtitle:
1785 if subtitle and not self.__subtitles_enabled:
1786 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1787 self.subtitle_window.show()
1788 self.__subtitles_enabled = True
1791 subtitle.disableSubtitles(self.subtitle_window.instance)
1793 self.subtitle_window.hide()
1794 self.__subtitles_enabled = False
1796 def setSelectedSubtitle(self, subtitle):
1797 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1799 self.__selected_subtitle = subtitle
1800 self.__serviceStarted()
1802 self.__selected_subtitle = subtitle
1804 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1805 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)