1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import *
9 from Components.Pixmap import Pixmap, PixmapConditional
10 from Components.PluginComponent import plugins
11 from Components.ProgressBar import *
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.Sources.CurrentService import CurrentService
14 from Components.Sources.EventInfo import EventInfo
15 from Components.Sources.RadioText import RadioText
16 from Components.Sources.FrontendStatus import FrontendStatus
17 from Components.Sources.Boolean import Boolean
18 from Components.Sources.Clock import Clock
19 from Components.TimerList import TimerEntryComponent
20 from Components.config import config, ConfigBoolean
22 from EpgSelection import EPGSelection
23 from Plugins.Plugin import PluginDescriptor
25 from Screen import Screen
26 from Screens.ChoiceBox import ChoiceBox
27 from Screens.Dish import Dish
28 from Screens.EventView import EventViewEPGSelect, EventViewSimple
29 from Screens.InputBox import InputBox
30 from Screens.MessageBox import MessageBox
31 from Screens.MinuteInput import MinuteInput
32 from Screens.TimerSelection import TimerSelection
33 from Screens.PictureInPicture import PictureInPicture
34 from Screens.SubtitleDisplay import SubtitleDisplay
35 from ServiceReference import ServiceReference
37 from Tools import Notifications
38 from Tools.Directories import *
40 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
48 from Menu import MainMenu, mdom
52 self.dishDialog = self.session.instantiateDialog(Dish)
53 self.onLayoutFinish.append(self.dishDialog.show)
55 class InfoBarShowHide:
56 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
64 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
66 "toggleShow": self.toggleShow,
70 self.__state = self.STATE_SHOWN
73 self.onExecBegin.append(self.show)
75 self.hideTimer = eTimer()
76 self.hideTimer.timeout.get().append(self.doTimerHide)
77 self.hideTimer.start(5000, True)
79 self.onShow.append(self.__onShow)
80 self.onHide.append(self.__onHide)
83 self.__state = self.STATE_SHOWN
86 def startHideTimer(self):
87 if self.__state == self.STATE_SHOWN and not self.__locked:
88 idx = config.usage.infobar_timeout.index
90 self.hideTimer.start(idx*1000, True)
93 self.__state = self.STATE_HIDDEN
99 def doTimerHide(self):
100 self.hideTimer.stop()
101 if self.__state == self.STATE_SHOWN:
104 def toggleShow(self):
105 if self.__state == self.STATE_SHOWN:
107 self.hideTimer.stop()
108 elif self.__state == self.STATE_HIDDEN:
112 self.__locked = self.__locked + 1
115 self.hideTimer.stop()
117 def unlockShow(self):
118 self.__locked = self.__locked - 1
120 self.startHideTimer()
122 # def startShow(self):
123 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
124 # self.__state = self.STATE_SHOWN
126 # def startHide(self):
127 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
128 # self.__state = self.STATE_HIDDEN
130 class NumberZap(Screen):
137 self.close(int(self["number"].getText()))
139 def keyNumberGlobal(self, number):
140 self.Timer.start(3000, True) #reset timer
141 self.field = self.field + str(number)
142 self["number"].setText(self.field)
143 if len(self.field) >= 4:
146 def __init__(self, session, number):
147 Screen.__init__(self, session)
148 self.field = str(number)
150 self["channel"] = Label(_("Channel:"))
152 self["number"] = Label(self.field)
154 self["actions"] = NumberActionMap( [ "SetupActions" ],
158 "1": self.keyNumberGlobal,
159 "2": self.keyNumberGlobal,
160 "3": self.keyNumberGlobal,
161 "4": self.keyNumberGlobal,
162 "5": self.keyNumberGlobal,
163 "6": self.keyNumberGlobal,
164 "7": self.keyNumberGlobal,
165 "8": self.keyNumberGlobal,
166 "9": self.keyNumberGlobal,
167 "0": self.keyNumberGlobal
170 self.Timer = eTimer()
171 self.Timer.timeout.get().append(self.keyOK)
172 self.Timer.start(3000, True)
174 class InfoBarNumberZap:
175 """ Handles an initial number for NumberZapping """
177 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
179 "1": self.keyNumberGlobal,
180 "2": self.keyNumberGlobal,
181 "3": self.keyNumberGlobal,
182 "4": self.keyNumberGlobal,
183 "5": self.keyNumberGlobal,
184 "6": self.keyNumberGlobal,
185 "7": self.keyNumberGlobal,
186 "8": self.keyNumberGlobal,
187 "9": self.keyNumberGlobal,
188 "0": self.keyNumberGlobal,
191 def keyNumberGlobal(self, number):
192 # print "You pressed number " + str(number)
194 self.servicelist.recallPrevService()
195 if config.usage.show_infobar_on_zap.value:
198 self.session.openWithCallback(self.numberEntered, NumberZap, number)
200 def numberEntered(self, retval):
201 # print self.servicelist
203 self.zapToNumber(retval)
205 def searchNumberHelper(self, serviceHandler, num, bouquet):
206 servicelist = serviceHandler.list(bouquet)
207 if not servicelist is None:
209 serviceIterator = servicelist.getNext()
210 if not serviceIterator.valid(): #check end of list
212 if serviceIterator.flags: #assume normal dvb service have no flags set
215 if not num: #found service with searched number ?
216 return serviceIterator, 0
219 def zapToNumber(self, number):
220 bouquet = self.servicelist.bouquet_root
222 serviceHandler = eServiceCenter.getInstance()
223 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
224 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
226 bouquetlist = serviceHandler.list(bouquet)
227 if not bouquetlist is None:
229 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
230 if not bouquet.valid(): #check end of list
232 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
234 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
235 if not service is None:
236 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
237 self.servicelist.clearPath()
238 if self.servicelist.bouquet_root != bouquet:
239 self.servicelist.enterPath(self.servicelist.bouquet_root)
240 self.servicelist.enterPath(bouquet)
241 self.servicelist.setCurrentSelection(service) #select the service in servicelist
242 self.servicelist.zap()
244 config.misc.initialchannelselection = ConfigBoolean(default = True)
246 class InfoBarChannelSelection:
247 """ ChannelSelection - handles the channelSelection dialog and the initial
248 channelChange actions which open the channelSelection dialog """
251 self.servicelist = self.session.instantiateDialog(ChannelSelection)
253 if config.misc.initialchannelselection.value:
254 self.onShown.append(self.firstRun)
256 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
258 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
259 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
260 "zapUp": (self.zapUp, _("previous channel")),
261 "zapDown": (self.zapDown, _("next channel")),
262 "historyBack": (self.historyBack, _("previous channel in history")),
263 "historyNext": (self.historyNext, _("next channel in history")),
264 "openServiceList": (self.openServiceList, _("open servicelist")),
267 def showTvChannelList(self, zap=False):
268 self.servicelist.setModeTv()
270 self.servicelist.zap()
271 self.session.execDialog(self.servicelist)
273 def showRadioChannelList(self, zap=False):
274 self.servicelist.setModeRadio()
276 self.servicelist.zap()
277 self.session.execDialog(self.servicelist)
280 self.onShown.remove(self.firstRun)
281 config.misc.initialchannelselection.value = False
282 config.misc.initialchannelselection.save()
283 self.switchChannelDown()
285 def historyBack(self):
286 self.servicelist.historyBack()
288 def historyNext(self):
289 self.servicelist.historyNext()
291 def switchChannelUp(self):
292 self.servicelist.moveUp()
293 self.session.execDialog(self.servicelist)
295 def switchChannelDown(self):
296 self.servicelist.moveDown()
297 self.session.execDialog(self.servicelist)
299 def openServiceList(self):
300 self.session.execDialog(self.servicelist)
303 if self.servicelist.inBouquet():
304 prev = self.servicelist.getCurrentSelection()
306 prev = prev.toString()
308 if config.usage.quickzap_bouquet_change.value:
309 if self.servicelist.atBegin():
310 self.servicelist.prevBouquet()
311 self.servicelist.moveUp()
312 cur = self.servicelist.getCurrentSelection()
313 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
316 self.servicelist.moveUp()
317 self.servicelist.zap()
318 if config.usage.show_infobar_on_zap.value:
322 if self.servicelist.inBouquet():
323 prev = self.servicelist.getCurrentSelection()
325 prev = prev.toString()
327 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
328 self.servicelist.nextBouquet()
330 self.servicelist.moveDown()
331 cur = self.servicelist.getCurrentSelection()
332 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
335 self.servicelist.moveDown()
336 self.servicelist.zap()
337 if config.usage.show_infobar_on_zap.value:
341 """ Handles a menu action, to open the (main) menu """
343 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
345 "mainMenu": (self.mainMenu, _("Enter main menu...")),
347 self.session.infobar = None
350 print "loading mainmenu XML..."
351 menu = mdom.childNodes[0]
352 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
354 self.session.infobar = self
355 # so we can access the currently active infobar from screens opened from within the mainmenu
356 # at the moment used from the SubserviceSelection
358 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
360 def mainMenuClosed(self, *val):
361 self.session.infobar = None
363 class InfoBarSimpleEventView:
364 """ Opens the Eventview for now/next """
366 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
368 "showEventInfo": (self.openEventView, _("show event details")),
371 def openEventView(self):
373 service = self.session.nav.getCurrentService()
374 ref = self.session.nav.getCurrentlyPlayingServiceReference()
375 info = service.info()
378 self.epglist.append(ptr)
381 self.epglist.append(ptr)
382 if len(self.epglist) > 0:
383 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
385 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
386 if len(self.epglist) > 1:
387 tmp = self.epglist[0]
388 self.epglist[0]=self.epglist[1]
390 setEvent(self.epglist[0])
393 """ EPG - Opens an EPG list when the showEPGList action fires """
395 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
397 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
400 self.is_now_next = False
402 self.bouquetSel = None
403 self.eventView = None
404 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
406 "showEventInfo": (self.openEventView, _("show EPG...")),
409 def zapToService(self, service):
410 if not service is None:
411 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
412 self.servicelist.clearPath()
413 if self.servicelist.bouquet_root != self.epg_bouquet:
414 self.servicelist.enterPath(self.servicelist.bouquet_root)
415 self.servicelist.enterPath(self.epg_bouquet)
416 self.servicelist.setCurrentSelection(service) #select the service in servicelist
417 self.servicelist.zap()
419 def getBouquetServices(self, bouquet):
421 servicelist = eServiceCenter.getInstance().list(bouquet)
422 if not servicelist is None:
424 service = servicelist.getNext()
425 if not service.valid(): #check if end of list
427 if service.flags: #ignore non playable services
429 services.append(ServiceReference(service))
432 def openBouquetEPG(self, bouquet, withCallback=True):
433 services = self.getBouquetServices(bouquet)
435 self.epg_bouquet = bouquet
437 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
439 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
441 def changeBouquetCB(self, direction, epg):
444 self.bouquetSel.down()
447 bouquet = self.bouquetSel.getCurrent()
448 services = self.getBouquetServices(bouquet)
450 self.epg_bouquet = bouquet
451 epg.setServices(services)
453 def closed(self, ret=False):
454 closedScreen = self.dlg_stack.pop()
455 if self.bouquetSel and closedScreen == self.bouquetSel:
456 self.bouquetSel = None
457 elif self.eventView and closedScreen == self.eventView:
458 self.eventView = None
460 dlgs=len(self.dlg_stack)
462 self.dlg_stack[dlgs-1].close(dlgs > 1)
464 def openMultiServiceEPG(self, withCallback=True):
465 bouquets = self.servicelist.getBouquetList()
470 if cnt > 1: # show bouquet list
472 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
473 self.dlg_stack.append(self.bouquetSel)
475 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
477 self.openBouquetEPG(bouquets[0][1], withCallback)
479 def openSingleServiceEPG(self):
480 ref=self.session.nav.getCurrentlyPlayingServiceReference()
481 self.session.open(EPGSelection, ref)
483 def openSimilarList(self, eventid, refstr):
484 self.session.open(EPGSelection, refstr, None, eventid)
486 def getNowNext(self):
488 service = self.session.nav.getCurrentService()
489 info = service and service.info()
490 ptr = info and info.getEvent(0)
492 self.epglist.append(ptr)
493 ptr = info and info.getEvent(1)
495 self.epglist.append(ptr)
497 def __evEventInfoChanged(self):
498 if self.is_now_next and len(self.dlg_stack) == 1:
500 assert self.eventView
501 if len(self.epglist):
502 self.eventView.setEvent(self.epglist[0])
504 def openEventView(self):
505 ref = self.session.nav.getCurrentlyPlayingServiceReference()
507 if len(self.epglist) == 0:
508 self.is_now_next = False
509 epg = eEPGCache.getInstance()
510 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
512 self.epglist.append(ptr)
513 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
515 self.epglist.append(ptr)
517 self.is_now_next = True
518 if len(self.epglist) > 0:
519 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
520 self.dlg_stack.append(self.eventView)
522 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
523 self.openMultiServiceEPG(False)
525 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
526 if len(self.epglist) > 1:
527 tmp = self.epglist[0]
528 self.epglist[0]=self.epglist[1]
530 setEvent(self.epglist[0])
533 """provides a snr/agc/ber display"""
535 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
538 """provides a current/next event info display"""
540 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
541 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
543 class InfoBarRadioText:
544 """provides radio (RDS) text info display"""
546 self["RadioText"] = RadioText(self.session.nav)
548 class InfoBarServiceName:
550 self["CurrentService"] = CurrentService(self.session.nav)
553 """handles actions like seeking, pause"""
555 # ispause, isff, issm
556 SEEK_STATE_PLAY = (0, 0, 0, ">")
557 SEEK_STATE_PAUSE = (1, 0, 0, "||")
558 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
559 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
560 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
561 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
562 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
563 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
565 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
566 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
567 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
568 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
570 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
571 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
572 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
575 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
577 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
578 iPlayableService.evStart: self.__serviceStarted,
580 iPlayableService.evEOF: self.__evEOF,
581 iPlayableService.evSOF: self.__evSOF,
584 class InfoBarSeekActionMap(HelpableActionMap):
585 def __init__(self, screen, *args, **kwargs):
586 HelpableActionMap.__init__(self, screen, *args, **kwargs)
589 def action(self, contexts, action):
590 if action[:5] == "seek:":
591 time = int(action[5:])
592 self.screen.seekRelative(time * 90000)
595 return HelpableActionMap.action(self, contexts, action)
597 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
599 "pauseService": (self.pauseService, _("pause")),
600 "unPauseService": (self.unPauseService, _("continue")),
602 "seekFwd": (self.seekFwd, _("skip forward")),
603 "seekFwdDown": self.seekFwdDown,
604 "seekFwdUp": self.seekFwdUp,
605 "seekBack": (self.seekBack, _("skip backward")),
606 "seekBackDown": self.seekBackDown,
607 "seekBackUp": self.seekBackUp,
609 # give them a little more priority to win over color buttons
611 self.seekstate = self.SEEK_STATE_PLAY
612 self.onClose.append(self.delTimer)
614 self.fwdtimer = False
615 self.fwdKeyTimer = eTimer()
616 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
618 self.rwdtimer = False
619 self.rwdKeyTimer = eTimer()
620 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
622 self.onPlayStateChanged = [ ]
624 self.lockedBecauseOfSkipping = False
637 service = self.session.nav.getCurrentService()
641 seek = service.seek()
643 if seek is None or not seek.isCurrentlySeekable():
648 def isSeekable(self):
649 if self.getSeek() is None:
653 def __seekableStatusChanged(self):
654 print "seekable status changed!"
655 if not self.isSeekable():
656 self["SeekActions"].setEnabled(False)
657 print "not seekable, return to play"
658 self.setSeekState(self.SEEK_STATE_PLAY)
660 self["SeekActions"].setEnabled(True)
663 def __serviceStarted(self):
664 self.seekstate = self.SEEK_STATE_PLAY
666 def setSeekState(self, state):
667 service = self.session.nav.getCurrentService()
672 if not self.isSeekable():
673 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
674 state = self.SEEK_STATE_PLAY
676 pauseable = service.pause()
678 if pauseable is None:
679 print "not pauseable."
680 state = self.SEEK_STATE_PLAY
682 oldstate = self.seekstate
683 self.seekstate = state
686 if oldstate[i] != self.seekstate[i]:
687 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
689 for c in self.onPlayStateChanged:
692 self.checkSkipShowHideLock()
696 def pauseService(self):
697 if self.seekstate == self.SEEK_STATE_PAUSE:
698 print "pause, but in fact unpause"
699 self.unPauseService()
701 if self.seekstate == self.SEEK_STATE_PLAY:
702 print "yes, playing."
704 print "no", self.seekstate
706 self.setSeekState(self.SEEK_STATE_PAUSE);
708 def unPauseService(self):
710 if self.seekstate == self.SEEK_STATE_PLAY:
712 self.setSeekState(self.SEEK_STATE_PLAY)
714 def doSeek(self, seektime):
715 print "doseek", seektime
716 service = self.session.nav.getCurrentService()
720 seekable = self.getSeek()
724 seekable.seekTo(90 * seektime)
726 def seekFwdDown(self):
727 print "start fwd timer"
729 self.fwdKeyTimer.start(1000)
731 def seekBackDown(self):
732 print "start rewind timer"
734 self.rwdKeyTimer.start(1000)
739 self.fwdKeyTimer.stop()
740 self.fwdtimer = False
745 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
746 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
747 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
748 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
749 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
750 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
751 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
752 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
753 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
754 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
755 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
756 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
757 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
758 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
759 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
761 self.setSeekState(lookup[self.seekstate])
763 def seekBackUp(self):
766 self.rwdKeyTimer.stop()
767 self.rwdtimer = False
772 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
773 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
774 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
775 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
776 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
777 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
778 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
779 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
780 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
781 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
782 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
783 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
784 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
785 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
786 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
788 self.setSeekState(lookup[self.seekstate])
790 if self.seekstate == self.SEEK_STATE_PAUSE:
791 seekable = self.getSeek()
792 if seekable is not None:
793 seekable.seekRelative(-1, 3)
795 def fwdTimerFire(self):
796 print "Display seek fwd"
797 self.fwdKeyTimer.stop()
798 self.fwdtimer = False
799 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
801 def fwdSeekTo(self, minutes):
802 print "Seek", minutes, "minutes forward"
804 seekable = self.getSeek()
805 if seekable is not None:
806 seekable.seekRelative(1, minutes * 60 * 90000)
808 def rwdTimerFire(self):
810 self.rwdKeyTimer.stop()
811 self.rwdtimer = False
812 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
814 def rwdSeekTo(self, minutes):
816 self.fwdSeekTo(0 - minutes)
818 def checkSkipShowHideLock(self):
819 wantlock = self.seekstate != self.SEEK_STATE_PLAY
821 if config.usage.show_infobar_on_zap.value:
822 if self.lockedBecauseOfSkipping and not wantlock:
824 self.lockedBecauseOfSkipping = False
826 if wantlock and not self.lockedBecauseOfSkipping:
828 self.lockedBecauseOfSkipping = True
831 if self.seekstate != self.SEEK_STATE_PLAY:
832 self.setSeekState(self.SEEK_STATE_PAUSE)
834 #self.getSeek().seekRelative(1, -90000)
835 self.setSeekState(self.SEEK_STATE_PLAY)
837 self.setSeekState(self.SEEK_STATE_PAUSE)
840 self.setSeekState(self.SEEK_STATE_PLAY)
843 def seekRelative(self, diff):
844 seekable = self.getSeek()
845 if seekable is not None:
846 seekable.seekRelative(1, diff)
848 def seekAbsolute(self, abs):
849 seekable = self.getSeek()
850 if seekable is not None:
853 from Screens.PVRState import PVRState, TimeshiftState
855 class InfoBarPVRState:
856 def __init__(self, screen=PVRState):
857 self.onPlayStateChanged.append(self.__playStateChanged)
858 self.pvrStateDialog = self.session.instantiateDialog(screen)
859 self.onShow.append(self.__mayShow)
860 self.onHide.append(self.pvrStateDialog.hide)
863 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
864 self.pvrStateDialog.show()
866 def __playStateChanged(self, state):
867 playstateString = state[3]
868 self.pvrStateDialog["state"].setText(playstateString)
871 class InfoBarTimeshiftState(InfoBarPVRState):
873 InfoBarPVRState.__init__(self, screen=TimeshiftState)
875 class InfoBarShowMovies:
877 # i don't really like this class.
878 # it calls a not further specified "movie list" on up/down/movieList,
879 # so this is not more than an action map
881 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
883 "movieList": (self.showMovies, "movie list"),
884 "up": (self.showMovies, "movie list"),
885 "down": (self.showMovies, "movie list")
888 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
892 # Timeshift works the following way:
893 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
894 # - normal playback TUNER unused PLAY enable disable disable
895 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
896 # - user presess pause again FILE record PLAY enable disable enable
897 # - user fast forwards FILE record FF enable disable enable
898 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
899 # - user backwards FILE record BACK # !! enable disable enable
903 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
904 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
905 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
906 # - the user can now PVR around
907 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
908 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
910 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
911 # - if the user rewinds, or press pause, timeshift will be activated again
913 # note that a timeshift can be enabled ("recording") and
914 # activated (currently time-shifting).
916 class InfoBarTimeshift:
918 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
920 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
921 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
923 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
925 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
926 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
927 }, prio=-1) # priority over record
929 self.timeshift_enabled = 0
930 self.timeshift_state = 0
931 self.ts_pause_timer = eTimer()
932 self.ts_pause_timer.timeout.get().append(self.pauseService)
934 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
936 iPlayableService.evStart: self.__serviceStarted,
937 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
940 def getTimeshift(self):
941 service = self.session.nav.getCurrentService()
942 return service and service.timeshift()
944 def startTimeshift(self):
945 print "enable timeshift"
946 ts = self.getTimeshift()
948 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
949 print "no ts interface"
952 if self.timeshift_enabled:
953 print "hu, timeshift already enabled?"
955 if not ts.startTimeshift():
957 self.timeshift_enabled = 1
959 # we remove the "relative time" for now.
960 #self.pvrStateDialog["timeshift"].setRelative(time.time())
963 self.setSeekState(self.SEEK_STATE_PAUSE)
965 # enable the "TimeshiftEnableActions", which will override
966 # the startTimeshift actions
967 self.__seekableStatusChanged()
969 print "timeshift failed"
971 def stopTimeshift(self):
972 if not self.timeshift_enabled:
974 print "disable timeshift"
975 ts = self.getTimeshift()
978 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
980 def stopTimeshiftConfirmed(self, confirmed):
984 ts = self.getTimeshift()
989 self.timeshift_enabled = 0
992 self.__seekableStatusChanged()
994 # activates timeshift, and seeks to (almost) the end
995 def activateTimeshiftEnd(self):
996 ts = self.getTimeshift()
1001 if ts.isTimeshiftActive():
1002 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1005 self.setSeekState(self.SEEK_STATE_PLAY)
1006 ts.activateTimeshift()
1007 self.seekRelative(0)
1009 # same as activateTimeshiftEnd, but pauses afterwards.
1010 def activateTimeshiftEndAndPause(self):
1011 state = self.seekstate
1012 self.activateTimeshiftEnd()
1014 # well, this is "andPause", but it could be pressed from pause,
1015 # when pausing on the (fake-)"live" picture, so an un-pause
1018 print "now, pauseService"
1019 if state == self.SEEK_STATE_PLAY:
1020 print "is PLAYING, start pause timer"
1021 self.ts_pause_timer.start(200, 1)
1024 self.unPauseService()
1026 def __seekableStatusChanged(self):
1029 print "self.isSeekable", self.isSeekable()
1030 print "self.timeshift_enabled", self.timeshift_enabled
1032 # when this service is not seekable, but timeshift
1033 # is enabled, this means we can activate
1035 if not self.isSeekable() and self.timeshift_enabled:
1038 print "timeshift activate:", enabled
1039 self["TimeshiftActivateActions"].setEnabled(enabled)
1041 def __serviceStarted(self):
1042 self.timeshift_enabled = False
1043 self.__seekableStatusChanged()
1045 from Screens.PiPSetup import PiPSetup
1047 class InfoBarExtensions:
1048 EXTENSION_SINGLE = 0
1054 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1056 "extensions": (self.showExtensionSelection, _("view extensions...")),
1059 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1060 self.list.append((type, extension, key))
1062 def updateExtension(self, extension, key = None):
1063 self.extensionsList.append(extension)
1065 if self.extensionKeys.has_key(key):
1069 for x in self.availableKeys:
1070 if not self.extensionKeys.has_key(x):
1075 self.extensionKeys[key] = len(self.extensionsList) - 1
1077 def updateExtensions(self):
1078 self.extensionsList = []
1079 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1080 self.extensionKeys = {}
1082 if x[0] == self.EXTENSION_SINGLE:
1083 self.updateExtension(x[1], x[2])
1086 self.updateExtension(y[0], y[1])
1089 def showExtensionSelection(self):
1090 self.updateExtensions()
1091 extensionsList = self.extensionsList[:]
1094 for x in self.availableKeys:
1095 if self.extensionKeys.has_key(x):
1096 entry = self.extensionKeys[x]
1097 extension = self.extensionsList[entry]
1099 name = str(extension[0]())
1100 list.append((extension[0](), extension))
1102 extensionsList.remove(extension)
1104 extensionsList.remove(extension)
1105 for x in extensionsList:
1106 list.append((x[0](), x))
1107 keys += [""] * len(extensionsList)
1108 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1110 def extensionCallback(self, answer):
1111 if answer is not None:
1114 from Tools.BoundFunction import boundFunction
1116 # depends on InfoBarExtensions
1117 from Components.PluginComponent import plugins
1119 class InfoBarPlugins:
1121 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1124 def getPluginName(self, name):
1127 def getPluginList(self):
1129 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1130 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1133 def runPlugin(self, plugin):
1134 plugin(session = self.session)
1136 # depends on InfoBarExtensions
1139 self.session.pipshown = False
1141 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1142 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1143 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1145 def available(self):
1149 return self.session.pipshown
1151 def getShowHideName(self):
1152 if self.session.pipshown:
1153 return _("Disable Picture in Picture")
1155 return _("Activate Picture in Picture")
1157 def getSwapName(self):
1158 return _("Swap Services")
1160 def getMoveName(self):
1161 return _("Move Picture in Picture")
1164 if self.session.pipshown:
1165 del self.session.pip
1166 self.session.pipshown = False
1168 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1169 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1170 if self.session.pip.playService(newservice):
1171 self.session.pipshown = True
1172 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1174 self.session.pipshown = False
1175 del self.session.pip
1176 self.session.nav.playService(newservice)
1179 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1180 if self.session.pip.servicePath:
1181 servicepath = self.servicelist.getCurrentServicePath()
1182 ref=servicepath[len(servicepath)-1]
1183 pipref=self.session.pip.getCurrentService()
1184 self.session.pip.playService(swapservice)
1185 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1186 if pipref.toString() != ref.toString(): # is a subservice ?
1187 self.session.nav.stopService() # stop portal
1188 self.session.nav.playService(pipref) # start subservice
1189 self.session.pip.servicePath=servicepath
1192 self.session.open(PiPSetup, pip = self.session.pip)
1194 from RecordTimer import parseEvent
1196 class InfoBarInstantRecord:
1197 """Instant Record - handles the instantRecord action in order to
1198 start/stop instant records"""
1200 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1202 "instantRecord": (self.instantRecord, _("Instant Record...")),
1205 self["BlinkingPoint"] = BlinkingPixmapConditional()
1206 self["BlinkingPoint"].hide()
1207 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1209 def stopCurrentRecording(self, entry = -1):
1210 if entry is not None and entry != -1:
1211 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1212 self.recording.remove(self.recording[entry])
1214 def startInstantRecording(self, limitEvent = False):
1215 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1217 # try to get event info
1220 service = self.session.nav.getCurrentService()
1221 epg = eEPGCache.getInstance()
1222 event = epg.lookupEventTime(serviceref, -1, 0)
1224 info = service.info()
1225 ev = info.getEvent(0)
1231 end = time.time() + 3600 * 10
1232 name = "instant record"
1236 if event is not None:
1237 curEvent = parseEvent(event)
1239 description = curEvent[3]
1240 eventid = curEvent[4]
1245 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1247 data = (begin, end, name, description, eventid)
1249 recording = self.session.nav.recordWithTimer(serviceref, *data)
1250 recording.dontSave = True
1251 self.recording.append(recording)
1253 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1255 def isInstantRecordRunning(self):
1256 print "self.recording:", self.recording
1257 if len(self.recording) > 0:
1258 for x in self.recording:
1263 def recordQuestionCallback(self, answer):
1264 print "pre:\n", self.recording
1266 if answer is None or answer[1] == "no":
1269 recording = self.recording[:]
1271 if not x in self.session.nav.RecordTimer.timer_list:
1272 self.recording.remove(x)
1273 elif x.dontSave and x.isRunning():
1274 list.append(TimerEntryComponent(x, False))
1276 if answer[1] == "changeduration":
1277 if len(self.recording) == 1:
1278 self.changeDuration(0)
1280 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1281 elif answer[1] == "stop":
1282 if len(self.recording) == 1:
1283 self.stopCurrentRecording(0)
1285 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1286 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1288 if answer[1] == "event":
1290 if answer[1] == "manualduration":
1291 self.selectedEntry = len(self.recording)
1292 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1293 self.startInstantRecording(limitEvent = limitEvent)
1295 print "after:\n", self.recording
1297 def changeDuration(self, entry):
1298 if entry is not None:
1299 self.selectedEntry = entry
1300 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1302 def inputCallback(self, value):
1303 if value is not None:
1304 print "stopping recording after", int(value), "minutes."
1305 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1306 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1308 def instantRecord(self):
1310 stat = os.stat(resolveFilename(SCOPE_HDD))
1312 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1315 if self.isInstantRecordRunning():
1316 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")])
1318 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")])
1320 from Tools.ISO639 import LanguageCodes
1322 class InfoBarAudioSelection:
1324 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1326 "audioSelection": (self.audioSelection, _("Audio Options...")),
1329 def audioSelection(self):
1330 service = self.session.nav.getCurrentService()
1331 audio = service and service.audioTracks()
1332 self.audioTracks = audio
1333 n = audio and audio.getNumberOfTracks() or 0
1334 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1336 print "tlist:", tlist
1338 self.audioChannel = service.audioChannel()
1341 i = audio.getTrackInfo(x)
1342 language = i.getLanguage()
1343 description = i.getDescription()
1345 if LanguageCodes.has_key(language):
1346 language = LanguageCodes[language][0]
1348 if len(description):
1349 description += " (" + language + ")"
1351 description = language
1353 tlist.append((description, x))
1355 selectedAudio = tlist[0][1]
1356 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1360 if x[1] != selectedAudio:
1365 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1366 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1368 del self.audioTracks
1370 def audioSelected(self, audio):
1371 if audio is not None:
1372 if isinstance(audio[1], str):
1373 if audio[1] == "mode":
1374 keys = ["red", "green", "yellow"]
1375 selection = self.audioChannel.getCurrentChannel()
1376 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1377 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1379 del self.audioChannel
1380 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1381 self.audioTracks.selectTrack(audio[1])
1383 del self.audioChannel
1384 del self.audioTracks
1386 def modeSelected(self, mode):
1387 if mode is not None:
1388 self.audioChannel.selectChannel(mode[1])
1389 del self.audioChannel
1391 class InfoBarSubserviceSelection:
1393 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1395 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1398 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1400 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1401 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1403 self["SubserviceQuickzapAction"].setEnabled(False)
1405 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1407 def checkSubservicesAvail(self, ev):
1408 if ev == iPlayableService.evUpdatedEventInfo:
1409 service = self.session.nav.getCurrentService()
1410 subservices = service and service.subServices()
1411 if not subservices or subservices.getNumberOfSubservices() == 0:
1412 self["SubserviceQuickzapAction"].setEnabled(False)
1414 def nextSubservice(self):
1415 self.changeSubservice(+1)
1417 def prevSubservice(self):
1418 self.changeSubservice(-1)
1420 def changeSubservice(self, direction):
1421 service = self.session.nav.getCurrentService()
1422 subservices = service and service.subServices()
1423 n = subservices and subservices.getNumberOfSubservices()
1426 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1428 if subservices.getSubservice(x).toString() == ref.toString():
1431 selection += direction
1436 newservice = subservices.getSubservice(selection)
1437 if newservice.valid():
1440 if config.usage.show_infobar_on_zap.value:
1442 self.session.nav.playService(newservice)
1444 def subserviceSelection(self):
1445 service = self.session.nav.getCurrentService()
1446 subservices = service and service.subServices()
1448 n = subservices and subservices.getNumberOfSubservices()
1451 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1454 i = subservices.getSubservice(x)
1455 if i.toString() == ref.toString():
1457 tlist.append((i.getName(), i))
1459 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1461 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1463 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1465 def subserviceSelected(self, service):
1466 if not service is None:
1467 if isinstance(service[1], str):
1468 if service[1] == "quickzap":
1469 from Screens.SubservicesQuickzap import SubservicesQuickzap
1470 self.session.open(SubservicesQuickzap, service[2])
1472 self["SubserviceQuickzapAction"].setEnabled(True)
1473 if config.usage.show_infobar_on_zap.value:
1475 self.session.nav.playService(service[1])
1477 class InfoBarAdditionalInfo:
1479 self["NimA"] = Pixmap()
1480 self["NimB"] = Pixmap()
1481 self["NimA_Active"] = Pixmap()
1482 self["NimB_Active"] = Pixmap()
1484 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1485 self["TimeshiftPossible"] = self["RecordingPossible"]
1486 self["ExtensionsAvailable"] = Boolean(fixed=1)
1488 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1489 res_mgr = eDVBResourceManagerPtr()
1490 if eDVBResourceManager.getInstance(res_mgr) == 0:
1491 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1493 def tunerUseMaskChanged(self, mask):
1495 self["NimA_Active"].show()
1497 self["NimA_Active"].hide()
1499 self["NimB_Active"].show()
1501 self["NimB_Active"].hide()
1503 def checkTunerState(self, service):
1504 info = service.frontendInfo()
1505 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1506 if feNumber is None:
1516 def gotServiceEvent(self, ev):
1517 service = self.session.nav.getCurrentService()
1518 if ev == iPlayableService.evStart:
1519 self.checkTunerState(service)
1521 class InfoBarNotifications:
1523 self.onExecBegin.append(self.checkNotifications)
1524 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1525 self.onClose.append(self.__removeNotification)
1527 def __removeNotification(self):
1528 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1530 def checkNotificationsIfExecing(self):
1532 self.checkNotifications()
1534 def checkNotifications(self):
1535 if len(Notifications.notifications):
1536 n = Notifications.notifications[0]
1537 Notifications.notifications = Notifications.notifications[1:]
1540 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1542 self.session.open(n[1], *n[2], **n[3])
1544 class InfoBarServiceNotifications:
1546 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1548 iPlayableService.evEnd: self.serviceHasEnded
1551 def serviceHasEnded(self):
1552 print "service end!"
1555 self.setSeekState(self.SEEK_STATE_PLAY)
1559 class InfoBarCueSheetSupport:
1565 ENABLE_RESUME_SUPPORT = False
1568 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1570 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1571 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1572 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1576 self.is_closing = False
1577 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1579 iPlayableService.evStart: self.__serviceStarted,
1582 def __serviceStarted(self):
1585 print "new service started! trying to download cuts!"
1586 self.downloadCuesheet()
1588 if self.ENABLE_RESUME_SUPPORT:
1591 for (pts, what) in self.cut_list:
1592 if what == self.CUT_TYPE_LAST:
1595 if last is not None:
1596 self.resume_point = last
1597 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1599 def playLastCB(self, answer):
1601 seekable = self.__getSeekable()
1602 if seekable is not None:
1603 seekable.seekTo(self.resume_point)
1605 def __getSeekable(self):
1606 service = self.session.nav.getCurrentService()
1609 return service.seek()
1611 def cueGetCurrentPosition(self):
1612 seek = self.__getSeekable()
1615 r = seek.getPlayPosition()
1620 def jumpPreviousNextMark(self, cmp, alternative=None):
1621 current_pos = self.cueGetCurrentPosition()
1622 if current_pos is None:
1624 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1625 if mark is not None:
1627 elif alternative is not None:
1632 seekable = self.__getSeekable()
1633 if seekable is not None:
1634 seekable.seekTo(pts)
1636 def jumpPreviousMark(self):
1637 # we add 2 seconds, so if the play position is <2s after
1638 # the mark, the mark before will be used
1639 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1641 def jumpNextMark(self):
1642 self.jumpPreviousNextMark(lambda x: x)
1644 def getNearestCutPoint(self, pts, cmp=abs):
1647 for cp in self.cut_list:
1648 diff = cmp(cp[0] - pts)
1649 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1653 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1654 current_pos = self.cueGetCurrentPosition()
1655 if current_pos is None:
1656 print "not seekable"
1659 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1661 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1663 return nearest_cutpoint
1665 self.removeMark(nearest_cutpoint)
1666 elif not onlyremove and not onlyreturn:
1667 self.addMark((current_pos, self.CUT_TYPE_MARK))
1672 def addMark(self, point):
1673 bisect.insort(self.cut_list, point)
1674 self.uploadCuesheet()
1676 def removeMark(self, point):
1677 self.cut_list.remove(point)
1678 self.uploadCuesheet()
1680 def __getCuesheet(self):
1681 service = self.session.nav.getCurrentService()
1684 return service.cueSheet()
1686 def uploadCuesheet(self):
1687 cue = self.__getCuesheet()
1690 print "upload failed, no cuesheet interface"
1692 cue.setCutList(self.cut_list)
1694 def downloadCuesheet(self):
1695 cue = self.__getCuesheet()
1698 print "upload failed, no cuesheet interface"
1700 self.cut_list = cue.getCutList()
1702 class InfoBarSummary(Screen):
1704 <screen position="0,0" size="132,64">
1705 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1706 <convert type="ClockToText">WithSeconds</convert>
1708 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1709 <convert type="ServiceName">Name</convert>
1713 def __init__(self, session, parent):
1714 Screen.__init__(self, session)
1715 self["CurrentService"] = CurrentService(self.session.nav)
1716 self["CurrentTime"] = Clock()
1718 class InfoBarSummarySupport:
1722 def createSummary(self):
1723 return InfoBarSummary
1725 class InfoBarTeletextPlugin:
1727 self.teletext_plugin = None
1729 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1730 self.teletext_plugin = p
1732 if self.teletext_plugin is not None:
1733 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1735 "startTeletext": (self.startTeletext, _("View teletext..."))
1738 print "no teletext plugin found!"
1740 def startTeletext(self):
1741 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1743 class InfoBarSubtitleSupport(object):
1745 object.__init__(self)
1746 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1747 self.__subtitles_enabled = False
1749 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1751 iPlayableService.evEnd: self.__serviceStopped,
1752 iPlayableService.evUpdatedInfo: self.__updatedInfo
1754 self.cached_subtitle_checked = False
1756 def __serviceStopped(self):
1757 self.subtitle_window.hide()
1758 self.__subtitles_enabled = False
1759 self.cached_subtitle_checked = False
1761 def __updatedInfo(self):
1762 if not self.cached_subtitle_checked:
1763 subtitle = self.getCurrentServiceSubtitle()
1764 self.cached_subtitle_checked = True
1766 self.__selected_subtitle = subtitle.getCachedSubtitle()
1767 if self.__selected_subtitle:
1768 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1769 self.subtitle_window.show()
1770 self.__subtitles_enabled = True
1772 def getCurrentServiceSubtitle(self):
1773 service = self.session.nav.getCurrentService()
1774 return service and service.subtitle()
1776 def setSubtitlesEnable(self, enable=True):
1777 subtitle = self.getCurrentServiceSubtitle()
1778 if enable and self.__selected_subtitle is not None:
1779 if subtitle and not self.__subtitles_enabled:
1780 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1781 self.subtitle_window.show()
1782 self.__subtitles_enabled = True
1785 subtitle.disableSubtitles(self.subtitle_window.instance)
1786 self.__subtitles_enabled = False
1787 self.subtitle_window.hide()
1789 def setSelectedSubtitle(self, subtitle):
1790 self.__selected_subtitle = subtitle
1792 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1793 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)