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
15 from ServiceReference import ServiceReference
16 from EpgSelection import EPGSelection
18 from Screens.MessageBox import MessageBox
19 from Screens.Dish import Dish
20 from Screens.Standby import Standby
21 from Screens.EventView import EventViewEPGSelect, EventViewSimple
22 from Screens.MinuteInput import MinuteInput
23 from Components.Harddisk import harddiskmanager
25 from Components.ServiceEventTracker import ServiceEventTracker
27 from Tools import Notifications
28 from Tools.Directories import *
30 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
37 from Components.config import config, currentConfigSelectionElement
40 from Menu import MainMenu, mdom
44 self.dishDialog = self.session.instantiateDialog(Dish)
45 self.onLayoutFinish.append(self.dishDialog.show)
47 class InfoBarShowHide:
48 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
56 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
58 "toggleShow": self.toggleShow,
62 self.__state = self.STATE_SHOWN
65 self.onExecBegin.append(self.show)
67 self.hideTimer = eTimer()
68 self.hideTimer.timeout.get().append(self.doTimerHide)
69 self.hideTimer.start(5000, True)
71 self.onShow.append(self.__onShow)
72 self.onHide.append(self.__onHide)
75 self.__state = self.STATE_SHOWN
78 def startHideTimer(self):
79 if self.__state == self.STATE_SHOWN and not self.__locked:
80 self.hideTimer.start(5000, True)
83 self.__state = self.STATE_HIDDEN
89 def doTimerHide(self):
91 if self.__state == self.STATE_SHOWN:
95 if self.__state == self.STATE_SHOWN:
98 elif self.__state == self.STATE_HIDDEN:
102 self.__locked = self.__locked + 1
105 self.hideTimer.stop()
107 def unlockShow(self):
108 self.__locked = self.__locked - 1
110 self.startHideTimer()
112 # def startShow(self):
113 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
114 # self.__state = self.STATE_SHOWN
116 # def startHide(self):
117 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
118 # self.__state = self.STATE_HIDDEN
120 class NumberZap(Screen):
127 self.close(int(self["number"].getText()))
129 def keyNumberGlobal(self, number):
130 self.Timer.start(3000, True) #reset timer
131 self.field = self.field + str(number)
132 self["number"].setText(self.field)
133 if len(self.field) >= 4:
136 def __init__(self, session, number):
137 Screen.__init__(self, session)
138 self.field = str(number)
140 self["channel"] = Label(_("Channel:"))
142 self["number"] = Label(self.field)
144 self["actions"] = NumberActionMap( [ "SetupActions" ],
148 "1": self.keyNumberGlobal,
149 "2": self.keyNumberGlobal,
150 "3": self.keyNumberGlobal,
151 "4": self.keyNumberGlobal,
152 "5": self.keyNumberGlobal,
153 "6": self.keyNumberGlobal,
154 "7": self.keyNumberGlobal,
155 "8": self.keyNumberGlobal,
156 "9": self.keyNumberGlobal,
157 "0": self.keyNumberGlobal
160 self.Timer = eTimer()
161 self.Timer.timeout.get().append(self.keyOK)
162 self.Timer.start(3000, True)
164 class InfoBarPowerKey:
165 """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
168 self.powerKeyTimer = eTimer()
169 self.powerKeyTimer.timeout.get().append(self.powertimer)
170 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
172 "powerdown": self.powerdown,
173 "powerup": self.powerup,
174 "discreteStandby": (self.standby, "Go standby"),
175 "discretePowerOff": (self.quit, "Go to deep standby"),
178 def powertimer(self):
179 print "PowerOff - Now!"
183 self.standbyblocked = 0
184 self.powerKeyTimer.start(3000, True)
187 self.powerKeyTimer.stop()
188 if self.standbyblocked == 0:
189 self.standbyblocked = 1
193 self.session.open(Standby, self)
199 class InfoBarNumberZap:
200 """ Handles an initial number for NumberZapping """
202 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
204 "1": self.keyNumberGlobal,
205 "2": self.keyNumberGlobal,
206 "3": self.keyNumberGlobal,
207 "4": self.keyNumberGlobal,
208 "5": self.keyNumberGlobal,
209 "6": self.keyNumberGlobal,
210 "7": self.keyNumberGlobal,
211 "8": self.keyNumberGlobal,
212 "9": self.keyNumberGlobal,
213 "0": self.keyNumberGlobal,
216 def keyNumberGlobal(self, number):
217 # print "You pressed number " + str(number)
219 self.servicelist.recallPrevService()
222 self.session.openWithCallback(self.numberEntered, NumberZap, number)
224 def numberEntered(self, retval):
225 # print self.servicelist
227 self.zapToNumber(retval)
229 def searchNumberHelper(self, serviceHandler, num, bouquet):
230 servicelist = serviceHandler.list(bouquet)
231 if not servicelist is None:
233 serviceIterator = servicelist.getNext()
234 if not serviceIterator.valid(): #check end of list
236 if serviceIterator.flags: #assume normal dvb service have no flags set
239 if not num: #found service with searched number ?
240 return serviceIterator, 0
243 def zapToNumber(self, number):
244 bouquet = self.servicelist.bouquet_root
246 serviceHandler = eServiceCenter.getInstance()
247 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
248 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
250 bouquetlist = serviceHandler.list(bouquet)
251 if not bouquetlist is None:
253 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
254 if not bouquet.valid(): #check end of list
256 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
258 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
259 if not service is None:
260 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
261 self.servicelist.clearPath()
262 if self.servicelist.bouquet_root != bouquet:
263 self.servicelist.enterPath(self.servicelist.bouquet_root)
264 self.servicelist.enterPath(bouquet)
265 self.servicelist.setCurrentSelection(service) #select the service in servicelist
266 self.servicelist.zap()
268 class InfoBarChannelSelection:
269 """ ChannelSelection - handles the channelSelection dialog and the initial
270 channelChange actions which open the channelSelection dialog """
273 self.servicelist = self.session.instantiateDialog(ChannelSelection)
275 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
277 "switchChannelUp": self.switchChannelUp,
278 "switchChannelDown": self.switchChannelDown,
279 "zapUp": (self.zapUp, _("previous channel")),
280 "zapDown": (self.zapDown, _("next channel")),
281 "historyBack": (self.historyBack, _("previous channel in history")),
282 "historyNext": (self.historyNext, _("next channel in history"))
285 def historyBack(self):
286 self.servicelist.historyBack()
288 def historyNext(self):
289 self.servicelist.historyNext()
291 def switchChannelUp(self):
292 self.servicelist.moveUp()
293 self.session.execDialog(self.servicelist)
295 def switchChannelDown(self):
296 self.servicelist.moveDown()
297 self.session.execDialog(self.servicelist)
300 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
301 if self.servicelist.inBouquet() and self.servicelist.atBegin():
302 self.servicelist.prevBouquet()
303 self.servicelist.moveUp()
304 self.servicelist.zap()
308 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
309 self.servicelist.nextBouquet()
311 self.servicelist.moveDown()
312 self.servicelist.zap()
316 """ Handles a menu action, to open the (main) menu """
318 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
320 "mainMenu": (self.mainMenu, "Enter main menu..."),
324 print "loading mainmenu XML..."
325 menu = mdom.childNodes[0]
326 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
327 self.session.open(MainMenu, menu, menu.childNodes)
329 class InfoBarSimpleEventView:
330 """ Opens the Eventview for now/next """
332 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
334 "showEventInfo": (self.openEventView, _("show event details")),
337 def openEventView(self):
339 service = self.session.nav.getCurrentService()
340 ref = self.session.nav.getCurrentlyPlayingServiceReference()
341 info = service.info()
344 self.epglist.append(ptr)
347 self.epglist.append(ptr)
348 if len(self.epglist) > 0:
349 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
351 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
352 if len(self.epglist) > 1:
353 tmp = self.epglist[0]
354 self.epglist[0]=self.epglist[1]
356 setEvent(self.epglist[0])
359 """ EPG - Opens an EPG list when the showEPGList action fires """
361 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
363 "showEventInfo": (self.openEventView, _("show EPG...")),
366 def zapToService(self, service):
367 if not service is None:
368 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
369 self.servicelist.clearPath()
370 if self.servicelist.bouquet_root != self.epg_bouquet:
371 self.servicelist.enterPath(self.servicelist.bouquet_root)
372 self.servicelist.enterPath(self.epg_bouquet)
373 self.servicelist.setCurrentSelection(service) #select the service in servicelist
374 self.servicelist.zap()
376 def openBouquetEPG(self, bouquet, withCallback=True):
377 ptr=eEPGCache.getInstance()
379 servicelist = eServiceCenter.getInstance().list(bouquet)
380 if not servicelist is None:
382 service = servicelist.getNext()
383 if not service.valid(): #check if end of list
385 if service.flags: #ignore non playable services
387 services.append(ServiceReference(service))
389 self.epg_bouquet = bouquet
391 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
393 self.session.open(EPGSelection, services, self.zapToService)
395 def closed(self, ret):
399 def openMultiServiceEPG(self, withCallback=True):
400 bouquets = self.servicelist.getBouquetList()
405 if cnt > 1: # show bouquet list
407 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
409 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
411 self.openBouquetEPG(bouquets[0][1], withCallback)
413 def openSingleServiceEPG(self):
414 ref=self.session.nav.getCurrentlyPlayingServiceReference()
415 ptr=eEPGCache.getInstance()
416 self.session.openWithCallback(self.closed, EPGSelection, ref)
418 def openEventView(self):
420 service = self.session.nav.getCurrentService()
421 ref = self.session.nav.getCurrentlyPlayingServiceReference()
422 info = service.info()
425 self.epglist.append(ptr)
428 self.epglist.append(ptr)
429 if len(self.epglist) == 0:
430 epg = eEPGCache.getInstance()
431 ptr = epg.lookupEventTime(ref, -1)
433 self.epglist.append(ptr)
434 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
436 self.epglist.append(ptr)
437 if len(self.epglist) > 0:
438 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
440 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
441 self.openMultiServiceEPG(False)
443 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
444 if len(self.epglist) > 1:
445 tmp = self.epglist[0]
446 self.epglist[0]=self.epglist[1]
448 setEvent(self.epglist[0])
453 """provides a snr/agc/ber display"""
455 self["snr"] = Label()
456 self["agc"] = Label()
457 self["ber"] = Label()
458 self["snr_percent"] = Label()
459 self["agc_percent"] = Label()
460 self["ber_count"] = Label()
461 self["snr_progress"] = ProgressBar()
462 self["agc_progress"] = ProgressBar()
463 self["ber_progress"] = ProgressBar()
464 self.timer = eTimer()
465 self.timer.timeout.get().append(self.updateTunerInfo)
466 self.timer.start(1000)
472 return (long)(log(val)/log(2))
475 def updateTunerInfo(self):
476 if self.instance.isVisible():
477 service = self.session.nav.getCurrentService()
481 if service is not None:
482 feinfo = service.frontendStatusInfo()
483 if feinfo is not None:
484 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
485 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
486 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
487 self["snr_percent"].setText("%d%%"%(snr))
488 self["agc_percent"].setText("%d%%"%(agc))
489 self["ber_count"].setText("%d"%(ber))
490 self["snr_progress"].setValue(snr)
491 self["agc_progress"].setValue(agc)
492 self["ber_progress"].setValue(self.calc(ber))
495 """provides a current/next event info display"""
497 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
498 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
500 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
501 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
503 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
504 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
506 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
508 class InfoBarServiceName:
510 self["ServiceName"] = ServiceName(self.session.nav)
513 """handles actions like seeking, pause"""
515 # ispause, isff, issm
516 SEEK_STATE_PLAY = (0, 0, 0, ">")
517 SEEK_STATE_PAUSE = (1, 0, 0, "||")
518 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
519 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
520 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
521 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
522 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
523 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
525 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
526 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
527 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
528 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
530 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
531 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
532 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
535 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
537 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
538 iPlayableService.evStart: self.__serviceStarted,
540 iPlayableService.evEOF: self.__evEOF,
541 iPlayableService.evSOF: self.__evSOF,
544 class InfoBarSeekActionMap(HelpableActionMap):
545 def __init__(self, screen, *args, **kwargs):
546 HelpableActionMap.__init__(self, screen, *args, **kwargs)
549 def action(self, contexts, action):
550 if action[:5] == "seek:":
551 time = int(action[5:])
552 self.screen.seekRelative(time * 90000)
554 HelpableActionMap.action(self, contexts, action)
556 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
558 "pauseService": (self.pauseService, "pause"),
559 "unPauseService": (self.unPauseService, "continue"),
561 "seekFwd": (self.seekFwd, "skip forward"),
562 "seekFwdDown": self.seekFwdDown,
563 "seekFwdUp": self.seekFwdUp,
564 "seekBack": (self.seekBack, "skip backward"),
565 "seekBackDown": self.seekBackDown,
566 "seekBackUp": self.seekBackUp,
568 # give them a little more priority to win over color buttons
570 self.seekstate = self.SEEK_STATE_PLAY
571 self.onClose.append(self.delTimer)
573 self.fwdtimer = False
574 self.fwdKeyTimer = eTimer()
575 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
577 self.rwdtimer = False
578 self.rwdKeyTimer = eTimer()
579 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
581 self.onPlayStateChanged = [ ]
583 self.lockedBecauseOfSkipping = False
596 service = self.session.nav.getCurrentService()
600 seek = service.seek()
602 if seek is None or not seek.isCurrentlySeekable():
607 def isSeekable(self):
608 if self.getSeek() is None:
612 def __seekableStatusChanged(self):
613 print "seekable status changed!"
614 if not self.isSeekable():
615 self["SeekActions"].setEnabled(False)
616 print "not seekable, return to play"
617 self.setSeekState(self.SEEK_STATE_PLAY)
619 self["SeekActions"].setEnabled(True)
622 def __serviceStarted(self):
623 self.seekstate = self.SEEK_STATE_PLAY
625 def setSeekState(self, state):
626 service = self.session.nav.getCurrentService()
631 if not self.isSeekable():
632 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
633 state = self.SEEK_STATE_PLAY
635 pauseable = service.pause()
637 if pauseable is None:
638 print "not pauseable."
639 state = self.SEEK_STATE_PLAY
641 oldstate = self.seekstate
642 self.seekstate = state
645 if oldstate[i] != self.seekstate[i]:
646 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
648 for c in self.onPlayStateChanged:
651 self.checkSkipShowHideLock()
655 def pauseService(self):
656 if self.seekstate == self.SEEK_STATE_PAUSE:
657 print "pause, but in fact unpause"
658 self.unPauseService()
660 if self.seekstate == self.SEEK_STATE_PLAY:
661 print "yes, playing."
663 print "no", self.seekstate
665 self.setSeekState(self.SEEK_STATE_PAUSE);
667 def unPauseService(self):
669 self.setSeekState(self.SEEK_STATE_PLAY);
671 def doSeek(self, seektime):
672 print "doseek", seektime
673 service = self.session.nav.getCurrentService()
677 seekable = self.getSeek()
681 seekable.seekTo(90 * seektime)
683 def seekFwdDown(self):
684 print "start fwd timer"
686 self.fwdKeyTimer.start(1000)
688 def seekBackDown(self):
689 print "start rewind timer"
691 self.rwdKeyTimer.start(1000)
696 self.fwdKeyTimer.stop()
697 self.fwdtimer = False
702 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
703 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
704 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
705 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
706 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
707 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
708 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
709 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
710 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
711 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
712 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
713 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
714 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
715 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
716 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
718 self.setSeekState(lookup[self.seekstate])
720 def seekBackUp(self):
723 self.rwdKeyTimer.stop()
724 self.rwdtimer = False
729 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
730 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
731 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
732 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
733 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
734 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
735 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
736 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
737 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
738 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
739 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
740 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
741 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
742 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
743 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
745 self.setSeekState(lookup[self.seekstate])
747 if self.seekstate == self.SEEK_STATE_PAUSE:
748 seekable = self.getSeek()
749 if seekable is not None:
750 seekable.seekRelative(-1, 2)
752 def fwdTimerFire(self):
753 print "Display seek fwd"
754 self.fwdKeyTimer.stop()
755 self.fwdtimer = False
756 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
758 def fwdSeekTo(self, minutes):
759 print "Seek", minutes, "minutes forward"
761 seekable = self.getSeek()
762 if seekable is not None:
763 seekable.seekRelative(1, minutes * 60 * 90000)
765 def rwdTimerFire(self):
767 self.rwdKeyTimer.stop()
768 self.rwdtimer = False
769 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
771 def rwdSeekTo(self, minutes):
773 self.fwdSeekTo(0 - minutes)
775 def checkSkipShowHideLock(self):
776 wantlock = self.seekstate != self.SEEK_STATE_PLAY
778 if self.lockedBecauseOfSkipping and not wantlock:
780 self.lockedBecauseOfSkipping = False
782 if wantlock and not self.lockedBecauseOfSkipping:
784 self.lockedBecauseOfSkipping = True
787 if self.seekstate != self.SEEK_STATE_PLAY:
788 self.setSeekState(self.SEEK_STATE_PAUSE)
790 #self.getSeek().seekRelative(1, -90000)
791 self.setSeekState(self.SEEK_STATE_PLAY)
793 self.setSeekState(self.SEEK_STATE_PAUSE)
796 self.setSeekState(self.SEEK_STATE_PLAY)
799 def seekRelative(self, diff):
800 seekable = self.getSeek()
801 if seekable is not None:
802 seekable.seekRelative(1, diff)
804 from Screens.PVRState import PVRState
806 class InfoBarPVRState:
808 self.onPlayStateChanged.append(self.__playStateChanged)
809 self.pvrStateDialog = self.session.instantiateDialog(PVRState)
810 self.onShow.append(self.__mayShow)
811 self.onHide.append(self.pvrStateDialog.hide)
814 if self.seekstate != self.SEEK_STATE_PLAY:
815 self.pvrStateDialog.show()
817 def __playStateChanged(self, state):
818 playstateString = state[3]
819 self.pvrStateDialog["state"].setText(playstateString)
822 class InfoBarShowMovies:
824 # i don't really like this class.
825 # it calls a not further specified "movie list" on up/down/movieList,
826 # so this is not more than an action map
828 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
830 "movieList": (self.showMovies, "movie list"),
831 "up": (self.showMovies, "movie list"),
832 "down": (self.showMovies, "movie list")
835 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
839 # Timeshift works the following way:
840 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
841 # - normal playback TUNER unused PLAY enable disable disable
842 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
843 # - user presess pause again FILE record PLAY enable disable enable
844 # - user fast forwards FILE record FF enable disable enable
845 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
846 # - user backwards FILE record BACK # !! enable disable enable
850 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
851 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
852 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
853 # - the user can now PVR around
854 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
855 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
857 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
858 # - if the user rewinds, or press pause, timeshift will be activated again
860 # note that a timeshift can be enabled ("recording") and
861 # activated (currently time-shifting).
863 class InfoBarTimeshift:
865 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
867 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
868 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
870 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
872 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
873 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
874 }, prio=-1) # priority over record
876 self.timeshift_enabled = 0
877 self.timeshift_state = 0
878 self.ts_pause_timer = eTimer()
879 self.ts_pause_timer.timeout.get().append(self.pauseService)
881 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
883 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
886 def getTimeshift(self):
887 service = self.session.nav.getCurrentService()
888 return service.timeshift()
890 def startTimeshift(self):
891 print "enable timeshift"
892 ts = self.getTimeshift()
894 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
895 print "no ts interface"
898 if self.timeshift_enabled:
899 print "hu, timeshift already enabled?"
901 if not ts.startTimeshift():
902 self.timeshift_enabled = 1
905 self.setSeekState(self.SEEK_STATE_PAUSE)
907 # enable the "TimeshiftEnableActions", which will override
908 # the startTimeshift actions
909 self.__seekableStatusChanged()
911 print "timeshift failed"
913 def stopTimeshift(self):
914 if not self.timeshift_enabled:
916 print "disable timeshift"
917 ts = self.getTimeshift()
920 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
922 def stopTimeshiftConfirmed(self, confirmed):
926 ts = self.getTimeshift()
931 self.timeshift_enabled = 0
934 self.__seekableStatusChanged()
936 # activates timeshift, and seeks to (almost) the end
937 def activateTimeshiftEnd(self):
938 ts = self.getTimeshift()
943 if ts.isTimeshiftActive():
944 print "!! activate timeshift called - but shouldn't this be a normal pause?"
947 self.setSeekState(self.SEEK_STATE_PLAY)
948 ts.activateTimeshift()
951 # same as activateTimeshiftEnd, but pauses afterwards.
952 def activateTimeshiftEndAndPause(self):
953 state = self.seekstate
954 self.activateTimeshiftEnd()
956 # well, this is "andPause", but it could be pressed from pause,
957 # when pausing on the (fake-)"live" picture, so an un-pause
960 print "now, pauseService"
961 if state == self.SEEK_STATE_PLAY:
962 print "is PLAYING, start pause timer"
963 self.ts_pause_timer.start(200, 1)
966 self.unPauseService()
968 def __seekableStatusChanged(self):
971 print "self.isSeekable", self.isSeekable()
972 print "self.timeshift_enabled", self.timeshift_enabled
974 # when this service is not seekable, but timeshift
975 # is enabled, this means we can activate
977 if not self.isSeekable() and self.timeshift_enabled:
980 print "timeshift activate:", enabled
981 self["TimeshiftActivateActions"].setEnabled(enabled)
983 from RecordTimer import parseEvent
985 class InfoBarInstantRecord:
986 """Instant Record - handles the instantRecord action in order to
987 start/stop instant records"""
989 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
991 "instantRecord": (self.instantRecord, "Instant Record..."),
993 self.recording = None
994 self["BlinkingPoint"] = BlinkingPixmapConditional()
995 self["BlinkingPoint"].hide()
996 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
998 def stopCurrentRecording(self):
999 self.session.nav.RecordTimer.removeEntry(self.recording)
1000 self.recording = None
1002 def startInstantRecording(self):
1003 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1005 # try to get event info
1008 service = self.session.nav.getCurrentService()
1009 epg = eEPGCache.getInstance()
1010 event = epg.lookupEventTime(serviceref, -1, 0)
1012 info = service.info()
1013 ev = info.getEvent(0)
1018 if event is not None:
1019 data = parseEvent(event)
1021 end = begin + 3600 * 10
1022 data = (begin, end, data[2], data[3], data[4])
1024 data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
1026 # fix me, description.
1027 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
1028 self.recording.dontSave = True
1030 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1032 def isInstantRecordRunning(self):
1033 if self.recording != None:
1034 if self.recording.isRunning():
1038 def recordQuestionCallback(self, answer):
1042 if self.isInstantRecordRunning():
1043 self.stopCurrentRecording()
1045 self.startInstantRecording()
1047 def instantRecord(self):
1049 stat = os.stat(resolveFilename(SCOPE_HDD))
1051 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1054 if self.isInstantRecordRunning():
1055 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
1057 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
1059 from Screens.AudioSelection import AudioSelection
1061 class InfoBarAudioSelection:
1063 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1065 "audioSelection": (self.audioSelection, "Audio Options..."),
1068 def audioSelection(self):
1069 service = self.session.nav.getCurrentService()
1070 audio = service.audioTracks()
1071 n = audio.getNumberOfTracks()
1073 self.session.open(AudioSelection, audio)
1075 from Screens.SubserviceSelection import SubserviceSelection
1077 class InfoBarSubserviceSelection:
1079 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1081 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1084 def subserviceSelection(self):
1085 service = self.session.nav.getCurrentService()
1086 subservices = service.subServices()
1087 n = subservices.getNumberOfSubservices()
1089 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1091 def subserviceSelected(self, service):
1092 if not service is None:
1093 self.session.nav.playService(service)
1095 class InfoBarAdditionalInfo:
1097 self["DolbyActive"] = Pixmap()
1098 self["CryptActive"] = Pixmap()
1099 self["FormatActive"] = Pixmap()
1101 self["ButtonRed"] = PixmapConditional(withTimer = False)
1102 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1103 self.onLayoutFinish.append(self["ButtonRed"].update)
1104 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1105 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1106 self.onLayoutFinish.append(self["ButtonRedText"].update)
1108 self["ButtonGreen"] = Pixmap()
1109 self["ButtonGreenText"] = Label(_("Subservices"))
1111 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1112 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1113 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1114 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1115 self.onLayoutFinish.append(self["ButtonYellow"].update)
1116 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1118 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1119 self["ButtonBlue"].setConnect(lambda: False)
1120 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1121 self["ButtonBlueText"].setConnect(lambda: False)
1122 self.onLayoutFinish.append(self["ButtonBlue"].update)
1123 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1125 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1127 def hideSubServiceIndication(self):
1128 self["ButtonGreen"].hide()
1129 self["ButtonGreenText"].hide()
1131 def showSubServiceIndication(self):
1132 self["ButtonGreen"].show()
1133 self["ButtonGreenText"].show()
1135 def checkFormat(self, service):
1136 info = service.info()
1137 if info is not None:
1138 aspect = info.getInfo(iServiceInformation.sAspect)
1139 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1140 self["FormatActive"].show()
1142 self["FormatActive"].hide()
1144 def checkSubservices(self, service):
1145 if service.subServices().getNumberOfSubservices() > 0:
1146 self.showSubServiceIndication()
1148 self.hideSubServiceIndication()
1150 def checkDolby(self, service):
1153 audio = service.audioTracks()
1154 if audio is not None:
1155 n = audio.getNumberOfTracks()
1157 i = audio.getTrackInfo(x)
1158 description = i.getDescription();
1159 if description.find("AC3") != -1 or description.find("DTS") != -1:
1163 self["DolbyActive"].show()
1165 self["DolbyActive"].hide()
1167 def checkCrypted(self, service):
1168 info = service.info()
1169 if info is not None:
1170 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1171 self["CryptActive"].show()
1173 self["CryptActive"].hide()
1175 def gotServiceEvent(self, ev):
1176 service = self.session.nav.getCurrentService()
1177 if ev == iPlayableService.evUpdatedEventInfo:
1178 self.checkSubservices(service)
1179 self.checkFormat(service)
1180 elif ev == iPlayableService.evUpdatedInfo:
1181 self.checkCrypted(service)
1182 self.checkDolby(service)
1183 elif ev == iPlayableService.evEnd:
1184 self.hideSubServiceIndication()
1185 self["CryptActive"].hide()
1186 self["DolbyActive"].hide()
1187 self["FormatActive"].hide()
1189 class InfoBarNotifications:
1191 self.onExecBegin.append(self.checkNotifications)
1192 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1194 def checkNotificationsIfExecing(self):
1196 self.checkNotifications()
1198 def checkNotifications(self):
1199 if len(Notifications.notifications):
1200 n = Notifications.notifications[0]
1201 Notifications.notifications = Notifications.notifications[1:]
1205 self.session.openWithCallback(cb, *n[1:])
1207 self.session.open(*n[1:])
1209 class InfoBarServiceNotifications:
1211 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1213 iPlayableService.evEnd: self.serviceHasEnded
1216 def serviceHasEnded(self):
1217 print "service end!"
1220 self.setSeekState(self.SEEK_STATE_PLAY)
1224 class InfoBarCueSheetSupport:
1230 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1232 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1233 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1234 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1238 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1240 iPlayableService.evStart: self.__serviceStarted,
1243 def __serviceStarted(self):
1244 print "new service started! trying to download cuts!"
1245 self.downloadCuesheet()
1247 def __getSeekable(self):
1248 service = self.session.nav.getCurrentService()
1251 return service.seek()
1253 def cueGetCurrentPosition(self):
1254 seek = self.__getSeekable()
1257 r = seek.getPlayPosition()
1262 def jumpPreviousNextMark(self, cmp, alternative=None):
1263 current_pos = self.cueGetCurrentPosition()
1264 if current_pos is None:
1266 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1267 if mark is not None:
1269 elif alternative is not None:
1274 seekable = self.__getSeekable()
1275 if seekable is not None:
1276 seekable.seekTo(pts)
1278 def jumpPreviousMark(self):
1279 # we add 2 seconds, so if the play position is <2s after
1280 # the mark, the mark before will be used
1281 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1283 def jumpNextMark(self):
1284 self.jumpPreviousNextMark(lambda x: x)
1286 def getNearestCutPoint(self, pts, cmp=abs):
1289 for cp in self.cut_list:
1290 diff = cmp(cp[0] - pts)
1291 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1295 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1296 current_pos = self.cueGetCurrentPosition()
1297 if current_pos is None:
1298 print "not seekable"
1301 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1303 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1305 return nearest_cutpoint
1307 self.removeMark(nearest_cutpoint)
1308 elif not onlyremove and not onlyreturn:
1309 self.addMark((current_pos, self.CUT_TYPE_MARK))
1314 def addMark(self, point):
1315 bisect.insort(self.cut_list, point)
1316 self.uploadCuesheet()
1318 def removeMark(self, point):
1319 self.cut_list.remove(point)
1320 self.uploadCuesheet()
1322 def __getCuesheet(self):
1323 service = self.session.nav.getCurrentService()
1326 return service.cueSheet()
1328 def uploadCuesheet(self):
1329 cue = self.__getCuesheet()
1332 print "upload failed, no cuesheet interface"
1334 cue.setCutList(self.cut_list)
1336 def downloadCuesheet(self):
1337 cue = self.__getCuesheet()
1340 print "upload failed, no cuesheet interface"
1342 self.cut_list = cue.getCutList()