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), "red")
1159 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1160 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1162 def available(self):
1166 return self.session.pipshown
1168 def getShowHideName(self):
1169 if self.session.pipshown:
1170 return _("Disable Picture in Picture")
1172 return _("Activate Picture in Picture")
1174 def getSwapName(self):
1175 return _("Swap Services")
1177 def getMoveName(self):
1178 return _("Move Picture in Picture")
1181 if self.session.pipshown:
1182 del self.session.pip
1183 self.session.pipshown = False
1185 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1186 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1187 if self.session.pip.playService(newservice):
1188 self.session.pipshown = True
1189 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1191 self.session.pipshown = False
1192 del self.session.pip
1193 self.session.nav.playService(newservice)
1196 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1197 if self.session.pip.servicePath:
1198 servicepath = self.servicelist.getCurrentServicePath()
1199 ref=servicepath[len(servicepath)-1]
1200 pipref=self.session.pip.getCurrentService()
1201 self.session.pip.playService(swapservice)
1202 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1203 if pipref.toString() != ref.toString(): # is a subservice ?
1204 self.session.nav.stopService() # stop portal
1205 self.session.nav.playService(pipref) # start subservice
1206 self.session.pip.servicePath=servicepath
1209 self.session.open(PiPSetup, pip = self.session.pip)
1211 from RecordTimer import parseEvent
1213 class InfoBarInstantRecord:
1214 """Instant Record - handles the instantRecord action in order to
1215 start/stop instant records"""
1217 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1219 "instantRecord": (self.instantRecord, _("Instant Record...")),
1222 self["BlinkingPoint"] = BlinkingPixmapConditional()
1223 self["BlinkingPoint"].hide()
1224 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1226 def stopCurrentRecording(self, entry = -1):
1227 if entry is not None and entry != -1:
1228 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1229 self.recording.remove(self.recording[entry])
1231 def startInstantRecording(self, limitEvent = False):
1232 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1234 # try to get event info
1237 service = self.session.nav.getCurrentService()
1238 epg = eEPGCache.getInstance()
1239 event = epg.lookupEventTime(serviceref, -1, 0)
1241 info = service.info()
1242 ev = info.getEvent(0)
1248 end = time.time() + 3600 * 10
1249 name = "instant record"
1253 if event is not None:
1254 curEvent = parseEvent(event)
1256 description = curEvent[3]
1257 eventid = curEvent[4]
1262 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1264 data = (begin, end, name, description, eventid)
1266 recording = self.session.nav.recordWithTimer(serviceref, *data)
1267 recording.dontSave = True
1268 self.recording.append(recording)
1270 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1272 def isInstantRecordRunning(self):
1273 print "self.recording:", self.recording
1274 if len(self.recording) > 0:
1275 for x in self.recording:
1280 def recordQuestionCallback(self, answer):
1281 print "pre:\n", self.recording
1283 if answer is None or answer[1] == "no":
1286 recording = self.recording[:]
1288 if not x in self.session.nav.RecordTimer.timer_list:
1289 self.recording.remove(x)
1290 elif x.dontSave and x.isRunning():
1291 list.append(TimerEntryComponent(x, False))
1293 if answer[1] == "changeduration":
1294 if len(self.recording) == 1:
1295 self.changeDuration(0)
1297 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1298 elif answer[1] == "stop":
1299 if len(self.recording) == 1:
1300 self.stopCurrentRecording(0)
1302 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1303 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1305 if answer[1] == "event":
1307 if answer[1] == "manualduration":
1308 self.selectedEntry = len(self.recording)
1309 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1310 self.startInstantRecording(limitEvent = limitEvent)
1312 print "after:\n", self.recording
1314 def changeDuration(self, entry):
1315 if entry is not None:
1316 self.selectedEntry = entry
1317 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1319 def inputCallback(self, value):
1320 if value is not None:
1321 print "stopping recording after", int(value), "minutes."
1322 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1323 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1325 def instantRecord(self):
1327 stat = os.stat(resolveFilename(SCOPE_HDD))
1329 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1332 if self.isInstantRecordRunning():
1333 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")])
1335 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")])
1337 from Tools.ISO639 import LanguageCodes
1339 class InfoBarAudioSelection:
1341 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1343 "audioSelection": (self.audioSelection, _("Audio Options...")),
1346 def audioSelection(self):
1347 service = self.session.nav.getCurrentService()
1348 audio = service and service.audioTracks()
1349 self.audioTracks = audio
1350 n = audio and audio.getNumberOfTracks() or 0
1351 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1353 print "tlist:", tlist
1355 self.audioChannel = service.audioChannel()
1358 i = audio.getTrackInfo(x)
1359 language = i.getLanguage()
1360 description = i.getDescription()
1362 if len(language) == 3:
1363 if language in LanguageCodes:
1364 language = LanguageCodes[language][0]
1366 if len(description):
1367 description += " (" + language + ")"
1369 description = language
1371 tlist.append((description, x))
1373 selectedAudio = tlist[0][1]
1374 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1378 if x[1] != selectedAudio:
1383 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1384 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1386 del self.audioTracks
1388 def audioSelected(self, audio):
1389 if audio is not None:
1390 if isinstance(audio[1], str):
1391 if audio[1] == "mode":
1392 keys = ["red", "green", "yellow"]
1393 selection = self.audioChannel.getCurrentChannel()
1394 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1395 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1397 del self.audioChannel
1398 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1399 self.audioTracks.selectTrack(audio[1])
1401 del self.audioChannel
1402 del self.audioTracks
1404 def modeSelected(self, mode):
1405 if mode is not None:
1406 self.audioChannel.selectChannel(mode[1])
1407 del self.audioChannel
1409 class InfoBarSubserviceSelection:
1411 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1413 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1416 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1418 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1419 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1421 self["SubserviceQuickzapAction"].setEnabled(False)
1423 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1425 def checkSubservicesAvail(self, ev):
1426 if ev == iPlayableService.evUpdatedEventInfo:
1427 service = self.session.nav.getCurrentService()
1428 subservices = service and service.subServices()
1429 if not subservices or subservices.getNumberOfSubservices() == 0:
1430 self["SubserviceQuickzapAction"].setEnabled(False)
1432 def nextSubservice(self):
1433 self.changeSubservice(+1)
1435 def prevSubservice(self):
1436 self.changeSubservice(-1)
1438 def changeSubservice(self, direction):
1439 service = self.session.nav.getCurrentService()
1440 subservices = service and service.subServices()
1441 n = subservices and subservices.getNumberOfSubservices()
1444 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1446 if subservices.getSubservice(x).toString() == ref.toString():
1449 selection += direction
1454 newservice = subservices.getSubservice(selection)
1455 if newservice.valid():
1459 self.session.nav.playService(newservice)
1461 def subserviceSelection(self):
1462 service = self.session.nav.getCurrentService()
1463 subservices = service and service.subServices()
1465 n = subservices and subservices.getNumberOfSubservices()
1468 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1471 i = subservices.getSubservice(x)
1472 if i.toString() == ref.toString():
1474 tlist.append((i.getName(), i))
1476 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1478 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1480 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1482 def subserviceSelected(self, service):
1483 if not service is None:
1484 if isinstance(service[1], str):
1485 if service[1] == "quickzap":
1486 from Screens.SubservicesQuickzap import SubservicesQuickzap
1487 self.session.open(SubservicesQuickzap, service[2])
1489 self["SubserviceQuickzapAction"].setEnabled(True)
1491 self.session.nav.playService(service[1])
1493 class InfoBarAdditionalInfo:
1495 self["NimA"] = Pixmap()
1496 self["NimB"] = Pixmap()
1497 self["NimA_Active"] = Pixmap()
1498 self["NimB_Active"] = Pixmap()
1500 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1501 self["TimeshiftPossible"] = self["RecordingPossible"]
1502 self["ExtensionsAvailable"] = Boolean(fixed=1)
1504 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1505 res_mgr = eDVBResourceManagerPtr()
1506 if eDVBResourceManager.getInstance(res_mgr) == 0:
1507 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1509 def tunerUseMaskChanged(self, mask):
1511 self["NimA_Active"].show()
1513 self["NimA_Active"].hide()
1515 self["NimB_Active"].show()
1517 self["NimB_Active"].hide()
1519 def checkTunerState(self, service):
1520 info = service.frontendInfo()
1521 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1522 if feNumber is None:
1532 def gotServiceEvent(self, ev):
1533 service = self.session.nav.getCurrentService()
1534 if ev == iPlayableService.evStart:
1535 self.checkTunerState(service)
1537 class InfoBarNotifications:
1539 self.onExecBegin.append(self.checkNotifications)
1540 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1541 self.onClose.append(self.__removeNotification)
1543 def __removeNotification(self):
1544 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1546 def checkNotificationsIfExecing(self):
1548 self.checkNotifications()
1550 def checkNotifications(self):
1551 if len(Notifications.notifications):
1552 n = Notifications.notifications[0]
1553 Notifications.notifications = Notifications.notifications[1:]
1556 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1558 self.session.open(n[1], *n[2], **n[3])
1560 class InfoBarServiceNotifications:
1562 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1564 iPlayableService.evEnd: self.serviceHasEnded
1567 def serviceHasEnded(self):
1568 print "service end!"
1571 self.setSeekState(self.SEEK_STATE_PLAY)
1575 class InfoBarCueSheetSupport:
1581 ENABLE_RESUME_SUPPORT = False
1584 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1586 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1587 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1588 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1592 self.is_closing = False
1593 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1595 iPlayableService.evStart: self.__serviceStarted,
1598 def __serviceStarted(self):
1601 print "new service started! trying to download cuts!"
1602 self.downloadCuesheet()
1604 if self.ENABLE_RESUME_SUPPORT:
1607 for (pts, what) in self.cut_list:
1608 if what == self.CUT_TYPE_LAST:
1611 if last is not None:
1612 self.resume_point = last
1613 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1615 def playLastCB(self, answer):
1617 seekable = self.__getSeekable()
1618 if seekable is not None:
1619 seekable.seekTo(self.resume_point)
1621 def __getSeekable(self):
1622 service = self.session.nav.getCurrentService()
1625 return service.seek()
1627 def cueGetCurrentPosition(self):
1628 seek = self.__getSeekable()
1631 r = seek.getPlayPosition()
1636 def jumpPreviousNextMark(self, cmp, alternative=None):
1637 current_pos = self.cueGetCurrentPosition()
1638 if current_pos is None:
1640 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1641 if mark is not None:
1643 elif alternative is not None:
1648 seekable = self.__getSeekable()
1649 if seekable is not None:
1650 seekable.seekTo(pts)
1652 def jumpPreviousMark(self):
1653 # we add 2 seconds, so if the play position is <2s after
1654 # the mark, the mark before will be used
1655 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1657 def jumpNextMark(self):
1658 self.jumpPreviousNextMark(lambda x: x)
1660 def getNearestCutPoint(self, pts, cmp=abs):
1663 for cp in self.cut_list:
1664 diff = cmp(cp[0] - pts)
1665 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1669 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1670 current_pos = self.cueGetCurrentPosition()
1671 if current_pos is None:
1672 print "not seekable"
1675 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1677 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1679 return nearest_cutpoint
1681 self.removeMark(nearest_cutpoint)
1682 elif not onlyremove and not onlyreturn:
1683 self.addMark((current_pos, self.CUT_TYPE_MARK))
1688 def addMark(self, point):
1689 bisect.insort(self.cut_list, point)
1690 self.uploadCuesheet()
1692 def removeMark(self, point):
1693 self.cut_list.remove(point)
1694 self.uploadCuesheet()
1696 def __getCuesheet(self):
1697 service = self.session.nav.getCurrentService()
1700 return service.cueSheet()
1702 def uploadCuesheet(self):
1703 cue = self.__getCuesheet()
1706 print "upload failed, no cuesheet interface"
1708 cue.setCutList(self.cut_list)
1710 def downloadCuesheet(self):
1711 cue = self.__getCuesheet()
1714 print "upload failed, no cuesheet interface"
1716 self.cut_list = cue.getCutList()
1718 class InfoBarSummary(Screen):
1720 <screen position="0,0" size="132,64">
1721 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1722 <convert type="ClockToText">WithSeconds</convert>
1724 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1725 <convert type="ServiceName">Name</convert>
1729 def __init__(self, session, parent):
1730 Screen.__init__(self, session)
1731 self["CurrentService"] = CurrentService(self.session.nav)
1732 self["CurrentTime"] = Clock()
1734 class InfoBarSummarySupport:
1738 def createSummary(self):
1739 return InfoBarSummary
1741 class InfoBarTeletextPlugin:
1743 self.teletext_plugin = None
1745 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1746 self.teletext_plugin = p
1748 if self.teletext_plugin is not None:
1749 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1751 "startTeletext": (self.startTeletext, _("View teletext..."))
1754 print "no teletext plugin found!"
1756 def startTeletext(self):
1757 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1759 class InfoBarSubtitleSupport(object):
1761 object.__init__(self)
1762 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1763 self.__subtitles_enabled = False
1765 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1767 iPlayableService.evStart: self.__serviceStarted,
1770 def __serviceStarted(self):
1771 # reenable if it was enabled
1772 r = self.__subtitles_enabled
1773 self.__subtitles_enabled = False
1774 self.__selected_subtitle = None
1775 self.setSubtitlesEnable(r)
1777 def getCurrentServiceSubtitle(self):
1778 service = self.session.nav.getCurrentService()
1779 return service and service.subtitle()
1781 def setSubtitlesEnable(self, enable=True):
1782 subtitle = self.getCurrentServiceSubtitle()
1783 if enable and self.__selected_subtitle:
1784 if subtitle and not self.__subtitles_enabled:
1785 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1786 self.subtitle_window.show()
1787 self.__subtitles_enabled = True
1790 subtitle.disableSubtitles(self.subtitle_window.instance)
1792 self.subtitle_window.hide()
1793 self.__subtitles_enabled = False
1795 def setSelectedSubtitle(self, subtitle):
1796 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1798 self.__selected_subtitle = subtitle
1799 self.__serviceStarted()
1801 self.__selected_subtitle = subtitle
1803 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1804 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)