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, configElement, ConfigSubsection, configSequence, configElementBoolean, configSelection, configElement_nonSave, getConfigListEntry
20 from Components.config import configfile, configsequencearg
22 from EpgSelection import EPGSelection
23 from Plugins.Plugin import PluginDescriptor
25 from Screen import Screen
26 from Screens.ChoiceBox import ChoiceBox
27 from Screens.Dish import Dish
28 from Screens.EventView import EventViewEPGSelect, EventViewSimple
29 from Screens.InputBox import InputBox
30 from Screens.MessageBox import MessageBox
31 from Screens.MinuteInput import MinuteInput
32 from Screens.TimerSelection import TimerSelection
33 from Screens.PictureInPicture import PictureInPicture
34 from Screens.SubtitleDisplay import SubtitleDisplay
35 from ServiceReference import ServiceReference
37 from Tools import Notifications
38 from Tools.Directories import *
40 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
47 from Components.config import config, currentConfigSelectionElement
50 from Menu import MainMenu, mdom
54 self.dishDialog = self.session.instantiateDialog(Dish)
55 self.onLayoutFinish.append(self.dishDialog.show)
57 class InfoBarShowHide:
58 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
66 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
68 "toggleShow": self.toggleShow,
72 self.__state = self.STATE_SHOWN
75 self.onExecBegin.append(self.show)
77 self.hideTimer = eTimer()
78 self.hideTimer.timeout.get().append(self.doTimerHide)
79 self.hideTimer.start(5000, True)
81 self.onShow.append(self.__onShow)
82 self.onHide.append(self.__onHide)
85 self.__state = self.STATE_SHOWN
88 def startHideTimer(self):
89 if self.__state == self.STATE_SHOWN and not self.__locked:
90 self.hideTimer.start(5000, True)
93 self.__state = self.STATE_HIDDEN
99 def doTimerHide(self):
100 self.hideTimer.stop()
101 if self.__state == self.STATE_SHOWN:
104 def toggleShow(self):
105 if self.__state == self.STATE_SHOWN:
107 self.hideTimer.stop()
108 elif self.__state == self.STATE_HIDDEN:
112 self.__locked = self.__locked + 1
115 self.hideTimer.stop()
117 def unlockShow(self):
118 self.__locked = self.__locked - 1
120 self.startHideTimer()
122 # def startShow(self):
123 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
124 # self.__state = self.STATE_SHOWN
126 # def startHide(self):
127 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
128 # self.__state = self.STATE_HIDDEN
130 class NumberZap(Screen):
137 self.close(int(self["number"].getText()))
139 def keyNumberGlobal(self, number):
140 self.Timer.start(3000, True) #reset timer
141 self.field = self.field + str(number)
142 self["number"].setText(self.field)
143 if len(self.field) >= 4:
146 def __init__(self, session, number):
147 Screen.__init__(self, session)
148 self.field = str(number)
150 self["channel"] = Label(_("Channel:"))
152 self["number"] = Label(self.field)
154 self["actions"] = NumberActionMap( [ "SetupActions" ],
158 "1": self.keyNumberGlobal,
159 "2": self.keyNumberGlobal,
160 "3": self.keyNumberGlobal,
161 "4": self.keyNumberGlobal,
162 "5": self.keyNumberGlobal,
163 "6": self.keyNumberGlobal,
164 "7": self.keyNumberGlobal,
165 "8": self.keyNumberGlobal,
166 "9": self.keyNumberGlobal,
167 "0": self.keyNumberGlobal
170 self.Timer = eTimer()
171 self.Timer.timeout.get().append(self.keyOK)
172 self.Timer.start(3000, True)
174 class InfoBarNumberZap:
175 """ Handles an initial number for NumberZapping """
177 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
179 "1": self.keyNumberGlobal,
180 "2": self.keyNumberGlobal,
181 "3": self.keyNumberGlobal,
182 "4": self.keyNumberGlobal,
183 "5": self.keyNumberGlobal,
184 "6": self.keyNumberGlobal,
185 "7": self.keyNumberGlobal,
186 "8": self.keyNumberGlobal,
187 "9": self.keyNumberGlobal,
188 "0": self.keyNumberGlobal,
191 def keyNumberGlobal(self, number):
192 # print "You pressed number " + str(number)
194 self.servicelist.recallPrevService()
197 self.session.openWithCallback(self.numberEntered, NumberZap, number)
199 def numberEntered(self, retval):
200 # print self.servicelist
202 self.zapToNumber(retval)
204 def searchNumberHelper(self, serviceHandler, num, bouquet):
205 servicelist = serviceHandler.list(bouquet)
206 if not servicelist is None:
208 serviceIterator = servicelist.getNext()
209 if not serviceIterator.valid(): #check end of list
211 if serviceIterator.flags: #assume normal dvb service have no flags set
214 if not num: #found service with searched number ?
215 return serviceIterator, 0
218 def zapToNumber(self, number):
219 bouquet = self.servicelist.bouquet_root
221 serviceHandler = eServiceCenter.getInstance()
222 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
223 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
225 bouquetlist = serviceHandler.list(bouquet)
226 if not bouquetlist is None:
228 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
229 if not bouquet.valid(): #check end of list
231 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
233 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
234 if not service is None:
235 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
236 self.servicelist.clearPath()
237 if self.servicelist.bouquet_root != bouquet:
238 self.servicelist.enterPath(self.servicelist.bouquet_root)
239 self.servicelist.enterPath(bouquet)
240 self.servicelist.setCurrentSelection(service) #select the service in servicelist
241 self.servicelist.zap()
243 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
245 class InfoBarChannelSelection:
246 """ ChannelSelection - handles the channelSelection dialog and the initial
247 channelChange actions which open the channelSelection dialog """
250 self.servicelist = self.session.instantiateDialog(ChannelSelection)
252 if config.misc.initialchannelselection.value == 1:
253 self.onShown.append(self.firstRun)
255 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
257 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
258 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
259 "zapUp": (self.zapUp, _("previous channel")),
260 "zapDown": (self.zapDown, _("next channel")),
261 "historyBack": (self.historyBack, _("previous channel in history")),
262 "historyNext": (self.historyNext, _("next channel in history")),
263 "openServiceList": (self.openServiceList, _("open servicelist")),
266 def showTvChannelList(self, zap=False):
267 self.servicelist.setModeTv()
269 self.servicelist.zap()
270 self.session.execDialog(self.servicelist)
272 def showRadioChannelList(self, zap=False):
273 self.servicelist.setModeRadio()
275 self.servicelist.zap()
276 self.session.execDialog(self.servicelist)
279 self.onShown.remove(self.firstRun)
280 config.misc.initialchannelselection.value = 0
281 config.misc.initialchannelselection.save()
282 self.switchChannelDown()
284 def historyBack(self):
285 self.servicelist.historyBack()
287 def historyNext(self):
288 self.servicelist.historyNext()
290 def switchChannelUp(self):
291 self.servicelist.moveUp()
292 self.session.execDialog(self.servicelist)
294 def switchChannelDown(self):
295 self.servicelist.moveDown()
296 self.session.execDialog(self.servicelist)
298 def openServiceList(self):
299 self.session.execDialog(self.servicelist)
302 if self.servicelist.inBouquet():
303 prev = self.servicelist.getCurrentSelection()
305 prev = prev.toString()
307 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
308 if self.servicelist.atBegin():
309 self.servicelist.prevBouquet()
310 self.servicelist.moveUp()
311 cur = self.servicelist.getCurrentSelection()
312 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
315 self.servicelist.moveUp()
316 self.servicelist.zap()
320 if self.servicelist.inBouquet():
321 prev = self.servicelist.getCurrentSelection()
323 prev = prev.toString()
325 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.atEnd():
326 self.servicelist.nextBouquet()
328 self.servicelist.moveDown()
329 cur = self.servicelist.getCurrentSelection()
330 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
333 self.servicelist.moveDown()
334 self.servicelist.zap()
338 """ Handles a menu action, to open the (main) menu """
340 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
342 "mainMenu": (self.mainMenu, _("Enter main menu...")),
346 print "loading mainmenu XML..."
347 menu = mdom.childNodes[0]
348 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
349 self.session.open(MainMenu, menu, menu.childNodes)
351 class InfoBarSimpleEventView:
352 """ Opens the Eventview for now/next """
354 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
356 "showEventInfo": (self.openEventView, _("show event details")),
359 def openEventView(self):
361 service = self.session.nav.getCurrentService()
362 ref = self.session.nav.getCurrentlyPlayingServiceReference()
363 info = service.info()
366 self.epglist.append(ptr)
369 self.epglist.append(ptr)
370 if len(self.epglist) > 0:
371 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
373 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
374 if len(self.epglist) > 1:
375 tmp = self.epglist[0]
376 self.epglist[0]=self.epglist[1]
378 setEvent(self.epglist[0])
381 """ EPG - Opens an EPG list when the showEPGList action fires """
383 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
385 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
388 self.is_now_next = False
390 self.bouquetSel = None
391 self.eventView = None
392 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
394 "showEventInfo": (self.openEventView, _("show EPG...")),
397 def zapToService(self, service):
398 if not service is None:
399 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
400 self.servicelist.clearPath()
401 if self.servicelist.bouquet_root != self.epg_bouquet:
402 self.servicelist.enterPath(self.servicelist.bouquet_root)
403 self.servicelist.enterPath(self.epg_bouquet)
404 self.servicelist.setCurrentSelection(service) #select the service in servicelist
405 self.servicelist.zap()
407 def getBouquetServices(self, bouquet):
409 servicelist = eServiceCenter.getInstance().list(bouquet)
410 if not servicelist is None:
412 service = servicelist.getNext()
413 if not service.valid(): #check if end of list
415 if service.flags: #ignore non playable services
417 services.append(ServiceReference(service))
420 def openBouquetEPG(self, bouquet, withCallback=True):
421 services = self.getBouquetServices(bouquet)
423 self.epg_bouquet = bouquet
425 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
427 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
429 def changeBouquetCB(self, direction, epg):
432 self.bouquetSel.down()
435 bouquet = self.bouquetSel.getCurrent()
436 services = self.getBouquetServices(bouquet)
438 self.epg_bouquet = bouquet
439 epg.setServices(services)
441 def closed(self, ret=False):
442 closedScreen = self.dlg_stack.pop()
443 if self.bouquetSel and closedScreen == self.bouquetSel:
444 self.bouquetSel = None
445 elif self.eventView and closedScreen == self.eventView:
446 self.eventView = None
448 dlgs=len(self.dlg_stack)
450 self.dlg_stack[dlgs-1].close(dlgs > 1)
452 def openMultiServiceEPG(self, withCallback=True):
453 bouquets = self.servicelist.getBouquetList()
458 if cnt > 1: # show bouquet list
460 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
461 self.dlg_stack.append(self.bouquetSel)
463 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
465 self.openBouquetEPG(bouquets[0][1], withCallback)
467 def openSingleServiceEPG(self):
468 ref=self.session.nav.getCurrentlyPlayingServiceReference()
469 self.session.open(EPGSelection, ref)
471 def openSimilarList(self, eventid, refstr):
472 self.session.open(EPGSelection, refstr, None, eventid)
474 def getNowNext(self):
476 service = self.session.nav.getCurrentService()
477 info = service and service.info()
478 ptr = info and info.getEvent(0)
480 self.epglist.append(ptr)
481 ptr = info and info.getEvent(1)
483 self.epglist.append(ptr)
485 def __evEventInfoChanged(self):
486 if self.is_now_next and len(self.dlg_stack) == 1:
488 assert self.eventView
489 if len(self.epglist):
490 self.eventView.setEvent(self.epglist[0])
492 def openEventView(self):
493 ref = self.session.nav.getCurrentlyPlayingServiceReference()
495 if len(self.epglist) == 0:
496 self.is_now_next = False
497 epg = eEPGCache.getInstance()
498 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
500 self.epglist.append(ptr)
501 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
503 self.epglist.append(ptr)
505 self.is_now_next = True
506 if len(self.epglist) > 0:
507 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
508 self.dlg_stack.append(self.eventView)
510 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
511 self.openMultiServiceEPG(False)
513 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
514 if len(self.epglist) > 1:
515 tmp = self.epglist[0]
516 self.epglist[0]=self.epglist[1]
518 setEvent(self.epglist[0])
521 """provides a snr/agc/ber display"""
523 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
526 """provides a current/next event info display"""
528 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
529 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
531 class InfoBarServiceName:
533 self["CurrentService"] = CurrentService(self.session.nav)
536 """handles actions like seeking, pause"""
538 # ispause, isff, issm
539 SEEK_STATE_PLAY = (0, 0, 0, ">")
540 SEEK_STATE_PAUSE = (1, 0, 0, "||")
541 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
542 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
543 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
544 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
545 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
546 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
548 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
549 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
550 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
551 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
553 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
554 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
555 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
558 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
560 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
561 iPlayableService.evStart: self.__serviceStarted,
563 iPlayableService.evEOF: self.__evEOF,
564 iPlayableService.evSOF: self.__evSOF,
567 class InfoBarSeekActionMap(HelpableActionMap):
568 def __init__(self, screen, *args, **kwargs):
569 HelpableActionMap.__init__(self, screen, *args, **kwargs)
572 def action(self, contexts, action):
573 if action[:5] == "seek:":
574 time = int(action[5:])
575 self.screen.seekRelative(time * 90000)
578 return HelpableActionMap.action(self, contexts, action)
580 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
582 "pauseService": (self.pauseService, _("pause")),
583 "unPauseService": (self.unPauseService, _("continue")),
585 "seekFwd": (self.seekFwd, _("skip forward")),
586 "seekFwdDown": self.seekFwdDown,
587 "seekFwdUp": self.seekFwdUp,
588 "seekBack": (self.seekBack, _("skip backward")),
589 "seekBackDown": self.seekBackDown,
590 "seekBackUp": self.seekBackUp,
592 # give them a little more priority to win over color buttons
594 self.seekstate = self.SEEK_STATE_PLAY
595 self.onClose.append(self.delTimer)
597 self.fwdtimer = False
598 self.fwdKeyTimer = eTimer()
599 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
601 self.rwdtimer = False
602 self.rwdKeyTimer = eTimer()
603 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
605 self.onPlayStateChanged = [ ]
607 self.lockedBecauseOfSkipping = False
620 service = self.session.nav.getCurrentService()
624 seek = service.seek()
626 if seek is None or not seek.isCurrentlySeekable():
631 def isSeekable(self):
632 if self.getSeek() is None:
636 def __seekableStatusChanged(self):
637 print "seekable status changed!"
638 if not self.isSeekable():
639 self["SeekActions"].setEnabled(False)
640 print "not seekable, return to play"
641 self.setSeekState(self.SEEK_STATE_PLAY)
643 self["SeekActions"].setEnabled(True)
646 def __serviceStarted(self):
647 self.seekstate = self.SEEK_STATE_PLAY
649 def setSeekState(self, state):
650 service = self.session.nav.getCurrentService()
655 if not self.isSeekable():
656 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
657 state = self.SEEK_STATE_PLAY
659 pauseable = service.pause()
661 if pauseable is None:
662 print "not pauseable."
663 state = self.SEEK_STATE_PLAY
665 oldstate = self.seekstate
666 self.seekstate = state
669 if oldstate[i] != self.seekstate[i]:
670 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
672 for c in self.onPlayStateChanged:
675 self.checkSkipShowHideLock()
679 def pauseService(self):
680 if self.seekstate == self.SEEK_STATE_PAUSE:
681 print "pause, but in fact unpause"
682 self.unPauseService()
684 if self.seekstate == self.SEEK_STATE_PLAY:
685 print "yes, playing."
687 print "no", self.seekstate
689 self.setSeekState(self.SEEK_STATE_PAUSE);
691 def unPauseService(self):
693 if self.seekstate == self.SEEK_STATE_PLAY:
695 self.setSeekState(self.SEEK_STATE_PLAY)
697 def doSeek(self, seektime):
698 print "doseek", seektime
699 service = self.session.nav.getCurrentService()
703 seekable = self.getSeek()
707 seekable.seekTo(90 * seektime)
709 def seekFwdDown(self):
710 print "start fwd timer"
712 self.fwdKeyTimer.start(1000)
714 def seekBackDown(self):
715 print "start rewind timer"
717 self.rwdKeyTimer.start(1000)
722 self.fwdKeyTimer.stop()
723 self.fwdtimer = False
728 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
729 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
730 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
731 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
732 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
733 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
734 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
735 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
736 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
737 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
738 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
739 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
740 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
741 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
742 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
744 self.setSeekState(lookup[self.seekstate])
746 def seekBackUp(self):
749 self.rwdKeyTimer.stop()
750 self.rwdtimer = False
755 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
756 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
757 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
758 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
759 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
760 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
761 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
762 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
763 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
764 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
765 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
766 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
767 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
768 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
769 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
771 self.setSeekState(lookup[self.seekstate])
773 if self.seekstate == self.SEEK_STATE_PAUSE:
774 seekable = self.getSeek()
775 if seekable is not None:
776 seekable.seekRelative(-1, 3)
778 def fwdTimerFire(self):
779 print "Display seek fwd"
780 self.fwdKeyTimer.stop()
781 self.fwdtimer = False
782 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
784 def fwdSeekTo(self, minutes):
785 print "Seek", minutes, "minutes forward"
787 seekable = self.getSeek()
788 if seekable is not None:
789 seekable.seekRelative(1, minutes * 60 * 90000)
791 def rwdTimerFire(self):
793 self.rwdKeyTimer.stop()
794 self.rwdtimer = False
795 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
797 def rwdSeekTo(self, minutes):
799 self.fwdSeekTo(0 - minutes)
801 def checkSkipShowHideLock(self):
802 wantlock = self.seekstate != self.SEEK_STATE_PLAY
804 if self.lockedBecauseOfSkipping and not wantlock:
806 self.lockedBecauseOfSkipping = False
808 if wantlock and not self.lockedBecauseOfSkipping:
810 self.lockedBecauseOfSkipping = True
813 if self.seekstate != self.SEEK_STATE_PLAY:
814 self.setSeekState(self.SEEK_STATE_PAUSE)
816 #self.getSeek().seekRelative(1, -90000)
817 self.setSeekState(self.SEEK_STATE_PLAY)
819 self.setSeekState(self.SEEK_STATE_PAUSE)
822 self.setSeekState(self.SEEK_STATE_PLAY)
825 def seekRelative(self, diff):
826 seekable = self.getSeek()
827 if seekable is not None:
828 seekable.seekRelative(1, diff)
830 from Screens.PVRState import PVRState, TimeshiftState
832 class InfoBarPVRState:
833 def __init__(self, screen=PVRState):
834 self.onPlayStateChanged.append(self.__playStateChanged)
835 self.pvrStateDialog = self.session.instantiateDialog(screen)
836 self.onShow.append(self.__mayShow)
837 self.onHide.append(self.pvrStateDialog.hide)
840 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
841 self.pvrStateDialog.show()
843 def __playStateChanged(self, state):
844 playstateString = state[3]
845 self.pvrStateDialog["state"].setText(playstateString)
848 class InfoBarTimeshiftState(InfoBarPVRState):
850 InfoBarPVRState.__init__(self, screen=TimeshiftState)
852 class InfoBarShowMovies:
854 # i don't really like this class.
855 # it calls a not further specified "movie list" on up/down/movieList,
856 # so this is not more than an action map
858 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
860 "movieList": (self.showMovies, "movie list"),
861 "up": (self.showMovies, "movie list"),
862 "down": (self.showMovies, "movie list")
865 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
869 # Timeshift works the following way:
870 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
871 # - normal playback TUNER unused PLAY enable disable disable
872 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
873 # - user presess pause again FILE record PLAY enable disable enable
874 # - user fast forwards FILE record FF enable disable enable
875 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
876 # - user backwards FILE record BACK # !! enable disable enable
880 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
881 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
882 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
883 # - the user can now PVR around
884 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
885 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
887 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
888 # - if the user rewinds, or press pause, timeshift will be activated again
890 # note that a timeshift can be enabled ("recording") and
891 # activated (currently time-shifting).
893 class InfoBarTimeshift:
895 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
897 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
898 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
900 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
902 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
903 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
904 }, prio=-1) # priority over record
906 self.timeshift_enabled = 0
907 self.timeshift_state = 0
908 self.ts_pause_timer = eTimer()
909 self.ts_pause_timer.timeout.get().append(self.pauseService)
911 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
913 iPlayableService.evStart: self.__serviceStarted,
914 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
917 def getTimeshift(self):
918 service = self.session.nav.getCurrentService()
919 return service and service.timeshift()
921 def startTimeshift(self):
922 print "enable timeshift"
923 ts = self.getTimeshift()
925 # self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
926 # print "no ts interface"
929 if self.timeshift_enabled:
930 print "hu, timeshift already enabled?"
932 if not ts.startTimeshift():
934 self.timeshift_enabled = 1
936 # we remove the "relative time" for now.
937 #self.pvrStateDialog["timeshift"].setRelative(time.time())
940 self.setSeekState(self.SEEK_STATE_PAUSE)
942 # enable the "TimeshiftEnableActions", which will override
943 # the startTimeshift actions
944 self.__seekableStatusChanged()
946 print "timeshift failed"
948 def stopTimeshift(self):
949 if not self.timeshift_enabled:
951 print "disable timeshift"
952 ts = self.getTimeshift()
955 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
957 def stopTimeshiftConfirmed(self, confirmed):
961 ts = self.getTimeshift()
966 self.timeshift_enabled = 0
969 self.__seekableStatusChanged()
971 # activates timeshift, and seeks to (almost) the end
972 def activateTimeshiftEnd(self):
973 ts = self.getTimeshift()
978 if ts.isTimeshiftActive():
979 print "!! activate timeshift called - but shouldn't this be a normal pause?"
982 self.setSeekState(self.SEEK_STATE_PLAY)
983 ts.activateTimeshift()
986 # same as activateTimeshiftEnd, but pauses afterwards.
987 def activateTimeshiftEndAndPause(self):
988 state = self.seekstate
989 self.activateTimeshiftEnd()
991 # well, this is "andPause", but it could be pressed from pause,
992 # when pausing on the (fake-)"live" picture, so an un-pause
995 print "now, pauseService"
996 if state == self.SEEK_STATE_PLAY:
997 print "is PLAYING, start pause timer"
998 self.ts_pause_timer.start(200, 1)
1001 self.unPauseService()
1003 def __seekableStatusChanged(self):
1006 print "self.isSeekable", self.isSeekable()
1007 print "self.timeshift_enabled", self.timeshift_enabled
1009 # when this service is not seekable, but timeshift
1010 # is enabled, this means we can activate
1012 if not self.isSeekable() and self.timeshift_enabled:
1015 print "timeshift activate:", enabled
1016 self["TimeshiftActivateActions"].setEnabled(enabled)
1018 def __serviceStarted(self):
1019 self.timeshift_enabled = False
1020 self.__seekableStatusChanged()
1022 from Screens.PiPSetup import PiPSetup
1024 class InfoBarExtensions:
1025 EXTENSION_SINGLE = 0
1031 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1033 "extensions": (self.showExtensionSelection, _("view extensions...")),
1036 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1037 self.list.append((type, extension, key))
1039 def updateExtension(self, extension, key = None):
1040 self.extensionsList.append(extension)
1042 if self.extensionKeys.has_key(key):
1046 for x in self.availableKeys:
1047 if not self.extensionKeys.has_key(x):
1052 self.extensionKeys[key] = len(self.extensionsList) - 1
1054 def updateExtensions(self):
1055 self.extensionsList = []
1056 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1057 self.extensionKeys = {}
1059 if x[0] == self.EXTENSION_SINGLE:
1060 self.updateExtension(x[1], x[2])
1063 self.updateExtension(y[0], y[1])
1066 def showExtensionSelection(self):
1067 self.updateExtensions()
1068 extensionsList = self.extensionsList[:]
1071 for x in self.availableKeys:
1072 if self.extensionKeys.has_key(x):
1073 entry = self.extensionKeys[x]
1074 extension = self.extensionsList[entry]
1076 name = str(extension[0]())
1077 list.append((extension[0](), extension))
1079 extensionsList.remove(extension)
1081 extensionsList.remove(extension)
1082 for x in extensionsList:
1083 list.append((x[0](), x))
1084 keys += [""] * len(extensionsList)
1085 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1087 def extensionCallback(self, answer):
1088 if answer is not None:
1091 from Tools.BoundFunction import boundFunction
1093 # depends on InfoBarExtensions
1094 from Components.PluginComponent import plugins
1096 class InfoBarPlugins:
1098 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1101 def getPluginName(self, name):
1104 def getPluginList(self):
1106 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1107 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1110 def runPlugin(self, plugin):
1111 plugin(session = self.session)
1113 # depends on InfoBarExtensions and InfoBarSubtitleSupport
1114 class InfoBarSubtitles:
1116 self.addExtension((self.getDisableSubtitleName, self.disableSubtitles, self.subtitlesEnabled), "4")
1117 self.addExtension(extension = self.getSubtitleList, type = InfoBarExtensions.EXTENSION_LIST)
1119 def getDisableSubtitleName(self):
1120 return _("Disable subtitles")
1122 def getSubtitleList(self):
1124 s = self.getCurrentServiceSubtitle()
1125 l = s and s.getSubtitleList() or [ ]
1128 list.append(((boundFunction(self.getSubtitleEntryName, x[0]), boundFunction(self.enableSubtitle, x[1]), lambda: True), None))
1131 def getSubtitleEntryName(self, name):
1132 return "Enable Subtitles: " + name
1134 def enableSubtitle(self, subtitles):
1135 print "enable subitles", subtitles
1136 self.selected_subtitle = subtitles
1137 self.subtitles_enabled = True
1139 def subtitlesEnabled(self):
1140 return self.subtitles_enabled
1142 def disableSubtitles(self):
1143 self.subtitles_enabled = False
1145 # depends on InfoBarExtensions
1148 self.session.pipshown = False
1150 self.addExtension((self.getShowHideName, self.showPiP, self.available), "1")
1151 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "2")
1152 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "3")
1155 def available(self):
1159 return self.session.pipshown
1161 def getShowHideName(self):
1162 if self.session.pipshown:
1163 return _("Disable Picture in Picture")
1165 return _("Activate Picture in Picture")
1167 def getSwapName(self):
1168 return _("Swap Services")
1170 def getMoveName(self):
1171 return _("Move Picture in Picture")
1174 if self.session.pipshown:
1175 del self.session.pip
1176 self.session.pipshown = False
1178 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1179 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1180 if self.session.pip.playService(newservice):
1181 self.session.pipshown = True
1182 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1184 self.session.pipshown = False
1185 del self.session.pip
1186 self.session.nav.playService(newservice)
1189 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1190 if self.session.pip.servicePath:
1191 servicepath = self.servicelist.getCurrentServicePath()
1192 ref=servicepath[len(servicepath)-1]
1193 pipref=self.session.pip.getCurrentService()
1194 self.session.pip.playService(swapservice)
1195 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1196 if pipref.toString() != ref.toString(): # is a subservice ?
1197 self.session.nav.stopService() # stop portal
1198 self.session.nav.playService(pipref) # start subservice
1199 self.session.pip.servicePath=servicepath
1202 self.session.open(PiPSetup, pip = self.session.pip)
1204 from RecordTimer import parseEvent
1206 class InfoBarInstantRecord:
1207 """Instant Record - handles the instantRecord action in order to
1208 start/stop instant records"""
1210 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1212 "instantRecord": (self.instantRecord, _("Instant Record...")),
1215 self["BlinkingPoint"] = BlinkingPixmapConditional()
1216 self["BlinkingPoint"].hide()
1217 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1219 def stopCurrentRecording(self, entry = -1):
1220 if entry is not None and entry != -1:
1221 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1222 self.recording.remove(self.recording[entry])
1224 def startInstantRecording(self, limitEvent = False):
1225 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1227 # try to get event info
1230 service = self.session.nav.getCurrentService()
1231 epg = eEPGCache.getInstance()
1232 event = epg.lookupEventTime(serviceref, -1, 0)
1234 info = service.info()
1235 ev = info.getEvent(0)
1241 end = time.time() + 3600 * 10
1242 name = "instant record"
1246 if event is not None:
1247 curEvent = parseEvent(event)
1249 description = curEvent[3]
1250 eventid = curEvent[4]
1255 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1257 data = (begin, end, name, description, eventid)
1259 recording = self.session.nav.recordWithTimer(serviceref, *data)
1260 recording.dontSave = True
1261 self.recording.append(recording)
1263 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1265 def isInstantRecordRunning(self):
1266 print "self.recording:", self.recording
1267 if len(self.recording) > 0:
1268 for x in self.recording:
1273 def recordQuestionCallback(self, answer):
1274 print "pre:\n", self.recording
1276 if answer is None or answer[1] == "no":
1279 recording = self.recording[:]
1281 if not x in self.session.nav.RecordTimer.timer_list:
1282 self.recording.remove(x)
1283 elif x.dontSave and x.isRunning():
1284 list.append(TimerEntryComponent(x, False))
1286 if answer[1] == "changeduration":
1287 if len(self.recording) == 1:
1288 self.changeDuration(0)
1290 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1291 elif answer[1] == "stop":
1292 if len(self.recording) == 1:
1293 self.stopCurrentRecording(0)
1295 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1296 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1298 if answer[1] == "event":
1300 if answer[1] == "manualduration":
1301 self.selectedEntry = len(self.recording)
1302 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1303 self.startInstantRecording(limitEvent = limitEvent)
1305 print "after:\n", self.recording
1307 def changeDuration(self, entry):
1308 if entry is not None:
1309 self.selectedEntry = entry
1310 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1312 def inputCallback(self, value):
1313 if value is not None:
1314 print "stopping recording after", int(value), "minutes."
1315 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1316 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1318 def instantRecord(self):
1320 stat = os.stat(resolveFilename(SCOPE_HDD))
1322 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1325 if self.isInstantRecordRunning():
1326 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")])
1328 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")])
1330 from Tools.ISO639 import LanguageCodes
1332 class InfoBarAudioSelection:
1334 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1336 "audioSelection": (self.audioSelection, _("Audio Options...")),
1339 def audioSelection(self):
1340 service = self.session.nav.getCurrentService()
1341 audio = service and service.audioTracks()
1342 self.audioTracks = audio
1343 n = audio and audio.getNumberOfTracks() or 0
1344 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1346 print "tlist:", tlist
1348 self.audioChannel = service.audioChannel()
1351 i = audio.getTrackInfo(x)
1352 language = i.getLanguage()
1353 description = i.getDescription()
1355 if len(language) == 3:
1356 if language in LanguageCodes:
1357 language = LanguageCodes[language][0]
1359 if len(description):
1360 description += " (" + language + ")"
1362 description = language
1364 tlist.append((description, x))
1366 selectedAudio = tlist[0][1]
1367 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1371 if x[1] != selectedAudio:
1376 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1377 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1379 del self.audioTracks
1381 def audioSelected(self, audio):
1382 if audio is not None:
1383 if isinstance(audio[1], str):
1384 if audio[1] == "mode":
1385 keys = ["red", "green", "yellow"]
1386 selection = self.audioChannel.getCurrentChannel()
1387 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1388 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1390 del self.audioChannel
1391 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1392 self.audioTracks.selectTrack(audio[1])
1394 del self.audioChannel
1395 del self.audioTracks
1397 def modeSelected(self, mode):
1398 if mode is not None:
1399 self.audioChannel.selectChannel(mode[1])
1400 del self.audioChannel
1403 class InfoBarSubserviceSelection:
1405 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1407 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1410 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1412 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1413 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1415 self["SubserviceQuickzapAction"].setEnabled(False)
1417 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1419 def checkSubservicesAvail(self, ev):
1420 if ev == iPlayableService.evUpdatedEventInfo:
1421 service = self.session.nav.getCurrentService()
1422 subservices = service and service.subServices()
1423 if not subservices or subservices.getNumberOfSubservices() == 0:
1424 self["SubserviceQuickzapAction"].setEnabled(False)
1426 def nextSubservice(self):
1427 self.changeSubservice(+1)
1429 def prevSubservice(self):
1430 self.changeSubservice(-1)
1432 def changeSubservice(self, direction):
1433 service = self.session.nav.getCurrentService()
1434 subservices = service and service.subServices()
1435 n = subservices and subservices.getNumberOfSubservices()
1438 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1440 if subservices.getSubservice(x).toString() == ref.toString():
1443 selection += direction
1448 newservice = subservices.getSubservice(selection)
1449 if newservice.valid():
1452 self.session.nav.playService(newservice)
1454 def subserviceSelection(self):
1455 service = self.session.nav.getCurrentService()
1456 subservices = service and service.subServices()
1458 n = subservices and subservices.getNumberOfSubservices()
1461 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1464 i = subservices.getSubservice(x)
1465 if i.toString() == ref.toString():
1467 tlist.append((i.getName(), i))
1469 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1471 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1473 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1475 def subserviceSelected(self, service):
1476 if not service is None:
1477 if isinstance(service[1], str):
1478 if service[1] == "quickzap":
1479 from Screens.SubservicesQuickzap import SubservicesQuickzap
1480 self.session.open(SubservicesQuickzap, service[2])
1482 self["SubserviceQuickzapAction"].setEnabled(True)
1483 self.session.nav.playService(service[1])
1485 class InfoBarAdditionalInfo:
1487 self["NimA"] = Pixmap()
1488 self["NimB"] = Pixmap()
1489 self["NimA_Active"] = Pixmap()
1490 self["NimB_Active"] = Pixmap()
1492 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1493 self["TimeshiftPossible"] = self["RecordingPossible"]
1494 self["ExtensionsAvailable"] = Boolean(fixed=1)
1496 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1497 res_mgr = eDVBResourceManagerPtr()
1498 if eDVBResourceManager.getInstance(res_mgr) == 0:
1499 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1501 def tunerUseMaskChanged(self, mask):
1503 self["NimA_Active"].show()
1505 self["NimA_Active"].hide()
1507 self["NimB_Active"].show()
1509 self["NimB_Active"].hide()
1511 def checkTunerState(self, service):
1512 info = service.frontendInfo()
1513 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1514 if feNumber is None:
1524 def gotServiceEvent(self, ev):
1525 service = self.session.nav.getCurrentService()
1526 if ev == iPlayableService.evStart:
1527 self.checkTunerState(service)
1529 class InfoBarNotifications:
1531 self.onExecBegin.append(self.checkNotifications)
1532 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1533 self.onClose.append(self.__removeNotification)
1535 def __removeNotification(self):
1536 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1538 def checkNotificationsIfExecing(self):
1540 self.checkNotifications()
1542 def checkNotifications(self):
1543 if len(Notifications.notifications):
1544 n = Notifications.notifications[0]
1545 Notifications.notifications = Notifications.notifications[1:]
1548 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1550 self.session.open(n[1], *n[2], **n[3])
1552 class InfoBarServiceNotifications:
1554 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1556 iPlayableService.evEnd: self.serviceHasEnded
1559 def serviceHasEnded(self):
1560 print "service end!"
1563 self.setSeekState(self.SEEK_STATE_PLAY)
1567 class InfoBarCueSheetSupport:
1573 ENABLE_RESUME_SUPPORT = False
1576 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1578 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1579 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1580 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1584 self.is_closing = False
1585 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1587 iPlayableService.evStart: self.__serviceStarted,
1590 def __serviceStarted(self):
1593 print "new service started! trying to download cuts!"
1594 self.downloadCuesheet()
1596 if self.ENABLE_RESUME_SUPPORT:
1599 for (pts, what) in self.cut_list:
1600 if what == self.CUT_TYPE_LAST:
1603 if last is not None:
1604 self.resume_point = last
1605 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1607 def playLastCB(self, answer):
1609 seekable = self.__getSeekable()
1610 if seekable is not None:
1611 seekable.seekTo(self.resume_point)
1613 def __getSeekable(self):
1614 service = self.session.nav.getCurrentService()
1617 return service.seek()
1619 def cueGetCurrentPosition(self):
1620 seek = self.__getSeekable()
1623 r = seek.getPlayPosition()
1628 def jumpPreviousNextMark(self, cmp, alternative=None):
1629 current_pos = self.cueGetCurrentPosition()
1630 if current_pos is None:
1632 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1633 if mark is not None:
1635 elif alternative is not None:
1640 seekable = self.__getSeekable()
1641 if seekable is not None:
1642 seekable.seekTo(pts)
1644 def jumpPreviousMark(self):
1645 # we add 2 seconds, so if the play position is <2s after
1646 # the mark, the mark before will be used
1647 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1649 def jumpNextMark(self):
1650 self.jumpPreviousNextMark(lambda x: x)
1652 def getNearestCutPoint(self, pts, cmp=abs):
1655 for cp in self.cut_list:
1656 diff = cmp(cp[0] - pts)
1657 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1661 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1662 current_pos = self.cueGetCurrentPosition()
1663 if current_pos is None:
1664 print "not seekable"
1667 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1669 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1671 return nearest_cutpoint
1673 self.removeMark(nearest_cutpoint)
1674 elif not onlyremove and not onlyreturn:
1675 self.addMark((current_pos, self.CUT_TYPE_MARK))
1680 def addMark(self, point):
1681 bisect.insort(self.cut_list, point)
1682 self.uploadCuesheet()
1684 def removeMark(self, point):
1685 self.cut_list.remove(point)
1686 self.uploadCuesheet()
1688 def __getCuesheet(self):
1689 service = self.session.nav.getCurrentService()
1692 return service.cueSheet()
1694 def uploadCuesheet(self):
1695 cue = self.__getCuesheet()
1698 print "upload failed, no cuesheet interface"
1700 cue.setCutList(self.cut_list)
1702 def downloadCuesheet(self):
1703 cue = self.__getCuesheet()
1706 print "upload failed, no cuesheet interface"
1708 self.cut_list = cue.getCutList()
1710 class InfoBarSummary(Screen):
1712 <screen position="0,0" size="132,64">
1713 <widget source="CurrentTime" render="Label" position="50,46" size="82,18" font="Regular;16" >
1714 <convert type="ClockToText">WithSeconds</convert>
1716 <widget source="CurrentService" render="Label" position="0,4" size="132,42" font="Regular;18" >
1717 <convert type="ServiceName">Name</convert>
1721 def __init__(self, session, parent):
1722 Screen.__init__(self, session)
1723 self["CurrentService"] = CurrentService(self.session.nav)
1724 self["CurrentTime"] = Clock()
1726 class InfoBarSummarySupport:
1730 def createSummary(self):
1731 return InfoBarSummary
1733 class InfoBarTeletextPlugin:
1735 self.teletext_plugin = None
1737 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1738 self.teletext_plugin = p
1740 if self.teletext_plugin is not None:
1741 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1743 "startTeletext": (self.startTeletext, _("View teletext..."))
1746 print "no teletext plugin found!"
1748 def startTeletext(self):
1749 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1751 class InfoBarSubtitleSupport(object):
1753 object.__init__(self)
1754 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1755 self.__subtitles_enabled = False
1757 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1759 iPlayableService.evStart: self.__serviceStarted,
1762 def __serviceStarted(self):
1763 # reenable if it was enabled
1764 r = self.__subtitles_enabled
1765 self.__subtitles_enabled = False
1766 self.__selected_subtitle = None
1767 self.setSubtitlesEnable(r)
1769 def getCurrentServiceSubtitle(self):
1770 service = self.session.nav.getCurrentService()
1771 return service and service.subtitle()
1773 def setSubtitlesEnable(self, enable=True):
1774 subtitle = self.getCurrentServiceSubtitle()
1775 if enable and self.__selected_subtitle:
1776 if subtitle and not self.__subtitles_enabled:
1777 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1778 self.subtitle_window.show()
1779 self.__subtitles_enabled = True
1782 subtitle.disableSubtitles(self.subtitle_window.instance)
1784 self.subtitle_window.hide()
1785 self.__subtitles_enabled = False
1787 def setSelectedSubtitle(self, subtitle):
1788 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1790 self.__selected_subtitle = subtitle
1791 self.__serviceStarted()
1793 self.__selected_subtitle = subtitle
1795 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1796 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)