1 from Screen import Screen
2 from Components.ActionMap import ActionMap, HelpableActionMap
3 from Components.ActionMap import NumberActionMap
4 from Components.Label import *
5 from Components.ProgressBar import *
6 from Components.config import configfile, configsequencearg
7 from Components.config import config, configElement, ConfigSubsection, configSequence
8 from ChannelSelection import ChannelSelection, BouquetSelector
10 from Components.Pixmap import Pixmap, PixmapConditional
11 from Components.BlinkingPixmap import BlinkingPixmapConditional
12 from Components.ServiceName import ServiceName
13 from Components.EventInfo import EventInfo, EventInfoProgress
14 from Components.Clock import Clock
16 from ServiceReference import ServiceReference
17 from EpgSelection import EPGSelection
19 from Screens.MessageBox import MessageBox
20 from Screens.ChoiceBox import ChoiceBox
21 from Screens.Dish import Dish
22 from Screens.Standby import Standby
23 from Screens.EventView import EventViewEPGSelect, EventViewSimple
24 from Screens.MinuteInput import MinuteInput
25 from Components.Harddisk import harddiskmanager
27 from Components.ServiceEventTracker import ServiceEventTracker
29 from Tools import Notifications
30 from Tools.Directories import *
32 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
39 from Components.config import config, currentConfigSelectionElement
42 from Menu import MainMenu, mdom
46 self.dishDialog = self.session.instantiateDialog(Dish)
47 self.onLayoutFinish.append(self.dishDialog.show)
49 class InfoBarShowHide:
50 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
58 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
60 "toggleShow": self.toggleShow,
64 self.__state = self.STATE_SHOWN
67 self.onExecBegin.append(self.show)
69 self.hideTimer = eTimer()
70 self.hideTimer.timeout.get().append(self.doTimerHide)
71 self.hideTimer.start(5000, True)
73 self.onShow.append(self.__onShow)
74 self.onHide.append(self.__onHide)
77 self.__state = self.STATE_SHOWN
80 def startHideTimer(self):
81 if self.__state == self.STATE_SHOWN and not self.__locked:
82 self.hideTimer.start(5000, True)
85 self.__state = self.STATE_HIDDEN
91 def doTimerHide(self):
93 if self.__state == self.STATE_SHOWN:
97 if self.__state == self.STATE_SHOWN:
100 elif self.__state == self.STATE_HIDDEN:
104 self.__locked = self.__locked + 1
107 self.hideTimer.stop()
109 def unlockShow(self):
110 self.__locked = self.__locked - 1
112 self.startHideTimer()
114 # def startShow(self):
115 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
116 # self.__state = self.STATE_SHOWN
118 # def startHide(self):
119 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
120 # self.__state = self.STATE_HIDDEN
122 class NumberZap(Screen):
129 self.close(int(self["number"].getText()))
131 def keyNumberGlobal(self, number):
132 self.Timer.start(3000, True) #reset timer
133 self.field = self.field + str(number)
134 self["number"].setText(self.field)
135 if len(self.field) >= 4:
138 def __init__(self, session, number):
139 Screen.__init__(self, session)
140 self.field = str(number)
142 self["channel"] = Label(_("Channel:"))
144 self["number"] = Label(self.field)
146 self["actions"] = NumberActionMap( [ "SetupActions" ],
150 "1": self.keyNumberGlobal,
151 "2": self.keyNumberGlobal,
152 "3": self.keyNumberGlobal,
153 "4": self.keyNumberGlobal,
154 "5": self.keyNumberGlobal,
155 "6": self.keyNumberGlobal,
156 "7": self.keyNumberGlobal,
157 "8": self.keyNumberGlobal,
158 "9": self.keyNumberGlobal,
159 "0": self.keyNumberGlobal
162 self.Timer = eTimer()
163 self.Timer.timeout.get().append(self.keyOK)
164 self.Timer.start(3000, True)
166 class InfoBarPowerKey:
167 """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
170 self.powerKeyTimer = eTimer()
171 self.powerKeyTimer.timeout.get().append(self.powertimer)
172 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
174 "powerdown": self.powerdown,
175 "powerup": self.powerup,
176 "discreteStandby": (self.standby, "Go standby"),
177 "discretePowerOff": (self.quit, "Go to deep standby"),
180 def powertimer(self):
181 print "PowerOff - Now!"
185 self.standbyblocked = 0
186 self.powerKeyTimer.start(3000, True)
189 self.powerKeyTimer.stop()
190 if self.standbyblocked == 0:
191 self.standbyblocked = 1
195 self.session.open(Standby, self)
201 class InfoBarNumberZap:
202 """ Handles an initial number for NumberZapping """
204 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
206 "1": self.keyNumberGlobal,
207 "2": self.keyNumberGlobal,
208 "3": self.keyNumberGlobal,
209 "4": self.keyNumberGlobal,
210 "5": self.keyNumberGlobal,
211 "6": self.keyNumberGlobal,
212 "7": self.keyNumberGlobal,
213 "8": self.keyNumberGlobal,
214 "9": self.keyNumberGlobal,
215 "0": self.keyNumberGlobal,
218 def keyNumberGlobal(self, number):
219 # print "You pressed number " + str(number)
221 self.servicelist.recallPrevService()
224 self.session.openWithCallback(self.numberEntered, NumberZap, number)
226 def numberEntered(self, retval):
227 # print self.servicelist
229 self.zapToNumber(retval)
231 def searchNumberHelper(self, serviceHandler, num, bouquet):
232 servicelist = serviceHandler.list(bouquet)
233 if not servicelist is None:
235 serviceIterator = servicelist.getNext()
236 if not serviceIterator.valid(): #check end of list
238 if serviceIterator.flags: #assume normal dvb service have no flags set
241 if not num: #found service with searched number ?
242 return serviceIterator, 0
245 def zapToNumber(self, number):
246 bouquet = self.servicelist.bouquet_root
248 serviceHandler = eServiceCenter.getInstance()
249 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
250 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
252 bouquetlist = serviceHandler.list(bouquet)
253 if not bouquetlist is None:
255 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
256 if not bouquet.valid(): #check end of list
258 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
260 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
261 if not service is None:
262 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
263 self.servicelist.clearPath()
264 if self.servicelist.bouquet_root != bouquet:
265 self.servicelist.enterPath(self.servicelist.bouquet_root)
266 self.servicelist.enterPath(bouquet)
267 self.servicelist.setCurrentSelection(service) #select the service in servicelist
268 self.servicelist.zap()
270 class InfoBarChannelSelection:
271 """ ChannelSelection - handles the channelSelection dialog and the initial
272 channelChange actions which open the channelSelection dialog """
275 self.servicelist = self.session.instantiateDialog(ChannelSelection)
277 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
279 "switchChannelUp": self.switchChannelUp,
280 "switchChannelDown": self.switchChannelDown,
281 "zapUp": (self.zapUp, _("previous channel")),
282 "zapDown": (self.zapDown, _("next channel")),
283 "historyBack": (self.historyBack, _("previous channel in history")),
284 "historyNext": (self.historyNext, _("next channel in history"))
287 def historyBack(self):
288 self.servicelist.historyBack()
290 def historyNext(self):
291 self.servicelist.historyNext()
293 def switchChannelUp(self):
294 self.servicelist.moveUp()
295 self.session.execDialog(self.servicelist)
297 def switchChannelDown(self):
298 self.servicelist.moveDown()
299 self.session.execDialog(self.servicelist)
302 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
303 if self.servicelist.inBouquet() and self.servicelist.atBegin():
304 self.servicelist.prevBouquet()
305 self.servicelist.moveUp()
306 self.servicelist.zap()
310 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
311 self.servicelist.nextBouquet()
313 self.servicelist.moveDown()
314 self.servicelist.zap()
318 """ Handles a menu action, to open the (main) menu """
320 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
322 "mainMenu": (self.mainMenu, "Enter main menu..."),
326 print "loading mainmenu XML..."
327 menu = mdom.childNodes[0]
328 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
329 self.session.open(MainMenu, menu, menu.childNodes)
331 class InfoBarSimpleEventView:
332 """ Opens the Eventview for now/next """
334 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
336 "showEventInfo": (self.openEventView, _("show event details")),
339 def openEventView(self):
341 service = self.session.nav.getCurrentService()
342 ref = self.session.nav.getCurrentlyPlayingServiceReference()
343 info = service.info()
346 self.epglist.append(ptr)
349 self.epglist.append(ptr)
350 if len(self.epglist) > 0:
351 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
353 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
354 if len(self.epglist) > 1:
355 tmp = self.epglist[0]
356 self.epglist[0]=self.epglist[1]
358 setEvent(self.epglist[0])
361 """ EPG - Opens an EPG list when the showEPGList action fires """
363 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
365 "showEventInfo": (self.openEventView, _("show EPG...")),
368 def zapToService(self, service):
369 if not service is None:
370 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
371 self.servicelist.clearPath()
372 if self.servicelist.bouquet_root != self.epg_bouquet:
373 self.servicelist.enterPath(self.servicelist.bouquet_root)
374 self.servicelist.enterPath(self.epg_bouquet)
375 self.servicelist.setCurrentSelection(service) #select the service in servicelist
376 self.servicelist.zap()
378 def openBouquetEPG(self, bouquet, withCallback=True):
379 ptr=eEPGCache.getInstance()
381 servicelist = eServiceCenter.getInstance().list(bouquet)
382 if not servicelist is None:
384 service = servicelist.getNext()
385 if not service.valid(): #check if end of list
387 if service.flags: #ignore non playable services
389 services.append(ServiceReference(service))
391 self.epg_bouquet = bouquet
393 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
395 self.session.open(EPGSelection, services, self.zapToService)
397 def closed(self, ret):
401 def openMultiServiceEPG(self, withCallback=True):
402 bouquets = self.servicelist.getBouquetList()
407 if cnt > 1: # show bouquet list
409 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
411 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
413 self.openBouquetEPG(bouquets[0][1], withCallback)
415 def openSingleServiceEPG(self):
416 ref=self.session.nav.getCurrentlyPlayingServiceReference()
417 ptr=eEPGCache.getInstance()
418 self.session.openWithCallback(self.closed, EPGSelection, ref)
420 def openEventView(self):
422 service = self.session.nav.getCurrentService()
423 ref = self.session.nav.getCurrentlyPlayingServiceReference()
424 info = service.info()
427 self.epglist.append(ptr)
430 self.epglist.append(ptr)
431 if len(self.epglist) == 0:
432 epg = eEPGCache.getInstance()
433 ptr = epg.lookupEventTime(ref, -1)
435 self.epglist.append(ptr)
436 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
438 self.epglist.append(ptr)
439 if len(self.epglist) > 0:
440 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
442 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
443 self.openMultiServiceEPG(False)
445 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
446 if len(self.epglist) > 1:
447 tmp = self.epglist[0]
448 self.epglist[0]=self.epglist[1]
450 setEvent(self.epglist[0])
455 """provides a snr/agc/ber display"""
457 self["snr"] = Label()
458 self["agc"] = Label()
459 self["ber"] = Label()
460 self["snr_percent"] = Label()
461 self["agc_percent"] = Label()
462 self["ber_count"] = Label()
463 self["snr_progress"] = ProgressBar()
464 self["agc_progress"] = ProgressBar()
465 self["ber_progress"] = ProgressBar()
466 self.timer = eTimer()
467 self.timer.timeout.get().append(self.updateTunerInfo)
468 self.timer.start(1000)
474 return (long)(log(val)/log(2))
477 def updateTunerInfo(self):
478 if self.instance.isVisible():
479 service = self.session.nav.getCurrentService()
483 if service is not None:
484 feinfo = service.frontendStatusInfo()
485 if feinfo is not None:
486 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
487 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
488 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
489 self["snr_percent"].setText("%d%%"%(snr))
490 self["agc_percent"].setText("%d%%"%(agc))
491 self["ber_count"].setText("%d"%(ber))
492 self["snr_progress"].setValue(snr)
493 self["agc_progress"].setValue(agc)
494 self["ber_progress"].setValue(self.calc(ber))
497 """provides a current/next event info display"""
499 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
500 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
502 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
503 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
505 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
506 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
508 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
510 class InfoBarServiceName:
512 self["ServiceName"] = ServiceName(self.session.nav)
515 """handles actions like seeking, pause"""
517 # ispause, isff, issm
518 SEEK_STATE_PLAY = (0, 0, 0, ">")
519 SEEK_STATE_PAUSE = (1, 0, 0, "||")
520 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
521 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
522 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
523 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
524 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
525 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
527 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
528 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
529 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
530 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
532 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
533 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
534 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
537 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
539 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
540 iPlayableService.evStart: self.__serviceStarted,
542 iPlayableService.evEOF: self.__evEOF,
543 iPlayableService.evSOF: self.__evSOF,
546 class InfoBarSeekActionMap(HelpableActionMap):
547 def __init__(self, screen, *args, **kwargs):
548 HelpableActionMap.__init__(self, screen, *args, **kwargs)
551 def action(self, contexts, action):
552 if action[:5] == "seek:":
553 time = int(action[5:])
554 self.screen.seekRelative(time * 90000)
556 HelpableActionMap.action(self, contexts, action)
558 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
560 "pauseService": (self.pauseService, "pause"),
561 "unPauseService": (self.unPauseService, "continue"),
563 "seekFwd": (self.seekFwd, "skip forward"),
564 "seekFwdDown": self.seekFwdDown,
565 "seekFwdUp": self.seekFwdUp,
566 "seekBack": (self.seekBack, "skip backward"),
567 "seekBackDown": self.seekBackDown,
568 "seekBackUp": self.seekBackUp,
570 # give them a little more priority to win over color buttons
572 self.seekstate = self.SEEK_STATE_PLAY
573 self.onClose.append(self.delTimer)
575 self.fwdtimer = False
576 self.fwdKeyTimer = eTimer()
577 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
579 self.rwdtimer = False
580 self.rwdKeyTimer = eTimer()
581 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
583 self.onPlayStateChanged = [ ]
585 self.lockedBecauseOfSkipping = False
598 service = self.session.nav.getCurrentService()
602 seek = service.seek()
604 if seek is None or not seek.isCurrentlySeekable():
609 def isSeekable(self):
610 if self.getSeek() is None:
614 def __seekableStatusChanged(self):
615 print "seekable status changed!"
616 if not self.isSeekable():
617 self["SeekActions"].setEnabled(False)
618 print "not seekable, return to play"
619 self.setSeekState(self.SEEK_STATE_PLAY)
621 self["SeekActions"].setEnabled(True)
624 def __serviceStarted(self):
625 self.seekstate = self.SEEK_STATE_PLAY
627 def setSeekState(self, state):
628 service = self.session.nav.getCurrentService()
633 if not self.isSeekable():
634 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
635 state = self.SEEK_STATE_PLAY
637 pauseable = service.pause()
639 if pauseable is None:
640 print "not pauseable."
641 state = self.SEEK_STATE_PLAY
643 oldstate = self.seekstate
644 self.seekstate = state
647 if oldstate[i] != self.seekstate[i]:
648 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
650 for c in self.onPlayStateChanged:
653 self.checkSkipShowHideLock()
657 def pauseService(self):
658 if self.seekstate == self.SEEK_STATE_PAUSE:
659 print "pause, but in fact unpause"
660 self.unPauseService()
662 if self.seekstate == self.SEEK_STATE_PLAY:
663 print "yes, playing."
665 print "no", self.seekstate
667 self.setSeekState(self.SEEK_STATE_PAUSE);
669 def unPauseService(self):
671 self.setSeekState(self.SEEK_STATE_PLAY);
673 def doSeek(self, seektime):
674 print "doseek", seektime
675 service = self.session.nav.getCurrentService()
679 seekable = self.getSeek()
683 seekable.seekTo(90 * seektime)
685 def seekFwdDown(self):
686 print "start fwd timer"
688 self.fwdKeyTimer.start(1000)
690 def seekBackDown(self):
691 print "start rewind timer"
693 self.rwdKeyTimer.start(1000)
698 self.fwdKeyTimer.stop()
699 self.fwdtimer = False
704 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
705 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
706 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
707 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
708 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
709 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
710 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
711 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
712 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
713 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
714 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
715 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
716 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
717 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
718 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
720 self.setSeekState(lookup[self.seekstate])
722 def seekBackUp(self):
725 self.rwdKeyTimer.stop()
726 self.rwdtimer = False
731 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
732 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
733 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
734 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
735 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
736 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
737 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
738 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
739 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
740 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
741 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
742 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
743 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
744 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
745 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
747 self.setSeekState(lookup[self.seekstate])
749 if self.seekstate == self.SEEK_STATE_PAUSE:
750 seekable = self.getSeek()
751 if seekable is not None:
752 seekable.seekRelative(-1, 3)
754 def fwdTimerFire(self):
755 print "Display seek fwd"
756 self.fwdKeyTimer.stop()
757 self.fwdtimer = False
758 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
760 def fwdSeekTo(self, minutes):
761 print "Seek", minutes, "minutes forward"
763 seekable = self.getSeek()
764 if seekable is not None:
765 seekable.seekRelative(1, minutes * 60 * 90000)
767 def rwdTimerFire(self):
769 self.rwdKeyTimer.stop()
770 self.rwdtimer = False
771 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
773 def rwdSeekTo(self, minutes):
775 self.fwdSeekTo(0 - minutes)
777 def checkSkipShowHideLock(self):
778 wantlock = self.seekstate != self.SEEK_STATE_PLAY
780 if self.lockedBecauseOfSkipping and not wantlock:
782 self.lockedBecauseOfSkipping = False
784 if wantlock and not self.lockedBecauseOfSkipping:
786 self.lockedBecauseOfSkipping = True
789 if self.seekstate != self.SEEK_STATE_PLAY:
790 self.setSeekState(self.SEEK_STATE_PAUSE)
792 #self.getSeek().seekRelative(1, -90000)
793 self.setSeekState(self.SEEK_STATE_PLAY)
795 self.setSeekState(self.SEEK_STATE_PAUSE)
798 self.setSeekState(self.SEEK_STATE_PLAY)
801 def seekRelative(self, diff):
802 seekable = self.getSeek()
803 if seekable is not None:
804 seekable.seekRelative(1, diff)
806 from Screens.PVRState import PVRState
808 class InfoBarPVRState:
810 self.onPlayStateChanged.append(self.__playStateChanged)
811 self.pvrStateDialog = self.session.instantiateDialog(PVRState)
812 self.onShow.append(self.__mayShow)
813 self.onHide.append(self.pvrStateDialog.hide)
816 if self.seekstate != self.SEEK_STATE_PLAY:
817 self.pvrStateDialog.show()
819 def __playStateChanged(self, state):
820 playstateString = state[3]
821 self.pvrStateDialog["state"].setText(playstateString)
824 class InfoBarShowMovies:
826 # i don't really like this class.
827 # it calls a not further specified "movie list" on up/down/movieList,
828 # so this is not more than an action map
830 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
832 "movieList": (self.showMovies, "movie list"),
833 "up": (self.showMovies, "movie list"),
834 "down": (self.showMovies, "movie list")
837 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
841 # Timeshift works the following way:
842 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
843 # - normal playback TUNER unused PLAY enable disable disable
844 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
845 # - user presess pause again FILE record PLAY enable disable enable
846 # - user fast forwards FILE record FF enable disable enable
847 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
848 # - user backwards FILE record BACK # !! enable disable enable
852 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
853 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
854 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
855 # - the user can now PVR around
856 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
857 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
859 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
860 # - if the user rewinds, or press pause, timeshift will be activated again
862 # note that a timeshift can be enabled ("recording") and
863 # activated (currently time-shifting).
865 class InfoBarTimeshift:
867 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
869 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
870 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
872 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
874 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
875 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
876 }, prio=-1) # priority over record
878 self.timeshift_enabled = 0
879 self.timeshift_state = 0
880 self.ts_pause_timer = eTimer()
881 self.ts_pause_timer.timeout.get().append(self.pauseService)
883 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
885 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
888 def getTimeshift(self):
889 service = self.session.nav.getCurrentService()
890 return service.timeshift()
892 def startTimeshift(self):
893 print "enable timeshift"
894 ts = self.getTimeshift()
896 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
897 print "no ts interface"
900 if self.timeshift_enabled:
901 print "hu, timeshift already enabled?"
903 if not ts.startTimeshift():
904 self.timeshift_enabled = 1
907 self.setSeekState(self.SEEK_STATE_PAUSE)
909 # enable the "TimeshiftEnableActions", which will override
910 # the startTimeshift actions
911 self.__seekableStatusChanged()
913 print "timeshift failed"
915 def stopTimeshift(self):
916 if not self.timeshift_enabled:
918 print "disable timeshift"
919 ts = self.getTimeshift()
922 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
924 def stopTimeshiftConfirmed(self, confirmed):
928 ts = self.getTimeshift()
933 self.timeshift_enabled = 0
936 self.__seekableStatusChanged()
938 # activates timeshift, and seeks to (almost) the end
939 def activateTimeshiftEnd(self):
940 ts = self.getTimeshift()
945 if ts.isTimeshiftActive():
946 print "!! activate timeshift called - but shouldn't this be a normal pause?"
949 self.setSeekState(self.SEEK_STATE_PLAY)
950 ts.activateTimeshift()
953 # same as activateTimeshiftEnd, but pauses afterwards.
954 def activateTimeshiftEndAndPause(self):
955 state = self.seekstate
956 self.activateTimeshiftEnd()
958 # well, this is "andPause", but it could be pressed from pause,
959 # when pausing on the (fake-)"live" picture, so an un-pause
962 print "now, pauseService"
963 if state == self.SEEK_STATE_PLAY:
964 print "is PLAYING, start pause timer"
965 self.ts_pause_timer.start(200, 1)
968 self.unPauseService()
970 def __seekableStatusChanged(self):
973 print "self.isSeekable", self.isSeekable()
974 print "self.timeshift_enabled", self.timeshift_enabled
976 # when this service is not seekable, but timeshift
977 # is enabled, this means we can activate
979 if not self.isSeekable() and self.timeshift_enabled:
982 print "timeshift activate:", enabled
983 self["TimeshiftActivateActions"].setEnabled(enabled)
985 from RecordTimer import parseEvent
987 class InfoBarInstantRecord:
988 """Instant Record - handles the instantRecord action in order to
989 start/stop instant records"""
991 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
993 "instantRecord": (self.instantRecord, "Instant Record..."),
995 self.recording = None
996 self["BlinkingPoint"] = BlinkingPixmapConditional()
997 self["BlinkingPoint"].hide()
998 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1000 def stopCurrentRecording(self):
1001 self.session.nav.RecordTimer.removeEntry(self.recording)
1002 self.recording = None
1004 def startInstantRecording(self, limitEvent = False):
1005 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1007 # try to get event info
1011 service = self.session.nav.getCurrentService()
1012 epg = eEPGCache.getInstance()
1013 event = epg.lookupEventTime(serviceref, -1, 0)
1015 info = service.info()
1016 ev = info.getEvent(0)
1021 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1023 if event is not None:
1024 data = parseEvent(event)
1026 end = begin + 3600 * 10
1027 data = (begin, end, data[2], data[3], data[4])
1029 data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
1031 # fix me, description.
1032 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
1033 self.recording.dontSave = True
1035 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1037 def isInstantRecordRunning(self):
1038 if self.recording != None:
1039 if self.recording.isRunning():
1043 def recordQuestionCallback(self, answer):
1044 if answer is None or answer[1] == "no":
1047 if self.isInstantRecordRunning():
1048 self.stopCurrentRecording()
1051 if answer[1] == "event":
1053 self.startInstantRecording(limitEvent = limitEvent)
1055 def instantRecord(self):
1057 stat = os.stat(resolveFilename(SCOPE_HDD))
1059 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1062 if self.isInstantRecordRunning():
1063 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Do you want to stop the current\n(instant) recording?"), list=[(_("yes"), "yes"), (_("no"), "no")])
1064 # self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
1066 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Do you want to stop the current\n(instant) recording?"), list=[(_("record indefinitely"), "indefinitely"), (_("stop after current event"), "event"), (_("don't record"), "no")])
1067 #self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
1069 from Screens.AudioSelection import AudioSelection
1071 class InfoBarAudioSelection:
1073 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1075 "audioSelection": (self.audioSelection, "Audio Options..."),
1078 def audioSelection(self):
1079 service = self.session.nav.getCurrentService()
1080 audio = service.audioTracks()
1081 n = audio.getNumberOfTracks()
1083 self.session.open(AudioSelection, audio)
1085 from Screens.SubserviceSelection import SubserviceSelection
1087 class InfoBarSubserviceSelection:
1089 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1091 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1094 def subserviceSelection(self):
1095 service = self.session.nav.getCurrentService()
1096 subservices = service.subServices()
1097 n = subservices.getNumberOfSubservices()
1099 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1101 def subserviceSelected(self, service):
1102 if not service is None:
1103 self.session.nav.playService(service)
1105 class InfoBarAdditionalInfo:
1107 self["DolbyActive"] = Pixmap()
1108 self["CryptActive"] = Pixmap()
1109 self["FormatActive"] = Pixmap()
1111 self["ButtonRed"] = PixmapConditional(withTimer = False)
1112 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1113 self.onLayoutFinish.append(self["ButtonRed"].update)
1114 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1115 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1116 self.onLayoutFinish.append(self["ButtonRedText"].update)
1118 self["ButtonGreen"] = Pixmap()
1119 self["ButtonGreenText"] = Label(_("Subservices"))
1121 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1122 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1123 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1124 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1125 self.onLayoutFinish.append(self["ButtonYellow"].update)
1126 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1128 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1129 self["ButtonBlue"].setConnect(lambda: False)
1130 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1131 self["ButtonBlueText"].setConnect(lambda: False)
1132 self.onLayoutFinish.append(self["ButtonBlue"].update)
1133 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1135 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1137 def hideSubServiceIndication(self):
1138 self["ButtonGreen"].hide()
1139 self["ButtonGreenText"].hide()
1141 def showSubServiceIndication(self):
1142 self["ButtonGreen"].show()
1143 self["ButtonGreenText"].show()
1145 def checkFormat(self, service):
1146 info = service.info()
1147 if info is not None:
1148 aspect = info.getInfo(iServiceInformation.sAspect)
1149 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1150 self["FormatActive"].show()
1152 self["FormatActive"].hide()
1154 def checkSubservices(self, service):
1155 if service.subServices().getNumberOfSubservices() > 0:
1156 self.showSubServiceIndication()
1158 self.hideSubServiceIndication()
1160 def checkDolby(self, service):
1163 audio = service.audioTracks()
1164 if audio is not None:
1165 n = audio.getNumberOfTracks()
1167 i = audio.getTrackInfo(x)
1168 description = i.getDescription();
1169 if description.find("AC3") != -1 or description.find("DTS") != -1:
1173 self["DolbyActive"].show()
1175 self["DolbyActive"].hide()
1177 def checkCrypted(self, service):
1178 info = service.info()
1179 if info is not None:
1180 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1181 self["CryptActive"].show()
1183 self["CryptActive"].hide()
1185 def gotServiceEvent(self, ev):
1186 service = self.session.nav.getCurrentService()
1187 if ev == iPlayableService.evUpdatedEventInfo:
1188 self.checkSubservices(service)
1189 self.checkFormat(service)
1190 elif ev == iPlayableService.evUpdatedInfo:
1191 self.checkCrypted(service)
1192 self.checkDolby(service)
1193 elif ev == iPlayableService.evEnd:
1194 self.hideSubServiceIndication()
1195 self["CryptActive"].hide()
1196 self["DolbyActive"].hide()
1197 self["FormatActive"].hide()
1199 class InfoBarNotifications:
1201 self.onExecBegin.append(self.checkNotifications)
1202 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1204 def checkNotificationsIfExecing(self):
1206 self.checkNotifications()
1208 def checkNotifications(self):
1209 if len(Notifications.notifications):
1210 n = Notifications.notifications[0]
1211 Notifications.notifications = Notifications.notifications[1:]
1215 self.session.openWithCallback(cb, *n[1:])
1217 self.session.open(*n[1:])
1219 class InfoBarServiceNotifications:
1221 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1223 iPlayableService.evEnd: self.serviceHasEnded
1226 def serviceHasEnded(self):
1227 print "service end!"
1230 self.setSeekState(self.SEEK_STATE_PLAY)
1234 class InfoBarCueSheetSupport:
1240 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1242 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1243 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1244 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1248 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1250 iPlayableService.evStart: self.__serviceStarted,
1253 def __serviceStarted(self):
1254 print "new service started! trying to download cuts!"
1255 self.downloadCuesheet()
1257 def __getSeekable(self):
1258 service = self.session.nav.getCurrentService()
1261 return service.seek()
1263 def cueGetCurrentPosition(self):
1264 seek = self.__getSeekable()
1267 r = seek.getPlayPosition()
1272 def jumpPreviousNextMark(self, cmp, alternative=None):
1273 current_pos = self.cueGetCurrentPosition()
1274 if current_pos is None:
1276 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1277 if mark is not None:
1279 elif alternative is not None:
1284 seekable = self.__getSeekable()
1285 if seekable is not None:
1286 seekable.seekTo(pts)
1288 def jumpPreviousMark(self):
1289 # we add 2 seconds, so if the play position is <2s after
1290 # the mark, the mark before will be used
1291 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1293 def jumpNextMark(self):
1294 self.jumpPreviousNextMark(lambda x: x)
1296 def getNearestCutPoint(self, pts, cmp=abs):
1299 for cp in self.cut_list:
1300 diff = cmp(cp[0] - pts)
1301 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1305 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1306 current_pos = self.cueGetCurrentPosition()
1307 if current_pos is None:
1308 print "not seekable"
1311 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1313 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1315 return nearest_cutpoint
1317 self.removeMark(nearest_cutpoint)
1318 elif not onlyremove and not onlyreturn:
1319 self.addMark((current_pos, self.CUT_TYPE_MARK))
1324 def addMark(self, point):
1325 bisect.insort(self.cut_list, point)
1326 self.uploadCuesheet()
1328 def removeMark(self, point):
1329 self.cut_list.remove(point)
1330 self.uploadCuesheet()
1332 def __getCuesheet(self):
1333 service = self.session.nav.getCurrentService()
1336 return service.cueSheet()
1338 def uploadCuesheet(self):
1339 cue = self.__getCuesheet()
1342 print "upload failed, no cuesheet interface"
1344 cue.setCutList(self.cut_list)
1346 def downloadCuesheet(self):
1347 cue = self.__getCuesheet()
1350 print "upload failed, no cuesheet interface"
1352 self.cut_list = cue.getCutList()
1354 class InfoBarSummary(Screen):
1356 <screen position="0,0" size="132,64">
1357 <widget name="Clock" position="50,46" size="82,18" font="Regular;19" />
1358 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;19" />
1361 def __init__(self, session, parent):
1362 Screen.__init__(self, session)
1363 self["CurrentService"] = ServiceName(self.session.nav)
1364 self["Clock"] = Clock()
1366 class InfoBarSummarySupport:
1370 def createSummary(self):
1371 return InfoBarSummary