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 if config.misc.initialchannelselection.value:
250 self.onShown.append(self.firstRun)
252 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
254 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
255 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
256 "zapUp": (self.zapUp, _("previous channel")),
257 "zapDown": (self.zapDown, _("next channel")),
258 "historyBack": (self.historyBack, _("previous channel in history")),
259 "historyNext": (self.historyNext, _("next channel in history")),
260 "openServiceList": (self.openServiceList, _("open servicelist")),
263 def showTvChannelList(self, zap=False):
264 self.servicelist.setModeTv()
266 self.servicelist.zap()
267 self.session.execDialog(self.servicelist)
269 def showRadioChannelList(self, zap=False):
270 self.servicelist.setModeRadio()
272 self.servicelist.zap()
273 self.session.execDialog(self.servicelist)
276 self.onShown.remove(self.firstRun)
277 config.misc.initialchannelselection.value = False
278 config.misc.initialchannelselection.save()
279 self.switchChannelDown()
281 def historyBack(self):
282 self.servicelist.historyBack()
284 def historyNext(self):
285 self.servicelist.historyNext()
287 def switchChannelUp(self):
288 self.servicelist.moveUp()
289 self.session.execDialog(self.servicelist)
291 def switchChannelDown(self):
292 self.servicelist.moveDown()
293 self.session.execDialog(self.servicelist)
295 def openServiceList(self):
296 self.session.execDialog(self.servicelist)
299 if self.servicelist.inBouquet():
300 prev = self.servicelist.getCurrentSelection()
302 prev = prev.toString()
304 if config.usage.quickzap_bouquet_change.value:
305 if self.servicelist.atBegin():
306 self.servicelist.prevBouquet()
307 self.servicelist.moveUp()
308 cur = self.servicelist.getCurrentSelection()
309 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
312 self.servicelist.moveUp()
313 self.servicelist.zap()
317 if self.servicelist.inBouquet():
318 prev = self.servicelist.getCurrentSelection()
320 prev = prev.toString()
322 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
323 self.servicelist.nextBouquet()
325 self.servicelist.moveDown()
326 cur = self.servicelist.getCurrentSelection()
327 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
330 self.servicelist.moveDown()
331 self.servicelist.zap()
335 """ Handles a menu action, to open the (main) menu """
337 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
339 "mainMenu": (self.mainMenu, _("Enter main menu...")),
343 print "loading mainmenu XML..."
344 menu = mdom.childNodes[0]
345 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
346 self.session.open(MainMenu, menu, menu.childNodes)
348 class InfoBarSimpleEventView:
349 """ Opens the Eventview for now/next """
351 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
353 "showEventInfo": (self.openEventView, _("show event details")),
356 def openEventView(self):
358 service = self.session.nav.getCurrentService()
359 ref = self.session.nav.getCurrentlyPlayingServiceReference()
360 info = service.info()
363 self.epglist.append(ptr)
366 self.epglist.append(ptr)
367 if len(self.epglist) > 0:
368 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
370 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
371 if len(self.epglist) > 1:
372 tmp = self.epglist[0]
373 self.epglist[0]=self.epglist[1]
375 setEvent(self.epglist[0])
378 """ EPG - Opens an EPG list when the showEPGList action fires """
380 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
382 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
385 self.is_now_next = False
387 self.bouquetSel = None
388 self.eventView = None
389 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
391 "showEventInfo": (self.openEventView, _("show EPG...")),
394 def zapToService(self, service):
395 if not service is None:
396 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
397 self.servicelist.clearPath()
398 if self.servicelist.bouquet_root != self.epg_bouquet:
399 self.servicelist.enterPath(self.servicelist.bouquet_root)
400 self.servicelist.enterPath(self.epg_bouquet)
401 self.servicelist.setCurrentSelection(service) #select the service in servicelist
402 self.servicelist.zap()
404 def getBouquetServices(self, bouquet):
406 servicelist = eServiceCenter.getInstance().list(bouquet)
407 if not servicelist is None:
409 service = servicelist.getNext()
410 if not service.valid(): #check if end of list
412 if service.flags: #ignore non playable services
414 services.append(ServiceReference(service))
417 def openBouquetEPG(self, bouquet, withCallback=True):
418 services = self.getBouquetServices(bouquet)
420 self.epg_bouquet = bouquet
422 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
424 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
426 def changeBouquetCB(self, direction, epg):
429 self.bouquetSel.down()
432 bouquet = self.bouquetSel.getCurrent()
433 services = self.getBouquetServices(bouquet)
435 self.epg_bouquet = bouquet
436 epg.setServices(services)
438 def closed(self, ret=False):
439 closedScreen = self.dlg_stack.pop()
440 if self.bouquetSel and closedScreen == self.bouquetSel:
441 self.bouquetSel = None
442 elif self.eventView and closedScreen == self.eventView:
443 self.eventView = None
445 dlgs=len(self.dlg_stack)
447 self.dlg_stack[dlgs-1].close(dlgs > 1)
449 def openMultiServiceEPG(self, withCallback=True):
450 bouquets = self.servicelist.getBouquetList()
455 if cnt > 1: # show bouquet list
457 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
458 self.dlg_stack.append(self.bouquetSel)
460 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
462 self.openBouquetEPG(bouquets[0][1], withCallback)
464 def openSingleServiceEPG(self):
465 ref=self.session.nav.getCurrentlyPlayingServiceReference()
466 self.session.open(EPGSelection, ref)
468 def openSimilarList(self, eventid, refstr):
469 self.session.open(EPGSelection, refstr, None, eventid)
471 def getNowNext(self):
473 service = self.session.nav.getCurrentService()
474 info = service and service.info()
475 ptr = info and info.getEvent(0)
477 self.epglist.append(ptr)
478 ptr = info and info.getEvent(1)
480 self.epglist.append(ptr)
482 def __evEventInfoChanged(self):
483 if self.is_now_next and len(self.dlg_stack) == 1:
485 assert self.eventView
486 if len(self.epglist):
487 self.eventView.setEvent(self.epglist[0])
489 def openEventView(self):
490 ref = self.session.nav.getCurrentlyPlayingServiceReference()
492 if len(self.epglist) == 0:
493 self.is_now_next = False
494 epg = eEPGCache.getInstance()
495 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
497 self.epglist.append(ptr)
498 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
500 self.epglist.append(ptr)
502 self.is_now_next = True
503 if len(self.epglist) > 0:
504 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
505 self.dlg_stack.append(self.eventView)
507 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
508 self.openMultiServiceEPG(False)
510 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
511 if len(self.epglist) > 1:
512 tmp = self.epglist[0]
513 self.epglist[0]=self.epglist[1]
515 setEvent(self.epglist[0])
518 """provides a snr/agc/ber display"""
520 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
523 """provides a current/next event info display"""
525 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
526 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
528 class InfoBarServiceName:
530 self["CurrentService"] = CurrentService(self.session.nav)
533 """handles actions like seeking, pause"""
535 # ispause, isff, issm
536 SEEK_STATE_PLAY = (0, 0, 0, ">")
537 SEEK_STATE_PAUSE = (1, 0, 0, "||")
538 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
539 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
540 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
541 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
542 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
543 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
545 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
546 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
547 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
548 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
550 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
551 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
552 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
555 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
557 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
558 iPlayableService.evStart: self.__serviceStarted,
560 iPlayableService.evEOF: self.__evEOF,
561 iPlayableService.evSOF: self.__evSOF,
564 class InfoBarSeekActionMap(HelpableActionMap):
565 def __init__(self, screen, *args, **kwargs):
566 HelpableActionMap.__init__(self, screen, *args, **kwargs)
569 def action(self, contexts, action):
570 if action[:5] == "seek:":
571 time = int(action[5:])
572 self.screen.seekRelative(time * 90000)
575 return HelpableActionMap.action(self, contexts, action)
577 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
579 "pauseService": (self.pauseService, _("pause")),
580 "unPauseService": (self.unPauseService, _("continue")),
582 "seekFwd": (self.seekFwd, _("skip forward")),
583 "seekFwdDown": self.seekFwdDown,
584 "seekFwdUp": self.seekFwdUp,
585 "seekBack": (self.seekBack, _("skip backward")),
586 "seekBackDown": self.seekBackDown,
587 "seekBackUp": self.seekBackUp,
589 # give them a little more priority to win over color buttons
591 self.seekstate = self.SEEK_STATE_PLAY
592 self.onClose.append(self.delTimer)
594 self.fwdtimer = False
595 self.fwdKeyTimer = eTimer()
596 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
598 self.rwdtimer = False
599 self.rwdKeyTimer = eTimer()
600 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
602 self.onPlayStateChanged = [ ]
604 self.lockedBecauseOfSkipping = False
617 service = self.session.nav.getCurrentService()
621 seek = service.seek()
623 if seek is None or not seek.isCurrentlySeekable():
628 def isSeekable(self):
629 if self.getSeek() is None:
633 def __seekableStatusChanged(self):
634 print "seekable status changed!"
635 if not self.isSeekable():
636 self["SeekActions"].setEnabled(False)
637 print "not seekable, return to play"
638 self.setSeekState(self.SEEK_STATE_PLAY)
640 self["SeekActions"].setEnabled(True)
643 def __serviceStarted(self):
644 self.seekstate = self.SEEK_STATE_PLAY
646 def setSeekState(self, state):
647 service = self.session.nav.getCurrentService()
652 if not self.isSeekable():
653 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
654 state = self.SEEK_STATE_PLAY
656 pauseable = service.pause()
658 if pauseable is None:
659 print "not pauseable."
660 state = self.SEEK_STATE_PLAY
662 oldstate = self.seekstate
663 self.seekstate = state
666 if oldstate[i] != self.seekstate[i]:
667 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
669 for c in self.onPlayStateChanged:
672 self.checkSkipShowHideLock()
676 def pauseService(self):
677 if self.seekstate == self.SEEK_STATE_PAUSE:
678 print "pause, but in fact unpause"
679 self.unPauseService()
681 if self.seekstate == self.SEEK_STATE_PLAY:
682 print "yes, playing."
684 print "no", self.seekstate
686 self.setSeekState(self.SEEK_STATE_PAUSE);
688 def unPauseService(self):
690 if self.seekstate == self.SEEK_STATE_PLAY:
692 self.setSeekState(self.SEEK_STATE_PLAY)
694 def doSeek(self, seektime):
695 print "doseek", seektime
696 service = self.session.nav.getCurrentService()
700 seekable = self.getSeek()
704 seekable.seekTo(90 * seektime)
706 def seekFwdDown(self):
707 print "start fwd timer"
709 self.fwdKeyTimer.start(1000)
711 def seekBackDown(self):
712 print "start rewind timer"
714 self.rwdKeyTimer.start(1000)
719 self.fwdKeyTimer.stop()
720 self.fwdtimer = False
725 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
726 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
727 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
728 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
729 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
730 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
731 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
732 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
733 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
734 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
735 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
736 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
737 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
738 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
739 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
741 self.setSeekState(lookup[self.seekstate])
743 def seekBackUp(self):
746 self.rwdKeyTimer.stop()
747 self.rwdtimer = False
752 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
753 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
754 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
755 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
756 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
757 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
758 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
759 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
760 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
761 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
762 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
763 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
764 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
765 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
766 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
768 self.setSeekState(lookup[self.seekstate])
770 if self.seekstate == self.SEEK_STATE_PAUSE:
771 seekable = self.getSeek()
772 if seekable is not None:
773 seekable.seekRelative(-1, 3)
775 def fwdTimerFire(self):
776 print "Display seek fwd"
777 self.fwdKeyTimer.stop()
778 self.fwdtimer = False
779 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
781 def fwdSeekTo(self, minutes):
782 print "Seek", minutes, "minutes forward"
784 seekable = self.getSeek()
785 if seekable is not None:
786 seekable.seekRelative(1, minutes * 60 * 90000)
788 def rwdTimerFire(self):
790 self.rwdKeyTimer.stop()
791 self.rwdtimer = False
792 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
794 def rwdSeekTo(self, minutes):
796 self.fwdSeekTo(0 - minutes)
798 def checkSkipShowHideLock(self):
799 wantlock = self.seekstate != self.SEEK_STATE_PLAY
801 if self.lockedBecauseOfSkipping and not wantlock:
803 self.lockedBecauseOfSkipping = False
805 if wantlock and not self.lockedBecauseOfSkipping:
807 self.lockedBecauseOfSkipping = True
810 if self.seekstate != self.SEEK_STATE_PLAY:
811 self.setSeekState(self.SEEK_STATE_PAUSE)
813 #self.getSeek().seekRelative(1, -90000)
814 self.setSeekState(self.SEEK_STATE_PLAY)
816 self.setSeekState(self.SEEK_STATE_PAUSE)
819 self.setSeekState(self.SEEK_STATE_PLAY)
822 def seekRelative(self, diff):
823 seekable = self.getSeek()
824 if seekable is not None:
825 seekable.seekRelative(1, diff)
827 def seekAbsolute(self, abs):
828 seekable = self.getSeek()
829 if seekable is not None:
832 from Screens.PVRState import PVRState, TimeshiftState
834 class InfoBarPVRState:
835 def __init__(self, screen=PVRState):
836 self.onPlayStateChanged.append(self.__playStateChanged)
837 self.pvrStateDialog = self.session.instantiateDialog(screen)
838 self.onShow.append(self.__mayShow)
839 self.onHide.append(self.pvrStateDialog.hide)
842 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
843 self.pvrStateDialog.show()
845 def __playStateChanged(self, state):
846 playstateString = state[3]
847 self.pvrStateDialog["state"].setText(playstateString)
850 class InfoBarTimeshiftState(InfoBarPVRState):
852 InfoBarPVRState.__init__(self, screen=TimeshiftState)
854 class InfoBarShowMovies:
856 # i don't really like this class.
857 # it calls a not further specified "movie list" on up/down/movieList,
858 # so this is not more than an action map
860 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
862 "movieList": (self.showMovies, "movie list"),
863 "up": (self.showMovies, "movie list"),
864 "down": (self.showMovies, "movie list")
867 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
871 # Timeshift works the following way:
872 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
873 # - normal playback TUNER unused PLAY enable disable disable
874 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
875 # - user presess pause again FILE record PLAY enable disable enable
876 # - user fast forwards FILE record FF enable disable enable
877 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
878 # - user backwards FILE record BACK # !! enable disable enable
882 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
883 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
884 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
885 # - the user can now PVR around
886 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
887 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
889 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
890 # - if the user rewinds, or press pause, timeshift will be activated again
892 # note that a timeshift can be enabled ("recording") and
893 # activated (currently time-shifting).
895 class InfoBarTimeshift:
897 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
899 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
900 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
902 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
904 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
905 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
906 }, prio=-1) # priority over record
908 self.timeshift_enabled = 0
909 self.timeshift_state = 0
910 self.ts_pause_timer = eTimer()
911 self.ts_pause_timer.timeout.get().append(self.pauseService)
913 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
915 iPlayableService.evStart: self.__serviceStarted,
916 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
919 def getTimeshift(self):
920 service = self.session.nav.getCurrentService()
921 return service and service.timeshift()
923 def startTimeshift(self):
924 print "enable timeshift"
925 ts = self.getTimeshift()
927 # self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
928 # print "no ts interface"
931 if self.timeshift_enabled:
932 print "hu, timeshift already enabled?"
934 if not ts.startTimeshift():
936 self.timeshift_enabled = 1
938 # we remove the "relative time" for now.
939 #self.pvrStateDialog["timeshift"].setRelative(time.time())
942 self.setSeekState(self.SEEK_STATE_PAUSE)
944 # enable the "TimeshiftEnableActions", which will override
945 # the startTimeshift actions
946 self.__seekableStatusChanged()
948 print "timeshift failed"
950 def stopTimeshift(self):
951 if not self.timeshift_enabled:
953 print "disable timeshift"
954 ts = self.getTimeshift()
957 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
959 def stopTimeshiftConfirmed(self, confirmed):
963 ts = self.getTimeshift()
968 self.timeshift_enabled = 0
971 self.__seekableStatusChanged()
973 # activates timeshift, and seeks to (almost) the end
974 def activateTimeshiftEnd(self):
975 ts = self.getTimeshift()
980 if ts.isTimeshiftActive():
981 print "!! activate timeshift called - but shouldn't this be a normal pause?"
984 self.setSeekState(self.SEEK_STATE_PLAY)
985 ts.activateTimeshift()
988 # same as activateTimeshiftEnd, but pauses afterwards.
989 def activateTimeshiftEndAndPause(self):
990 state = self.seekstate
991 self.activateTimeshiftEnd()
993 # well, this is "andPause", but it could be pressed from pause,
994 # when pausing on the (fake-)"live" picture, so an un-pause
997 print "now, pauseService"
998 if state == self.SEEK_STATE_PLAY:
999 print "is PLAYING, start pause timer"
1000 self.ts_pause_timer.start(200, 1)
1003 self.unPauseService()
1005 def __seekableStatusChanged(self):
1008 print "self.isSeekable", self.isSeekable()
1009 print "self.timeshift_enabled", self.timeshift_enabled
1011 # when this service is not seekable, but timeshift
1012 # is enabled, this means we can activate
1014 if not self.isSeekable() and self.timeshift_enabled:
1017 print "timeshift activate:", enabled
1018 self["TimeshiftActivateActions"].setEnabled(enabled)
1020 def __serviceStarted(self):
1021 self.timeshift_enabled = False
1022 self.__seekableStatusChanged()
1024 from Screens.PiPSetup import PiPSetup
1026 class InfoBarExtensions:
1027 EXTENSION_SINGLE = 0
1033 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1035 "extensions": (self.showExtensionSelection, _("view extensions...")),
1038 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1039 self.list.append((type, extension, key))
1041 def updateExtension(self, extension, key = None):
1042 self.extensionsList.append(extension)
1044 if self.extensionKeys.has_key(key):
1048 for x in self.availableKeys:
1049 if not self.extensionKeys.has_key(x):
1054 self.extensionKeys[key] = len(self.extensionsList) - 1
1056 def updateExtensions(self):
1057 self.extensionsList = []
1058 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1059 self.extensionKeys = {}
1061 if x[0] == self.EXTENSION_SINGLE:
1062 self.updateExtension(x[1], x[2])
1065 self.updateExtension(y[0], y[1])
1068 def showExtensionSelection(self):
1069 self.updateExtensions()
1070 extensionsList = self.extensionsList[:]
1073 for x in self.availableKeys:
1074 if self.extensionKeys.has_key(x):
1075 entry = self.extensionKeys[x]
1076 extension = self.extensionsList[entry]
1078 name = str(extension[0]())
1079 list.append((extension[0](), extension))
1081 extensionsList.remove(extension)
1083 extensionsList.remove(extension)
1084 for x in extensionsList:
1085 list.append((x[0](), x))
1086 keys += [""] * len(extensionsList)
1087 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1089 def extensionCallback(self, answer):
1090 if answer is not None:
1093 from Tools.BoundFunction import boundFunction
1095 # depends on InfoBarExtensions
1096 from Components.PluginComponent import plugins
1098 class InfoBarPlugins:
1100 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1103 def getPluginName(self, name):
1106 def getPluginList(self):
1108 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1109 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1112 def runPlugin(self, plugin):
1113 plugin(session = self.session)
1115 # depends on InfoBarExtensions and InfoBarSubtitleSupport
1116 class InfoBarSubtitles:
1118 self.addExtension((self.getDisableSubtitleName, self.disableSubtitles, self.subtitlesEnabled), "4")
1119 self.addExtension(extension = self.getSubtitleList, type = InfoBarExtensions.EXTENSION_LIST)
1121 def getDisableSubtitleName(self):
1122 return _("Disable subtitles")
1124 def getSubtitleList(self):
1126 s = self.getCurrentServiceSubtitle()
1127 l = s and s.getSubtitleList() or [ ]
1130 list.append(((boundFunction(self.getSubtitleEntryName, x[0]), boundFunction(self.enableSubtitle, x[1]), lambda: True), None))
1133 def getSubtitleEntryName(self, name):
1134 return "Enable Subtitles: " + name
1136 def enableSubtitle(self, subtitles):
1137 print "enable subitles", subtitles
1138 self.selected_subtitle = subtitles
1139 self.subtitles_enabled = True
1141 def subtitlesEnabled(self):
1142 return self.subtitles_enabled
1144 def disableSubtitles(self):
1145 self.subtitles_enabled = False
1147 # depends on InfoBarExtensions
1150 self.session.pipshown = False
1152 self.addExtension((self.getShowHideName, self.showPiP, self.available), "1")
1153 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "2")
1154 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "3")
1157 def available(self):
1161 return self.session.pipshown
1163 def getShowHideName(self):
1164 if self.session.pipshown:
1165 return _("Disable Picture in Picture")
1167 return _("Activate Picture in Picture")
1169 def getSwapName(self):
1170 return _("Swap Services")
1172 def getMoveName(self):
1173 return _("Move Picture in Picture")
1176 if self.session.pipshown:
1177 del self.session.pip
1178 self.session.pipshown = False
1180 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1181 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1182 if self.session.pip.playService(newservice):
1183 self.session.pipshown = True
1184 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1186 self.session.pipshown = False
1187 del self.session.pip
1188 self.session.nav.playService(newservice)
1191 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1192 if self.session.pip.servicePath:
1193 servicepath = self.servicelist.getCurrentServicePath()
1194 ref=servicepath[len(servicepath)-1]
1195 pipref=self.session.pip.getCurrentService()
1196 self.session.pip.playService(swapservice)
1197 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1198 if pipref.toString() != ref.toString(): # is a subservice ?
1199 self.session.nav.stopService() # stop portal
1200 self.session.nav.playService(pipref) # start subservice
1201 self.session.pip.servicePath=servicepath
1204 self.session.open(PiPSetup, pip = self.session.pip)
1206 from RecordTimer import parseEvent
1208 class InfoBarInstantRecord:
1209 """Instant Record - handles the instantRecord action in order to
1210 start/stop instant records"""
1212 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1214 "instantRecord": (self.instantRecord, _("Instant Record...")),
1217 self["BlinkingPoint"] = BlinkingPixmapConditional()
1218 self["BlinkingPoint"].hide()
1219 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1221 def stopCurrentRecording(self, entry = -1):
1222 if entry is not None and entry != -1:
1223 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1224 self.recording.remove(self.recording[entry])
1226 def startInstantRecording(self, limitEvent = False):
1227 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1229 # try to get event info
1232 service = self.session.nav.getCurrentService()
1233 epg = eEPGCache.getInstance()
1234 event = epg.lookupEventTime(serviceref, -1, 0)
1236 info = service.info()
1237 ev = info.getEvent(0)
1243 end = time.time() + 3600 * 10
1244 name = "instant record"
1248 if event is not None:
1249 curEvent = parseEvent(event)
1251 description = curEvent[3]
1252 eventid = curEvent[4]
1257 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1259 data = (begin, end, name, description, eventid)
1261 recording = self.session.nav.recordWithTimer(serviceref, *data)
1262 recording.dontSave = True
1263 self.recording.append(recording)
1265 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1267 def isInstantRecordRunning(self):
1268 print "self.recording:", self.recording
1269 if len(self.recording) > 0:
1270 for x in self.recording:
1275 def recordQuestionCallback(self, answer):
1276 print "pre:\n", self.recording
1278 if answer is None or answer[1] == "no":
1281 recording = self.recording[:]
1283 if not x in self.session.nav.RecordTimer.timer_list:
1284 self.recording.remove(x)
1285 elif x.dontSave and x.isRunning():
1286 list.append(TimerEntryComponent(x, False))
1288 if answer[1] == "changeduration":
1289 if len(self.recording) == 1:
1290 self.changeDuration(0)
1292 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1293 elif answer[1] == "stop":
1294 if len(self.recording) == 1:
1295 self.stopCurrentRecording(0)
1297 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1298 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1300 if answer[1] == "event":
1302 if answer[1] == "manualduration":
1303 self.selectedEntry = len(self.recording)
1304 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1305 self.startInstantRecording(limitEvent = limitEvent)
1307 print "after:\n", self.recording
1309 def changeDuration(self, entry):
1310 if entry is not None:
1311 self.selectedEntry = entry
1312 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1314 def inputCallback(self, value):
1315 if value is not None:
1316 print "stopping recording after", int(value), "minutes."
1317 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1318 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1320 def instantRecord(self):
1322 stat = os.stat(resolveFilename(SCOPE_HDD))
1324 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1327 if self.isInstantRecordRunning():
1328 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")])
1330 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")])
1332 from Tools.ISO639 import LanguageCodes
1334 class InfoBarAudioSelection:
1336 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1338 "audioSelection": (self.audioSelection, _("Audio Options...")),
1341 def audioSelection(self):
1342 service = self.session.nav.getCurrentService()
1343 audio = service and service.audioTracks()
1344 self.audioTracks = audio
1345 n = audio and audio.getNumberOfTracks() or 0
1346 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1348 print "tlist:", tlist
1350 self.audioChannel = service.audioChannel()
1353 i = audio.getTrackInfo(x)
1354 language = i.getLanguage()
1355 description = i.getDescription()
1357 if len(language) == 3:
1358 if language in LanguageCodes:
1359 language = LanguageCodes[language][0]
1361 if len(description):
1362 description += " (" + language + ")"
1364 description = language
1366 tlist.append((description, x))
1368 selectedAudio = tlist[0][1]
1369 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1373 if x[1] != selectedAudio:
1378 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1379 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1381 del self.audioTracks
1383 def audioSelected(self, audio):
1384 if audio is not None:
1385 if isinstance(audio[1], str):
1386 if audio[1] == "mode":
1387 keys = ["red", "green", "yellow"]
1388 selection = self.audioChannel.getCurrentChannel()
1389 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1390 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1392 del self.audioChannel
1393 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1394 self.audioTracks.selectTrack(audio[1])
1396 del self.audioChannel
1397 del self.audioTracks
1399 def modeSelected(self, mode):
1400 if mode is not None:
1401 self.audioChannel.selectChannel(mode[1])
1402 del self.audioChannel
1405 class InfoBarSubserviceSelection:
1407 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1409 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1412 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1414 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1415 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1417 self["SubserviceQuickzapAction"].setEnabled(False)
1419 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1421 def checkSubservicesAvail(self, ev):
1422 if ev == iPlayableService.evUpdatedEventInfo:
1423 service = self.session.nav.getCurrentService()
1424 subservices = service and service.subServices()
1425 if not subservices or subservices.getNumberOfSubservices() == 0:
1426 self["SubserviceQuickzapAction"].setEnabled(False)
1428 def nextSubservice(self):
1429 self.changeSubservice(+1)
1431 def prevSubservice(self):
1432 self.changeSubservice(-1)
1434 def changeSubservice(self, direction):
1435 service = self.session.nav.getCurrentService()
1436 subservices = service and service.subServices()
1437 n = subservices and subservices.getNumberOfSubservices()
1440 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1442 if subservices.getSubservice(x).toString() == ref.toString():
1445 selection += direction
1450 newservice = subservices.getSubservice(selection)
1451 if newservice.valid():
1455 self.session.nav.playService(newservice)
1457 def subserviceSelection(self):
1458 service = self.session.nav.getCurrentService()
1459 subservices = service and service.subServices()
1461 n = subservices and subservices.getNumberOfSubservices()
1464 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1467 i = subservices.getSubservice(x)
1468 if i.toString() == ref.toString():
1470 tlist.append((i.getName(), i))
1472 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1474 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1476 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1478 def subserviceSelected(self, service):
1479 if not service is None:
1480 if isinstance(service[1], str):
1481 if service[1] == "quickzap":
1482 from Screens.SubservicesQuickzap import SubservicesQuickzap
1483 self.session.open(SubservicesQuickzap, service[2])
1485 self["SubserviceQuickzapAction"].setEnabled(True)
1487 self.session.nav.playService(service[1])
1489 class InfoBarAdditionalInfo:
1491 self["NimA"] = Pixmap()
1492 self["NimB"] = Pixmap()
1493 self["NimA_Active"] = Pixmap()
1494 self["NimB_Active"] = Pixmap()
1496 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1497 self["TimeshiftPossible"] = self["RecordingPossible"]
1498 self["ExtensionsAvailable"] = Boolean(fixed=1)
1500 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1501 res_mgr = eDVBResourceManagerPtr()
1502 if eDVBResourceManager.getInstance(res_mgr) == 0:
1503 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1505 def tunerUseMaskChanged(self, mask):
1507 self["NimA_Active"].show()
1509 self["NimA_Active"].hide()
1511 self["NimB_Active"].show()
1513 self["NimB_Active"].hide()
1515 def checkTunerState(self, service):
1516 info = service.frontendInfo()
1517 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1518 if feNumber is None:
1528 def gotServiceEvent(self, ev):
1529 service = self.session.nav.getCurrentService()
1530 if ev == iPlayableService.evStart:
1531 self.checkTunerState(service)
1533 class InfoBarNotifications:
1535 self.onExecBegin.append(self.checkNotifications)
1536 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1537 self.onClose.append(self.__removeNotification)
1539 def __removeNotification(self):
1540 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1542 def checkNotificationsIfExecing(self):
1544 self.checkNotifications()
1546 def checkNotifications(self):
1547 if len(Notifications.notifications):
1548 n = Notifications.notifications[0]
1549 Notifications.notifications = Notifications.notifications[1:]
1552 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1554 self.session.open(n[1], *n[2], **n[3])
1556 class InfoBarServiceNotifications:
1558 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1560 iPlayableService.evEnd: self.serviceHasEnded
1563 def serviceHasEnded(self):
1564 print "service end!"
1567 self.setSeekState(self.SEEK_STATE_PLAY)
1571 class InfoBarCueSheetSupport:
1577 ENABLE_RESUME_SUPPORT = False
1580 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1582 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1583 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1584 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1588 self.is_closing = False
1589 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1591 iPlayableService.evStart: self.__serviceStarted,
1594 def __serviceStarted(self):
1597 print "new service started! trying to download cuts!"
1598 self.downloadCuesheet()
1600 if self.ENABLE_RESUME_SUPPORT:
1603 for (pts, what) in self.cut_list:
1604 if what == self.CUT_TYPE_LAST:
1607 if last is not None:
1608 self.resume_point = last
1609 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1611 def playLastCB(self, answer):
1613 seekable = self.__getSeekable()
1614 if seekable is not None:
1615 seekable.seekTo(self.resume_point)
1617 def __getSeekable(self):
1618 service = self.session.nav.getCurrentService()
1621 return service.seek()
1623 def cueGetCurrentPosition(self):
1624 seek = self.__getSeekable()
1627 r = seek.getPlayPosition()
1632 def jumpPreviousNextMark(self, cmp, alternative=None):
1633 current_pos = self.cueGetCurrentPosition()
1634 if current_pos is None:
1636 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1637 if mark is not None:
1639 elif alternative is not None:
1644 seekable = self.__getSeekable()
1645 if seekable is not None:
1646 seekable.seekTo(pts)
1648 def jumpPreviousMark(self):
1649 # we add 2 seconds, so if the play position is <2s after
1650 # the mark, the mark before will be used
1651 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1653 def jumpNextMark(self):
1654 self.jumpPreviousNextMark(lambda x: x)
1656 def getNearestCutPoint(self, pts, cmp=abs):
1659 for cp in self.cut_list:
1660 diff = cmp(cp[0] - pts)
1661 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1665 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1666 current_pos = self.cueGetCurrentPosition()
1667 if current_pos is None:
1668 print "not seekable"
1671 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1673 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1675 return nearest_cutpoint
1677 self.removeMark(nearest_cutpoint)
1678 elif not onlyremove and not onlyreturn:
1679 self.addMark((current_pos, self.CUT_TYPE_MARK))
1684 def addMark(self, point):
1685 bisect.insort(self.cut_list, point)
1686 self.uploadCuesheet()
1688 def removeMark(self, point):
1689 self.cut_list.remove(point)
1690 self.uploadCuesheet()
1692 def __getCuesheet(self):
1693 service = self.session.nav.getCurrentService()
1696 return service.cueSheet()
1698 def uploadCuesheet(self):
1699 cue = self.__getCuesheet()
1702 print "upload failed, no cuesheet interface"
1704 cue.setCutList(self.cut_list)
1706 def downloadCuesheet(self):
1707 cue = self.__getCuesheet()
1710 print "upload failed, no cuesheet interface"
1712 self.cut_list = cue.getCutList()
1714 class InfoBarSummary(Screen):
1716 <screen position="0,0" size="132,64">
1717 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1718 <convert type="ClockToText">WithSeconds</convert>
1720 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1721 <convert type="ServiceName">Name</convert>
1725 def __init__(self, session, parent):
1726 Screen.__init__(self, session)
1727 self["CurrentService"] = CurrentService(self.session.nav)
1728 self["CurrentTime"] = Clock()
1730 class InfoBarSummarySupport:
1734 def createSummary(self):
1735 return InfoBarSummary
1737 class InfoBarTeletextPlugin:
1739 self.teletext_plugin = None
1741 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1742 self.teletext_plugin = p
1744 if self.teletext_plugin is not None:
1745 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1747 "startTeletext": (self.startTeletext, _("View teletext..."))
1750 print "no teletext plugin found!"
1752 def startTeletext(self):
1753 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1755 class InfoBarSubtitleSupport(object):
1757 object.__init__(self)
1758 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1759 self.__subtitles_enabled = False
1761 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1763 iPlayableService.evStart: self.__serviceStarted,
1766 def __serviceStarted(self):
1767 # reenable if it was enabled
1768 r = self.__subtitles_enabled
1769 self.__subtitles_enabled = False
1770 self.__selected_subtitle = None
1771 self.setSubtitlesEnable(r)
1773 def getCurrentServiceSubtitle(self):
1774 service = self.session.nav.getCurrentService()
1775 return service and service.subtitle()
1777 def setSubtitlesEnable(self, enable=True):
1778 subtitle = self.getCurrentServiceSubtitle()
1779 if enable and self.__selected_subtitle:
1780 if subtitle and not self.__subtitles_enabled:
1781 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1782 self.subtitle_window.show()
1783 self.__subtitles_enabled = True
1786 subtitle.disableSubtitles(self.subtitle_window.instance)
1788 self.subtitle_window.hide()
1789 self.__subtitles_enabled = False
1791 def setSelectedSubtitle(self, subtitle):
1792 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1794 self.__selected_subtitle = subtitle
1795 self.__serviceStarted()
1797 self.__selected_subtitle = subtitle
1799 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1800 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)