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
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, _("next channel")),
280 "zapDown": (self.zapDown, _("previous channel")),
283 def switchChannelUp(self):
284 self.servicelist.moveUp()
285 self.session.execDialog(self.servicelist)
287 def switchChannelDown(self):
288 self.servicelist.moveDown()
289 self.session.execDialog(self.servicelist)
292 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
293 if self.servicelist.inBouquet() and self.servicelist.atBegin():
294 self.servicelist.prevBouquet()
295 self.servicelist.moveUp()
296 self.servicelist.zap()
300 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
301 self.servicelist.nextBouquet()
303 self.servicelist.moveDown()
304 self.servicelist.zap()
308 """ Handles a menu action, to open the (main) menu """
310 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
312 "mainMenu": (self.mainMenu, "Enter main menu..."),
316 print "loading mainmenu XML..."
317 menu = mdom.childNodes[0]
318 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
319 self.session.open(MainMenu, menu, menu.childNodes)
322 """ EPG - Opens an EPG list when the showEPGList action fires """
324 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
326 "showEventInfo": (self.openEventView, _("show EPG...")),
329 def zapToService(self, service):
330 if not service is None:
331 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
332 self.servicelist.clearPath()
333 if self.servicelist.bouquet_root != self.epg_bouquet:
334 self.servicelist.enterPath(self.servicelist.bouquet_root)
335 self.servicelist.enterPath(self.epg_bouquet)
336 self.servicelist.setCurrentSelection(service) #select the service in servicelist
337 self.servicelist.zap()
339 def openBouquetEPG(self, bouquet):
340 ptr=eEPGCache.getInstance()
342 servicelist = eServiceCenter.getInstance().list(bouquet)
343 if not servicelist is None:
345 service = servicelist.getNext()
346 if not service.valid(): #check if end of list
348 if service.flags: #ignore non playable services
350 services.append(ServiceReference(service))
352 self.epg_bouquet = bouquet
353 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
355 def closed(self, ret):
359 def openMultiServiceEPG(self):
360 bouquets = self.servicelist.getBouquetList()
365 if cnt > 1: # show bouquet list
366 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
368 self.openBouquetEPG(bouquets[0][1])
370 def openSingleServiceEPG(self):
371 ref=self.session.nav.getCurrentlyPlayingServiceReference()
372 ptr=eEPGCache.getInstance()
373 self.session.openWithCallback(self.closed, EPGSelection, ref)
375 def openEventView(self):
377 service = self.session.nav.getCurrentService()
378 ref = self.session.nav.getCurrentlyPlayingServiceReference()
379 info = service.info()
382 self.epglist.append(ptr)
385 self.epglist.append(ptr)
386 if len(self.epglist) == 0:
387 epg = eEPGCache.getInstance()
388 ptr = epg.lookupEventTime(ref, -1)
390 self.epglist.append(ptr)
391 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
393 self.epglist.append(ptr)
394 if len(self.epglist) > 0:
395 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
397 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
398 self.openMultiServiceEPG()
400 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
401 if len(self.epglist) > 1:
402 tmp = self.epglist[0]
403 self.epglist[0]=self.epglist[1]
405 setEvent(self.epglist[0])
410 """provides a snr/agc/ber display"""
412 self["snr"] = Label()
413 self["agc"] = Label()
414 self["ber"] = Label()
415 self["snr_percent"] = Label()
416 self["agc_percent"] = Label()
417 self["ber_count"] = Label()
418 self["snr_progress"] = ProgressBar()
419 self["agc_progress"] = ProgressBar()
420 self["ber_progress"] = ProgressBar()
421 self.timer = eTimer()
422 self.timer.timeout.get().append(self.updateTunerInfo)
423 self.timer.start(1000)
429 return (long)(log(val)/log(2))
432 def updateTunerInfo(self):
433 if self.instance.isVisible():
434 service = self.session.nav.getCurrentService()
438 if service is not None:
439 feinfo = service.frontendStatusInfo()
440 if feinfo is not None:
441 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
442 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
443 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
444 self["snr_percent"].setText("%d%%"%(snr))
445 self["agc_percent"].setText("%d%%"%(agc))
446 self["ber_count"].setText("%d"%(ber))
447 self["snr_progress"].setValue(snr)
448 self["agc_progress"].setValue(agc)
449 self["ber_progress"].setValue(self.calc(ber))
452 """provides a current/next event info display"""
454 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
455 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
457 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
458 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
460 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
461 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
463 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
465 class InfoBarServiceName:
467 self["ServiceName"] = ServiceName(self.session.nav)
470 """handles actions like seeking, pause"""
472 # ispause, isff, issm
473 SEEK_STATE_PLAY = (0, 0, 0, ">")
474 SEEK_STATE_PAUSE = (1, 0, 0, "||")
475 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
476 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
477 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
478 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
479 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
480 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
482 SEEK_STATE_BACK_4X = (0, -4, 0, "<< 4x")
483 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
484 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
485 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
487 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
488 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
489 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
492 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
494 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
495 iPlayableService.evStart: self.__serviceStarted,
497 iPlayableService.evEOF: self.__evEOF,
498 iPlayableService.evSOF: self.__evSOF,
500 self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions",
502 "pauseService": (self.pauseService, "pause"),
503 "unPauseService": (self.unPauseService, "continue"),
505 "seekFwd": (self.seekFwd, "skip forward"),
506 "seekFwdUp": (self.seekFwdUp, "skip forward"),
507 "seekBack": (self.seekBack, "skip backward"),
508 "seekBackUp": (self.seekBackUp, "skip backward"),
510 # give them a little more priority to win over color buttons
512 self.seekstate = self.SEEK_STATE_PLAY
513 self.onClose.append(self.delTimer)
515 self.fwdtimer = False
516 self.fwdKeyTimer = eTimer()
517 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
519 self.rwdtimer = False
520 self.rwdKeyTimer = eTimer()
521 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
523 self.onPlayStateChanged = [ ]
525 self.lockedBecauseOfSkipping = False
538 service = self.session.nav.getCurrentService()
542 seek = service.seek()
544 if seek is None or not seek.isCurrentlySeekable():
549 def isSeekable(self):
550 if self.getSeek() is None:
554 def __seekableStatusChanged(self):
555 print "seekable status changed!"
556 if not self.isSeekable():
557 self["SeekActions"].setEnabled(False)
558 print "not seekable, return to play"
559 self.setSeekState(self.SEEK_STATE_PLAY)
561 self["SeekActions"].setEnabled(True)
564 def __serviceStarted(self):
565 self.seekstate = self.SEEK_STATE_PLAY
567 def setSeekState(self, state):
568 service = self.session.nav.getCurrentService()
573 if not self.isSeekable():
574 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
575 state = self.SEEK_STATE_PLAY
577 pauseable = service.pause()
579 if pauseable is None:
580 print "not pauseable."
581 state = self.SEEK_STATE_PLAY
583 oldstate = self.seekstate
584 self.seekstate = state
587 if oldstate[i] != self.seekstate[i]:
588 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
590 for c in self.onPlayStateChanged:
593 self.checkSkipShowHideLock()
597 def pauseService(self):
598 if self.seekstate == self.SEEK_STATE_PAUSE:
599 print "pause, but in fact unpause"
600 self.unPauseService()
602 if self.seekstate == self.SEEK_STATE_PLAY:
603 print "yes, playing."
605 print "no", self.seekstate
607 self.setSeekState(self.SEEK_STATE_PAUSE);
609 def unPauseService(self):
611 self.setSeekState(self.SEEK_STATE_PLAY);
613 def doSeek(self, seektime):
614 print "doseek", seektime
615 service = self.session.nav.getCurrentService()
619 seekable = self.getSeek()
623 seekable.seekTo(90 * seektime)
626 print "start fwd timer"
628 self.fwdKeyTimer.start(500)
631 print "start rewind timer"
633 self.rwdKeyTimer.start(500)
638 self.fwdKeyTimer.stop()
639 self.fwdtimer = False
641 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
642 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
643 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
644 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
645 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
646 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
647 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
648 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
649 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
650 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
651 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
652 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
653 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
654 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
655 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
657 self.setSeekState(lookup[self.seekstate]);
659 def seekBackUp(self):
662 self.rwdKeyTimer.stop()
663 self.rwdtimer = False
666 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
667 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
668 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
669 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
670 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
671 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
672 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
673 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
674 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
675 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
676 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
677 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
678 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
679 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
680 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
682 self.setSeekState(lookup[self.seekstate]);
684 def fwdTimerFire(self):
685 print "Display seek fwd"
686 self.fwdKeyTimer.stop()
687 self.fwdtimer = False
688 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
690 def fwdSeekTo(self, minutes):
691 print "Seek", minutes, "minutes forward"
693 seekable = self.getSeek()
694 if seekable is not None:
695 seekable.seekRelative(1, minutes * 60 * 90000)
697 def rwdTimerFire(self):
699 self.rwdKeyTimer.stop()
700 self.rwdtimer = False
701 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
703 def rwdSeekTo(self, minutes):
705 self.fwdSeekTo(0 - minutes)
707 def checkSkipShowHideLock(self):
708 wantlock = self.seekstate != self.SEEK_STATE_PLAY
710 if self.lockedBecauseOfSkipping and not wantlock:
712 self.lockedBecauseOfSkipping = False
714 if wantlock and not self.lockedBecauseOfSkipping:
716 self.lockedBecauseOfSkipping = True
719 self.setSeekState(self.SEEK_STATE_PAUSE)
722 self.setSeekState(self.SEEK_STATE_PLAY)
725 def seekRelative(self, diff):
726 seekable = self.getSeek()
727 if seekable is not None:
728 seekable.seekRelative(0, diff)
730 from Screens.PVRState import PVRState
732 class InfoBarPVRState:
734 self.onPlayStateChanged.append(self.__playStateChanged)
735 self.pvrStateDialog = self.session.instantiateDialog(PVRState)
736 self.onShow.append(self.__mayShow)
737 self.onHide.append(self.pvrStateDialog.hide)
740 if self.seekstate != self.SEEK_STATE_PLAY:
741 self.pvrStateDialog.show()
743 def __playStateChanged(self, state):
744 playstateString = state[3]
745 self.pvrStateDialog["state"].setText(playstateString)
748 class InfoBarShowMovies:
750 # i don't really like this class.
751 # it calls a not further specified "movie list" on up/down/movieList,
752 # so this is not more than an action map
754 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
756 "movieList": (self.showMovies, "movie list"),
757 "up": (self.showMovies, "movie list"),
758 "down": (self.showMovies, "movie list")
761 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
765 # Timeshift works the following way:
766 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
767 # - normal playback TUNER unused PLAY enable disable disable
768 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
769 # - user presess pause again FILE record PLAY enable disable enable
770 # - user fast forwards FILE record FF enable disable enable
771 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
772 # - user backwards FILE record BACK # !! enable disable enable
776 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
777 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
778 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
779 # - the user can now PVR around
780 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
781 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
783 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
784 # - if the user rewinds, or press pause, timeshift will be activated again
786 # note that a timeshift can be enabled ("recording") and
787 # activated (currently time-shifting).
789 class InfoBarTimeshift:
791 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
793 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
794 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
796 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
798 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
799 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
800 }, prio=-1) # priority over record
802 self.timeshift_enabled = 0
803 self.timeshift_state = 0
804 self.ts_pause_timer = eTimer()
805 self.ts_pause_timer.timeout.get().append(self.pauseService)
807 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
809 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
812 def getTimeshift(self):
813 service = self.session.nav.getCurrentService()
814 return service.timeshift()
816 def startTimeshift(self):
817 print "enable timeshift"
818 ts = self.getTimeshift()
820 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
821 print "no ts interface"
824 if self.timeshift_enabled:
825 print "hu, timeshift already enabled?"
827 if not ts.startTimeshift():
828 self.timeshift_enabled = 1
831 self.setSeekState(self.SEEK_STATE_PAUSE)
833 # enable the "TimeshiftEnableActions", which will override
834 # the startTimeshift actions
835 self.__seekableStatusChanged()
837 print "timeshift failed"
839 def stopTimeshift(self):
840 if not self.timeshift_enabled:
842 print "disable timeshift"
843 ts = self.getTimeshift()
846 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
848 def stopTimeshiftConfirmed(self, confirmed):
852 ts = self.getTimeshift()
857 self.timeshift_enabled = 0
860 self.__seekableStatusChanged()
862 # activates timeshift, and seeks to (almost) the end
863 def activateTimeshiftEnd(self):
864 ts = self.getTimeshift()
869 if ts.isTimeshiftActive():
870 print "!! activate timeshift called - but shouldn't this be a normal pause?"
873 self.setSeekState(self.SEEK_STATE_PLAY)
874 ts.activateTimeshift()
877 # same as activateTimeshiftEnd, but pauses afterwards.
878 def activateTimeshiftEndAndPause(self):
879 state = self.seekstate
880 self.activateTimeshiftEnd()
882 # well, this is "andPause", but it could be pressed from pause,
883 # when pausing on the (fake-)"live" picture, so an un-pause
886 print "now, pauseService"
887 if state == self.SEEK_STATE_PLAY:
888 print "is PLAYING, start pause timer"
889 self.ts_pause_timer.start(200, 1)
892 self.unPauseService()
894 def __seekableStatusChanged(self):
897 print "self.isSeekable", self.isSeekable()
898 print "self.timeshift_enabled", self.timeshift_enabled
900 # when this service is not seekable, but timeshift
901 # is enabled, this means we can activate
903 if not self.isSeekable() and self.timeshift_enabled:
906 print "timeshift activate:", enabled
907 self["TimeshiftActivateActions"].setEnabled(enabled)
909 from RecordTimer import parseEvent
911 class InfoBarInstantRecord:
912 """Instant Record - handles the instantRecord action in order to
913 start/stop instant records"""
915 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
917 "instantRecord": (self.instantRecord, "Instant Record..."),
919 self.recording = None
920 self["BlinkingPoint"] = BlinkingPixmapConditional()
921 self.onLayoutFinish.append(self["BlinkingPoint"].hideWidget)
922 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
924 def stopCurrentRecording(self):
925 self.session.nav.RecordTimer.removeEntry(self.recording)
926 self.recording = None
928 def startInstantRecording(self):
929 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
931 # try to get event info
934 service = self.session.nav.getCurrentService()
935 info = service.info()
936 ev = info.getEvent(0)
941 if event is not None:
942 data = parseEvent(event)
944 end = begin + 3600 * 10
946 data = (begin, end, data[2], data[3], data[4])
948 data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
950 # fix me, description.
951 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
952 self.recording.dontSave = True
954 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
956 def isInstantRecordRunning(self):
957 if self.recording != None:
958 if self.recording.isRunning():
962 def recordQuestionCallback(self, answer):
966 if self.isInstantRecordRunning():
967 self.stopCurrentRecording()
969 self.startInstantRecording()
971 def instantRecord(self):
973 stat = os.stat(resolveFilename(SCOPE_HDD))
975 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
978 if self.isInstantRecordRunning():
979 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
981 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
983 from Screens.AudioSelection import AudioSelection
985 class InfoBarAudioSelection:
987 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
989 "audioSelection": (self.audioSelection, "Audio Options..."),
992 def audioSelection(self):
993 service = self.session.nav.getCurrentService()
994 audio = service.audioTracks()
995 n = audio.getNumberOfTracks()
997 self.session.open(AudioSelection, audio)
999 from Screens.SubserviceSelection import SubserviceSelection
1001 class InfoBarSubserviceSelection:
1003 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1005 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1008 def subserviceSelection(self):
1009 service = self.session.nav.getCurrentService()
1010 subservices = service.subServices()
1011 n = subservices.getNumberOfSubservices()
1013 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1015 def subserviceSelected(self, service):
1016 if not service is None:
1017 self.session.nav.playService(service)
1019 class InfoBarAdditionalInfo:
1021 self["DolbyActive"] = Pixmap()
1022 self["CryptActive"] = Pixmap()
1023 self["FormatActive"] = Pixmap()
1025 self["ButtonRed"] = PixmapConditional(withTimer = False)
1026 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1027 self.onShown.append(self["ButtonRed"].update)
1028 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1029 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1030 self.onShown.append(self["ButtonRedText"].update)
1032 self["ButtonGreen"] = Pixmap()
1033 self["ButtonGreenText"] = Label(_("Subservices"))
1035 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1036 self["ButtonYellow"].setConnect(lambda: False)
1038 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1039 self["ButtonBlue"].setConnect(lambda: False)
1041 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1043 def hideSubServiceIndication(self):
1044 self["ButtonGreen"].hideWidget()
1045 self["ButtonGreenText"].hide()
1047 def showSubServiceIndication(self):
1048 self["ButtonGreen"].showWidget()
1049 self["ButtonGreenText"].show()
1051 def checkFormat(self, service):
1052 info = service.info()
1053 if info is not None:
1054 aspect = info.getInfo(iServiceInformation.sAspect)
1055 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1056 self["FormatActive"].showWidget()
1058 self["FormatActive"].hideWidget()
1060 def checkSubservices(self, service):
1061 if service.subServices().getNumberOfSubservices() > 0:
1062 self.showSubServiceIndication()
1064 self.hideSubServiceIndication()
1066 def checkDolby(self, service):
1069 audio = service.audioTracks()
1070 if audio is not None:
1071 n = audio.getNumberOfTracks()
1073 i = audio.getTrackInfo(x)
1074 description = i.getDescription();
1075 if description.find("AC3") != -1 or description.find("DTS") != -1:
1079 self["DolbyActive"].showWidget()
1081 self["DolbyActive"].hideWidget()
1083 def checkCrypted(self, service):
1084 info = service.info()
1085 if info is not None:
1086 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1087 self["CryptActive"].showWidget()
1089 self["CryptActive"].hideWidget()
1091 def gotServiceEvent(self, ev):
1092 service = self.session.nav.getCurrentService()
1093 if ev == iPlayableService.evUpdatedEventInfo:
1094 self.checkSubservices(service)
1095 self.checkFormat(service)
1096 elif ev == iPlayableService.evUpdatedInfo:
1097 self.checkCrypted(service)
1098 self.checkDolby(service)
1099 elif ev == iPlayableService.evEnd:
1100 self.hideSubServiceIndication()
1101 self["CryptActive"].hideWidget()
1102 self["DolbyActive"].hideWidget()
1103 self["FormatActive"].hideWidget()
1105 class InfoBarNotifications:
1107 self.onExecBegin.append(self.checkNotifications)
1108 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1110 def checkNotificationsIfExecing(self):
1112 self.checkNotifications()
1114 def checkNotifications(self):
1115 if len(Notifications.notifications):
1116 n = Notifications.notifications[0]
1117 Notifications.notifications = Notifications.notifications[1:]
1121 self.session.openWithCallback(cb, *n[1:])
1123 self.session.open(*n[1:])
1125 class InfoBarServiceNotifications:
1127 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1129 iPlayableService.evEnd: self.serviceHasEnded
1132 def serviceHasEnded(self):
1133 print "service end!"
1136 self.setSeekState(self.SEEK_STATE_PLAY)
1140 class InfoBarCueSheetSupport:
1146 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1148 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1149 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1150 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1154 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1156 iPlayableService.evStart: self.__serviceStarted,
1159 def __serviceStarted(self):
1160 print "new service started! trying to download cuts!"
1161 self.downloadCuesheet()
1163 def __getSeekable(self):
1164 service = self.session.nav.getCurrentService()
1167 return service.seek()
1169 def __getCurrentPosition(self):
1170 seek = self.__getSeekable()
1173 r = seek.getPlayPosition()
1178 def jumpPreviousNextMark(self, cmp, alternative=None):
1179 current_pos = self.__getCurrentPosition()
1180 if current_pos is None:
1182 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1183 if mark is not None:
1185 elif alternative is not None:
1190 seekable = self.__getSeekable()
1191 if seekable is not None:
1192 seekable.seekTo(pts)
1194 def jumpPreviousMark(self):
1195 print "jumpPreviousMark"
1196 # we add 2 seconds, so if the play position is <2s after
1197 # the mark, the mark before will be used
1198 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1200 def jumpNextMark(self):
1201 print "jumpNextMark"
1202 self.jumpPreviousNextMark(lambda x: x)
1204 def getNearestCutPoint(self, pts, cmp=abs):
1207 for cp in self.cut_list:
1208 diff = cmp(cp[0] - pts)
1209 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1213 def toggleMark(self):
1215 current_pos = self.__getCurrentPosition()
1216 if current_pos is None:
1217 print "not seekable"
1220 print "current position: ", current_pos
1222 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1223 print "nearest_cutpoint: ", nearest_cutpoint
1225 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < 5*90000:
1226 self.cut_list.remove(nearest_cutpoint)
1228 bisect.insort(self.cut_list, (current_pos, self.CUT_TYPE_MARK))
1230 self.uploadCuesheet()
1232 def __getCuesheet(self):
1233 service = self.session.nav.getCurrentService()
1236 return service.cueSheet()
1238 def uploadCuesheet(self):
1239 cue = self.__getCuesheet()
1242 print "upload failed, no cuesheet interface"
1244 cue.setCutList(self.cut_list)
1246 def downloadCuesheet(self):
1247 cue = self.__getCuesheet()
1250 print "upload failed, no cuesheet interface"
1252 self.cut_list = cue.getCutList()
1254 print "cuts:", self.cut_list