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.Clock import Clock
7 from Components.EventInfo import EventInfo, EventInfoProgress
8 from Components.Harddisk import harddiskmanager
9 from Components.Input import Input
10 from Components.Label import *
11 from Components.Pixmap import Pixmap, PixmapConditional
12 from Components.PluginComponent import plugins
13 from Components.ProgressBar import *
14 from Components.ServiceEventTracker import ServiceEventTracker
15 from Components.ServiceName import ServiceName
16 from Components.config import config, configElement, ConfigSubsection, configSequence, configElementBoolean
17 from Components.config import configfile, configsequencearg
18 from Components.TimerList import TimerEntryComponent
19 from Components.TunerInfo import TunerInfo
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 ServiceReference import ServiceReference
35 from Tools import Notifications
36 from Tools.Directories import *
38 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
45 from Components.config import config, currentConfigSelectionElement
48 from Menu import MainMenu, mdom
52 self.dishDialog = self.session.instantiateDialog(Dish)
53 self.onLayoutFinish.append(self.dishDialog.show)
55 class InfoBarShowHide:
56 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
64 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
66 "toggleShow": self.toggleShow,
70 self.__state = self.STATE_SHOWN
73 self.onExecBegin.append(self.show)
75 self.hideTimer = eTimer()
76 self.hideTimer.timeout.get().append(self.doTimerHide)
77 self.hideTimer.start(5000, True)
79 self.onShow.append(self.__onShow)
80 self.onHide.append(self.__onHide)
83 self.__state = self.STATE_SHOWN
86 def startHideTimer(self):
87 if self.__state == self.STATE_SHOWN and not self.__locked:
88 self.hideTimer.start(5000, True)
91 self.__state = self.STATE_HIDDEN
97 def doTimerHide(self):
99 if self.__state == self.STATE_SHOWN:
102 def toggleShow(self):
103 if self.__state == self.STATE_SHOWN:
105 self.hideTimer.stop()
106 elif self.__state == self.STATE_HIDDEN:
110 self.__locked = self.__locked + 1
113 self.hideTimer.stop()
115 def unlockShow(self):
116 self.__locked = self.__locked - 1
118 self.startHideTimer()
120 # def startShow(self):
121 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
122 # self.__state = self.STATE_SHOWN
124 # def startHide(self):
125 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
126 # self.__state = self.STATE_HIDDEN
128 class NumberZap(Screen):
135 self.close(int(self["number"].getText()))
137 def keyNumberGlobal(self, number):
138 self.Timer.start(3000, True) #reset timer
139 self.field = self.field + str(number)
140 self["number"].setText(self.field)
141 if len(self.field) >= 4:
144 def __init__(self, session, number):
145 Screen.__init__(self, session)
146 self.field = str(number)
148 self["channel"] = Label(_("Channel:"))
150 self["number"] = Label(self.field)
152 self["actions"] = NumberActionMap( [ "SetupActions" ],
156 "1": self.keyNumberGlobal,
157 "2": self.keyNumberGlobal,
158 "3": self.keyNumberGlobal,
159 "4": self.keyNumberGlobal,
160 "5": self.keyNumberGlobal,
161 "6": self.keyNumberGlobal,
162 "7": self.keyNumberGlobal,
163 "8": self.keyNumberGlobal,
164 "9": self.keyNumberGlobal,
165 "0": self.keyNumberGlobal
168 self.Timer = eTimer()
169 self.Timer.timeout.get().append(self.keyOK)
170 self.Timer.start(3000, True)
172 class InfoBarNumberZap:
173 """ Handles an initial number for NumberZapping """
175 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
177 "1": self.keyNumberGlobal,
178 "2": self.keyNumberGlobal,
179 "3": self.keyNumberGlobal,
180 "4": self.keyNumberGlobal,
181 "5": self.keyNumberGlobal,
182 "6": self.keyNumberGlobal,
183 "7": self.keyNumberGlobal,
184 "8": self.keyNumberGlobal,
185 "9": self.keyNumberGlobal,
186 "0": self.keyNumberGlobal,
189 def keyNumberGlobal(self, number):
190 # print "You pressed number " + str(number)
192 self.servicelist.recallPrevService()
195 self.session.openWithCallback(self.numberEntered, NumberZap, number)
197 def numberEntered(self, retval):
198 # print self.servicelist
200 self.zapToNumber(retval)
202 def searchNumberHelper(self, serviceHandler, num, bouquet):
203 servicelist = serviceHandler.list(bouquet)
204 if not servicelist is None:
206 serviceIterator = servicelist.getNext()
207 if not serviceIterator.valid(): #check end of list
209 if serviceIterator.flags: #assume normal dvb service have no flags set
212 if not num: #found service with searched number ?
213 return serviceIterator, 0
216 def zapToNumber(self, number):
217 bouquet = self.servicelist.bouquet_root
219 serviceHandler = eServiceCenter.getInstance()
220 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
221 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
223 bouquetlist = serviceHandler.list(bouquet)
224 if not bouquetlist is None:
226 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
227 if not bouquet.valid(): #check end of list
229 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
231 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
232 if not service is None:
233 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
234 self.servicelist.clearPath()
235 if self.servicelist.bouquet_root != bouquet:
236 self.servicelist.enterPath(self.servicelist.bouquet_root)
237 self.servicelist.enterPath(bouquet)
238 self.servicelist.setCurrentSelection(service) #select the service in servicelist
239 self.servicelist.zap()
241 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
243 class InfoBarChannelSelection:
244 """ ChannelSelection - handles the channelSelection dialog and the initial
245 channelChange actions which open the channelSelection dialog """
248 self.servicelist = self.session.instantiateDialog(ChannelSelection)
250 if config.misc.initialchannelselection.value == 1:
251 self.onShown.append(self.firstRun)
253 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
255 "switchChannelUp": self.switchChannelUp,
256 "switchChannelDown": self.switchChannelDown,
257 "zapUp": (self.zapUp, _("previous channel")),
258 "zapDown": (self.zapDown, _("next channel")),
259 "historyBack": (self.historyBack, _("previous channel in history")),
260 "historyNext": (self.historyNext, _("next channel in history"))
264 self.onShown.remove(self.firstRun)
265 config.misc.initialchannelselection.value = 0
266 config.misc.initialchannelselection.save()
267 self.switchChannelDown()
269 def historyBack(self):
270 self.servicelist.historyBack()
272 def historyNext(self):
273 self.servicelist.historyNext()
275 def switchChannelUp(self):
276 self.servicelist.moveUp()
277 self.session.execDialog(self.servicelist)
279 def switchChannelDown(self):
280 self.servicelist.moveDown()
281 self.session.execDialog(self.servicelist)
284 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
285 if self.servicelist.inBouquet() and self.servicelist.atBegin():
286 self.servicelist.prevBouquet()
287 self.servicelist.moveUp()
288 self.servicelist.zap()
292 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
293 self.servicelist.nextBouquet()
295 self.servicelist.moveDown()
296 self.servicelist.zap()
300 """ Handles a menu action, to open the (main) menu """
302 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
304 "mainMenu": (self.mainMenu, "Enter main menu..."),
308 print "loading mainmenu XML..."
309 menu = mdom.childNodes[0]
310 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
311 self.session.open(MainMenu, menu, menu.childNodes)
313 class InfoBarSimpleEventView:
314 """ Opens the Eventview for now/next """
316 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
318 "showEventInfo": (self.openEventView, _("show event details")),
321 def openEventView(self):
323 service = self.session.nav.getCurrentService()
324 ref = self.session.nav.getCurrentlyPlayingServiceReference()
325 info = service.info()
328 self.epglist.append(ptr)
331 self.epglist.append(ptr)
332 if len(self.epglist) > 0:
333 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
335 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
336 if len(self.epglist) > 1:
337 tmp = self.epglist[0]
338 self.epglist[0]=self.epglist[1]
340 setEvent(self.epglist[0])
343 """ EPG - Opens an EPG list when the showEPGList action fires """
345 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
347 "showEventInfo": (self.openEventView, _("show EPG...")),
350 def zapToService(self, service):
351 if not service is None:
352 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
353 self.servicelist.clearPath()
354 if self.servicelist.bouquet_root != self.epg_bouquet:
355 self.servicelist.enterPath(self.servicelist.bouquet_root)
356 self.servicelist.enterPath(self.epg_bouquet)
357 self.servicelist.setCurrentSelection(service) #select the service in servicelist
358 self.servicelist.zap()
360 def openBouquetEPG(self, bouquet, withCallback=True):
361 ptr=eEPGCache.getInstance()
363 servicelist = eServiceCenter.getInstance().list(bouquet)
364 if not servicelist is None:
366 service = servicelist.getNext()
367 if not service.valid(): #check if end of list
369 if service.flags: #ignore non playable services
371 services.append(ServiceReference(service))
373 self.epg_bouquet = bouquet
375 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
377 self.session.open(EPGSelection, services, self.zapToService)
379 def closed(self, ret):
383 def openMultiServiceEPG(self, withCallback=True):
384 bouquets = self.servicelist.getBouquetList()
389 if cnt > 1: # show bouquet list
391 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
393 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
395 self.openBouquetEPG(bouquets[0][1], withCallback)
397 def openSingleServiceEPG(self):
398 ref=self.session.nav.getCurrentlyPlayingServiceReference()
399 self.session.open(EPGSelection, ref)
401 def openSimilarList(self, eventid, refstr):
402 self.session.open(EPGSelection, refstr, None, eventid)
404 def openEventView(self):
406 service = self.session.nav.getCurrentService()
407 ref = self.session.nav.getCurrentlyPlayingServiceReference()
408 info = service.info()
411 self.epglist.append(ptr)
414 self.epglist.append(ptr)
415 if len(self.epglist) == 0:
416 epg = eEPGCache.getInstance()
417 ptr = epg.lookupEventTime(ref, -1)
419 self.epglist.append(ptr)
420 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
422 self.epglist.append(ptr)
423 if len(self.epglist) > 0:
424 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
426 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
427 self.openMultiServiceEPG(False)
429 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
430 if len(self.epglist) > 1:
431 tmp = self.epglist[0]
432 self.epglist[0]=self.epglist[1]
434 setEvent(self.epglist[0])
437 """provides a snr/agc/ber display"""
439 self["snr"] = Label()
440 self["agc"] = Label()
441 self["ber"] = Label()
442 self["snr_percent"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
443 self["agc_percent"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
444 self["ber_count"] = TunerInfo(TunerInfo.BER_VALUE, servicefkt = self.session.nav.getCurrentService)
445 self["snr_progress"] = TunerInfo(TunerInfo.SNR_BAR, servicefkt = self.session.nav.getCurrentService)
446 self["agc_progress"] = TunerInfo(TunerInfo.AGC_BAR, servicefkt = self.session.nav.getCurrentService)
447 self["ber_progress"] = TunerInfo(TunerInfo.BER_BAR, servicefkt = self.session.nav.getCurrentService)
448 self.timer = eTimer()
449 self.timer.timeout.get().append(self.updateTunerInfo)
450 self.timer.start(1000)
452 def updateTunerInfo(self):
453 if self.instance.isVisible():
454 self["snr_percent"].update()
455 self["agc_percent"].update()
456 self["ber_count"].update()
457 self["snr_progress"].update()
458 self["agc_progress"].update()
459 self["ber_progress"].update()
462 """provides a current/next event info display"""
464 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
465 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
467 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
468 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
470 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
471 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
473 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
475 class InfoBarServiceName:
477 self["ServiceName"] = ServiceName(self.session.nav)
480 """handles actions like seeking, pause"""
482 # ispause, isff, issm
483 SEEK_STATE_PLAY = (0, 0, 0, ">")
484 SEEK_STATE_PAUSE = (1, 0, 0, "||")
485 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
486 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
487 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
488 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
489 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
490 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
492 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
493 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
494 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
495 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
497 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
498 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
499 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
502 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
504 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
505 iPlayableService.evStart: self.__serviceStarted,
507 iPlayableService.evEOF: self.__evEOF,
508 iPlayableService.evSOF: self.__evSOF,
511 class InfoBarSeekActionMap(HelpableActionMap):
512 def __init__(self, screen, *args, **kwargs):
513 HelpableActionMap.__init__(self, screen, *args, **kwargs)
516 def action(self, contexts, action):
517 if action[:5] == "seek:":
518 time = int(action[5:])
519 self.screen.seekRelative(time * 90000)
522 return HelpableActionMap.action(self, contexts, action)
524 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
526 "pauseService": (self.pauseService, "pause"),
527 "unPauseService": (self.unPauseService, "continue"),
529 "seekFwd": (self.seekFwd, "skip forward"),
530 "seekFwdDown": self.seekFwdDown,
531 "seekFwdUp": self.seekFwdUp,
532 "seekBack": (self.seekBack, "skip backward"),
533 "seekBackDown": self.seekBackDown,
534 "seekBackUp": self.seekBackUp,
536 # give them a little more priority to win over color buttons
538 self.seekstate = self.SEEK_STATE_PLAY
539 self.onClose.append(self.delTimer)
541 self.fwdtimer = False
542 self.fwdKeyTimer = eTimer()
543 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
545 self.rwdtimer = False
546 self.rwdKeyTimer = eTimer()
547 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
549 self.onPlayStateChanged = [ ]
551 self.lockedBecauseOfSkipping = False
564 service = self.session.nav.getCurrentService()
568 seek = service.seek()
570 if seek is None or not seek.isCurrentlySeekable():
575 def isSeekable(self):
576 if self.getSeek() is None:
580 def __seekableStatusChanged(self):
581 print "seekable status changed!"
582 if not self.isSeekable():
583 self["SeekActions"].setEnabled(False)
584 print "not seekable, return to play"
585 self.setSeekState(self.SEEK_STATE_PLAY)
587 self["SeekActions"].setEnabled(True)
590 def __serviceStarted(self):
591 self.seekstate = self.SEEK_STATE_PLAY
593 def setSeekState(self, state):
594 service = self.session.nav.getCurrentService()
599 if not self.isSeekable():
600 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
601 state = self.SEEK_STATE_PLAY
603 pauseable = service.pause()
605 if pauseable is None:
606 print "not pauseable."
607 state = self.SEEK_STATE_PLAY
609 oldstate = self.seekstate
610 self.seekstate = state
613 if oldstate[i] != self.seekstate[i]:
614 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
616 for c in self.onPlayStateChanged:
619 self.checkSkipShowHideLock()
623 def pauseService(self):
624 if self.seekstate == self.SEEK_STATE_PAUSE:
625 print "pause, but in fact unpause"
626 self.unPauseService()
628 if self.seekstate == self.SEEK_STATE_PLAY:
629 print "yes, playing."
631 print "no", self.seekstate
633 self.setSeekState(self.SEEK_STATE_PAUSE);
635 def unPauseService(self):
637 self.setSeekState(self.SEEK_STATE_PLAY);
639 def doSeek(self, seektime):
640 print "doseek", seektime
641 service = self.session.nav.getCurrentService()
645 seekable = self.getSeek()
649 seekable.seekTo(90 * seektime)
651 def seekFwdDown(self):
652 print "start fwd timer"
654 self.fwdKeyTimer.start(1000)
656 def seekBackDown(self):
657 print "start rewind timer"
659 self.rwdKeyTimer.start(1000)
664 self.fwdKeyTimer.stop()
665 self.fwdtimer = False
670 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
671 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
672 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
673 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
674 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
675 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
676 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
677 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
678 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
679 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
680 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
681 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
682 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
683 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
684 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
686 self.setSeekState(lookup[self.seekstate])
688 def seekBackUp(self):
691 self.rwdKeyTimer.stop()
692 self.rwdtimer = False
697 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
698 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
699 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
700 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
701 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
702 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
703 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
704 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
705 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
706 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
707 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
708 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
709 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
710 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
711 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
713 self.setSeekState(lookup[self.seekstate])
715 if self.seekstate == self.SEEK_STATE_PAUSE:
716 seekable = self.getSeek()
717 if seekable is not None:
718 seekable.seekRelative(-1, 3)
720 def fwdTimerFire(self):
721 print "Display seek fwd"
722 self.fwdKeyTimer.stop()
723 self.fwdtimer = False
724 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
726 def fwdSeekTo(self, minutes):
727 print "Seek", minutes, "minutes forward"
729 seekable = self.getSeek()
730 if seekable is not None:
731 seekable.seekRelative(1, minutes * 60 * 90000)
733 def rwdTimerFire(self):
735 self.rwdKeyTimer.stop()
736 self.rwdtimer = False
737 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
739 def rwdSeekTo(self, minutes):
741 self.fwdSeekTo(0 - minutes)
743 def checkSkipShowHideLock(self):
744 wantlock = self.seekstate != self.SEEK_STATE_PLAY
746 if self.lockedBecauseOfSkipping and not wantlock:
748 self.lockedBecauseOfSkipping = False
750 if wantlock and not self.lockedBecauseOfSkipping:
752 self.lockedBecauseOfSkipping = True
755 if self.seekstate != self.SEEK_STATE_PLAY:
756 self.setSeekState(self.SEEK_STATE_PAUSE)
758 #self.getSeek().seekRelative(1, -90000)
759 self.setSeekState(self.SEEK_STATE_PLAY)
761 self.setSeekState(self.SEEK_STATE_PAUSE)
764 self.setSeekState(self.SEEK_STATE_PLAY)
767 def seekRelative(self, diff):
768 seekable = self.getSeek()
769 if seekable is not None:
770 seekable.seekRelative(1, diff)
772 from Screens.PVRState import PVRState, TimeshiftState
774 class InfoBarPVRState:
775 def __init__(self, screen=PVRState):
776 self.onPlayStateChanged.append(self.__playStateChanged)
777 self.pvrStateDialog = self.session.instantiateDialog(screen)
778 self.onShow.append(self.__mayShow)
779 self.onHide.append(self.pvrStateDialog.hide)
782 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
783 self.pvrStateDialog.show()
785 def __playStateChanged(self, state):
786 playstateString = state[3]
787 self.pvrStateDialog["state"].setText(playstateString)
790 class InfoBarTimeshiftState(InfoBarPVRState):
792 InfoBarPVRState.__init__(self, screen=TimeshiftState)
795 class InfoBarShowMovies:
797 # i don't really like this class.
798 # it calls a not further specified "movie list" on up/down/movieList,
799 # so this is not more than an action map
801 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
803 "movieList": (self.showMovies, "movie list"),
804 "up": (self.showMovies, "movie list"),
805 "down": (self.showMovies, "movie list")
808 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
812 # Timeshift works the following way:
813 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
814 # - normal playback TUNER unused PLAY enable disable disable
815 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
816 # - user presess pause again FILE record PLAY enable disable enable
817 # - user fast forwards FILE record FF enable disable enable
818 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
819 # - user backwards FILE record BACK # !! enable disable enable
823 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
824 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
825 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
826 # - the user can now PVR around
827 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
828 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
830 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
831 # - if the user rewinds, or press pause, timeshift will be activated again
833 # note that a timeshift can be enabled ("recording") and
834 # activated (currently time-shifting).
836 class InfoBarTimeshift:
838 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
840 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
841 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
843 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
845 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
846 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
847 }, prio=-1) # priority over record
849 self.timeshift_enabled = 0
850 self.timeshift_state = 0
851 self.ts_pause_timer = eTimer()
852 self.ts_pause_timer.timeout.get().append(self.pauseService)
854 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
856 iPlayableService.evStart: self.__serviceStarted,
857 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
860 def getTimeshift(self):
861 service = self.session.nav.getCurrentService()
862 return service and service.timeshift()
864 def startTimeshift(self):
865 print "enable timeshift"
866 ts = self.getTimeshift()
868 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
869 print "no ts interface"
872 if self.timeshift_enabled:
873 print "hu, timeshift already enabled?"
875 if not ts.startTimeshift():
877 self.timeshift_enabled = 1
878 self.pvrStateDialog["timeshift"].setRelative(time.time())
881 self.setSeekState(self.SEEK_STATE_PAUSE)
883 # enable the "TimeshiftEnableActions", which will override
884 # the startTimeshift actions
885 self.__seekableStatusChanged()
887 print "timeshift failed"
889 def stopTimeshift(self):
890 if not self.timeshift_enabled:
892 print "disable timeshift"
893 ts = self.getTimeshift()
896 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
898 def stopTimeshiftConfirmed(self, confirmed):
902 ts = self.getTimeshift()
907 self.timeshift_enabled = 0
910 self.__seekableStatusChanged()
912 # activates timeshift, and seeks to (almost) the end
913 def activateTimeshiftEnd(self):
914 ts = self.getTimeshift()
919 if ts.isTimeshiftActive():
920 print "!! activate timeshift called - but shouldn't this be a normal pause?"
923 self.setSeekState(self.SEEK_STATE_PLAY)
924 ts.activateTimeshift()
927 # same as activateTimeshiftEnd, but pauses afterwards.
928 def activateTimeshiftEndAndPause(self):
929 state = self.seekstate
930 self.activateTimeshiftEnd()
932 # well, this is "andPause", but it could be pressed from pause,
933 # when pausing on the (fake-)"live" picture, so an un-pause
936 print "now, pauseService"
937 if state == self.SEEK_STATE_PLAY:
938 print "is PLAYING, start pause timer"
939 self.ts_pause_timer.start(200, 1)
942 self.unPauseService()
944 def __seekableStatusChanged(self):
947 print "self.isSeekable", self.isSeekable()
948 print "self.timeshift_enabled", self.timeshift_enabled
950 # when this service is not seekable, but timeshift
951 # is enabled, this means we can activate
953 if not self.isSeekable() and self.timeshift_enabled:
956 print "timeshift activate:", enabled
957 self["TimeshiftActivateActions"].setEnabled(enabled)
959 def __serviceStarted(self):
960 self.timeshift_enabled = False
961 self.__seekableStatusChanged()
963 class InfoBarExtensions:
965 self.pipshown = False
967 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
969 #"extensions": (self.extensions, "Extensions..."),
972 def extensions(self):
974 if self.pipshown == False:
975 list.append((_("Activate Picture in Picture"), "pipon"))
976 elif self.pipshown == True:
977 list.append((_("Disable Picture in Picture"), "pipoff"))
978 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
980 def extensionCallback(self, answer):
981 if answer is not None:
982 if answer[1] == "pipon":
983 self.session.nav.stopService()
984 self.pip = self.session.instantiateDialog(PictureInPicture)
987 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
988 self.pipservice = eServiceCenter.getInstance().play(newservice)
989 if self.pipservice and not self.pipservice.setTarget(1):
990 self.pipservice.start()
993 self.pipservice = None
996 elif answer[1] == "pipoff":
998 self.pipservice = None
1000 self.pipshown = False
1002 from RecordTimer import parseEvent
1004 class InfoBarInstantRecord:
1005 """Instant Record - handles the instantRecord action in order to
1006 start/stop instant records"""
1008 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1010 "instantRecord": (self.instantRecord, "Instant Record..."),
1013 self["BlinkingPoint"] = BlinkingPixmapConditional()
1014 self["BlinkingPoint"].hide()
1015 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1017 def stopCurrentRecording(self, entry = -1):
1018 if entry is not None and entry != -1:
1019 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1020 self.recording.remove(self.recording[entry])
1022 def startInstantRecording(self, limitEvent = False):
1023 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1025 # try to get event info
1028 service = self.session.nav.getCurrentService()
1029 epg = eEPGCache.getInstance()
1030 event = epg.lookupEventTime(serviceref, -1, 0)
1032 info = service.info()
1033 ev = info.getEvent(0)
1039 end = time.time() + 3600 * 10
1040 name = "instant record"
1044 if event is not None:
1045 curEvent = parseEvent(event)
1047 description = curEvent[3]
1048 eventid = curEvent[4]
1053 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1055 data = (begin, end, name, description, eventid)
1057 recording = self.session.nav.recordWithTimer(serviceref, *data)
1058 recording.dontSave = True
1059 self.recording.append(recording)
1061 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1063 def isInstantRecordRunning(self):
1064 print "self.recording:", self.recording
1065 if len(self.recording) > 0:
1066 for x in self.recording:
1071 def recordQuestionCallback(self, answer):
1072 print "pre:\n", self.recording
1074 if answer is None or answer[1] == "no":
1077 recording = self.recording[:]
1079 if not x in self.session.nav.RecordTimer.timer_list:
1080 self.recording.remove(x)
1081 elif x.dontSave and x.isRunning():
1082 list.append(TimerEntryComponent(x, False))
1084 if answer[1] == "changeduration":
1085 if len(self.recording) == 1:
1086 self.changeDuration(0)
1088 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1089 elif answer[1] == "stop":
1090 if len(self.recording) == 1:
1091 self.stopCurrentRecording(0)
1093 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1094 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1096 if answer[1] == "event":
1098 if answer[1] == "manualduration":
1099 self.selectedEntry = len(self.recording)
1100 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1101 self.startInstantRecording(limitEvent = limitEvent)
1103 print "after:\n", self.recording
1105 def changeDuration(self, entry):
1106 if entry is not None:
1107 self.selectedEntry = entry
1108 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1110 def inputCallback(self, value):
1111 if value is not None:
1112 print "stopping recording after", int(value), "minutes."
1113 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1114 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1116 def instantRecord(self):
1118 stat = os.stat(resolveFilename(SCOPE_HDD))
1120 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1123 if self.isInstantRecordRunning():
1124 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")])
1126 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")])
1128 from Screens.AudioSelection import AudioSelection
1130 class InfoBarAudioSelection:
1132 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1134 "audioSelection": (self.audioSelection, "Audio Options..."),
1137 def audioSelection(self):
1138 service = self.session.nav.getCurrentService()
1139 audio = service.audioTracks()
1140 n = audio.getNumberOfTracks()
1142 self.session.open(AudioSelection, audio)
1144 from Screens.SubserviceSelection import SubserviceSelection
1146 class InfoBarSubserviceSelection:
1148 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1150 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1153 def subserviceSelection(self):
1154 service = self.session.nav.getCurrentService()
1155 subservices = service.subServices()
1156 n = subservices.getNumberOfSubservices()
1158 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1160 def subserviceSelected(self, service):
1161 if not service is None:
1162 self.session.nav.playService(service)
1164 class InfoBarAdditionalInfo:
1166 self["DolbyActive"] = Pixmap()
1167 self["CryptActive"] = Pixmap()
1168 self["FormatActive"] = Pixmap()
1170 self["ButtonRed"] = PixmapConditional(withTimer = False)
1171 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1172 self.onLayoutFinish.append(self["ButtonRed"].update)
1173 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1174 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1175 self.onLayoutFinish.append(self["ButtonRedText"].update)
1177 self["ButtonGreen"] = Pixmap()
1178 self["ButtonGreenText"] = Label(_("Subservices"))
1180 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1181 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1182 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1183 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1184 self.onLayoutFinish.append(self["ButtonYellow"].update)
1185 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1187 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1188 self["ButtonBlue"].setConnect(lambda: False)
1189 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1190 self["ButtonBlueText"].setConnect(lambda: False)
1191 self.onLayoutFinish.append(self["ButtonBlue"].update)
1192 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1194 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1196 def hideSubServiceIndication(self):
1197 self["ButtonGreen"].hide()
1198 self["ButtonGreenText"].hide()
1200 def showSubServiceIndication(self):
1201 self["ButtonGreen"].show()
1202 self["ButtonGreenText"].show()
1204 def checkFormat(self, service):
1205 info = service.info()
1206 if info is not None:
1207 aspect = info.getInfo(iServiceInformation.sAspect)
1208 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1209 self["FormatActive"].show()
1211 self["FormatActive"].hide()
1213 def checkSubservices(self, service):
1214 if service.subServices().getNumberOfSubservices() > 0:
1215 self.showSubServiceIndication()
1217 self.hideSubServiceIndication()
1219 def checkDolby(self, service):
1222 audio = service.audioTracks()
1223 if audio is not None:
1224 n = audio.getNumberOfTracks()
1226 i = audio.getTrackInfo(x)
1227 description = i.getDescription();
1228 if description.find("AC3") != -1 or description.find("DTS") != -1:
1232 self["DolbyActive"].show()
1234 self["DolbyActive"].hide()
1236 def checkCrypted(self, service):
1237 info = service.info()
1238 if info is not None:
1239 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1240 self["CryptActive"].show()
1242 self["CryptActive"].hide()
1244 def gotServiceEvent(self, ev):
1245 service = self.session.nav.getCurrentService()
1246 if ev == iPlayableService.evUpdatedEventInfo:
1247 self.checkSubservices(service)
1248 self.checkFormat(service)
1249 elif ev == iPlayableService.evUpdatedInfo:
1250 self.checkCrypted(service)
1251 self.checkDolby(service)
1252 elif ev == iPlayableService.evEnd:
1253 self.hideSubServiceIndication()
1254 self["CryptActive"].hide()
1255 self["DolbyActive"].hide()
1256 self["FormatActive"].hide()
1258 class InfoBarNotifications:
1260 self.onExecBegin.append(self.checkNotifications)
1261 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1263 def checkNotificationsIfExecing(self):
1265 self.checkNotifications()
1267 def checkNotifications(self):
1268 if len(Notifications.notifications):
1269 n = Notifications.notifications[0]
1270 Notifications.notifications = Notifications.notifications[1:]
1274 self.session.openWithCallback(cb, *n[1:])
1276 self.session.open(*n[1:])
1278 class InfoBarServiceNotifications:
1280 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1282 iPlayableService.evEnd: self.serviceHasEnded
1285 def serviceHasEnded(self):
1286 print "service end!"
1289 self.setSeekState(self.SEEK_STATE_PLAY)
1293 class InfoBarCueSheetSupport:
1299 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1301 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1302 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1303 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1307 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1309 iPlayableService.evStart: self.__serviceStarted,
1312 def __serviceStarted(self):
1313 print "new service started! trying to download cuts!"
1314 self.downloadCuesheet()
1316 def __getSeekable(self):
1317 service = self.session.nav.getCurrentService()
1320 return service.seek()
1322 def cueGetCurrentPosition(self):
1323 seek = self.__getSeekable()
1326 r = seek.getPlayPosition()
1331 def jumpPreviousNextMark(self, cmp, alternative=None):
1332 current_pos = self.cueGetCurrentPosition()
1333 if current_pos is None:
1335 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1336 if mark is not None:
1338 elif alternative is not None:
1343 seekable = self.__getSeekable()
1344 if seekable is not None:
1345 seekable.seekTo(pts)
1347 def jumpPreviousMark(self):
1348 # we add 2 seconds, so if the play position is <2s after
1349 # the mark, the mark before will be used
1350 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1352 def jumpNextMark(self):
1353 self.jumpPreviousNextMark(lambda x: x)
1355 def getNearestCutPoint(self, pts, cmp=abs):
1358 for cp in self.cut_list:
1359 diff = cmp(cp[0] - pts)
1360 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1364 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1365 current_pos = self.cueGetCurrentPosition()
1366 if current_pos is None:
1367 print "not seekable"
1370 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1372 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1374 return nearest_cutpoint
1376 self.removeMark(nearest_cutpoint)
1377 elif not onlyremove and not onlyreturn:
1378 self.addMark((current_pos, self.CUT_TYPE_MARK))
1383 def addMark(self, point):
1384 bisect.insort(self.cut_list, point)
1385 self.uploadCuesheet()
1387 def removeMark(self, point):
1388 self.cut_list.remove(point)
1389 self.uploadCuesheet()
1391 def __getCuesheet(self):
1392 service = self.session.nav.getCurrentService()
1395 return service.cueSheet()
1397 def uploadCuesheet(self):
1398 cue = self.__getCuesheet()
1401 print "upload failed, no cuesheet interface"
1403 cue.setCutList(self.cut_list)
1405 def downloadCuesheet(self):
1406 cue = self.__getCuesheet()
1409 print "upload failed, no cuesheet interface"
1411 self.cut_list = cue.getCutList()
1413 class InfoBarSummary(Screen):
1415 <screen position="0,0" size="132,64">
1416 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1417 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1420 def __init__(self, session, parent):
1421 Screen.__init__(self, session)
1422 self["CurrentService"] = ServiceName(self.session.nav)
1423 self["Clock"] = Clock()
1425 class InfoBarSummarySupport:
1429 def createSummary(self):
1430 return InfoBarSummary
1432 class InfoBarTeletextPlugin:
1434 self.teletext_plugin = None
1436 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1437 self.teletext_plugin = p
1439 if self.teletext_plugin is not None:
1440 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1442 "startTeletext": (self.startTeletext, "View teletext...")
1445 print "no teletext plugin found!"
1447 def startTeletext(self):
1448 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())