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, configElementBoolean
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
15 from Components.Input import Input
17 from ServiceReference import ServiceReference
18 from EpgSelection import EPGSelection
20 from Screens.MessageBox import MessageBox
21 from Screens.ChoiceBox import ChoiceBox
22 from Screens.InputBox import InputBox
23 from Screens.Dish import Dish
24 from Screens.Standby import Standby
25 from Screens.EventView import EventViewEPGSelect, EventViewSimple
26 from Screens.MinuteInput import MinuteInput
27 from Components.Harddisk import harddiskmanager
29 from Components.ServiceEventTracker import ServiceEventTracker
31 from Tools import Notifications
32 from Tools.Directories import *
34 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
41 from Components.config import config, currentConfigSelectionElement
44 from Menu import MainMenu, mdom
48 self.dishDialog = self.session.instantiateDialog(Dish)
49 self.onLayoutFinish.append(self.dishDialog.show)
51 class InfoBarShowHide:
52 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
60 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
62 "toggleShow": self.toggleShow,
66 self.__state = self.STATE_SHOWN
69 self.onExecBegin.append(self.show)
71 self.hideTimer = eTimer()
72 self.hideTimer.timeout.get().append(self.doTimerHide)
73 self.hideTimer.start(5000, True)
75 self.onShow.append(self.__onShow)
76 self.onHide.append(self.__onHide)
79 self.__state = self.STATE_SHOWN
82 def startHideTimer(self):
83 if self.__state == self.STATE_SHOWN and not self.__locked:
84 self.hideTimer.start(5000, True)
87 self.__state = self.STATE_HIDDEN
93 def doTimerHide(self):
95 if self.__state == self.STATE_SHOWN:
99 if self.__state == self.STATE_SHOWN:
101 self.hideTimer.stop()
102 elif self.__state == self.STATE_HIDDEN:
106 self.__locked = self.__locked + 1
109 self.hideTimer.stop()
111 def unlockShow(self):
112 self.__locked = self.__locked - 1
114 self.startHideTimer()
116 # def startShow(self):
117 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
118 # self.__state = self.STATE_SHOWN
120 # def startHide(self):
121 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
122 # self.__state = self.STATE_HIDDEN
124 class NumberZap(Screen):
131 self.close(int(self["number"].getText()))
133 def keyNumberGlobal(self, number):
134 self.Timer.start(3000, True) #reset timer
135 self.field = self.field + str(number)
136 self["number"].setText(self.field)
137 if len(self.field) >= 4:
140 def __init__(self, session, number):
141 Screen.__init__(self, session)
142 self.field = str(number)
144 self["channel"] = Label(_("Channel:"))
146 self["number"] = Label(self.field)
148 self["actions"] = NumberActionMap( [ "SetupActions" ],
152 "1": self.keyNumberGlobal,
153 "2": self.keyNumberGlobal,
154 "3": self.keyNumberGlobal,
155 "4": self.keyNumberGlobal,
156 "5": self.keyNumberGlobal,
157 "6": self.keyNumberGlobal,
158 "7": self.keyNumberGlobal,
159 "8": self.keyNumberGlobal,
160 "9": self.keyNumberGlobal,
161 "0": self.keyNumberGlobal
164 self.Timer = eTimer()
165 self.Timer.timeout.get().append(self.keyOK)
166 self.Timer.start(3000, True)
168 class InfoBarPowerKey:
169 """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
172 self.powerKeyTimer = eTimer()
173 self.powerKeyTimer.timeout.get().append(self.powertimer)
174 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
176 "powerdown": self.powerdown,
177 "powerup": self.powerup,
178 "discreteStandby": (self.standby, "Go standby"),
179 "discretePowerOff": (self.quit, "Go to deep standby"),
182 def powertimer(self):
183 print "PowerOff - Now!"
187 self.standbyblocked = 0
188 self.powerKeyTimer.start(3000, True)
191 self.powerKeyTimer.stop()
192 if self.standbyblocked == 0:
193 self.standbyblocked = 1
197 self.session.open(Standby, self)
203 class InfoBarNumberZap:
204 """ Handles an initial number for NumberZapping """
206 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
208 "1": self.keyNumberGlobal,
209 "2": self.keyNumberGlobal,
210 "3": self.keyNumberGlobal,
211 "4": self.keyNumberGlobal,
212 "5": self.keyNumberGlobal,
213 "6": self.keyNumberGlobal,
214 "7": self.keyNumberGlobal,
215 "8": self.keyNumberGlobal,
216 "9": self.keyNumberGlobal,
217 "0": self.keyNumberGlobal,
220 def keyNumberGlobal(self, number):
221 # print "You pressed number " + str(number)
223 self.servicelist.recallPrevService()
226 self.session.openWithCallback(self.numberEntered, NumberZap, number)
228 def numberEntered(self, retval):
229 # print self.servicelist
231 self.zapToNumber(retval)
233 def searchNumberHelper(self, serviceHandler, num, bouquet):
234 servicelist = serviceHandler.list(bouquet)
235 if not servicelist is None:
237 serviceIterator = servicelist.getNext()
238 if not serviceIterator.valid(): #check end of list
240 if serviceIterator.flags: #assume normal dvb service have no flags set
243 if not num: #found service with searched number ?
244 return serviceIterator, 0
247 def zapToNumber(self, number):
248 bouquet = self.servicelist.bouquet_root
250 serviceHandler = eServiceCenter.getInstance()
251 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
252 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
254 bouquetlist = serviceHandler.list(bouquet)
255 if not bouquetlist is None:
257 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
258 if not bouquet.valid(): #check end of list
260 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
262 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
263 if not service is None:
264 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
265 self.servicelist.clearPath()
266 if self.servicelist.bouquet_root != bouquet:
267 self.servicelist.enterPath(self.servicelist.bouquet_root)
268 self.servicelist.enterPath(bouquet)
269 self.servicelist.setCurrentSelection(service) #select the service in servicelist
270 self.servicelist.zap()
272 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
274 class InfoBarChannelSelection:
275 """ ChannelSelection - handles the channelSelection dialog and the initial
276 channelChange actions which open the channelSelection dialog """
279 self.servicelist = self.session.instantiateDialog(ChannelSelection)
281 if config.misc.initialchannelselection.value == 1:
282 self.onShown.append(self.firstRun)
284 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
286 "switchChannelUp": self.switchChannelUp,
287 "switchChannelDown": self.switchChannelDown,
288 "zapUp": (self.zapUp, _("previous channel")),
289 "zapDown": (self.zapDown, _("next channel")),
290 "historyBack": (self.historyBack, _("previous channel in history")),
291 "historyNext": (self.historyNext, _("next channel in history"))
295 self.onShown.remove(self.firstRun)
296 config.misc.initialchannelselection.value = 0
297 config.misc.initialchannelselection.save()
298 self.switchChannelDown()
300 def historyBack(self):
301 self.servicelist.historyBack()
303 def historyNext(self):
304 self.servicelist.historyNext()
306 def switchChannelUp(self):
307 self.servicelist.moveUp()
308 self.session.execDialog(self.servicelist)
310 def switchChannelDown(self):
311 self.servicelist.moveDown()
312 self.session.execDialog(self.servicelist)
315 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
316 if self.servicelist.inBouquet() and self.servicelist.atBegin():
317 self.servicelist.prevBouquet()
318 self.servicelist.moveUp()
319 self.servicelist.zap()
323 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
324 self.servicelist.nextBouquet()
326 self.servicelist.moveDown()
327 self.servicelist.zap()
331 """ Handles a menu action, to open the (main) menu """
333 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
335 "mainMenu": (self.mainMenu, "Enter main menu..."),
339 print "loading mainmenu XML..."
340 menu = mdom.childNodes[0]
341 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
342 self.session.open(MainMenu, menu, menu.childNodes)
344 class InfoBarSimpleEventView:
345 """ Opens the Eventview for now/next """
347 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
349 "showEventInfo": (self.openEventView, _("show event details")),
352 def openEventView(self):
354 service = self.session.nav.getCurrentService()
355 ref = self.session.nav.getCurrentlyPlayingServiceReference()
356 info = service.info()
359 self.epglist.append(ptr)
362 self.epglist.append(ptr)
363 if len(self.epglist) > 0:
364 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
366 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
367 if len(self.epglist) > 1:
368 tmp = self.epglist[0]
369 self.epglist[0]=self.epglist[1]
371 setEvent(self.epglist[0])
374 """ EPG - Opens an EPG list when the showEPGList action fires """
376 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
378 "showEventInfo": (self.openEventView, _("show EPG...")),
381 def zapToService(self, service):
382 if not service is None:
383 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
384 self.servicelist.clearPath()
385 if self.servicelist.bouquet_root != self.epg_bouquet:
386 self.servicelist.enterPath(self.servicelist.bouquet_root)
387 self.servicelist.enterPath(self.epg_bouquet)
388 self.servicelist.setCurrentSelection(service) #select the service in servicelist
389 self.servicelist.zap()
391 def openBouquetEPG(self, bouquet, withCallback=True):
392 ptr=eEPGCache.getInstance()
394 servicelist = eServiceCenter.getInstance().list(bouquet)
395 if not servicelist is None:
397 service = servicelist.getNext()
398 if not service.valid(): #check if end of list
400 if service.flags: #ignore non playable services
402 services.append(ServiceReference(service))
404 self.epg_bouquet = bouquet
406 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
408 self.session.open(EPGSelection, services, self.zapToService)
410 def closed(self, ret):
414 def openMultiServiceEPG(self, withCallback=True):
415 bouquets = self.servicelist.getBouquetList()
420 if cnt > 1: # show bouquet list
422 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
424 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
426 self.openBouquetEPG(bouquets[0][1], withCallback)
428 def openSingleServiceEPG(self):
429 ref=self.session.nav.getCurrentlyPlayingServiceReference()
430 ptr=eEPGCache.getInstance()
431 self.session.openWithCallback(self.closed, EPGSelection, ref)
433 def openEventView(self):
435 service = self.session.nav.getCurrentService()
436 ref = self.session.nav.getCurrentlyPlayingServiceReference()
437 info = service.info()
440 self.epglist.append(ptr)
443 self.epglist.append(ptr)
444 if len(self.epglist) == 0:
445 epg = eEPGCache.getInstance()
446 ptr = epg.lookupEventTime(ref, -1)
448 self.epglist.append(ptr)
449 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
451 self.epglist.append(ptr)
452 if len(self.epglist) > 0:
453 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
455 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
456 self.openMultiServiceEPG(False)
458 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
459 if len(self.epglist) > 1:
460 tmp = self.epglist[0]
461 self.epglist[0]=self.epglist[1]
463 setEvent(self.epglist[0])
468 """provides a snr/agc/ber display"""
470 self["snr"] = Label()
471 self["agc"] = Label()
472 self["ber"] = Label()
473 self["snr_percent"] = Label()
474 self["agc_percent"] = Label()
475 self["ber_count"] = Label()
476 self["snr_progress"] = ProgressBar()
477 self["agc_progress"] = ProgressBar()
478 self["ber_progress"] = ProgressBar()
479 self.timer = eTimer()
480 self.timer.timeout.get().append(self.updateTunerInfo)
481 self.timer.start(1000)
487 return (long)(log(val)/log(2))
490 def updateTunerInfo(self):
491 if self.instance.isVisible():
492 service = self.session.nav.getCurrentService()
496 if service is not None:
497 feinfo = service.frontendStatusInfo()
498 if feinfo is not None:
499 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
500 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
501 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
502 self["snr_percent"].setText("%d%%"%(snr))
503 self["agc_percent"].setText("%d%%"%(agc))
504 self["ber_count"].setText("%d"%(ber))
505 self["snr_progress"].setValue(snr)
506 self["agc_progress"].setValue(agc)
507 self["ber_progress"].setValue(self.calc(ber))
510 """provides a current/next event info display"""
512 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
513 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
515 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
516 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
518 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
519 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
521 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
523 class InfoBarServiceName:
525 self["ServiceName"] = ServiceName(self.session.nav)
528 """handles actions like seeking, pause"""
530 # ispause, isff, issm
531 SEEK_STATE_PLAY = (0, 0, 0, ">")
532 SEEK_STATE_PAUSE = (1, 0, 0, "||")
533 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
534 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
535 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
536 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
537 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
538 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
540 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
541 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
542 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
543 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
545 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
546 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
547 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
550 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
552 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
553 iPlayableService.evStart: self.__serviceStarted,
555 iPlayableService.evEOF: self.__evEOF,
556 iPlayableService.evSOF: self.__evSOF,
559 class InfoBarSeekActionMap(HelpableActionMap):
560 def __init__(self, screen, *args, **kwargs):
561 HelpableActionMap.__init__(self, screen, *args, **kwargs)
564 def action(self, contexts, action):
565 if action[:5] == "seek:":
566 time = int(action[5:])
567 self.screen.seekRelative(time * 90000)
570 return HelpableActionMap.action(self, contexts, action)
572 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
574 "pauseService": (self.pauseService, "pause"),
575 "unPauseService": (self.unPauseService, "continue"),
577 "seekFwd": (self.seekFwd, "skip forward"),
578 "seekFwdDown": self.seekFwdDown,
579 "seekFwdUp": self.seekFwdUp,
580 "seekBack": (self.seekBack, "skip backward"),
581 "seekBackDown": self.seekBackDown,
582 "seekBackUp": self.seekBackUp,
584 # give them a little more priority to win over color buttons
586 self.seekstate = self.SEEK_STATE_PLAY
587 self.onClose.append(self.delTimer)
589 self.fwdtimer = False
590 self.fwdKeyTimer = eTimer()
591 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
593 self.rwdtimer = False
594 self.rwdKeyTimer = eTimer()
595 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
597 self.onPlayStateChanged = [ ]
599 self.lockedBecauseOfSkipping = False
612 service = self.session.nav.getCurrentService()
616 seek = service.seek()
618 if seek is None or not seek.isCurrentlySeekable():
623 def isSeekable(self):
624 if self.getSeek() is None:
628 def __seekableStatusChanged(self):
629 print "seekable status changed!"
630 if not self.isSeekable():
631 self["SeekActions"].setEnabled(False)
632 print "not seekable, return to play"
633 self.setSeekState(self.SEEK_STATE_PLAY)
635 self["SeekActions"].setEnabled(True)
638 def __serviceStarted(self):
639 self.seekstate = self.SEEK_STATE_PLAY
641 def setSeekState(self, state):
642 service = self.session.nav.getCurrentService()
647 if not self.isSeekable():
648 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
649 state = self.SEEK_STATE_PLAY
651 pauseable = service.pause()
653 if pauseable is None:
654 print "not pauseable."
655 state = self.SEEK_STATE_PLAY
657 oldstate = self.seekstate
658 self.seekstate = state
661 if oldstate[i] != self.seekstate[i]:
662 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
664 for c in self.onPlayStateChanged:
667 self.checkSkipShowHideLock()
671 def pauseService(self):
672 if self.seekstate == self.SEEK_STATE_PAUSE:
673 print "pause, but in fact unpause"
674 self.unPauseService()
676 if self.seekstate == self.SEEK_STATE_PLAY:
677 print "yes, playing."
679 print "no", self.seekstate
681 self.setSeekState(self.SEEK_STATE_PAUSE);
683 def unPauseService(self):
685 self.setSeekState(self.SEEK_STATE_PLAY);
687 def doSeek(self, seektime):
688 print "doseek", seektime
689 service = self.session.nav.getCurrentService()
693 seekable = self.getSeek()
697 seekable.seekTo(90 * seektime)
699 def seekFwdDown(self):
700 print "start fwd timer"
702 self.fwdKeyTimer.start(1000)
704 def seekBackDown(self):
705 print "start rewind timer"
707 self.rwdKeyTimer.start(1000)
712 self.fwdKeyTimer.stop()
713 self.fwdtimer = False
718 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
719 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
720 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
721 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
722 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
723 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
724 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
725 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
726 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
727 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
728 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
729 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
730 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
731 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
732 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
734 self.setSeekState(lookup[self.seekstate])
736 def seekBackUp(self):
739 self.rwdKeyTimer.stop()
740 self.rwdtimer = False
745 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
746 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
747 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
748 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
749 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
750 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
751 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
752 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
753 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
754 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
755 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
756 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
757 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
758 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
759 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
761 self.setSeekState(lookup[self.seekstate])
763 if self.seekstate == self.SEEK_STATE_PAUSE:
764 seekable = self.getSeek()
765 if seekable is not None:
766 seekable.seekRelative(-1, 3)
768 def fwdTimerFire(self):
769 print "Display seek fwd"
770 self.fwdKeyTimer.stop()
771 self.fwdtimer = False
772 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
774 def fwdSeekTo(self, minutes):
775 print "Seek", minutes, "minutes forward"
777 seekable = self.getSeek()
778 if seekable is not None:
779 seekable.seekRelative(1, minutes * 60 * 90000)
781 def rwdTimerFire(self):
783 self.rwdKeyTimer.stop()
784 self.rwdtimer = False
785 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
787 def rwdSeekTo(self, minutes):
789 self.fwdSeekTo(0 - minutes)
791 def checkSkipShowHideLock(self):
792 wantlock = self.seekstate != self.SEEK_STATE_PLAY
794 if self.lockedBecauseOfSkipping and not wantlock:
796 self.lockedBecauseOfSkipping = False
798 if wantlock and not self.lockedBecauseOfSkipping:
800 self.lockedBecauseOfSkipping = True
803 if self.seekstate != self.SEEK_STATE_PLAY:
804 self.setSeekState(self.SEEK_STATE_PAUSE)
806 #self.getSeek().seekRelative(1, -90000)
807 self.setSeekState(self.SEEK_STATE_PLAY)
809 self.setSeekState(self.SEEK_STATE_PAUSE)
812 self.setSeekState(self.SEEK_STATE_PLAY)
815 def seekRelative(self, diff):
816 seekable = self.getSeek()
817 if seekable is not None:
818 seekable.seekRelative(1, diff)
820 from Screens.PVRState import PVRState, TimeshiftState
822 class InfoBarPVRState:
823 def __init__(self, screen=PVRState):
824 self.onPlayStateChanged.append(self.__playStateChanged)
825 self.pvrStateDialog = self.session.instantiateDialog(screen)
826 self.onShow.append(self.__mayShow)
827 self.onHide.append(self.pvrStateDialog.hide)
830 if self.seekstate != self.SEEK_STATE_PLAY:
831 self.pvrStateDialog.show()
833 def __playStateChanged(self, state):
834 playstateString = state[3]
835 self.pvrStateDialog["state"].setText(playstateString)
838 class InfoBarTimeshiftState(InfoBarPVRState):
840 InfoBarPVRState.__init__(self, screen=TimeshiftState)
843 class InfoBarShowMovies:
845 # i don't really like this class.
846 # it calls a not further specified "movie list" on up/down/movieList,
847 # so this is not more than an action map
849 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
851 "movieList": (self.showMovies, "movie list"),
852 "up": (self.showMovies, "movie list"),
853 "down": (self.showMovies, "movie list")
856 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
860 # Timeshift works the following way:
861 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
862 # - normal playback TUNER unused PLAY enable disable disable
863 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
864 # - user presess pause again FILE record PLAY enable disable enable
865 # - user fast forwards FILE record FF enable disable enable
866 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
867 # - user backwards FILE record BACK # !! enable disable enable
871 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
872 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
873 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
874 # - the user can now PVR around
875 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
876 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
878 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
879 # - if the user rewinds, or press pause, timeshift will be activated again
881 # note that a timeshift can be enabled ("recording") and
882 # activated (currently time-shifting).
884 class InfoBarTimeshift:
886 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
888 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
889 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
891 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
893 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
894 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
895 }, prio=-1) # priority over record
897 self.timeshift_enabled = 0
898 self.timeshift_state = 0
899 self.ts_pause_timer = eTimer()
900 self.ts_pause_timer.timeout.get().append(self.pauseService)
902 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
904 iPlayableService.evStart: self.__serviceStarted,
905 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
908 def getTimeshift(self):
909 service = self.session.nav.getCurrentService()
910 return service.timeshift()
912 def startTimeshift(self):
913 print "enable timeshift"
914 ts = self.getTimeshift()
916 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
917 print "no ts interface"
920 if self.timeshift_enabled:
921 print "hu, timeshift already enabled?"
923 if not ts.startTimeshift():
925 self.timeshift_enabled = 1
926 self.pvrStateDialog["timeshift"].setRelative(time.time())
929 self.setSeekState(self.SEEK_STATE_PAUSE)
931 # enable the "TimeshiftEnableActions", which will override
932 # the startTimeshift actions
933 self.__seekableStatusChanged()
935 print "timeshift failed"
937 def stopTimeshift(self):
938 if not self.timeshift_enabled:
940 print "disable timeshift"
941 ts = self.getTimeshift()
944 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
946 def stopTimeshiftConfirmed(self, confirmed):
950 ts = self.getTimeshift()
955 self.timeshift_enabled = 0
958 self.__seekableStatusChanged()
960 # activates timeshift, and seeks to (almost) the end
961 def activateTimeshiftEnd(self):
962 ts = self.getTimeshift()
967 if ts.isTimeshiftActive():
968 print "!! activate timeshift called - but shouldn't this be a normal pause?"
971 self.setSeekState(self.SEEK_STATE_PLAY)
972 ts.activateTimeshift()
975 # same as activateTimeshiftEnd, but pauses afterwards.
976 def activateTimeshiftEndAndPause(self):
977 state = self.seekstate
978 self.activateTimeshiftEnd()
980 # well, this is "andPause", but it could be pressed from pause,
981 # when pausing on the (fake-)"live" picture, so an un-pause
984 print "now, pauseService"
985 if state == self.SEEK_STATE_PLAY:
986 print "is PLAYING, start pause timer"
987 self.ts_pause_timer.start(200, 1)
990 self.unPauseService()
992 def __seekableStatusChanged(self):
995 print "self.isSeekable", self.isSeekable()
996 print "self.timeshift_enabled", self.timeshift_enabled
998 # when this service is not seekable, but timeshift
999 # is enabled, this means we can activate
1001 if not self.isSeekable() and self.timeshift_enabled:
1004 print "timeshift activate:", enabled
1005 self["TimeshiftActivateActions"].setEnabled(enabled)
1007 def __serviceStarted(self):
1008 self.timeshift_enabled = False
1009 self.__seekableStatusChanged()
1011 from RecordTimer import parseEvent
1013 class InfoBarInstantRecord:
1014 """Instant Record - handles the instantRecord action in order to
1015 start/stop instant records"""
1017 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1019 "instantRecord": (self.instantRecord, "Instant Record..."),
1021 self.recording = None
1022 self["BlinkingPoint"] = BlinkingPixmapConditional()
1023 self["BlinkingPoint"].hide()
1024 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1026 def stopCurrentRecording(self):
1027 self.session.nav.RecordTimer.removeEntry(self.recording)
1028 self.recording = None
1030 def startInstantRecording(self, limitEvent = False):
1031 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1033 # try to get event info
1036 service = self.session.nav.getCurrentService()
1037 epg = eEPGCache.getInstance()
1038 event = epg.lookupEventTime(serviceref, -1, 0)
1040 info = service.info()
1041 ev = info.getEvent(0)
1047 end = time.time() + 3600 * 10
1048 name = "instant record"
1052 if event is not None:
1053 curEvent = parseEvent(event)
1055 description = curEvent[3]
1056 eventid = curEvent[4]
1061 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1063 data = (begin, end, name, description, eventid)
1065 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
1066 self.recording.dontSave = True
1068 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1070 def isInstantRecordRunning(self):
1071 if self.recording != None:
1072 if self.recording.isRunning():
1076 def recordQuestionCallback(self, answer):
1077 if answer is None or answer[1] == "no":
1080 if self.isInstantRecordRunning():
1081 if answer[1] == "manualduration":
1082 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1084 self.stopCurrentRecording()
1087 if answer[1] == "event":
1089 if answer[1] == "manualduration":
1090 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1091 self.startInstantRecording(limitEvent = limitEvent)
1093 def inputCallback(self, value):
1094 if value is not None:
1095 print "stopping recording after", int(value), "minutes."
1096 if self.recording is not None:
1097 self.recording.end = time.time() + 60 * int(value)
1098 self.session.nav.RecordTimer.timeChanged(self.recording)
1100 def instantRecord(self):
1102 stat = os.stat(resolveFilename(SCOPE_HDD))
1104 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1107 if self.isInstantRecordRunning():
1108 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("A recording is currently running.\nWhat do you want to do?"), list=[(_("stop recording"), "yes"), (_("enter recording duration"), "manualduration"), (_("do nothing"), "no")])
1109 # self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
1111 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Start recording?"), list=[(_("record indefinitely"), "indefinitely"), (_("stop after current event"), "event"), (_("enter recording duration"), "manualduration"),(_("don't record"), "no")])
1112 #self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
1114 from Screens.AudioSelection import AudioSelection
1116 class InfoBarAudioSelection:
1118 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1120 "audioSelection": (self.audioSelection, "Audio Options..."),
1123 def audioSelection(self):
1124 service = self.session.nav.getCurrentService()
1125 audio = service.audioTracks()
1126 n = audio.getNumberOfTracks()
1128 self.session.open(AudioSelection, audio)
1130 from Screens.SubserviceSelection import SubserviceSelection
1132 class InfoBarSubserviceSelection:
1134 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1136 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1139 def subserviceSelection(self):
1140 service = self.session.nav.getCurrentService()
1141 subservices = service.subServices()
1142 n = subservices.getNumberOfSubservices()
1144 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1146 def subserviceSelected(self, service):
1147 if not service is None:
1148 self.session.nav.playService(service)
1150 class InfoBarAdditionalInfo:
1152 self["DolbyActive"] = Pixmap()
1153 self["CryptActive"] = Pixmap()
1154 self["FormatActive"] = Pixmap()
1156 self["ButtonRed"] = PixmapConditional(withTimer = False)
1157 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1158 self.onLayoutFinish.append(self["ButtonRed"].update)
1159 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1160 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1161 self.onLayoutFinish.append(self["ButtonRedText"].update)
1163 self["ButtonGreen"] = Pixmap()
1164 self["ButtonGreenText"] = Label(_("Subservices"))
1166 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1167 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1168 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1169 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1170 self.onLayoutFinish.append(self["ButtonYellow"].update)
1171 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1173 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1174 self["ButtonBlue"].setConnect(lambda: False)
1175 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1176 self["ButtonBlueText"].setConnect(lambda: False)
1177 self.onLayoutFinish.append(self["ButtonBlue"].update)
1178 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1180 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1182 def hideSubServiceIndication(self):
1183 self["ButtonGreen"].hide()
1184 self["ButtonGreenText"].hide()
1186 def showSubServiceIndication(self):
1187 self["ButtonGreen"].show()
1188 self["ButtonGreenText"].show()
1190 def checkFormat(self, service):
1191 info = service.info()
1192 if info is not None:
1193 aspect = info.getInfo(iServiceInformation.sAspect)
1194 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1195 self["FormatActive"].show()
1197 self["FormatActive"].hide()
1199 def checkSubservices(self, service):
1200 if service.subServices().getNumberOfSubservices() > 0:
1201 self.showSubServiceIndication()
1203 self.hideSubServiceIndication()
1205 def checkDolby(self, service):
1208 audio = service.audioTracks()
1209 if audio is not None:
1210 n = audio.getNumberOfTracks()
1212 i = audio.getTrackInfo(x)
1213 description = i.getDescription();
1214 if description.find("AC3") != -1 or description.find("DTS") != -1:
1218 self["DolbyActive"].show()
1220 self["DolbyActive"].hide()
1222 def checkCrypted(self, service):
1223 info = service.info()
1224 if info is not None:
1225 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1226 self["CryptActive"].show()
1228 self["CryptActive"].hide()
1230 def gotServiceEvent(self, ev):
1231 service = self.session.nav.getCurrentService()
1232 if ev == iPlayableService.evUpdatedEventInfo:
1233 self.checkSubservices(service)
1234 self.checkFormat(service)
1235 elif ev == iPlayableService.evUpdatedInfo:
1236 self.checkCrypted(service)
1237 self.checkDolby(service)
1238 elif ev == iPlayableService.evEnd:
1239 self.hideSubServiceIndication()
1240 self["CryptActive"].hide()
1241 self["DolbyActive"].hide()
1242 self["FormatActive"].hide()
1244 class InfoBarNotifications:
1246 self.onExecBegin.append(self.checkNotifications)
1247 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1249 def checkNotificationsIfExecing(self):
1251 self.checkNotifications()
1253 def checkNotifications(self):
1254 if len(Notifications.notifications):
1255 n = Notifications.notifications[0]
1256 Notifications.notifications = Notifications.notifications[1:]
1260 self.session.openWithCallback(cb, *n[1:])
1262 self.session.open(*n[1:])
1264 class InfoBarServiceNotifications:
1266 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1268 iPlayableService.evEnd: self.serviceHasEnded
1271 def serviceHasEnded(self):
1272 print "service end!"
1275 self.setSeekState(self.SEEK_STATE_PLAY)
1279 class InfoBarCueSheetSupport:
1285 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1287 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1288 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1289 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1293 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1295 iPlayableService.evStart: self.__serviceStarted,
1298 def __serviceStarted(self):
1299 print "new service started! trying to download cuts!"
1300 self.downloadCuesheet()
1302 def __getSeekable(self):
1303 service = self.session.nav.getCurrentService()
1306 return service.seek()
1308 def cueGetCurrentPosition(self):
1309 seek = self.__getSeekable()
1312 r = seek.getPlayPosition()
1317 def jumpPreviousNextMark(self, cmp, alternative=None):
1318 current_pos = self.cueGetCurrentPosition()
1319 if current_pos is None:
1321 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1322 if mark is not None:
1324 elif alternative is not None:
1329 seekable = self.__getSeekable()
1330 if seekable is not None:
1331 seekable.seekTo(pts)
1333 def jumpPreviousMark(self):
1334 # we add 2 seconds, so if the play position is <2s after
1335 # the mark, the mark before will be used
1336 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1338 def jumpNextMark(self):
1339 self.jumpPreviousNextMark(lambda x: x)
1341 def getNearestCutPoint(self, pts, cmp=abs):
1344 for cp in self.cut_list:
1345 diff = cmp(cp[0] - pts)
1346 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1350 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1351 current_pos = self.cueGetCurrentPosition()
1352 if current_pos is None:
1353 print "not seekable"
1356 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1358 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1360 return nearest_cutpoint
1362 self.removeMark(nearest_cutpoint)
1363 elif not onlyremove and not onlyreturn:
1364 self.addMark((current_pos, self.CUT_TYPE_MARK))
1369 def addMark(self, point):
1370 bisect.insort(self.cut_list, point)
1371 self.uploadCuesheet()
1373 def removeMark(self, point):
1374 self.cut_list.remove(point)
1375 self.uploadCuesheet()
1377 def __getCuesheet(self):
1378 service = self.session.nav.getCurrentService()
1381 return service.cueSheet()
1383 def uploadCuesheet(self):
1384 cue = self.__getCuesheet()
1387 print "upload failed, no cuesheet interface"
1389 cue.setCutList(self.cut_list)
1391 def downloadCuesheet(self):
1392 cue = self.__getCuesheet()
1395 print "upload failed, no cuesheet interface"
1397 self.cut_list = cue.getCutList()
1399 class InfoBarSummary(Screen):
1401 <screen position="0,0" size="132,64">
1402 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1403 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1406 def __init__(self, session, parent):
1407 Screen.__init__(self, session)
1408 self["CurrentService"] = ServiceName(self.session.nav)
1409 self["Clock"] = Clock()
1411 class InfoBarSummarySupport:
1415 def createSummary(self):
1416 return InfoBarSummary