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 def fwdTimerFire(self):
748 print "Display seek fwd"
749 self.fwdKeyTimer.stop()
750 self.fwdtimer = False
751 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
753 def fwdSeekTo(self, minutes):
754 print "Seek", minutes, "minutes forward"
756 seekable = self.getSeek()
757 if seekable is not None:
758 seekable.seekRelative(1, minutes * 60 * 90000)
760 def rwdTimerFire(self):
762 self.rwdKeyTimer.stop()
763 self.rwdtimer = False
764 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
766 def rwdSeekTo(self, minutes):
768 self.fwdSeekTo(0 - minutes)
770 def checkSkipShowHideLock(self):
771 wantlock = self.seekstate != self.SEEK_STATE_PLAY
773 if self.lockedBecauseOfSkipping and not wantlock:
775 self.lockedBecauseOfSkipping = False
777 if wantlock and not self.lockedBecauseOfSkipping:
779 self.lockedBecauseOfSkipping = True
782 if self.seekstate != self.SEEK_STATE_PLAY:
783 self.setSeekState(self.SEEK_STATE_PAUSE)
785 #self.getSeek().seekRelative(1, -90000)
786 self.setSeekState(self.SEEK_STATE_PLAY)
788 self.setSeekState(self.SEEK_STATE_PAUSE)
791 self.setSeekState(self.SEEK_STATE_PLAY)
794 def seekRelative(self, diff):
795 seekable = self.getSeek()
796 if seekable is not None:
797 seekable.seekRelative(1, diff)
799 from Screens.PVRState import PVRState
801 class InfoBarPVRState:
803 self.onPlayStateChanged.append(self.__playStateChanged)
804 self.pvrStateDialog = self.session.instantiateDialog(PVRState)
805 self.onShow.append(self.__mayShow)
806 self.onHide.append(self.pvrStateDialog.hide)
809 if self.seekstate != self.SEEK_STATE_PLAY:
810 self.pvrStateDialog.show()
812 def __playStateChanged(self, state):
813 playstateString = state[3]
814 self.pvrStateDialog["state"].setText(playstateString)
817 class InfoBarShowMovies:
819 # i don't really like this class.
820 # it calls a not further specified "movie list" on up/down/movieList,
821 # so this is not more than an action map
823 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
825 "movieList": (self.showMovies, "movie list"),
826 "up": (self.showMovies, "movie list"),
827 "down": (self.showMovies, "movie list")
830 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
834 # Timeshift works the following way:
835 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
836 # - normal playback TUNER unused PLAY enable disable disable
837 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
838 # - user presess pause again FILE record PLAY enable disable enable
839 # - user fast forwards FILE record FF enable disable enable
840 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
841 # - user backwards FILE record BACK # !! enable disable enable
845 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
846 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
847 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
848 # - the user can now PVR around
849 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
850 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
852 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
853 # - if the user rewinds, or press pause, timeshift will be activated again
855 # note that a timeshift can be enabled ("recording") and
856 # activated (currently time-shifting).
858 class InfoBarTimeshift:
860 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
862 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
863 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
865 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
867 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
868 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
869 }, prio=-1) # priority over record
871 self.timeshift_enabled = 0
872 self.timeshift_state = 0
873 self.ts_pause_timer = eTimer()
874 self.ts_pause_timer.timeout.get().append(self.pauseService)
876 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
878 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
881 def getTimeshift(self):
882 service = self.session.nav.getCurrentService()
883 return service.timeshift()
885 def startTimeshift(self):
886 print "enable timeshift"
887 ts = self.getTimeshift()
889 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
890 print "no ts interface"
893 if self.timeshift_enabled:
894 print "hu, timeshift already enabled?"
896 if not ts.startTimeshift():
897 self.timeshift_enabled = 1
900 self.setSeekState(self.SEEK_STATE_PAUSE)
902 # enable the "TimeshiftEnableActions", which will override
903 # the startTimeshift actions
904 self.__seekableStatusChanged()
906 print "timeshift failed"
908 def stopTimeshift(self):
909 if not self.timeshift_enabled:
911 print "disable timeshift"
912 ts = self.getTimeshift()
915 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
917 def stopTimeshiftConfirmed(self, confirmed):
921 ts = self.getTimeshift()
926 self.timeshift_enabled = 0
929 self.__seekableStatusChanged()
931 # activates timeshift, and seeks to (almost) the end
932 def activateTimeshiftEnd(self):
933 ts = self.getTimeshift()
938 if ts.isTimeshiftActive():
939 print "!! activate timeshift called - but shouldn't this be a normal pause?"
942 self.setSeekState(self.SEEK_STATE_PLAY)
943 ts.activateTimeshift()
946 # same as activateTimeshiftEnd, but pauses afterwards.
947 def activateTimeshiftEndAndPause(self):
948 state = self.seekstate
949 self.activateTimeshiftEnd()
951 # well, this is "andPause", but it could be pressed from pause,
952 # when pausing on the (fake-)"live" picture, so an un-pause
955 print "now, pauseService"
956 if state == self.SEEK_STATE_PLAY:
957 print "is PLAYING, start pause timer"
958 self.ts_pause_timer.start(200, 1)
961 self.unPauseService()
963 def __seekableStatusChanged(self):
966 print "self.isSeekable", self.isSeekable()
967 print "self.timeshift_enabled", self.timeshift_enabled
969 # when this service is not seekable, but timeshift
970 # is enabled, this means we can activate
972 if not self.isSeekable() and self.timeshift_enabled:
975 print "timeshift activate:", enabled
976 self["TimeshiftActivateActions"].setEnabled(enabled)
978 from RecordTimer import parseEvent
980 class InfoBarInstantRecord:
981 """Instant Record - handles the instantRecord action in order to
982 start/stop instant records"""
984 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
986 "instantRecord": (self.instantRecord, "Instant Record..."),
988 self.recording = None
989 self["BlinkingPoint"] = BlinkingPixmapConditional()
990 self["BlinkingPoint"].hide()
991 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
993 def stopCurrentRecording(self):
994 self.session.nav.RecordTimer.removeEntry(self.recording)
995 self.recording = None
997 def startInstantRecording(self):
998 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1000 # try to get event info
1003 service = self.session.nav.getCurrentService()
1004 epg = eEPGCache.getInstance()
1005 event = epg.lookupEventTime(serviceref, -1, 0)
1007 info = service.info()
1008 ev = info.getEvent(0)
1013 if event is not None:
1014 data = parseEvent(event)
1016 end = begin + 3600 * 10
1017 data = (begin, end, data[2], data[3], data[4])
1019 data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
1021 # fix me, description.
1022 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
1023 self.recording.dontSave = True
1025 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1027 def isInstantRecordRunning(self):
1028 if self.recording != None:
1029 if self.recording.isRunning():
1033 def recordQuestionCallback(self, answer):
1037 if self.isInstantRecordRunning():
1038 self.stopCurrentRecording()
1040 self.startInstantRecording()
1042 def instantRecord(self):
1044 stat = os.stat(resolveFilename(SCOPE_HDD))
1046 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1049 if self.isInstantRecordRunning():
1050 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
1052 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
1054 from Screens.AudioSelection import AudioSelection
1056 class InfoBarAudioSelection:
1058 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1060 "audioSelection": (self.audioSelection, "Audio Options..."),
1063 def audioSelection(self):
1064 service = self.session.nav.getCurrentService()
1065 audio = service.audioTracks()
1066 n = audio.getNumberOfTracks()
1068 self.session.open(AudioSelection, audio)
1070 from Screens.SubserviceSelection import SubserviceSelection
1072 class InfoBarSubserviceSelection:
1074 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1076 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1079 def subserviceSelection(self):
1080 service = self.session.nav.getCurrentService()
1081 subservices = service.subServices()
1082 n = subservices.getNumberOfSubservices()
1084 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1086 def subserviceSelected(self, service):
1087 if not service is None:
1088 self.session.nav.playService(service)
1090 class InfoBarAdditionalInfo:
1092 self["DolbyActive"] = Pixmap()
1093 self["CryptActive"] = Pixmap()
1094 self["FormatActive"] = Pixmap()
1096 self["ButtonRed"] = PixmapConditional(withTimer = False)
1097 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1098 self.onLayoutFinish.append(self["ButtonRed"].update)
1099 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1100 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1101 self.onLayoutFinish.append(self["ButtonRedText"].update)
1103 self["ButtonGreen"] = Pixmap()
1104 self["ButtonGreenText"] = Label(_("Subservices"))
1106 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1107 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1108 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1109 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1110 self.onLayoutFinish.append(self["ButtonYellow"].update)
1111 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1113 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1114 self["ButtonBlue"].setConnect(lambda: False)
1115 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1116 self["ButtonBlueText"].setConnect(lambda: False)
1117 self.onLayoutFinish.append(self["ButtonBlue"].update)
1118 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1120 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1122 def hideSubServiceIndication(self):
1123 self["ButtonGreen"].hide()
1124 self["ButtonGreenText"].hide()
1126 def showSubServiceIndication(self):
1127 self["ButtonGreen"].show()
1128 self["ButtonGreenText"].show()
1130 def checkFormat(self, service):
1131 info = service.info()
1132 if info is not None:
1133 aspect = info.getInfo(iServiceInformation.sAspect)
1134 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1135 self["FormatActive"].show()
1137 self["FormatActive"].hide()
1139 def checkSubservices(self, service):
1140 if service.subServices().getNumberOfSubservices() > 0:
1141 self.showSubServiceIndication()
1143 self.hideSubServiceIndication()
1145 def checkDolby(self, service):
1148 audio = service.audioTracks()
1149 if audio is not None:
1150 n = audio.getNumberOfTracks()
1152 i = audio.getTrackInfo(x)
1153 description = i.getDescription();
1154 if description.find("AC3") != -1 or description.find("DTS") != -1:
1158 self["DolbyActive"].show()
1160 self["DolbyActive"].hide()
1162 def checkCrypted(self, service):
1163 info = service.info()
1164 if info is not None:
1165 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1166 self["CryptActive"].show()
1168 self["CryptActive"].hide()
1170 def gotServiceEvent(self, ev):
1171 service = self.session.nav.getCurrentService()
1172 if ev == iPlayableService.evUpdatedEventInfo:
1173 self.checkSubservices(service)
1174 self.checkFormat(service)
1175 elif ev == iPlayableService.evUpdatedInfo:
1176 self.checkCrypted(service)
1177 self.checkDolby(service)
1178 elif ev == iPlayableService.evEnd:
1179 self.hideSubServiceIndication()
1180 self["CryptActive"].hide()
1181 self["DolbyActive"].hide()
1182 self["FormatActive"].hide()
1184 class InfoBarNotifications:
1186 self.onExecBegin.append(self.checkNotifications)
1187 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1189 def checkNotificationsIfExecing(self):
1191 self.checkNotifications()
1193 def checkNotifications(self):
1194 if len(Notifications.notifications):
1195 n = Notifications.notifications[0]
1196 Notifications.notifications = Notifications.notifications[1:]
1200 self.session.openWithCallback(cb, *n[1:])
1202 self.session.open(*n[1:])
1204 class InfoBarServiceNotifications:
1206 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1208 iPlayableService.evEnd: self.serviceHasEnded
1211 def serviceHasEnded(self):
1212 print "service end!"
1215 self.setSeekState(self.SEEK_STATE_PLAY)
1219 class InfoBarCueSheetSupport:
1225 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1227 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1228 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1229 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1233 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1235 iPlayableService.evStart: self.__serviceStarted,
1238 def __serviceStarted(self):
1239 print "new service started! trying to download cuts!"
1240 self.downloadCuesheet()
1242 def __getSeekable(self):
1243 service = self.session.nav.getCurrentService()
1246 return service.seek()
1248 def cueGetCurrentPosition(self):
1249 seek = self.__getSeekable()
1252 r = seek.getPlayPosition()
1257 def jumpPreviousNextMark(self, cmp, alternative=None):
1258 current_pos = self.cueGetCurrentPosition()
1259 if current_pos is None:
1261 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1262 if mark is not None:
1264 elif alternative is not None:
1269 seekable = self.__getSeekable()
1270 if seekable is not None:
1271 seekable.seekTo(pts)
1273 def jumpPreviousMark(self):
1274 # we add 2 seconds, so if the play position is <2s after
1275 # the mark, the mark before will be used
1276 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1278 def jumpNextMark(self):
1279 self.jumpPreviousNextMark(lambda x: x)
1281 def getNearestCutPoint(self, pts, cmp=abs):
1284 for cp in self.cut_list:
1285 diff = cmp(cp[0] - pts)
1286 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1290 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000):
1291 current_pos = self.cueGetCurrentPosition()
1292 if current_pos is None:
1293 print "not seekable"
1296 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1298 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1300 self.removeMark(nearest_cutpoint)
1301 elif not onlyremove:
1302 self.addMark((current_pos, self.CUT_TYPE_MARK))
1304 def addMark(self, point):
1305 bisect.insort(self.cut_list, point)
1306 self.uploadCuesheet()
1308 def removeMark(self, point):
1309 self.cut_list.remove(point)
1310 self.uploadCuesheet()
1312 def __getCuesheet(self):
1313 service = self.session.nav.getCurrentService()
1316 return service.cueSheet()
1318 def uploadCuesheet(self):
1319 cue = self.__getCuesheet()
1322 print "upload failed, no cuesheet interface"
1324 cue.setCutList(self.cut_list)
1326 def downloadCuesheet(self):
1327 cue = self.__getCuesheet()
1330 print "upload failed, no cuesheet interface"
1332 self.cut_list = cue.getCutList()