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
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 class InfoBarChannelSelection:
273 """ ChannelSelection - handles the channelSelection dialog and the initial
274 channelChange actions which open the channelSelection dialog """
277 self.servicelist = self.session.instantiateDialog(ChannelSelection)
279 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
281 "switchChannelUp": self.switchChannelUp,
282 "switchChannelDown": self.switchChannelDown,
283 "zapUp": (self.zapUp, _("previous channel")),
284 "zapDown": (self.zapDown, _("next channel")),
285 "historyBack": (self.historyBack, _("previous channel in history")),
286 "historyNext": (self.historyNext, _("next channel in history"))
289 def historyBack(self):
290 self.servicelist.historyBack()
292 def historyNext(self):
293 self.servicelist.historyNext()
295 def switchChannelUp(self):
296 self.servicelist.moveUp()
297 self.session.execDialog(self.servicelist)
299 def switchChannelDown(self):
300 self.servicelist.moveDown()
301 self.session.execDialog(self.servicelist)
304 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
305 if self.servicelist.inBouquet() and self.servicelist.atBegin():
306 self.servicelist.prevBouquet()
307 self.servicelist.moveUp()
308 self.servicelist.zap()
312 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
313 self.servicelist.nextBouquet()
315 self.servicelist.moveDown()
316 self.servicelist.zap()
320 """ Handles a menu action, to open the (main) menu """
322 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
324 "mainMenu": (self.mainMenu, "Enter main menu..."),
328 print "loading mainmenu XML..."
329 menu = mdom.childNodes[0]
330 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
331 self.session.open(MainMenu, menu, menu.childNodes)
333 class InfoBarSimpleEventView:
334 """ Opens the Eventview for now/next """
336 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
338 "showEventInfo": (self.openEventView, _("show event details")),
341 def openEventView(self):
343 service = self.session.nav.getCurrentService()
344 ref = self.session.nav.getCurrentlyPlayingServiceReference()
345 info = service.info()
348 self.epglist.append(ptr)
351 self.epglist.append(ptr)
352 if len(self.epglist) > 0:
353 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
355 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
356 if len(self.epglist) > 1:
357 tmp = self.epglist[0]
358 self.epglist[0]=self.epglist[1]
360 setEvent(self.epglist[0])
363 """ EPG - Opens an EPG list when the showEPGList action fires """
365 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
367 "showEventInfo": (self.openEventView, _("show EPG...")),
370 def zapToService(self, service):
371 if not service is None:
372 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
373 self.servicelist.clearPath()
374 if self.servicelist.bouquet_root != self.epg_bouquet:
375 self.servicelist.enterPath(self.servicelist.bouquet_root)
376 self.servicelist.enterPath(self.epg_bouquet)
377 self.servicelist.setCurrentSelection(service) #select the service in servicelist
378 self.servicelist.zap()
380 def openBouquetEPG(self, bouquet, withCallback=True):
381 ptr=eEPGCache.getInstance()
383 servicelist = eServiceCenter.getInstance().list(bouquet)
384 if not servicelist is None:
386 service = servicelist.getNext()
387 if not service.valid(): #check if end of list
389 if service.flags: #ignore non playable services
391 services.append(ServiceReference(service))
393 self.epg_bouquet = bouquet
395 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
397 self.session.open(EPGSelection, services, self.zapToService)
399 def closed(self, ret):
403 def openMultiServiceEPG(self, withCallback=True):
404 bouquets = self.servicelist.getBouquetList()
409 if cnt > 1: # show bouquet list
411 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
413 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
415 self.openBouquetEPG(bouquets[0][1], withCallback)
417 def openSingleServiceEPG(self):
418 ref=self.session.nav.getCurrentlyPlayingServiceReference()
419 ptr=eEPGCache.getInstance()
420 self.session.openWithCallback(self.closed, EPGSelection, ref)
422 def openEventView(self):
424 service = self.session.nav.getCurrentService()
425 ref = self.session.nav.getCurrentlyPlayingServiceReference()
426 info = service.info()
429 self.epglist.append(ptr)
432 self.epglist.append(ptr)
433 if len(self.epglist) == 0:
434 epg = eEPGCache.getInstance()
435 ptr = epg.lookupEventTime(ref, -1)
437 self.epglist.append(ptr)
438 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
440 self.epglist.append(ptr)
441 if len(self.epglist) > 0:
442 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
444 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
445 self.openMultiServiceEPG(False)
447 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
448 if len(self.epglist) > 1:
449 tmp = self.epglist[0]
450 self.epglist[0]=self.epglist[1]
452 setEvent(self.epglist[0])
457 """provides a snr/agc/ber display"""
459 self["snr"] = Label()
460 self["agc"] = Label()
461 self["ber"] = Label()
462 self["snr_percent"] = Label()
463 self["agc_percent"] = Label()
464 self["ber_count"] = Label()
465 self["snr_progress"] = ProgressBar()
466 self["agc_progress"] = ProgressBar()
467 self["ber_progress"] = ProgressBar()
468 self.timer = eTimer()
469 self.timer.timeout.get().append(self.updateTunerInfo)
470 self.timer.start(1000)
476 return (long)(log(val)/log(2))
479 def updateTunerInfo(self):
480 if self.instance.isVisible():
481 service = self.session.nav.getCurrentService()
485 if service is not None:
486 feinfo = service.frontendStatusInfo()
487 if feinfo is not None:
488 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
489 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
490 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
491 self["snr_percent"].setText("%d%%"%(snr))
492 self["agc_percent"].setText("%d%%"%(agc))
493 self["ber_count"].setText("%d"%(ber))
494 self["snr_progress"].setValue(snr)
495 self["agc_progress"].setValue(agc)
496 self["ber_progress"].setValue(self.calc(ber))
499 """provides a current/next event info display"""
501 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
502 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
504 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
505 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
507 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
508 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
510 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
512 class InfoBarServiceName:
514 self["ServiceName"] = ServiceName(self.session.nav)
517 """handles actions like seeking, pause"""
519 # ispause, isff, issm
520 SEEK_STATE_PLAY = (0, 0, 0, ">")
521 SEEK_STATE_PAUSE = (1, 0, 0, "||")
522 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
523 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
524 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
525 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
526 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
527 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
529 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
530 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
531 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
532 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
534 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
535 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
536 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
539 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
541 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
542 iPlayableService.evStart: self.__serviceStarted,
544 iPlayableService.evEOF: self.__evEOF,
545 iPlayableService.evSOF: self.__evSOF,
548 class InfoBarSeekActionMap(HelpableActionMap):
549 def __init__(self, screen, *args, **kwargs):
550 HelpableActionMap.__init__(self, screen, *args, **kwargs)
553 def action(self, contexts, action):
554 if action[:5] == "seek:":
555 time = int(action[5:])
556 self.screen.seekRelative(time * 90000)
559 return HelpableActionMap.action(self, contexts, action)
561 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
563 "pauseService": (self.pauseService, "pause"),
564 "unPauseService": (self.unPauseService, "continue"),
566 "seekFwd": (self.seekFwd, "skip forward"),
567 "seekFwdDown": self.seekFwdDown,
568 "seekFwdUp": self.seekFwdUp,
569 "seekBack": (self.seekBack, "skip backward"),
570 "seekBackDown": self.seekBackDown,
571 "seekBackUp": self.seekBackUp,
573 # give them a little more priority to win over color buttons
575 self.seekstate = self.SEEK_STATE_PLAY
576 self.onClose.append(self.delTimer)
578 self.fwdtimer = False
579 self.fwdKeyTimer = eTimer()
580 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
582 self.rwdtimer = False
583 self.rwdKeyTimer = eTimer()
584 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
586 self.onPlayStateChanged = [ ]
588 self.lockedBecauseOfSkipping = False
601 service = self.session.nav.getCurrentService()
605 seek = service.seek()
607 if seek is None or not seek.isCurrentlySeekable():
612 def isSeekable(self):
613 if self.getSeek() is None:
617 def __seekableStatusChanged(self):
618 print "seekable status changed!"
619 if not self.isSeekable():
620 self["SeekActions"].setEnabled(False)
621 print "not seekable, return to play"
622 self.setSeekState(self.SEEK_STATE_PLAY)
624 self["SeekActions"].setEnabled(True)
627 def __serviceStarted(self):
628 self.seekstate = self.SEEK_STATE_PLAY
630 def setSeekState(self, state):
631 service = self.session.nav.getCurrentService()
636 if not self.isSeekable():
637 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
638 state = self.SEEK_STATE_PLAY
640 pauseable = service.pause()
642 if pauseable is None:
643 print "not pauseable."
644 state = self.SEEK_STATE_PLAY
646 oldstate = self.seekstate
647 self.seekstate = state
650 if oldstate[i] != self.seekstate[i]:
651 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
653 for c in self.onPlayStateChanged:
656 self.checkSkipShowHideLock()
660 def pauseService(self):
661 if self.seekstate == self.SEEK_STATE_PAUSE:
662 print "pause, but in fact unpause"
663 self.unPauseService()
665 if self.seekstate == self.SEEK_STATE_PLAY:
666 print "yes, playing."
668 print "no", self.seekstate
670 self.setSeekState(self.SEEK_STATE_PAUSE);
672 def unPauseService(self):
674 self.setSeekState(self.SEEK_STATE_PLAY);
676 def doSeek(self, seektime):
677 print "doseek", seektime
678 service = self.session.nav.getCurrentService()
682 seekable = self.getSeek()
686 seekable.seekTo(90 * seektime)
688 def seekFwdDown(self):
689 print "start fwd timer"
691 self.fwdKeyTimer.start(1000)
693 def seekBackDown(self):
694 print "start rewind timer"
696 self.rwdKeyTimer.start(1000)
701 self.fwdKeyTimer.stop()
702 self.fwdtimer = False
707 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
708 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
709 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
710 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
711 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
712 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
713 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
714 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
715 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
716 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
717 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
718 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
719 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
720 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
721 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
723 self.setSeekState(lookup[self.seekstate])
725 def seekBackUp(self):
728 self.rwdKeyTimer.stop()
729 self.rwdtimer = False
734 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
735 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
736 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
737 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
738 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
739 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
740 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
741 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
742 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
743 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
744 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
745 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
746 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
747 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
748 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
750 self.setSeekState(lookup[self.seekstate])
752 if self.seekstate == self.SEEK_STATE_PAUSE:
753 seekable = self.getSeek()
754 if seekable is not None:
755 seekable.seekRelative(-1, 3)
757 def fwdTimerFire(self):
758 print "Display seek fwd"
759 self.fwdKeyTimer.stop()
760 self.fwdtimer = False
761 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
763 def fwdSeekTo(self, minutes):
764 print "Seek", minutes, "minutes forward"
766 seekable = self.getSeek()
767 if seekable is not None:
768 seekable.seekRelative(1, minutes * 60 * 90000)
770 def rwdTimerFire(self):
772 self.rwdKeyTimer.stop()
773 self.rwdtimer = False
774 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
776 def rwdSeekTo(self, minutes):
778 self.fwdSeekTo(0 - minutes)
780 def checkSkipShowHideLock(self):
781 wantlock = self.seekstate != self.SEEK_STATE_PLAY
783 if self.lockedBecauseOfSkipping and not wantlock:
785 self.lockedBecauseOfSkipping = False
787 if wantlock and not self.lockedBecauseOfSkipping:
789 self.lockedBecauseOfSkipping = True
792 if self.seekstate != self.SEEK_STATE_PLAY:
793 self.setSeekState(self.SEEK_STATE_PAUSE)
795 #self.getSeek().seekRelative(1, -90000)
796 self.setSeekState(self.SEEK_STATE_PLAY)
798 self.setSeekState(self.SEEK_STATE_PAUSE)
801 self.setSeekState(self.SEEK_STATE_PLAY)
804 def seekRelative(self, diff):
805 seekable = self.getSeek()
806 if seekable is not None:
807 seekable.seekRelative(1, diff)
809 from Screens.PVRState import PVRState, TimeshiftState
811 class InfoBarPVRState:
812 def __init__(self, screen=PVRState):
813 self.onPlayStateChanged.append(self.__playStateChanged)
814 self.pvrStateDialog = self.session.instantiateDialog(screen)
815 self.onShow.append(self.__mayShow)
816 self.onHide.append(self.pvrStateDialog.hide)
819 if self.seekstate != self.SEEK_STATE_PLAY:
820 self.pvrStateDialog.show()
822 def __playStateChanged(self, state):
823 playstateString = state[3]
824 self.pvrStateDialog["state"].setText(playstateString)
827 class InfoBarTimeshiftState(InfoBarPVRState):
829 InfoBarPVRState.__init__(self, screen=TimeshiftState)
832 class InfoBarShowMovies:
834 # i don't really like this class.
835 # it calls a not further specified "movie list" on up/down/movieList,
836 # so this is not more than an action map
838 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
840 "movieList": (self.showMovies, "movie list"),
841 "up": (self.showMovies, "movie list"),
842 "down": (self.showMovies, "movie list")
845 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
849 # Timeshift works the following way:
850 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
851 # - normal playback TUNER unused PLAY enable disable disable
852 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
853 # - user presess pause again FILE record PLAY enable disable enable
854 # - user fast forwards FILE record FF enable disable enable
855 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
856 # - user backwards FILE record BACK # !! enable disable enable
860 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
861 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
862 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
863 # - the user can now PVR around
864 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
865 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
867 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
868 # - if the user rewinds, or press pause, timeshift will be activated again
870 # note that a timeshift can be enabled ("recording") and
871 # activated (currently time-shifting).
873 class InfoBarTimeshift:
875 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
877 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
878 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
880 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
882 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
883 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
884 }, prio=-1) # priority over record
886 self.timeshift_enabled = 0
887 self.timeshift_state = 0
888 self.ts_pause_timer = eTimer()
889 self.ts_pause_timer.timeout.get().append(self.pauseService)
891 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
893 iPlayableService.evStart: self.__serviceStarted,
894 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
897 def getTimeshift(self):
898 service = self.session.nav.getCurrentService()
899 return service.timeshift()
901 def startTimeshift(self):
902 print "enable timeshift"
903 ts = self.getTimeshift()
905 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
906 print "no ts interface"
909 if self.timeshift_enabled:
910 print "hu, timeshift already enabled?"
912 if not ts.startTimeshift():
914 self.timeshift_enabled = 1
915 self.pvrStateDialog["timeshift"].setRelative(time.time())
918 self.setSeekState(self.SEEK_STATE_PAUSE)
920 # enable the "TimeshiftEnableActions", which will override
921 # the startTimeshift actions
922 self.__seekableStatusChanged()
924 print "timeshift failed"
926 def stopTimeshift(self):
927 if not self.timeshift_enabled:
929 print "disable timeshift"
930 ts = self.getTimeshift()
933 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
935 def stopTimeshiftConfirmed(self, confirmed):
939 ts = self.getTimeshift()
944 self.timeshift_enabled = 0
947 self.__seekableStatusChanged()
949 # activates timeshift, and seeks to (almost) the end
950 def activateTimeshiftEnd(self):
951 ts = self.getTimeshift()
956 if ts.isTimeshiftActive():
957 print "!! activate timeshift called - but shouldn't this be a normal pause?"
960 self.setSeekState(self.SEEK_STATE_PLAY)
961 ts.activateTimeshift()
964 # same as activateTimeshiftEnd, but pauses afterwards.
965 def activateTimeshiftEndAndPause(self):
966 state = self.seekstate
967 self.activateTimeshiftEnd()
969 # well, this is "andPause", but it could be pressed from pause,
970 # when pausing on the (fake-)"live" picture, so an un-pause
973 print "now, pauseService"
974 if state == self.SEEK_STATE_PLAY:
975 print "is PLAYING, start pause timer"
976 self.ts_pause_timer.start(200, 1)
979 self.unPauseService()
981 def __seekableStatusChanged(self):
984 print "self.isSeekable", self.isSeekable()
985 print "self.timeshift_enabled", self.timeshift_enabled
987 # when this service is not seekable, but timeshift
988 # is enabled, this means we can activate
990 if not self.isSeekable() and self.timeshift_enabled:
993 print "timeshift activate:", enabled
994 self["TimeshiftActivateActions"].setEnabled(enabled)
996 def __serviceStarted(self):
997 self.timeshift_enabled = False
998 self.__seekableStatusChanged()
1000 from RecordTimer import parseEvent
1002 class InfoBarInstantRecord:
1003 """Instant Record - handles the instantRecord action in order to
1004 start/stop instant records"""
1006 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1008 "instantRecord": (self.instantRecord, "Instant Record..."),
1010 self.recording = None
1011 self["BlinkingPoint"] = BlinkingPixmapConditional()
1012 self["BlinkingPoint"].hide()
1013 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1015 def stopCurrentRecording(self):
1016 self.session.nav.RecordTimer.removeEntry(self.recording)
1017 self.recording = None
1019 def startInstantRecording(self, limitEvent = False):
1020 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1022 # try to get event info
1025 service = self.session.nav.getCurrentService()
1026 epg = eEPGCache.getInstance()
1027 event = epg.lookupEventTime(serviceref, -1, 0)
1029 info = service.info()
1030 ev = info.getEvent(0)
1036 end = time.time() + 3600 * 10
1037 name = "instant record"
1041 if event is not None:
1042 curEvent = parseEvent(event)
1044 description = curEvent[3]
1045 eventid = curEvent[4]
1050 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1052 data = (begin, end, name, description, eventid)
1054 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
1055 self.recording.dontSave = True
1057 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1059 def isInstantRecordRunning(self):
1060 if self.recording != None:
1061 if self.recording.isRunning():
1065 def recordQuestionCallback(self, answer):
1066 if answer is None or answer[1] == "no":
1069 if self.isInstantRecordRunning():
1070 if answer[1] == "manualduration":
1071 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1073 self.stopCurrentRecording()
1076 if answer[1] == "event":
1078 if answer[1] == "manualduration":
1079 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1080 self.startInstantRecording(limitEvent = limitEvent)
1082 def inputCallback(self, value):
1083 if value is not None:
1084 print "stopping recording after", int(value), "minutes."
1085 if self.recording is not None:
1086 self.recording.end = time.time() + 60 * int(value)
1087 self.session.nav.RecordTimer.timeChanged(self.recording)
1089 def instantRecord(self):
1091 stat = os.stat(resolveFilename(SCOPE_HDD))
1093 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1096 if self.isInstantRecordRunning():
1097 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")])
1098 # self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
1100 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")])
1101 #self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
1103 from Screens.AudioSelection import AudioSelection
1105 class InfoBarAudioSelection:
1107 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1109 "audioSelection": (self.audioSelection, "Audio Options..."),
1112 def audioSelection(self):
1113 service = self.session.nav.getCurrentService()
1114 audio = service.audioTracks()
1115 n = audio.getNumberOfTracks()
1117 self.session.open(AudioSelection, audio)
1119 from Screens.SubserviceSelection import SubserviceSelection
1121 class InfoBarSubserviceSelection:
1123 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1125 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1128 def subserviceSelection(self):
1129 service = self.session.nav.getCurrentService()
1130 subservices = service.subServices()
1131 n = subservices.getNumberOfSubservices()
1133 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1135 def subserviceSelected(self, service):
1136 if not service is None:
1137 self.session.nav.playService(service)
1139 class InfoBarAdditionalInfo:
1141 self["DolbyActive"] = Pixmap()
1142 self["CryptActive"] = Pixmap()
1143 self["FormatActive"] = Pixmap()
1145 self["ButtonRed"] = PixmapConditional(withTimer = False)
1146 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1147 self.onLayoutFinish.append(self["ButtonRed"].update)
1148 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1149 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1150 self.onLayoutFinish.append(self["ButtonRedText"].update)
1152 self["ButtonGreen"] = Pixmap()
1153 self["ButtonGreenText"] = Label(_("Subservices"))
1155 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1156 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1157 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1158 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1159 self.onLayoutFinish.append(self["ButtonYellow"].update)
1160 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1162 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1163 self["ButtonBlue"].setConnect(lambda: False)
1164 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1165 self["ButtonBlueText"].setConnect(lambda: False)
1166 self.onLayoutFinish.append(self["ButtonBlue"].update)
1167 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1169 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1171 def hideSubServiceIndication(self):
1172 self["ButtonGreen"].hide()
1173 self["ButtonGreenText"].hide()
1175 def showSubServiceIndication(self):
1176 self["ButtonGreen"].show()
1177 self["ButtonGreenText"].show()
1179 def checkFormat(self, service):
1180 info = service.info()
1181 if info is not None:
1182 aspect = info.getInfo(iServiceInformation.sAspect)
1183 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1184 self["FormatActive"].show()
1186 self["FormatActive"].hide()
1188 def checkSubservices(self, service):
1189 if service.subServices().getNumberOfSubservices() > 0:
1190 self.showSubServiceIndication()
1192 self.hideSubServiceIndication()
1194 def checkDolby(self, service):
1197 audio = service.audioTracks()
1198 if audio is not None:
1199 n = audio.getNumberOfTracks()
1201 i = audio.getTrackInfo(x)
1202 description = i.getDescription();
1203 if description.find("AC3") != -1 or description.find("DTS") != -1:
1207 self["DolbyActive"].show()
1209 self["DolbyActive"].hide()
1211 def checkCrypted(self, service):
1212 info = service.info()
1213 if info is not None:
1214 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1215 self["CryptActive"].show()
1217 self["CryptActive"].hide()
1219 def gotServiceEvent(self, ev):
1220 service = self.session.nav.getCurrentService()
1221 if ev == iPlayableService.evUpdatedEventInfo:
1222 self.checkSubservices(service)
1223 self.checkFormat(service)
1224 elif ev == iPlayableService.evUpdatedInfo:
1225 self.checkCrypted(service)
1226 self.checkDolby(service)
1227 elif ev == iPlayableService.evEnd:
1228 self.hideSubServiceIndication()
1229 self["CryptActive"].hide()
1230 self["DolbyActive"].hide()
1231 self["FormatActive"].hide()
1233 class InfoBarNotifications:
1235 self.onExecBegin.append(self.checkNotifications)
1236 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1238 def checkNotificationsIfExecing(self):
1240 self.checkNotifications()
1242 def checkNotifications(self):
1243 if len(Notifications.notifications):
1244 n = Notifications.notifications[0]
1245 Notifications.notifications = Notifications.notifications[1:]
1249 self.session.openWithCallback(cb, *n[1:])
1251 self.session.open(*n[1:])
1253 class InfoBarServiceNotifications:
1255 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1257 iPlayableService.evEnd: self.serviceHasEnded
1260 def serviceHasEnded(self):
1261 print "service end!"
1264 self.setSeekState(self.SEEK_STATE_PLAY)
1268 class InfoBarCueSheetSupport:
1274 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1276 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1277 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1278 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1282 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1284 iPlayableService.evStart: self.__serviceStarted,
1287 def __serviceStarted(self):
1288 print "new service started! trying to download cuts!"
1289 self.downloadCuesheet()
1291 def __getSeekable(self):
1292 service = self.session.nav.getCurrentService()
1295 return service.seek()
1297 def cueGetCurrentPosition(self):
1298 seek = self.__getSeekable()
1301 r = seek.getPlayPosition()
1306 def jumpPreviousNextMark(self, cmp, alternative=None):
1307 current_pos = self.cueGetCurrentPosition()
1308 if current_pos is None:
1310 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1311 if mark is not None:
1313 elif alternative is not None:
1318 seekable = self.__getSeekable()
1319 if seekable is not None:
1320 seekable.seekTo(pts)
1322 def jumpPreviousMark(self):
1323 # we add 2 seconds, so if the play position is <2s after
1324 # the mark, the mark before will be used
1325 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1327 def jumpNextMark(self):
1328 self.jumpPreviousNextMark(lambda x: x)
1330 def getNearestCutPoint(self, pts, cmp=abs):
1333 for cp in self.cut_list:
1334 diff = cmp(cp[0] - pts)
1335 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1339 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1340 current_pos = self.cueGetCurrentPosition()
1341 if current_pos is None:
1342 print "not seekable"
1345 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1347 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1349 return nearest_cutpoint
1351 self.removeMark(nearest_cutpoint)
1352 elif not onlyremove and not onlyreturn:
1353 self.addMark((current_pos, self.CUT_TYPE_MARK))
1358 def addMark(self, point):
1359 bisect.insort(self.cut_list, point)
1360 self.uploadCuesheet()
1362 def removeMark(self, point):
1363 self.cut_list.remove(point)
1364 self.uploadCuesheet()
1366 def __getCuesheet(self):
1367 service = self.session.nav.getCurrentService()
1370 return service.cueSheet()
1372 def uploadCuesheet(self):
1373 cue = self.__getCuesheet()
1376 print "upload failed, no cuesheet interface"
1378 cue.setCutList(self.cut_list)
1380 def downloadCuesheet(self):
1381 cue = self.__getCuesheet()
1384 print "upload failed, no cuesheet interface"
1386 self.cut_list = cue.getCutList()
1388 class InfoBarSummary(Screen):
1390 <screen position="0,0" size="132,64">
1391 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1392 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1395 def __init__(self, session, parent):
1396 Screen.__init__(self, session)
1397 self["CurrentService"] = ServiceName(self.session.nav)
1398 self["Clock"] = Clock()
1400 class InfoBarSummarySupport:
1404 def createSummary(self):
1405 return InfoBarSummary