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
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
36 from Components.config import config, currentConfigSelectionElement
39 from Menu import MainMenu, mdom
43 self.dishDialog = self.session.instantiateDialog(Dish)
44 self.onShown.append(self.dishDialog.show)
46 class InfoBarShowHide:
47 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
55 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
57 "toggleShow": self.toggleShow,
61 self.__state = self.STATE_SHOWN
64 self.onExecBegin.append(self.show)
66 self.hideTimer = eTimer()
67 self.hideTimer.timeout.get().append(self.doTimerHide)
68 self.hideTimer.start(5000, True)
70 self.onShow.append(self.__onShow)
71 self.onHide.append(self.__onHide)
74 self.__state = self.STATE_SHOWN
77 def startHideTimer(self):
78 if self.__state == self.STATE_SHOWN and not self.__locked:
79 self.hideTimer.start(5000, True)
82 self.__state = self.STATE_HIDDEN
88 def doTimerHide(self):
90 if self.__state == self.STATE_SHOWN:
94 if self.__state == self.STATE_SHOWN:
97 elif self.__state == self.STATE_HIDDEN:
101 self.__locked = self.__locked + 1
104 self.hideTimer.stop()
106 def unlockShow(self):
107 self.__locked = self.__locked - 1
109 self.startHideTimer()
111 # def startShow(self):
112 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
113 # self.__state = self.STATE_SHOWN
115 # def startHide(self):
116 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
117 # self.__state = self.STATE_HIDDEN
119 class NumberZap(Screen):
126 self.close(int(self["number"].getText()))
128 def keyNumberGlobal(self, number):
129 self.Timer.start(3000, True) #reset timer
130 self.field = self.field + str(number)
131 self["number"].setText(self.field)
132 if len(self.field) >= 4:
135 def __init__(self, session, number):
136 Screen.__init__(self, session)
137 self.field = str(number)
139 self["channel"] = Label(_("Channel:"))
141 self["number"] = Label(self.field)
143 self["actions"] = NumberActionMap( [ "SetupActions" ],
147 "1": self.keyNumberGlobal,
148 "2": self.keyNumberGlobal,
149 "3": self.keyNumberGlobal,
150 "4": self.keyNumberGlobal,
151 "5": self.keyNumberGlobal,
152 "6": self.keyNumberGlobal,
153 "7": self.keyNumberGlobal,
154 "8": self.keyNumberGlobal,
155 "9": self.keyNumberGlobal,
156 "0": self.keyNumberGlobal
159 self.Timer = eTimer()
160 self.Timer.timeout.get().append(self.keyOK)
161 self.Timer.start(3000, True)
163 class InfoBarPowerKey:
164 """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
167 self.powerKeyTimer = eTimer()
168 self.powerKeyTimer.timeout.get().append(self.powertimer)
169 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
171 "powerdown": self.powerdown,
172 "powerup": self.powerup,
173 "discreteStandby": (self.standby, "Go standby"),
174 "discretePowerOff": (self.quit, "Go to deep standby"),
177 def powertimer(self):
178 print "PowerOff - Now!"
182 self.standbyblocked = 0
183 self.powerKeyTimer.start(3000, True)
186 self.powerKeyTimer.stop()
187 if self.standbyblocked == 0:
188 self.standbyblocked = 1
192 self.session.open(Standby, self)
198 class InfoBarNumberZap:
199 """ Handles an initial number for NumberZapping """
201 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
203 "1": self.keyNumberGlobal,
204 "2": self.keyNumberGlobal,
205 "3": self.keyNumberGlobal,
206 "4": self.keyNumberGlobal,
207 "5": self.keyNumberGlobal,
208 "6": self.keyNumberGlobal,
209 "7": self.keyNumberGlobal,
210 "8": self.keyNumberGlobal,
211 "9": self.keyNumberGlobal,
212 "0": self.keyNumberGlobal,
215 def keyNumberGlobal(self, number):
216 # print "You pressed number " + str(number)
218 self.servicelist.recallPrevService()
221 self.session.openWithCallback(self.numberEntered, NumberZap, number)
223 def numberEntered(self, retval):
224 # print self.servicelist
226 self.zapToNumber(retval)
228 def searchNumberHelper(self, serviceHandler, num, bouquet):
229 servicelist = serviceHandler.list(bouquet)
230 if not servicelist is None:
232 serviceIterator = servicelist.getNext()
233 if not serviceIterator.valid(): #check end of list
235 if serviceIterator.flags: #assume normal dvb service have no flags set
238 if not num: #found service with searched number ?
239 return serviceIterator, 0
242 def zapToNumber(self, number):
243 bouquet = self.servicelist.bouquet_root
245 serviceHandler = eServiceCenter.getInstance()
246 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
247 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
249 bouquetlist = serviceHandler.list(bouquet)
250 if not bouquetlist is None:
252 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
253 if not bouquet.valid(): #check end of list
255 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
257 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
258 if not service is None:
259 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
260 self.servicelist.clearPath()
261 if self.servicelist.bouquet_root != bouquet:
262 self.servicelist.enterPath(self.servicelist.bouquet_root)
263 self.servicelist.enterPath(bouquet)
264 self.servicelist.setCurrentSelection(service) #select the service in servicelist
265 self.servicelist.zap()
267 class InfoBarChannelSelection:
268 """ ChannelSelection - handles the channelSelection dialog and the initial
269 channelChange actions which open the channelSelection dialog """
272 self.servicelist = self.session.instantiateDialog(ChannelSelection)
274 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
276 "switchChannelUp": self.switchChannelUp,
277 "switchChannelDown": self.switchChannelDown,
278 "zapUp": (self.zapUp, _("next channel")),
279 "zapDown": (self.zapDown, _("previous channel")),
282 def switchChannelUp(self):
283 self.servicelist.moveUp()
284 self.session.execDialog(self.servicelist)
286 def switchChannelDown(self):
287 self.servicelist.moveDown()
288 self.session.execDialog(self.servicelist)
291 self.servicelist.moveUp()
292 self.servicelist.zap()
296 self.servicelist.moveDown()
297 self.servicelist.zap()
301 """ Handles a menu action, to open the (main) menu """
303 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
305 "mainMenu": (self.mainMenu, "Enter main menu..."),
309 print "loading mainmenu XML..."
310 menu = mdom.childNodes[0]
311 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
312 self.session.open(MainMenu, menu, menu.childNodes)
315 """ EPG - Opens an EPG list when the showEPGList action fires """
317 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
319 "showEventInfo": (self.openEventView, _("show EPG...")),
322 def zapToService(self, service):
323 if not service is None:
324 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
325 self.servicelist.clearPath()
326 if self.servicelist.bouquet_root != self.epg_bouquet:
327 self.servicelist.enterPath(self.servicelist.bouquet_root)
328 self.servicelist.enterPath(self.epg_bouquet)
329 self.servicelist.setCurrentSelection(service) #select the service in servicelist
330 self.servicelist.zap()
332 def openBouquetEPG(self, bouquet):
333 ptr=eEPGCache.getInstance()
335 servicelist = eServiceCenter.getInstance().list(bouquet)
336 if not servicelist is None:
338 service = servicelist.getNext()
339 if not service.valid(): #check if end of list
341 if service.flags: #ignore non playable services
343 services.append(ServiceReference(service))
345 self.epg_bouquet = bouquet
346 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
348 def closed(self, ret):
352 def openMultiServiceEPG(self):
353 bouquets = self.servicelist.getBouquetList()
358 if cnt > 1: # show bouquet list
359 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
361 self.openBouquetEPG(bouquets[0][1])
363 def openSingleServiceEPG(self):
364 ref=self.session.nav.getCurrentlyPlayingServiceReference()
365 ptr=eEPGCache.getInstance()
366 self.session.openWithCallback(self.closed, EPGSelection, ref)
368 def openEventView(self):
370 service = self.session.nav.getCurrentService()
371 ref = self.session.nav.getCurrentlyPlayingServiceReference()
372 info = service.info()
375 self.epglist.append(ptr)
378 self.epglist.append(ptr)
379 if len(self.epglist) == 0:
380 epg = eEPGCache.getInstance()
381 ptr = epg.lookupEventTime(ref, -1)
383 self.epglist.append(ptr)
384 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
386 self.epglist.append(ptr)
387 if len(self.epglist) > 0:
388 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
390 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
391 self.openMultiServiceEPG()
393 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
394 if len(self.epglist) > 1:
395 tmp = self.epglist[0]
396 self.epglist[0]=self.epglist[1]
398 setEvent(self.epglist[0])
403 """provides a snr/agc/ber display"""
405 self["snr"] = Label()
406 self["agc"] = Label()
407 self["ber"] = Label()
408 self["snr_percent"] = Label()
409 self["agc_percent"] = Label()
410 self["ber_count"] = Label()
411 self["snr_progress"] = ProgressBar()
412 self["agc_progress"] = ProgressBar()
413 self["ber_progress"] = ProgressBar()
414 self.timer = eTimer()
415 self.timer.timeout.get().append(self.updateTunerInfo)
416 self.timer.start(1000)
422 return (long)(log(val)/log(2))
425 def updateTunerInfo(self):
426 if self.instance.isVisible():
427 service = self.session.nav.getCurrentService()
431 if service is not None:
432 feinfo = service.frontendStatusInfo()
433 if feinfo is not None:
434 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
435 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
436 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
437 self["snr_percent"].setText("%d%%"%(snr))
438 self["agc_percent"].setText("%d%%"%(agc))
439 self["ber_count"].setText("%d"%(ber))
440 self["snr_progress"].setValue(snr)
441 self["agc_progress"].setValue(agc)
442 self["ber_progress"].setValue(self.calc(ber))
445 """provides a current/next event info display"""
447 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
448 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
450 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
451 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
453 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
454 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
456 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
458 class InfoBarServiceName:
460 self["ServiceName"] = ServiceName(self.session.nav)
463 """handles actions like seeking, pause"""
465 # ispause, isff, issm
466 SEEK_STATE_PLAY = (0, 0, 0, ">")
467 SEEK_STATE_PAUSE = (1, 0, 0, "||")
468 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
469 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
470 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
471 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
472 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
473 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
475 SEEK_STATE_BACK_4X = (0, -4, 0, "<< 4x")
476 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
477 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
478 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
480 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
481 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
482 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
485 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
487 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
488 iPlayableService.evStart: self.__serviceStarted,
490 iPlayableService.evEOF: self.__evEOF,
491 iPlayableService.evSOF: self.__evSOF,
493 self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions",
495 "pauseService": (self.pauseService, "pause"),
496 "unPauseService": (self.unPauseService, "continue"),
498 "seekFwd": (self.seekFwd, "skip forward"),
499 "seekFwdUp": (self.seekFwdUp, "skip forward"),
500 "seekBack": (self.seekBack, "skip backward"),
501 "seekBackUp": (self.seekBackUp, "skip backward"),
503 # give them a little more priority to win over color buttons
505 self.seekstate = self.SEEK_STATE_PLAY
506 self.onClose.append(self.delTimer)
508 self.fwdtimer = False
509 self.fwdKeyTimer = eTimer()
510 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
512 self.rwdtimer = False
513 self.rwdKeyTimer = eTimer()
514 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
516 self.onPlayStateChanged = [ ]
518 self.lockedBecauseOfSkipping = False
531 service = self.session.nav.getCurrentService()
535 seek = service.seek()
537 if seek is None or not seek.isCurrentlySeekable():
542 def isSeekable(self):
543 if self.getSeek() is None:
547 def __seekableStatusChanged(self):
548 print "seekable status changed!"
549 if not self.isSeekable():
550 self["SeekActions"].setEnabled(False)
551 print "not seekable, return to play"
552 self.setSeekState(self.SEEK_STATE_PLAY)
554 self["SeekActions"].setEnabled(True)
557 def __serviceStarted(self):
558 self.seekstate = self.SEEK_STATE_PLAY
560 def setSeekState(self, state):
561 service = self.session.nav.getCurrentService()
566 if not self.isSeekable():
567 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
568 state = self.SEEK_STATE_PLAY
570 pauseable = service.pause()
572 if pauseable is None:
573 print "not pauseable."
574 state = self.SEEK_STATE_PLAY
576 oldstate = self.seekstate
577 self.seekstate = state
580 if oldstate[i] != self.seekstate[i]:
581 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
583 for c in self.onPlayStateChanged:
586 self.checkSkipShowHideLock()
590 def pauseService(self):
591 if self.seekstate == self.SEEK_STATE_PAUSE:
592 print "pause, but in fact unpause"
593 self.unPauseService()
595 if self.seekstate == self.SEEK_STATE_PLAY:
596 print "yes, playing."
598 print "no", self.seekstate
600 self.setSeekState(self.SEEK_STATE_PAUSE);
602 def unPauseService(self):
604 self.setSeekState(self.SEEK_STATE_PLAY);
606 def doSeek(self, seektime):
607 print "doseek", seektime
608 service = self.session.nav.getCurrentService()
612 seekable = self.getSeek()
616 seekable.seekTo(90 * seektime)
619 print "start fwd timer"
621 self.fwdKeyTimer.start(500)
624 print "start rewind timer"
626 self.rwdKeyTimer.start(500)
631 self.fwdKeyTimer.stop()
632 self.fwdtimer = False
634 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
635 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
636 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
637 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
638 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
639 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
640 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
641 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
642 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
643 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
644 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
645 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
646 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
647 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
648 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
650 self.setSeekState(lookup[self.seekstate]);
652 def seekBackUp(self):
655 self.rwdKeyTimer.stop()
656 self.rwdtimer = False
659 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
660 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
661 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
662 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
663 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
664 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
665 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
666 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
667 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
668 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
669 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
670 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
671 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
672 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
673 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
675 self.setSeekState(lookup[self.seekstate]);
677 def fwdTimerFire(self):
678 print "Display seek fwd"
679 self.fwdKeyTimer.stop()
680 self.fwdtimer = False
681 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
683 def fwdSeekTo(self, minutes):
684 print "Seek", minutes, "minutes forward"
686 seekable = self.getSeek()
687 if seekable is not None:
688 seekable.seekRelative(1, minutes * 60 * 90000)
690 def rwdTimerFire(self):
692 self.rwdKeyTimer.stop()
693 self.rwdtimer = False
694 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
696 def rwdSeekTo(self, minutes):
698 self.fwdSeekTo(0 - minutes)
700 def checkSkipShowHideLock(self):
701 wantlock = self.seekstate != self.SEEK_STATE_PLAY
703 if self.lockedBecauseOfSkipping and not wantlock:
705 self.lockedBecauseOfSkipping = False
707 if wantlock and not self.lockedBecauseOfSkipping:
709 self.lockedBecauseOfSkipping = True
712 self.setSeekState(self.SEEK_STATE_PAUSE)
715 self.setSeekState(self.SEEK_STATE_PLAY)
718 def seekRelative(self, diff):
719 seekable = self.getSeek()
720 if seekable is not None:
721 seekable.seekRelative(0, diff)
723 from Screens.PVRState import PVRState
725 class InfoBarPVRState:
727 self.onPlayStateChanged.append(self.__playStateChanged)
728 self.pvrStateDialog = self.session.instantiateDialog(PVRState)
729 self.onShow.append(self.__mayShow)
730 self.onHide.append(self.pvrStateDialog.hide)
733 if self.seekstate != self.SEEK_STATE_PLAY:
734 self.pvrStateDialog.show()
736 def __playStateChanged(self, state):
737 playstateString = state[3]
738 self.pvrStateDialog["state"].setText(playstateString)
741 class InfoBarShowMovies:
743 # i don't really like this class.
744 # it calls a not further specified "movie list" on up/down/movieList,
745 # so this is not more than an action map
747 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
749 "movieList": (self.showMovies, "movie list"),
750 "up": (self.showMovies, "movie list"),
751 "down": (self.showMovies, "movie list")
754 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
758 # Timeshift works the following way:
759 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
760 # - normal playback TUNER unused PLAY enable disable disable
761 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
762 # - user presess pause again FILE record PLAY enable disable enable
763 # - user fast forwards FILE record FF enable disable enable
764 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
765 # - user backwards FILE record BACK # !! enable disable enable
769 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
770 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
771 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
772 # - the user can now PVR around
773 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
774 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
776 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
777 # - if the user rewinds, or press pause, timeshift will be activated again
779 # note that a timeshift can be enabled ("recording") and
780 # activated (currently time-shifting).
782 class InfoBarTimeshift:
784 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
786 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
787 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
789 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
791 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
792 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
793 }, prio=-1) # priority over record
795 self.timeshift_enabled = 0
796 self.timeshift_state = 0
797 self.ts_pause_timer = eTimer()
798 self.ts_pause_timer.timeout.get().append(self.pauseService)
800 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
802 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
805 def getTimeshift(self):
806 service = self.session.nav.getCurrentService()
807 return service.timeshift()
809 def startTimeshift(self):
810 print "enable timeshift"
811 ts = self.getTimeshift()
813 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
814 print "no ts interface"
817 if self.timeshift_enabled:
818 print "hu, timeshift already enabled?"
820 if not ts.startTimeshift():
821 self.timeshift_enabled = 1
824 self.setSeekState(self.SEEK_STATE_PAUSE)
826 # enable the "TimeshiftEnableActions", which will override
827 # the startTimeshift actions
828 self.__seekableStatusChanged()
830 print "timeshift failed"
832 def stopTimeshift(self):
833 print "disable timeshift"
834 ts = self.getTimeshift()
838 self.timeshift_enabled = 0
841 self.__seekableStatusChanged()
843 # activates timeshift, and seeks to (almost) the end
844 def activateTimeshiftEnd(self):
845 ts = self.getTimeshift()
850 if ts.isTimeshiftActive():
851 print "!! activate timeshift called - but shouldn't this be a normal pause?"
854 self.setSeekState(self.SEEK_STATE_PLAY)
855 ts.activateTimeshift()
858 # same as activateTimeshiftEnd, but pauses afterwards.
859 def activateTimeshiftEndAndPause(self):
860 state = self.seekstate
861 self.activateTimeshiftEnd()
863 # well, this is "andPause", but it could be pressed from pause,
864 # when pausing on the (fake-)"live" picture, so an un-pause
867 print "now, pauseService"
868 if state == self.SEEK_STATE_PLAY:
869 print "is PLAYING, start pause timer"
870 self.ts_pause_timer.start(200, 1)
873 self.unPauseService()
875 def __seekableStatusChanged(self):
878 print "self.isSeekable", self.isSeekable()
879 print "self.timeshift_enabled", self.timeshift_enabled
881 # when this service is not seekable, but timeshift
882 # is enabled, this means we can activate
884 if not self.isSeekable() and self.timeshift_enabled:
887 print "timeshift activate:", enabled
888 self["TimeshiftActivateActions"].setEnabled(enabled)
890 from RecordTimer import parseEvent
892 class InfoBarInstantRecord:
893 """Instant Record - handles the instantRecord action in order to
894 start/stop instant records"""
896 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
898 "instantRecord": (self.instantRecord, "Instant Record..."),
900 self.recording = None
902 self["BlinkingPoint"] = BlinkingPixmapConditional()
903 self.onShown.append(self["BlinkingPoint"].hideWidget)
904 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
906 def stopCurrentRecording(self):
907 self.session.nav.RecordTimer.removeEntry(self.recording)
908 self.recording = None
910 def startInstantRecording(self):
911 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
913 # try to get event info
916 service = self.session.nav.getCurrentService()
917 info = service.info()
918 ev = info.getEvent(0)
923 if event is not None:
924 data = parseEvent(event)
926 end = begin + 3600 * 10
928 data = (begin, end, data[2], data[3], data[4])
930 data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
932 # fix me, description.
933 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
934 self.recording.dontSave = True
936 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
938 def isInstantRecordRunning(self):
939 if self.recording != None:
940 if self.recording.isRunning():
944 def recordQuestionCallback(self, answer):
948 if self.isInstantRecordRunning():
949 self.stopCurrentRecording()
951 self.startInstantRecording()
953 def instantRecord(self):
955 stat = os.stat(resolveFilename(SCOPE_HDD))
957 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
960 if self.isInstantRecordRunning():
961 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
963 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
965 from Screens.AudioSelection import AudioSelection
967 class InfoBarAudioSelection:
969 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
971 "audioSelection": (self.audioSelection, "Audio Options..."),
974 def audioSelection(self):
975 service = self.session.nav.getCurrentService()
976 audio = service.audioTracks()
977 n = audio.getNumberOfTracks()
979 self.session.open(AudioSelection, audio)
981 from Screens.SubserviceSelection import SubserviceSelection
983 class InfoBarSubserviceSelection:
985 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
987 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
990 def subserviceSelection(self):
991 service = self.session.nav.getCurrentService()
992 subservices = service.subServices()
993 n = subservices.getNumberOfSubservices()
995 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
997 def subserviceSelected(self, service):
998 if not service is None:
999 self.session.nav.playService(service)
1001 class InfoBarAdditionalInfo:
1003 self["DolbyActive"] = Pixmap()
1004 self["CryptActive"] = Pixmap()
1005 self["FormatActive"] = Pixmap()
1007 self["ButtonRed"] = PixmapConditional(withTimer = False)
1008 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1009 self.onShown.append(self["ButtonRed"].update)
1010 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1011 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1012 self.onShown.append(self["ButtonRedText"].update)
1014 self["ButtonGreen"] = Pixmap()
1015 self["ButtonGreenText"] = Label(_("Subservices"))
1017 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1018 self["ButtonYellow"].setConnect(lambda: False)
1020 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1021 self["ButtonBlue"].setConnect(lambda: False)
1023 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1025 def hideSubServiceIndication(self):
1026 self["ButtonGreen"].hideWidget()
1027 self["ButtonGreenText"].hide()
1029 def showSubServiceIndication(self):
1030 self["ButtonGreen"].showWidget()
1031 self["ButtonGreenText"].show()
1033 def checkFormat(self, service):
1034 info = service.info()
1035 if info is not None:
1036 aspect = info.getInfo(iServiceInformation.sAspect)
1037 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1038 self["FormatActive"].showWidget()
1040 self["FormatActive"].hideWidget()
1042 def checkSubservices(self, service):
1043 if service.subServices().getNumberOfSubservices() > 0:
1044 self.showSubServiceIndication()
1046 self.hideSubServiceIndication()
1048 def checkDolby(self, service):
1051 audio = service.audioTracks()
1052 if audio is not None:
1053 n = audio.getNumberOfTracks()
1055 i = audio.getTrackInfo(x)
1056 description = i.getDescription();
1057 if description.find("AC3") != -1 or description.find("DTS") != -1:
1061 self["DolbyActive"].showWidget()
1063 self["DolbyActive"].hideWidget()
1065 def checkCrypted(self, service):
1066 info = service.info()
1067 if info is not None:
1068 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1069 self["CryptActive"].showWidget()
1071 self["CryptActive"].hideWidget()
1073 def gotServiceEvent(self, ev):
1074 service = self.session.nav.getCurrentService()
1075 if ev == iPlayableService.evUpdatedEventInfo:
1076 self.checkSubservices(service)
1077 self.checkFormat(service)
1078 elif ev == iPlayableService.evUpdatedInfo:
1079 self.checkCrypted(service)
1080 self.checkDolby(service)
1081 elif ev == iPlayableService.evEnd:
1082 self.hideSubServiceIndication()
1083 self["CryptActive"].hideWidget()
1084 self["DolbyActive"].hideWidget()
1085 self["FormatActive"].hideWidget()
1087 class InfoBarNotifications:
1089 self.onExecBegin.append(self.checkNotifications)
1090 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1092 def checkNotificationsIfExecing(self):
1094 self.checkNotifications()
1096 def checkNotifications(self):
1097 if len(Notifications.notifications):
1098 n = Notifications.notifications[0]
1099 Notifications.notifications = Notifications.notifications[1:]
1103 self.session.openWithCallback(cb, *n[1:])
1105 self.session.open(*n[1:])
1107 class InfoBarServiceNotifications:
1109 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1111 iPlayableService.evEnd: self.serviceHasEnded
1114 def serviceHasEnded(self):
1115 print "service end!"
1118 self.setSeekState(self.SEEK_STATE_PLAY)