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.FrontendStatus import FrontendStatus
16 from Components.Sources.Boolean import Boolean
17 from Components.Sources.Clock import Clock
18 from Components.TimerList import TimerEntryComponent
19 from Components.config import config, ConfigBoolean
21 from EpgSelection import EPGSelection
22 from Plugins.Plugin import PluginDescriptor
24 from Screen import Screen
25 from Screens.ChoiceBox import ChoiceBox
26 from Screens.Dish import Dish
27 from Screens.EventView import EventViewEPGSelect, EventViewSimple
28 from Screens.InputBox import InputBox
29 from Screens.MessageBox import MessageBox
30 from Screens.MinuteInput import MinuteInput
31 from Screens.TimerSelection import TimerSelection
32 from Screens.PictureInPicture import PictureInPicture
33 from Screens.SubtitleDisplay import SubtitleDisplay
34 from ServiceReference import ServiceReference
36 from Tools import Notifications
37 from Tools.Directories import *
39 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
47 from Menu import MainMenu, mdom
51 self.dishDialog = self.session.instantiateDialog(Dish)
52 self.onLayoutFinish.append(self.dishDialog.show)
54 class InfoBarShowHide:
55 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
63 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
65 "toggleShow": self.toggleShow,
69 self.__state = self.STATE_SHOWN
72 self.onExecBegin.append(self.show)
74 self.hideTimer = eTimer()
75 self.hideTimer.timeout.get().append(self.doTimerHide)
76 self.hideTimer.start(5000, True)
78 self.onShow.append(self.__onShow)
79 self.onHide.append(self.__onHide)
82 self.__state = self.STATE_SHOWN
85 def startHideTimer(self):
86 if self.__state == self.STATE_SHOWN and not self.__locked:
87 self.hideTimer.start(5000, True)
90 self.__state = self.STATE_HIDDEN
96 def doTimerHide(self):
98 if self.__state == self.STATE_SHOWN:
101 def toggleShow(self):
102 if self.__state == self.STATE_SHOWN:
104 self.hideTimer.stop()
105 elif self.__state == self.STATE_HIDDEN:
109 self.__locked = self.__locked + 1
112 self.hideTimer.stop()
114 def unlockShow(self):
115 self.__locked = self.__locked - 1
117 self.startHideTimer()
119 # def startShow(self):
120 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
121 # self.__state = self.STATE_SHOWN
123 # def startHide(self):
124 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
125 # self.__state = self.STATE_HIDDEN
127 class NumberZap(Screen):
134 self.close(int(self["number"].getText()))
136 def keyNumberGlobal(self, number):
137 self.Timer.start(3000, True) #reset timer
138 self.field = self.field + str(number)
139 self["number"].setText(self.field)
140 if len(self.field) >= 4:
143 def __init__(self, session, number):
144 Screen.__init__(self, session)
145 self.field = str(number)
147 self["channel"] = Label(_("Channel:"))
149 self["number"] = Label(self.field)
151 self["actions"] = NumberActionMap( [ "SetupActions" ],
155 "1": self.keyNumberGlobal,
156 "2": self.keyNumberGlobal,
157 "3": self.keyNumberGlobal,
158 "4": self.keyNumberGlobal,
159 "5": self.keyNumberGlobal,
160 "6": self.keyNumberGlobal,
161 "7": self.keyNumberGlobal,
162 "8": self.keyNumberGlobal,
163 "9": self.keyNumberGlobal,
164 "0": self.keyNumberGlobal
167 self.Timer = eTimer()
168 self.Timer.timeout.get().append(self.keyOK)
169 self.Timer.start(3000, True)
171 class InfoBarNumberZap:
172 """ Handles an initial number for NumberZapping """
174 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
176 "1": self.keyNumberGlobal,
177 "2": self.keyNumberGlobal,
178 "3": self.keyNumberGlobal,
179 "4": self.keyNumberGlobal,
180 "5": self.keyNumberGlobal,
181 "6": self.keyNumberGlobal,
182 "7": self.keyNumberGlobal,
183 "8": self.keyNumberGlobal,
184 "9": self.keyNumberGlobal,
185 "0": self.keyNumberGlobal,
188 def keyNumberGlobal(self, number):
189 # print "You pressed number " + str(number)
191 self.servicelist.recallPrevService()
194 self.session.openWithCallback(self.numberEntered, NumberZap, number)
196 def numberEntered(self, retval):
197 # print self.servicelist
199 self.zapToNumber(retval)
201 def searchNumberHelper(self, serviceHandler, num, bouquet):
202 servicelist = serviceHandler.list(bouquet)
203 if not servicelist is None:
205 serviceIterator = servicelist.getNext()
206 if not serviceIterator.valid(): #check end of list
208 if serviceIterator.flags: #assume normal dvb service have no flags set
211 if not num: #found service with searched number ?
212 return serviceIterator, 0
215 def zapToNumber(self, number):
216 bouquet = self.servicelist.bouquet_root
218 serviceHandler = eServiceCenter.getInstance()
219 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
220 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
222 bouquetlist = serviceHandler.list(bouquet)
223 if not bouquetlist is None:
225 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
226 if not bouquet.valid(): #check end of list
228 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
230 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
231 if not service is None:
232 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
233 self.servicelist.clearPath()
234 if self.servicelist.bouquet_root != bouquet:
235 self.servicelist.enterPath(self.servicelist.bouquet_root)
236 self.servicelist.enterPath(bouquet)
237 self.servicelist.setCurrentSelection(service) #select the service in servicelist
238 self.servicelist.zap()
240 config.misc.initialchannelselection = ConfigBoolean(default = True)
242 class InfoBarChannelSelection:
243 """ ChannelSelection - handles the channelSelection dialog and the initial
244 channelChange actions which open the channelSelection dialog """
247 self.servicelist = self.session.instantiateDialog(ChannelSelection)
249 print "__init__: servicelist is", self.servicelist
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 print "servicelist is", self.servicelist
281 self.switchChannelDown()
283 def historyBack(self):
284 self.servicelist.historyBack()
286 def historyNext(self):
287 self.servicelist.historyNext()
289 def switchChannelUp(self):
290 self.servicelist.moveUp()
291 self.session.execDialog(self.servicelist)
293 def switchChannelDown(self):
294 self.servicelist.moveDown()
295 self.session.execDialog(self.servicelist)
297 def openServiceList(self):
298 self.session.execDialog(self.servicelist)
301 if self.servicelist.inBouquet():
302 prev = self.servicelist.getCurrentSelection()
304 prev = prev.toString()
306 if config.usage.quickzap_bouquet_change.value:
307 if self.servicelist.atBegin():
308 self.servicelist.prevBouquet()
309 self.servicelist.moveUp()
310 cur = self.servicelist.getCurrentSelection()
311 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
314 self.servicelist.moveUp()
315 self.servicelist.zap()
319 if self.servicelist.inBouquet():
320 prev = self.servicelist.getCurrentSelection()
322 prev = prev.toString()
324 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
325 self.servicelist.nextBouquet()
327 self.servicelist.moveDown()
328 cur = self.servicelist.getCurrentSelection()
329 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
332 self.servicelist.moveDown()
333 self.servicelist.zap()
337 """ Handles a menu action, to open the (main) menu """
339 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
341 "mainMenu": (self.mainMenu, _("Enter main menu...")),
345 print "loading mainmenu XML..."
346 menu = mdom.childNodes[0]
347 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
348 self.session.open(MainMenu, menu, menu.childNodes)
350 class InfoBarSimpleEventView:
351 """ Opens the Eventview for now/next """
353 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
355 "showEventInfo": (self.openEventView, _("show event details")),
358 def openEventView(self):
360 service = self.session.nav.getCurrentService()
361 ref = self.session.nav.getCurrentlyPlayingServiceReference()
362 info = service.info()
365 self.epglist.append(ptr)
368 self.epglist.append(ptr)
369 if len(self.epglist) > 0:
370 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
372 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
373 if len(self.epglist) > 1:
374 tmp = self.epglist[0]
375 self.epglist[0]=self.epglist[1]
377 setEvent(self.epglist[0])
380 """ EPG - Opens an EPG list when the showEPGList action fires """
382 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
384 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
387 self.is_now_next = False
389 self.bouquetSel = None
390 self.eventView = None
391 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
393 "showEventInfo": (self.openEventView, _("show EPG...")),
396 def zapToService(self, service):
397 if not service is None:
398 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
399 self.servicelist.clearPath()
400 if self.servicelist.bouquet_root != self.epg_bouquet:
401 self.servicelist.enterPath(self.servicelist.bouquet_root)
402 self.servicelist.enterPath(self.epg_bouquet)
403 self.servicelist.setCurrentSelection(service) #select the service in servicelist
404 self.servicelist.zap()
406 def getBouquetServices(self, bouquet):
408 servicelist = eServiceCenter.getInstance().list(bouquet)
409 if not servicelist is None:
411 service = servicelist.getNext()
412 if not service.valid(): #check if end of list
414 if service.flags: #ignore non playable services
416 services.append(ServiceReference(service))
419 def openBouquetEPG(self, bouquet, withCallback=True):
420 services = self.getBouquetServices(bouquet)
422 self.epg_bouquet = bouquet
424 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
426 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
428 def changeBouquetCB(self, direction, epg):
431 self.bouquetSel.down()
434 bouquet = self.bouquetSel.getCurrent()
435 services = self.getBouquetServices(bouquet)
437 self.epg_bouquet = bouquet
438 epg.setServices(services)
440 def closed(self, ret=False):
441 closedScreen = self.dlg_stack.pop()
442 if self.bouquetSel and closedScreen == self.bouquetSel:
443 self.bouquetSel = None
444 elif self.eventView and closedScreen == self.eventView:
445 self.eventView = None
447 dlgs=len(self.dlg_stack)
449 self.dlg_stack[dlgs-1].close(dlgs > 1)
451 def openMultiServiceEPG(self, withCallback=True):
452 bouquets = self.servicelist.getBouquetList()
457 if cnt > 1: # show bouquet list
459 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
460 self.dlg_stack.append(self.bouquetSel)
462 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
464 self.openBouquetEPG(bouquets[0][1], withCallback)
466 def openSingleServiceEPG(self):
467 ref=self.session.nav.getCurrentlyPlayingServiceReference()
468 self.session.open(EPGSelection, ref)
470 def openSimilarList(self, eventid, refstr):
471 self.session.open(EPGSelection, refstr, None, eventid)
473 def getNowNext(self):
475 service = self.session.nav.getCurrentService()
476 info = service and service.info()
477 ptr = info and info.getEvent(0)
479 self.epglist.append(ptr)
480 ptr = info and info.getEvent(1)
482 self.epglist.append(ptr)
484 def __evEventInfoChanged(self):
485 if self.is_now_next and len(self.dlg_stack) == 1:
487 assert self.eventView
488 if len(self.epglist):
489 self.eventView.setEvent(self.epglist[0])
491 def openEventView(self):
492 ref = self.session.nav.getCurrentlyPlayingServiceReference()
494 if len(self.epglist) == 0:
495 self.is_now_next = False
496 epg = eEPGCache.getInstance()
497 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
499 self.epglist.append(ptr)
500 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
502 self.epglist.append(ptr)
504 self.is_now_next = True
505 if len(self.epglist) > 0:
506 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
507 self.dlg_stack.append(self.eventView)
509 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
510 self.openMultiServiceEPG(False)
512 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
513 if len(self.epglist) > 1:
514 tmp = self.epglist[0]
515 self.epglist[0]=self.epglist[1]
517 setEvent(self.epglist[0])
520 """provides a snr/agc/ber display"""
522 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
525 """provides a current/next event info display"""
527 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
528 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
530 class InfoBarServiceName:
532 self["CurrentService"] = CurrentService(self.session.nav)
535 """handles actions like seeking, pause"""
537 # ispause, isff, issm
538 SEEK_STATE_PLAY = (0, 0, 0, ">")
539 SEEK_STATE_PAUSE = (1, 0, 0, "||")
540 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
541 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
542 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
543 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
544 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
545 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
547 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
548 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
549 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
550 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
552 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
553 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
554 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
557 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
559 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
560 iPlayableService.evStart: self.__serviceStarted,
562 iPlayableService.evEOF: self.__evEOF,
563 iPlayableService.evSOF: self.__evSOF,
566 class InfoBarSeekActionMap(HelpableActionMap):
567 def __init__(self, screen, *args, **kwargs):
568 HelpableActionMap.__init__(self, screen, *args, **kwargs)
571 def action(self, contexts, action):
572 if action[:5] == "seek:":
573 time = int(action[5:])
574 self.screen.seekRelative(time * 90000)
577 return HelpableActionMap.action(self, contexts, action)
579 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
581 "pauseService": (self.pauseService, _("pause")),
582 "unPauseService": (self.unPauseService, _("continue")),
584 "seekFwd": (self.seekFwd, _("skip forward")),
585 "seekFwdDown": self.seekFwdDown,
586 "seekFwdUp": self.seekFwdUp,
587 "seekBack": (self.seekBack, _("skip backward")),
588 "seekBackDown": self.seekBackDown,
589 "seekBackUp": self.seekBackUp,
591 # give them a little more priority to win over color buttons
593 self.seekstate = self.SEEK_STATE_PLAY
594 self.onClose.append(self.delTimer)
596 self.fwdtimer = False
597 self.fwdKeyTimer = eTimer()
598 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
600 self.rwdtimer = False
601 self.rwdKeyTimer = eTimer()
602 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
604 self.onPlayStateChanged = [ ]
606 self.lockedBecauseOfSkipping = False
619 service = self.session.nav.getCurrentService()
623 seek = service.seek()
625 if seek is None or not seek.isCurrentlySeekable():
630 def isSeekable(self):
631 if self.getSeek() is None:
635 def __seekableStatusChanged(self):
636 print "seekable status changed!"
637 if not self.isSeekable():
638 self["SeekActions"].setEnabled(False)
639 print "not seekable, return to play"
640 self.setSeekState(self.SEEK_STATE_PLAY)
642 self["SeekActions"].setEnabled(True)
645 def __serviceStarted(self):
646 self.seekstate = self.SEEK_STATE_PLAY
648 def setSeekState(self, state):
649 service = self.session.nav.getCurrentService()
654 if not self.isSeekable():
655 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
656 state = self.SEEK_STATE_PLAY
658 pauseable = service.pause()
660 if pauseable is None:
661 print "not pauseable."
662 state = self.SEEK_STATE_PLAY
664 oldstate = self.seekstate
665 self.seekstate = state
668 if oldstate[i] != self.seekstate[i]:
669 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
671 for c in self.onPlayStateChanged:
674 self.checkSkipShowHideLock()
678 def pauseService(self):
679 if self.seekstate == self.SEEK_STATE_PAUSE:
680 print "pause, but in fact unpause"
681 self.unPauseService()
683 if self.seekstate == self.SEEK_STATE_PLAY:
684 print "yes, playing."
686 print "no", self.seekstate
688 self.setSeekState(self.SEEK_STATE_PAUSE);
690 def unPauseService(self):
692 if self.seekstate == self.SEEK_STATE_PLAY:
694 self.setSeekState(self.SEEK_STATE_PLAY)
696 def doSeek(self, seektime):
697 print "doseek", seektime
698 service = self.session.nav.getCurrentService()
702 seekable = self.getSeek()
706 seekable.seekTo(90 * seektime)
708 def seekFwdDown(self):
709 print "start fwd timer"
711 self.fwdKeyTimer.start(1000)
713 def seekBackDown(self):
714 print "start rewind timer"
716 self.rwdKeyTimer.start(1000)
721 self.fwdKeyTimer.stop()
722 self.fwdtimer = False
727 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
728 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
729 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
730 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
731 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
732 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
733 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
734 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
735 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
736 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
737 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
738 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
739 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
740 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
741 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
743 self.setSeekState(lookup[self.seekstate])
745 def seekBackUp(self):
748 self.rwdKeyTimer.stop()
749 self.rwdtimer = False
754 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
755 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
756 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
757 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
758 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
759 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
760 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
761 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
762 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
763 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
764 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
765 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
766 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
767 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
768 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
770 self.setSeekState(lookup[self.seekstate])
772 if self.seekstate == self.SEEK_STATE_PAUSE:
773 seekable = self.getSeek()
774 if seekable is not None:
775 seekable.seekRelative(-1, 3)
777 def fwdTimerFire(self):
778 print "Display seek fwd"
779 self.fwdKeyTimer.stop()
780 self.fwdtimer = False
781 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
783 def fwdSeekTo(self, minutes):
784 print "Seek", minutes, "minutes forward"
786 seekable = self.getSeek()
787 if seekable is not None:
788 seekable.seekRelative(1, minutes * 60 * 90000)
790 def rwdTimerFire(self):
792 self.rwdKeyTimer.stop()
793 self.rwdtimer = False
794 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
796 def rwdSeekTo(self, minutes):
798 self.fwdSeekTo(0 - minutes)
800 def checkSkipShowHideLock(self):
801 wantlock = self.seekstate != self.SEEK_STATE_PLAY
803 if self.lockedBecauseOfSkipping and not wantlock:
805 self.lockedBecauseOfSkipping = False
807 if wantlock and not self.lockedBecauseOfSkipping:
809 self.lockedBecauseOfSkipping = True
812 if self.seekstate != self.SEEK_STATE_PLAY:
813 self.setSeekState(self.SEEK_STATE_PAUSE)
815 #self.getSeek().seekRelative(1, -90000)
816 self.setSeekState(self.SEEK_STATE_PLAY)
818 self.setSeekState(self.SEEK_STATE_PAUSE)
821 self.setSeekState(self.SEEK_STATE_PLAY)
824 def seekRelative(self, diff):
825 seekable = self.getSeek()
826 if seekable is not None:
827 seekable.seekRelative(1, diff)
829 def seekAbsolute(self, abs):
830 seekable = self.getSeek()
831 if seekable is not None:
834 from Screens.PVRState import PVRState, TimeshiftState
836 class InfoBarPVRState:
837 def __init__(self, screen=PVRState):
838 self.onPlayStateChanged.append(self.__playStateChanged)
839 self.pvrStateDialog = self.session.instantiateDialog(screen)
840 self.onShow.append(self.__mayShow)
841 self.onHide.append(self.pvrStateDialog.hide)
844 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
845 self.pvrStateDialog.show()
847 def __playStateChanged(self, state):
848 playstateString = state[3]
849 self.pvrStateDialog["state"].setText(playstateString)
852 class InfoBarTimeshiftState(InfoBarPVRState):
854 InfoBarPVRState.__init__(self, screen=TimeshiftState)
856 class InfoBarShowMovies:
858 # i don't really like this class.
859 # it calls a not further specified "movie list" on up/down/movieList,
860 # so this is not more than an action map
862 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
864 "movieList": (self.showMovies, "movie list"),
865 "up": (self.showMovies, "movie list"),
866 "down": (self.showMovies, "movie list")
869 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
873 # Timeshift works the following way:
874 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
875 # - normal playback TUNER unused PLAY enable disable disable
876 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
877 # - user presess pause again FILE record PLAY enable disable enable
878 # - user fast forwards FILE record FF enable disable enable
879 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
880 # - user backwards FILE record BACK # !! enable disable enable
884 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
885 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
886 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
887 # - the user can now PVR around
888 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
889 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
891 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
892 # - if the user rewinds, or press pause, timeshift will be activated again
894 # note that a timeshift can be enabled ("recording") and
895 # activated (currently time-shifting).
897 class InfoBarTimeshift:
899 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
901 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
902 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
904 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
906 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
907 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
908 }, prio=-1) # priority over record
910 self.timeshift_enabled = 0
911 self.timeshift_state = 0
912 self.ts_pause_timer = eTimer()
913 self.ts_pause_timer.timeout.get().append(self.pauseService)
915 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
917 iPlayableService.evStart: self.__serviceStarted,
918 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
921 def getTimeshift(self):
922 service = self.session.nav.getCurrentService()
923 return service and service.timeshift()
925 def startTimeshift(self):
926 print "enable timeshift"
927 ts = self.getTimeshift()
929 # self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
930 # print "no ts interface"
933 if self.timeshift_enabled:
934 print "hu, timeshift already enabled?"
936 if not ts.startTimeshift():
938 self.timeshift_enabled = 1
940 # we remove the "relative time" for now.
941 #self.pvrStateDialog["timeshift"].setRelative(time.time())
944 self.setSeekState(self.SEEK_STATE_PAUSE)
946 # enable the "TimeshiftEnableActions", which will override
947 # the startTimeshift actions
948 self.__seekableStatusChanged()
950 print "timeshift failed"
952 def stopTimeshift(self):
953 if not self.timeshift_enabled:
955 print "disable timeshift"
956 ts = self.getTimeshift()
959 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
961 def stopTimeshiftConfirmed(self, confirmed):
965 ts = self.getTimeshift()
970 self.timeshift_enabled = 0
973 self.__seekableStatusChanged()
975 # activates timeshift, and seeks to (almost) the end
976 def activateTimeshiftEnd(self):
977 ts = self.getTimeshift()
982 if ts.isTimeshiftActive():
983 print "!! activate timeshift called - but shouldn't this be a normal pause?"
986 self.setSeekState(self.SEEK_STATE_PLAY)
987 ts.activateTimeshift()
990 # same as activateTimeshiftEnd, but pauses afterwards.
991 def activateTimeshiftEndAndPause(self):
992 state = self.seekstate
993 self.activateTimeshiftEnd()
995 # well, this is "andPause", but it could be pressed from pause,
996 # when pausing on the (fake-)"live" picture, so an un-pause
999 print "now, pauseService"
1000 if state == self.SEEK_STATE_PLAY:
1001 print "is PLAYING, start pause timer"
1002 self.ts_pause_timer.start(200, 1)
1005 self.unPauseService()
1007 def __seekableStatusChanged(self):
1010 print "self.isSeekable", self.isSeekable()
1011 print "self.timeshift_enabled", self.timeshift_enabled
1013 # when this service is not seekable, but timeshift
1014 # is enabled, this means we can activate
1016 if not self.isSeekable() and self.timeshift_enabled:
1019 print "timeshift activate:", enabled
1020 self["TimeshiftActivateActions"].setEnabled(enabled)
1022 def __serviceStarted(self):
1023 self.timeshift_enabled = False
1024 self.__seekableStatusChanged()
1026 from Screens.PiPSetup import PiPSetup
1028 class InfoBarExtensions:
1029 EXTENSION_SINGLE = 0
1035 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1037 "extensions": (self.showExtensionSelection, _("view extensions...")),
1040 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1041 self.list.append((type, extension, key))
1043 def updateExtension(self, extension, key = None):
1044 self.extensionsList.append(extension)
1046 if self.extensionKeys.has_key(key):
1050 for x in self.availableKeys:
1051 if not self.extensionKeys.has_key(x):
1056 self.extensionKeys[key] = len(self.extensionsList) - 1
1058 def updateExtensions(self):
1059 self.extensionsList = []
1060 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1061 self.extensionKeys = {}
1063 if x[0] == self.EXTENSION_SINGLE:
1064 self.updateExtension(x[1], x[2])
1067 self.updateExtension(y[0], y[1])
1070 def showExtensionSelection(self):
1071 self.updateExtensions()
1072 extensionsList = self.extensionsList[:]
1075 for x in self.availableKeys:
1076 if self.extensionKeys.has_key(x):
1077 entry = self.extensionKeys[x]
1078 extension = self.extensionsList[entry]
1080 name = str(extension[0]())
1081 list.append((extension[0](), extension))
1083 extensionsList.remove(extension)
1085 extensionsList.remove(extension)
1086 for x in extensionsList:
1087 list.append((x[0](), x))
1088 keys += [""] * len(extensionsList)
1089 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1091 def extensionCallback(self, answer):
1092 if answer is not None:
1095 from Tools.BoundFunction import boundFunction
1097 # depends on InfoBarExtensions
1098 from Components.PluginComponent import plugins
1100 class InfoBarPlugins:
1102 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1105 def getPluginName(self, name):
1108 def getPluginList(self):
1110 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1111 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1114 def runPlugin(self, plugin):
1115 plugin(session = self.session)
1117 # depends on InfoBarExtensions and InfoBarSubtitleSupport
1118 class InfoBarSubtitles:
1120 self.addExtension((self.getDisableSubtitleName, self.disableSubtitles, self.subtitlesEnabled), "4")
1121 self.addExtension(extension = self.getSubtitleList, type = InfoBarExtensions.EXTENSION_LIST)
1123 def getDisableSubtitleName(self):
1124 return _("Disable subtitles")
1126 def getSubtitleList(self):
1128 s = self.getCurrentServiceSubtitle()
1129 l = s and s.getSubtitleList() or [ ]
1132 list.append(((boundFunction(self.getSubtitleEntryName, x[0]), boundFunction(self.enableSubtitle, x[1]), lambda: True), None))
1135 def getSubtitleEntryName(self, name):
1136 return "Enable Subtitles: " + name
1138 def enableSubtitle(self, subtitles):
1139 print "enable subitles", subtitles
1140 self.selected_subtitle = subtitles
1141 self.subtitles_enabled = True
1143 def subtitlesEnabled(self):
1144 return self.subtitles_enabled
1146 def disableSubtitles(self):
1147 self.subtitles_enabled = False
1149 # depends on InfoBarExtensions
1152 self.session.pipshown = False
1154 self.addExtension((self.getShowHideName, self.showPiP, self.available), "1")
1155 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "2")
1156 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "3")
1159 def available(self):
1163 return self.session.pipshown
1165 def getShowHideName(self):
1166 if self.session.pipshown:
1167 return _("Disable Picture in Picture")
1169 return _("Activate Picture in Picture")
1171 def getSwapName(self):
1172 return _("Swap Services")
1174 def getMoveName(self):
1175 return _("Move Picture in Picture")
1178 if self.session.pipshown:
1179 del self.session.pip
1180 self.session.pipshown = False
1182 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1183 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1184 if self.session.pip.playService(newservice):
1185 self.session.pipshown = True
1186 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1188 self.session.pipshown = False
1189 del self.session.pip
1190 self.session.nav.playService(newservice)
1193 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1194 if self.session.pip.servicePath:
1195 servicepath = self.servicelist.getCurrentServicePath()
1196 ref=servicepath[len(servicepath)-1]
1197 pipref=self.session.pip.getCurrentService()
1198 self.session.pip.playService(swapservice)
1199 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1200 if pipref.toString() != ref.toString(): # is a subservice ?
1201 self.session.nav.stopService() # stop portal
1202 self.session.nav.playService(pipref) # start subservice
1203 self.session.pip.servicePath=servicepath
1206 self.session.open(PiPSetup, pip = self.session.pip)
1208 from RecordTimer import parseEvent
1210 class InfoBarInstantRecord:
1211 """Instant Record - handles the instantRecord action in order to
1212 start/stop instant records"""
1214 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1216 "instantRecord": (self.instantRecord, _("Instant Record...")),
1219 self["BlinkingPoint"] = BlinkingPixmapConditional()
1220 self["BlinkingPoint"].hide()
1221 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1223 def stopCurrentRecording(self, entry = -1):
1224 if entry is not None and entry != -1:
1225 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1226 self.recording.remove(self.recording[entry])
1228 def startInstantRecording(self, limitEvent = False):
1229 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1231 # try to get event info
1234 service = self.session.nav.getCurrentService()
1235 epg = eEPGCache.getInstance()
1236 event = epg.lookupEventTime(serviceref, -1, 0)
1238 info = service.info()
1239 ev = info.getEvent(0)
1245 end = time.time() + 3600 * 10
1246 name = "instant record"
1250 if event is not None:
1251 curEvent = parseEvent(event)
1253 description = curEvent[3]
1254 eventid = curEvent[4]
1259 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1261 data = (begin, end, name, description, eventid)
1263 recording = self.session.nav.recordWithTimer(serviceref, *data)
1264 recording.dontSave = True
1265 self.recording.append(recording)
1267 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1269 def isInstantRecordRunning(self):
1270 print "self.recording:", self.recording
1271 if len(self.recording) > 0:
1272 for x in self.recording:
1277 def recordQuestionCallback(self, answer):
1278 print "pre:\n", self.recording
1280 if answer is None or answer[1] == "no":
1283 recording = self.recording[:]
1285 if not x in self.session.nav.RecordTimer.timer_list:
1286 self.recording.remove(x)
1287 elif x.dontSave and x.isRunning():
1288 list.append(TimerEntryComponent(x, False))
1290 if answer[1] == "changeduration":
1291 if len(self.recording) == 1:
1292 self.changeDuration(0)
1294 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1295 elif answer[1] == "stop":
1296 if len(self.recording) == 1:
1297 self.stopCurrentRecording(0)
1299 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1300 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1302 if answer[1] == "event":
1304 if answer[1] == "manualduration":
1305 self.selectedEntry = len(self.recording)
1306 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1307 self.startInstantRecording(limitEvent = limitEvent)
1309 print "after:\n", self.recording
1311 def changeDuration(self, entry):
1312 if entry is not None:
1313 self.selectedEntry = entry
1314 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1316 def inputCallback(self, value):
1317 if value is not None:
1318 print "stopping recording after", int(value), "minutes."
1319 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1320 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1322 def instantRecord(self):
1324 stat = os.stat(resolveFilename(SCOPE_HDD))
1326 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1329 if self.isInstantRecordRunning():
1330 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")])
1332 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")])
1334 from Tools.ISO639 import LanguageCodes
1336 class InfoBarAudioSelection:
1338 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1340 "audioSelection": (self.audioSelection, _("Audio Options...")),
1343 def audioSelection(self):
1344 service = self.session.nav.getCurrentService()
1345 audio = service and service.audioTracks()
1346 self.audioTracks = audio
1347 n = audio and audio.getNumberOfTracks() or 0
1348 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1350 print "tlist:", tlist
1352 self.audioChannel = service.audioChannel()
1355 i = audio.getTrackInfo(x)
1356 language = i.getLanguage()
1357 description = i.getDescription()
1359 if len(language) == 3:
1360 if language in LanguageCodes:
1361 language = LanguageCodes[language][0]
1363 if len(description):
1364 description += " (" + language + ")"
1366 description = language
1368 tlist.append((description, x))
1370 selectedAudio = tlist[0][1]
1371 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1375 if x[1] != selectedAudio:
1380 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1381 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1383 del self.audioTracks
1385 def audioSelected(self, audio):
1386 if audio is not None:
1387 if isinstance(audio[1], str):
1388 if audio[1] == "mode":
1389 keys = ["red", "green", "yellow"]
1390 selection = self.audioChannel.getCurrentChannel()
1391 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1392 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1394 del self.audioChannel
1395 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1396 self.audioTracks.selectTrack(audio[1])
1398 del self.audioChannel
1399 del self.audioTracks
1401 def modeSelected(self, mode):
1402 if mode is not None:
1403 self.audioChannel.selectChannel(mode[1])
1404 del self.audioChannel
1407 class InfoBarSubserviceSelection:
1409 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1411 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1414 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1416 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1417 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1419 self["SubserviceQuickzapAction"].setEnabled(False)
1421 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1423 def checkSubservicesAvail(self, ev):
1424 if ev == iPlayableService.evUpdatedEventInfo:
1425 service = self.session.nav.getCurrentService()
1426 subservices = service and service.subServices()
1427 if not subservices or subservices.getNumberOfSubservices() == 0:
1428 self["SubserviceQuickzapAction"].setEnabled(False)
1430 def nextSubservice(self):
1431 self.changeSubservice(+1)
1433 def prevSubservice(self):
1434 self.changeSubservice(-1)
1436 def changeSubservice(self, direction):
1437 service = self.session.nav.getCurrentService()
1438 subservices = service and service.subServices()
1439 n = subservices and subservices.getNumberOfSubservices()
1442 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1444 if subservices.getSubservice(x).toString() == ref.toString():
1447 selection += direction
1452 newservice = subservices.getSubservice(selection)
1453 if newservice.valid():
1457 self.session.nav.playService(newservice)
1459 def subserviceSelection(self):
1460 service = self.session.nav.getCurrentService()
1461 subservices = service and service.subServices()
1463 n = subservices and subservices.getNumberOfSubservices()
1466 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1469 i = subservices.getSubservice(x)
1470 if i.toString() == ref.toString():
1472 tlist.append((i.getName(), i))
1474 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1476 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1478 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1480 def subserviceSelected(self, service):
1481 if not service is None:
1482 if isinstance(service[1], str):
1483 if service[1] == "quickzap":
1484 from Screens.SubservicesQuickzap import SubservicesQuickzap
1485 self.session.open(SubservicesQuickzap, service[2])
1487 self["SubserviceQuickzapAction"].setEnabled(True)
1489 self.session.nav.playService(service[1])
1491 class InfoBarAdditionalInfo:
1493 self["NimA"] = Pixmap()
1494 self["NimB"] = Pixmap()
1495 self["NimA_Active"] = Pixmap()
1496 self["NimB_Active"] = Pixmap()
1498 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1499 self["TimeshiftPossible"] = self["RecordingPossible"]
1500 self["ExtensionsAvailable"] = Boolean(fixed=1)
1502 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1503 res_mgr = eDVBResourceManagerPtr()
1504 if eDVBResourceManager.getInstance(res_mgr) == 0:
1505 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1507 def tunerUseMaskChanged(self, mask):
1509 self["NimA_Active"].show()
1511 self["NimA_Active"].hide()
1513 self["NimB_Active"].show()
1515 self["NimB_Active"].hide()
1517 def checkTunerState(self, service):
1518 info = service.frontendInfo()
1519 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1520 if feNumber is None:
1530 def gotServiceEvent(self, ev):
1531 service = self.session.nav.getCurrentService()
1532 if ev == iPlayableService.evStart:
1533 self.checkTunerState(service)
1535 class InfoBarNotifications:
1537 self.onExecBegin.append(self.checkNotifications)
1538 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1539 self.onClose.append(self.__removeNotification)
1541 def __removeNotification(self):
1542 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1544 def checkNotificationsIfExecing(self):
1546 self.checkNotifications()
1548 def checkNotifications(self):
1549 if len(Notifications.notifications):
1550 n = Notifications.notifications[0]
1551 Notifications.notifications = Notifications.notifications[1:]
1554 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1556 self.session.open(n[1], *n[2], **n[3])
1558 class InfoBarServiceNotifications:
1560 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1562 iPlayableService.evEnd: self.serviceHasEnded
1565 def serviceHasEnded(self):
1566 print "service end!"
1569 self.setSeekState(self.SEEK_STATE_PLAY)
1573 class InfoBarCueSheetSupport:
1579 ENABLE_RESUME_SUPPORT = False
1582 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1584 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1585 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1586 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1590 self.is_closing = False
1591 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1593 iPlayableService.evStart: self.__serviceStarted,
1596 def __serviceStarted(self):
1599 print "new service started! trying to download cuts!"
1600 self.downloadCuesheet()
1602 if self.ENABLE_RESUME_SUPPORT:
1605 for (pts, what) in self.cut_list:
1606 if what == self.CUT_TYPE_LAST:
1609 if last is not None:
1610 self.resume_point = last
1611 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1613 def playLastCB(self, answer):
1615 seekable = self.__getSeekable()
1616 if seekable is not None:
1617 seekable.seekTo(self.resume_point)
1619 def __getSeekable(self):
1620 service = self.session.nav.getCurrentService()
1623 return service.seek()
1625 def cueGetCurrentPosition(self):
1626 seek = self.__getSeekable()
1629 r = seek.getPlayPosition()
1634 def jumpPreviousNextMark(self, cmp, alternative=None):
1635 current_pos = self.cueGetCurrentPosition()
1636 if current_pos is None:
1638 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1639 if mark is not None:
1641 elif alternative is not None:
1646 seekable = self.__getSeekable()
1647 if seekable is not None:
1648 seekable.seekTo(pts)
1650 def jumpPreviousMark(self):
1651 # we add 2 seconds, so if the play position is <2s after
1652 # the mark, the mark before will be used
1653 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1655 def jumpNextMark(self):
1656 self.jumpPreviousNextMark(lambda x: x)
1658 def getNearestCutPoint(self, pts, cmp=abs):
1661 for cp in self.cut_list:
1662 diff = cmp(cp[0] - pts)
1663 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1667 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1668 current_pos = self.cueGetCurrentPosition()
1669 if current_pos is None:
1670 print "not seekable"
1673 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1675 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1677 return nearest_cutpoint
1679 self.removeMark(nearest_cutpoint)
1680 elif not onlyremove and not onlyreturn:
1681 self.addMark((current_pos, self.CUT_TYPE_MARK))
1686 def addMark(self, point):
1687 bisect.insort(self.cut_list, point)
1688 self.uploadCuesheet()
1690 def removeMark(self, point):
1691 self.cut_list.remove(point)
1692 self.uploadCuesheet()
1694 def __getCuesheet(self):
1695 service = self.session.nav.getCurrentService()
1698 return service.cueSheet()
1700 def uploadCuesheet(self):
1701 cue = self.__getCuesheet()
1704 print "upload failed, no cuesheet interface"
1706 cue.setCutList(self.cut_list)
1708 def downloadCuesheet(self):
1709 cue = self.__getCuesheet()
1712 print "upload failed, no cuesheet interface"
1714 self.cut_list = cue.getCutList()
1716 class InfoBarSummary(Screen):
1718 <screen position="0,0" size="132,64">
1719 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1720 <convert type="ClockToText">WithSeconds</convert>
1722 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1723 <convert type="ServiceName">Name</convert>
1727 def __init__(self, session, parent):
1728 Screen.__init__(self, session)
1729 self["CurrentService"] = CurrentService(self.session.nav)
1730 self["CurrentTime"] = Clock()
1732 class InfoBarSummarySupport:
1736 def createSummary(self):
1737 return InfoBarSummary
1739 class InfoBarTeletextPlugin:
1741 self.teletext_plugin = None
1743 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1744 self.teletext_plugin = p
1746 if self.teletext_plugin is not None:
1747 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1749 "startTeletext": (self.startTeletext, _("View teletext..."))
1752 print "no teletext plugin found!"
1754 def startTeletext(self):
1755 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1757 class InfoBarSubtitleSupport(object):
1759 object.__init__(self)
1760 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1761 self.__subtitles_enabled = False
1763 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1765 iPlayableService.evStart: self.__serviceStarted,
1768 def __serviceStarted(self):
1769 # reenable if it was enabled
1770 r = self.__subtitles_enabled
1771 self.__subtitles_enabled = False
1772 self.__selected_subtitle = None
1773 self.setSubtitlesEnable(r)
1775 def getCurrentServiceSubtitle(self):
1776 service = self.session.nav.getCurrentService()
1777 return service and service.subtitle()
1779 def setSubtitlesEnable(self, enable=True):
1780 subtitle = self.getCurrentServiceSubtitle()
1781 if enable and self.__selected_subtitle:
1782 if subtitle and not self.__subtitles_enabled:
1783 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1784 self.subtitle_window.show()
1785 self.__subtitles_enabled = True
1788 subtitle.disableSubtitles(self.subtitle_window.instance)
1790 self.subtitle_window.hide()
1791 self.__subtitles_enabled = False
1793 def setSelectedSubtitle(self, subtitle):
1794 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1796 self.__selected_subtitle = subtitle
1797 self.__serviceStarted()
1799 self.__selected_subtitle = subtitle
1801 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1802 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)