1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Clock import Clock
7 from Components.EventInfo import EventInfo, EventInfoProgress
8 from Components.Harddisk import harddiskmanager
9 from Components.Input import Input
10 from Components.Label import *
11 from Components.Pixmap import Pixmap, PixmapConditional
12 from Components.PluginComponent import plugins
13 from Components.ProgressBar import *
14 from Components.ServiceEventTracker import ServiceEventTracker
15 from Components.ServiceName import ServiceName
16 from Components.config import config, configElement, ConfigSubsection, configSequence, configElementBoolean
17 from Components.config import configfile, configsequencearg
19 from EpgSelection import EPGSelection
20 from Plugins.Plugin import PluginDescriptor
22 from Screen import Screen
23 from Screens.ChoiceBox import ChoiceBox
24 from Screens.Dish import Dish
25 from Screens.EventView import EventViewEPGSelect, EventViewSimple
26 from Screens.InputBox import InputBox
27 from Screens.MessageBox import MessageBox
28 from Screens.MinuteInput import MinuteInput
29 from ServiceReference import ServiceReference
31 from Tools import Notifications
32 from Tools.Directories import *
34 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
41 from Components.config import config, currentConfigSelectionElement
44 from Menu import MainMenu, mdom
48 self.dishDialog = self.session.instantiateDialog(Dish)
49 self.onLayoutFinish.append(self.dishDialog.show)
51 class InfoBarShowHide:
52 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
60 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
62 "toggleShow": self.toggleShow,
66 self.__state = self.STATE_SHOWN
69 self.onExecBegin.append(self.show)
71 self.hideTimer = eTimer()
72 self.hideTimer.timeout.get().append(self.doTimerHide)
73 self.hideTimer.start(5000, True)
75 self.onShow.append(self.__onShow)
76 self.onHide.append(self.__onHide)
79 self.__state = self.STATE_SHOWN
82 def startHideTimer(self):
83 if self.__state == self.STATE_SHOWN and not self.__locked:
84 self.hideTimer.start(5000, True)
87 self.__state = self.STATE_HIDDEN
93 def doTimerHide(self):
95 if self.__state == self.STATE_SHOWN:
99 if self.__state == self.STATE_SHOWN:
101 self.hideTimer.stop()
102 elif self.__state == self.STATE_HIDDEN:
106 self.__locked = self.__locked + 1
109 self.hideTimer.stop()
111 def unlockShow(self):
112 self.__locked = self.__locked - 1
114 self.startHideTimer()
116 # def startShow(self):
117 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
118 # self.__state = self.STATE_SHOWN
120 # def startHide(self):
121 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
122 # self.__state = self.STATE_HIDDEN
124 class NumberZap(Screen):
131 self.close(int(self["number"].getText()))
133 def keyNumberGlobal(self, number):
134 self.Timer.start(3000, True) #reset timer
135 self.field = self.field + str(number)
136 self["number"].setText(self.field)
137 if len(self.field) >= 4:
140 def __init__(self, session, number):
141 Screen.__init__(self, session)
142 self.field = str(number)
144 self["channel"] = Label(_("Channel:"))
146 self["number"] = Label(self.field)
148 self["actions"] = NumberActionMap( [ "SetupActions" ],
152 "1": self.keyNumberGlobal,
153 "2": self.keyNumberGlobal,
154 "3": self.keyNumberGlobal,
155 "4": self.keyNumberGlobal,
156 "5": self.keyNumberGlobal,
157 "6": self.keyNumberGlobal,
158 "7": self.keyNumberGlobal,
159 "8": self.keyNumberGlobal,
160 "9": self.keyNumberGlobal,
161 "0": self.keyNumberGlobal
164 self.Timer = eTimer()
165 self.Timer.timeout.get().append(self.keyOK)
166 self.Timer.start(3000, True)
168 class InfoBarNumberZap:
169 """ Handles an initial number for NumberZapping """
171 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
173 "1": self.keyNumberGlobal,
174 "2": self.keyNumberGlobal,
175 "3": self.keyNumberGlobal,
176 "4": self.keyNumberGlobal,
177 "5": self.keyNumberGlobal,
178 "6": self.keyNumberGlobal,
179 "7": self.keyNumberGlobal,
180 "8": self.keyNumberGlobal,
181 "9": self.keyNumberGlobal,
182 "0": self.keyNumberGlobal,
185 def keyNumberGlobal(self, number):
186 # print "You pressed number " + str(number)
188 self.servicelist.recallPrevService()
191 self.session.openWithCallback(self.numberEntered, NumberZap, number)
193 def numberEntered(self, retval):
194 # print self.servicelist
196 self.zapToNumber(retval)
198 def searchNumberHelper(self, serviceHandler, num, bouquet):
199 servicelist = serviceHandler.list(bouquet)
200 if not servicelist is None:
202 serviceIterator = servicelist.getNext()
203 if not serviceIterator.valid(): #check end of list
205 if serviceIterator.flags: #assume normal dvb service have no flags set
208 if not num: #found service with searched number ?
209 return serviceIterator, 0
212 def zapToNumber(self, number):
213 bouquet = self.servicelist.bouquet_root
215 serviceHandler = eServiceCenter.getInstance()
216 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
217 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
219 bouquetlist = serviceHandler.list(bouquet)
220 if not bouquetlist is None:
222 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
223 if not bouquet.valid(): #check end of list
225 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
227 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
228 if not service is None:
229 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
230 self.servicelist.clearPath()
231 if self.servicelist.bouquet_root != bouquet:
232 self.servicelist.enterPath(self.servicelist.bouquet_root)
233 self.servicelist.enterPath(bouquet)
234 self.servicelist.setCurrentSelection(service) #select the service in servicelist
235 self.servicelist.zap()
237 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
239 class InfoBarChannelSelection:
240 """ ChannelSelection - handles the channelSelection dialog and the initial
241 channelChange actions which open the channelSelection dialog """
244 self.servicelist = self.session.instantiateDialog(ChannelSelection)
246 if config.misc.initialchannelselection.value == 1:
247 self.onShown.append(self.firstRun)
249 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
251 "switchChannelUp": self.switchChannelUp,
252 "switchChannelDown": self.switchChannelDown,
253 "zapUp": (self.zapUp, _("previous channel")),
254 "zapDown": (self.zapDown, _("next channel")),
255 "historyBack": (self.historyBack, _("previous channel in history")),
256 "historyNext": (self.historyNext, _("next channel in history"))
260 self.onShown.remove(self.firstRun)
261 config.misc.initialchannelselection.value = 0
262 config.misc.initialchannelselection.save()
263 self.switchChannelDown()
265 def historyBack(self):
266 self.servicelist.historyBack()
268 def historyNext(self):
269 self.servicelist.historyNext()
271 def switchChannelUp(self):
272 self.servicelist.moveUp()
273 self.session.execDialog(self.servicelist)
275 def switchChannelDown(self):
276 self.servicelist.moveDown()
277 self.session.execDialog(self.servicelist)
280 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
281 if self.servicelist.inBouquet() and self.servicelist.atBegin():
282 self.servicelist.prevBouquet()
283 self.servicelist.moveUp()
284 self.servicelist.zap()
288 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
289 self.servicelist.nextBouquet()
291 self.servicelist.moveDown()
292 self.servicelist.zap()
296 """ Handles a menu action, to open the (main) menu """
298 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
300 "mainMenu": (self.mainMenu, "Enter main menu..."),
304 print "loading mainmenu XML..."
305 menu = mdom.childNodes[0]
306 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
307 self.session.open(MainMenu, menu, menu.childNodes)
309 class InfoBarSimpleEventView:
310 """ Opens the Eventview for now/next """
312 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
314 "showEventInfo": (self.openEventView, _("show event details")),
317 def openEventView(self):
319 service = self.session.nav.getCurrentService()
320 ref = self.session.nav.getCurrentlyPlayingServiceReference()
321 info = service.info()
324 self.epglist.append(ptr)
327 self.epglist.append(ptr)
328 if len(self.epglist) > 0:
329 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
331 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
332 if len(self.epglist) > 1:
333 tmp = self.epglist[0]
334 self.epglist[0]=self.epglist[1]
336 setEvent(self.epglist[0])
339 """ EPG - Opens an EPG list when the showEPGList action fires """
341 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
343 "showEventInfo": (self.openEventView, _("show EPG...")),
346 def zapToService(self, service):
347 if not service is None:
348 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
349 self.servicelist.clearPath()
350 if self.servicelist.bouquet_root != self.epg_bouquet:
351 self.servicelist.enterPath(self.servicelist.bouquet_root)
352 self.servicelist.enterPath(self.epg_bouquet)
353 self.servicelist.setCurrentSelection(service) #select the service in servicelist
354 self.servicelist.zap()
356 def openBouquetEPG(self, bouquet, withCallback=True):
357 ptr=eEPGCache.getInstance()
359 servicelist = eServiceCenter.getInstance().list(bouquet)
360 if not servicelist is None:
362 service = servicelist.getNext()
363 if not service.valid(): #check if end of list
365 if service.flags: #ignore non playable services
367 services.append(ServiceReference(service))
369 self.epg_bouquet = bouquet
371 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
373 self.session.open(EPGSelection, services, self.zapToService)
375 def closed(self, ret):
379 def openMultiServiceEPG(self, withCallback=True):
380 bouquets = self.servicelist.getBouquetList()
385 if cnt > 1: # show bouquet list
387 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
389 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
391 self.openBouquetEPG(bouquets[0][1], withCallback)
393 def openSingleServiceEPG(self):
394 ref=self.session.nav.getCurrentlyPlayingServiceReference()
395 ptr=eEPGCache.getInstance()
396 self.session.openWithCallback(self.closed, EPGSelection, ref)
398 def openEventView(self):
400 service = self.session.nav.getCurrentService()
401 ref = self.session.nav.getCurrentlyPlayingServiceReference()
402 info = service.info()
405 self.epglist.append(ptr)
408 self.epglist.append(ptr)
409 if len(self.epglist) == 0:
410 epg = eEPGCache.getInstance()
411 ptr = epg.lookupEventTime(ref, -1)
413 self.epglist.append(ptr)
414 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
416 self.epglist.append(ptr)
417 if len(self.epglist) > 0:
418 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
420 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
421 self.openMultiServiceEPG(False)
423 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
424 if len(self.epglist) > 1:
425 tmp = self.epglist[0]
426 self.epglist[0]=self.epglist[1]
428 setEvent(self.epglist[0])
433 """provides a snr/agc/ber display"""
435 self["snr"] = Label()
436 self["agc"] = Label()
437 self["ber"] = Label()
438 self["snr_percent"] = Label()
439 self["agc_percent"] = Label()
440 self["ber_count"] = Label()
441 self["snr_progress"] = ProgressBar()
442 self["agc_progress"] = ProgressBar()
443 self["ber_progress"] = ProgressBar()
444 self.timer = eTimer()
445 self.timer.timeout.get().append(self.updateTunerInfo)
446 self.timer.start(1000)
452 return (long)(log(val)/log(2))
455 def updateTunerInfo(self):
456 if self.instance.isVisible():
457 service = self.session.nav.getCurrentService()
461 if service is not None:
462 feinfo = service.frontendStatusInfo()
463 if feinfo is not None:
464 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
465 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
466 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
467 self["snr_percent"].setText("%d%%"%(snr))
468 self["agc_percent"].setText("%d%%"%(agc))
469 self["ber_count"].setText("%d"%(ber))
470 self["snr_progress"].setValue(snr)
471 self["agc_progress"].setValue(agc)
472 self["ber_progress"].setValue(self.calc(ber))
475 """provides a current/next event info display"""
477 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
478 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
480 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
481 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
483 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
484 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
486 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
488 class InfoBarServiceName:
490 self["ServiceName"] = ServiceName(self.session.nav)
493 """handles actions like seeking, pause"""
495 # ispause, isff, issm
496 SEEK_STATE_PLAY = (0, 0, 0, ">")
497 SEEK_STATE_PAUSE = (1, 0, 0, "||")
498 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
499 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
500 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
501 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
502 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
503 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
505 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
506 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
507 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
508 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
510 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
511 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
512 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
515 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
517 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
518 iPlayableService.evStart: self.__serviceStarted,
520 iPlayableService.evEOF: self.__evEOF,
521 iPlayableService.evSOF: self.__evSOF,
524 class InfoBarSeekActionMap(HelpableActionMap):
525 def __init__(self, screen, *args, **kwargs):
526 HelpableActionMap.__init__(self, screen, *args, **kwargs)
529 def action(self, contexts, action):
530 if action[:5] == "seek:":
531 time = int(action[5:])
532 self.screen.seekRelative(time * 90000)
535 return HelpableActionMap.action(self, contexts, action)
537 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
539 "pauseService": (self.pauseService, "pause"),
540 "unPauseService": (self.unPauseService, "continue"),
542 "seekFwd": (self.seekFwd, "skip forward"),
543 "seekFwdDown": self.seekFwdDown,
544 "seekFwdUp": self.seekFwdUp,
545 "seekBack": (self.seekBack, "skip backward"),
546 "seekBackDown": self.seekBackDown,
547 "seekBackUp": self.seekBackUp,
549 # give them a little more priority to win over color buttons
551 self.seekstate = self.SEEK_STATE_PLAY
552 self.onClose.append(self.delTimer)
554 self.fwdtimer = False
555 self.fwdKeyTimer = eTimer()
556 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
558 self.rwdtimer = False
559 self.rwdKeyTimer = eTimer()
560 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
562 self.onPlayStateChanged = [ ]
564 self.lockedBecauseOfSkipping = False
577 service = self.session.nav.getCurrentService()
581 seek = service.seek()
583 if seek is None or not seek.isCurrentlySeekable():
588 def isSeekable(self):
589 if self.getSeek() is None:
593 def __seekableStatusChanged(self):
594 print "seekable status changed!"
595 if not self.isSeekable():
596 self["SeekActions"].setEnabled(False)
597 print "not seekable, return to play"
598 self.setSeekState(self.SEEK_STATE_PLAY)
600 self["SeekActions"].setEnabled(True)
603 def __serviceStarted(self):
604 self.seekstate = self.SEEK_STATE_PLAY
606 def setSeekState(self, state):
607 service = self.session.nav.getCurrentService()
612 if not self.isSeekable():
613 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
614 state = self.SEEK_STATE_PLAY
616 pauseable = service.pause()
618 if pauseable is None:
619 print "not pauseable."
620 state = self.SEEK_STATE_PLAY
622 oldstate = self.seekstate
623 self.seekstate = state
626 if oldstate[i] != self.seekstate[i]:
627 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
629 for c in self.onPlayStateChanged:
632 self.checkSkipShowHideLock()
636 def pauseService(self):
637 if self.seekstate == self.SEEK_STATE_PAUSE:
638 print "pause, but in fact unpause"
639 self.unPauseService()
641 if self.seekstate == self.SEEK_STATE_PLAY:
642 print "yes, playing."
644 print "no", self.seekstate
646 self.setSeekState(self.SEEK_STATE_PAUSE);
648 def unPauseService(self):
650 self.setSeekState(self.SEEK_STATE_PLAY);
652 def doSeek(self, seektime):
653 print "doseek", seektime
654 service = self.session.nav.getCurrentService()
658 seekable = self.getSeek()
662 seekable.seekTo(90 * seektime)
664 def seekFwdDown(self):
665 print "start fwd timer"
667 self.fwdKeyTimer.start(1000)
669 def seekBackDown(self):
670 print "start rewind timer"
672 self.rwdKeyTimer.start(1000)
677 self.fwdKeyTimer.stop()
678 self.fwdtimer = False
683 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
684 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
685 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
686 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
687 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
688 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
689 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
690 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
691 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
692 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
693 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
694 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
695 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
696 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
697 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
699 self.setSeekState(lookup[self.seekstate])
701 def seekBackUp(self):
704 self.rwdKeyTimer.stop()
705 self.rwdtimer = False
710 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
711 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
712 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
713 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
714 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
715 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
716 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
717 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
718 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
719 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
720 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
721 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
722 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
723 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
724 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
726 self.setSeekState(lookup[self.seekstate])
728 if self.seekstate == self.SEEK_STATE_PAUSE:
729 seekable = self.getSeek()
730 if seekable is not None:
731 seekable.seekRelative(-1, 3)
733 def fwdTimerFire(self):
734 print "Display seek fwd"
735 self.fwdKeyTimer.stop()
736 self.fwdtimer = False
737 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
739 def fwdSeekTo(self, minutes):
740 print "Seek", minutes, "minutes forward"
742 seekable = self.getSeek()
743 if seekable is not None:
744 seekable.seekRelative(1, minutes * 60 * 90000)
746 def rwdTimerFire(self):
748 self.rwdKeyTimer.stop()
749 self.rwdtimer = False
750 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
752 def rwdSeekTo(self, minutes):
754 self.fwdSeekTo(0 - minutes)
756 def checkSkipShowHideLock(self):
757 wantlock = self.seekstate != self.SEEK_STATE_PLAY
759 if self.lockedBecauseOfSkipping and not wantlock:
761 self.lockedBecauseOfSkipping = False
763 if wantlock and not self.lockedBecauseOfSkipping:
765 self.lockedBecauseOfSkipping = True
768 if self.seekstate != self.SEEK_STATE_PLAY:
769 self.setSeekState(self.SEEK_STATE_PAUSE)
771 #self.getSeek().seekRelative(1, -90000)
772 self.setSeekState(self.SEEK_STATE_PLAY)
774 self.setSeekState(self.SEEK_STATE_PAUSE)
777 self.setSeekState(self.SEEK_STATE_PLAY)
780 def seekRelative(self, diff):
781 seekable = self.getSeek()
782 if seekable is not None:
783 seekable.seekRelative(1, diff)
785 from Screens.PVRState import PVRState, TimeshiftState
787 class InfoBarPVRState:
788 def __init__(self, screen=PVRState):
789 self.onPlayStateChanged.append(self.__playStateChanged)
790 self.pvrStateDialog = self.session.instantiateDialog(screen)
791 self.onShow.append(self.__mayShow)
792 self.onHide.append(self.pvrStateDialog.hide)
795 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
796 self.pvrStateDialog.show()
798 def __playStateChanged(self, state):
799 playstateString = state[3]
800 self.pvrStateDialog["state"].setText(playstateString)
803 class InfoBarTimeshiftState(InfoBarPVRState):
805 InfoBarPVRState.__init__(self, screen=TimeshiftState)
808 class InfoBarShowMovies:
810 # i don't really like this class.
811 # it calls a not further specified "movie list" on up/down/movieList,
812 # so this is not more than an action map
814 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
816 "movieList": (self.showMovies, "movie list"),
817 "up": (self.showMovies, "movie list"),
818 "down": (self.showMovies, "movie list")
821 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
825 # Timeshift works the following way:
826 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
827 # - normal playback TUNER unused PLAY enable disable disable
828 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
829 # - user presess pause again FILE record PLAY enable disable enable
830 # - user fast forwards FILE record FF enable disable enable
831 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
832 # - user backwards FILE record BACK # !! enable disable enable
836 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
837 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
838 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
839 # - the user can now PVR around
840 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
841 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
843 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
844 # - if the user rewinds, or press pause, timeshift will be activated again
846 # note that a timeshift can be enabled ("recording") and
847 # activated (currently time-shifting).
849 class InfoBarTimeshift:
851 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
853 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
854 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
856 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
858 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
859 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
860 }, prio=-1) # priority over record
862 self.timeshift_enabled = 0
863 self.timeshift_state = 0
864 self.ts_pause_timer = eTimer()
865 self.ts_pause_timer.timeout.get().append(self.pauseService)
867 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
869 iPlayableService.evStart: self.__serviceStarted,
870 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
873 def getTimeshift(self):
874 service = self.session.nav.getCurrentService()
875 return service.timeshift()
877 def startTimeshift(self):
878 print "enable timeshift"
879 ts = self.getTimeshift()
881 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
882 print "no ts interface"
885 if self.timeshift_enabled:
886 print "hu, timeshift already enabled?"
888 if not ts.startTimeshift():
890 self.timeshift_enabled = 1
891 self.pvrStateDialog["timeshift"].setRelative(time.time())
894 self.setSeekState(self.SEEK_STATE_PAUSE)
896 # enable the "TimeshiftEnableActions", which will override
897 # the startTimeshift actions
898 self.__seekableStatusChanged()
900 print "timeshift failed"
902 def stopTimeshift(self):
903 if not self.timeshift_enabled:
905 print "disable timeshift"
906 ts = self.getTimeshift()
909 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
911 def stopTimeshiftConfirmed(self, confirmed):
915 ts = self.getTimeshift()
920 self.timeshift_enabled = 0
923 self.__seekableStatusChanged()
925 # activates timeshift, and seeks to (almost) the end
926 def activateTimeshiftEnd(self):
927 ts = self.getTimeshift()
932 if ts.isTimeshiftActive():
933 print "!! activate timeshift called - but shouldn't this be a normal pause?"
936 self.setSeekState(self.SEEK_STATE_PLAY)
937 ts.activateTimeshift()
940 # same as activateTimeshiftEnd, but pauses afterwards.
941 def activateTimeshiftEndAndPause(self):
942 state = self.seekstate
943 self.activateTimeshiftEnd()
945 # well, this is "andPause", but it could be pressed from pause,
946 # when pausing on the (fake-)"live" picture, so an un-pause
949 print "now, pauseService"
950 if state == self.SEEK_STATE_PLAY:
951 print "is PLAYING, start pause timer"
952 self.ts_pause_timer.start(200, 1)
955 self.unPauseService()
957 def __seekableStatusChanged(self):
960 print "self.isSeekable", self.isSeekable()
961 print "self.timeshift_enabled", self.timeshift_enabled
963 # when this service is not seekable, but timeshift
964 # is enabled, this means we can activate
966 if not self.isSeekable() and self.timeshift_enabled:
969 print "timeshift activate:", enabled
970 self["TimeshiftActivateActions"].setEnabled(enabled)
972 def __serviceStarted(self):
973 self.timeshift_enabled = False
974 self.__seekableStatusChanged()
976 from RecordTimer import parseEvent
978 class InfoBarInstantRecord:
979 """Instant Record - handles the instantRecord action in order to
980 start/stop instant records"""
982 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
984 "instantRecord": (self.instantRecord, "Instant Record..."),
986 self.recording = None
987 self["BlinkingPoint"] = BlinkingPixmapConditional()
988 self["BlinkingPoint"].hide()
989 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
991 def stopCurrentRecording(self):
992 self.session.nav.RecordTimer.removeEntry(self.recording)
993 self.recording = None
995 def startInstantRecording(self, limitEvent = False):
996 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
998 # try to get event info
1001 service = self.session.nav.getCurrentService()
1002 epg = eEPGCache.getInstance()
1003 event = epg.lookupEventTime(serviceref, -1, 0)
1005 info = service.info()
1006 ev = info.getEvent(0)
1012 end = time.time() + 3600 * 10
1013 name = "instant record"
1017 if event is not None:
1018 curEvent = parseEvent(event)
1020 description = curEvent[3]
1021 eventid = curEvent[4]
1026 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1028 data = (begin, end, name, description, eventid)
1030 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
1031 self.recording.dontSave = True
1033 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1035 def isInstantRecordRunning(self):
1036 if self.recording != None:
1037 if self.recording.isRunning():
1041 def recordQuestionCallback(self, answer):
1042 if answer is None or answer[1] == "no":
1045 if self.isInstantRecordRunning():
1046 if answer[1] == "manualduration":
1047 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1049 self.stopCurrentRecording()
1052 if answer[1] == "event":
1054 if answer[1] == "manualduration":
1055 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1056 self.startInstantRecording(limitEvent = limitEvent)
1058 def inputCallback(self, value):
1059 if value is not None:
1060 print "stopping recording after", int(value), "minutes."
1061 if self.recording is not None:
1062 self.recording.end = time.time() + 60 * int(value)
1063 self.session.nav.RecordTimer.timeChanged(self.recording)
1065 def instantRecord(self):
1067 stat = os.stat(resolveFilename(SCOPE_HDD))
1069 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1072 if self.isInstantRecordRunning():
1073 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("A recording is currently running.\nWhat do you want to do?"), list=[(_("stop recording"), "yes"), (_("enter recording duration"), "manualduration"), (_("do nothing"), "no")])
1074 # self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
1076 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Start recording?"), list=[(_("record indefinitely"), "indefinitely"), (_("stop after current event"), "event"), (_("enter recording duration"), "manualduration"),(_("don't record"), "no")])
1077 #self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
1079 from Screens.AudioSelection import AudioSelection
1081 class InfoBarAudioSelection:
1083 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1085 "audioSelection": (self.audioSelection, "Audio Options..."),
1088 def audioSelection(self):
1089 service = self.session.nav.getCurrentService()
1090 audio = service.audioTracks()
1091 n = audio.getNumberOfTracks()
1093 self.session.open(AudioSelection, audio)
1095 from Screens.SubserviceSelection import SubserviceSelection
1097 class InfoBarSubserviceSelection:
1099 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1101 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1104 def subserviceSelection(self):
1105 service = self.session.nav.getCurrentService()
1106 subservices = service.subServices()
1107 n = subservices.getNumberOfSubservices()
1109 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1111 def subserviceSelected(self, service):
1112 if not service is None:
1113 self.session.nav.playService(service)
1115 class InfoBarAdditionalInfo:
1117 self["DolbyActive"] = Pixmap()
1118 self["CryptActive"] = Pixmap()
1119 self["FormatActive"] = Pixmap()
1121 self["ButtonRed"] = PixmapConditional(withTimer = False)
1122 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1123 self.onLayoutFinish.append(self["ButtonRed"].update)
1124 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1125 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1126 self.onLayoutFinish.append(self["ButtonRedText"].update)
1128 self["ButtonGreen"] = Pixmap()
1129 self["ButtonGreenText"] = Label(_("Subservices"))
1131 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1132 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1133 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1134 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1135 self.onLayoutFinish.append(self["ButtonYellow"].update)
1136 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1138 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1139 self["ButtonBlue"].setConnect(lambda: False)
1140 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1141 self["ButtonBlueText"].setConnect(lambda: False)
1142 self.onLayoutFinish.append(self["ButtonBlue"].update)
1143 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1145 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1147 def hideSubServiceIndication(self):
1148 self["ButtonGreen"].hide()
1149 self["ButtonGreenText"].hide()
1151 def showSubServiceIndication(self):
1152 self["ButtonGreen"].show()
1153 self["ButtonGreenText"].show()
1155 def checkFormat(self, service):
1156 info = service.info()
1157 if info is not None:
1158 aspect = info.getInfo(iServiceInformation.sAspect)
1159 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1160 self["FormatActive"].show()
1162 self["FormatActive"].hide()
1164 def checkSubservices(self, service):
1165 if service.subServices().getNumberOfSubservices() > 0:
1166 self.showSubServiceIndication()
1168 self.hideSubServiceIndication()
1170 def checkDolby(self, service):
1173 audio = service.audioTracks()
1174 if audio is not None:
1175 n = audio.getNumberOfTracks()
1177 i = audio.getTrackInfo(x)
1178 description = i.getDescription();
1179 if description.find("AC3") != -1 or description.find("DTS") != -1:
1183 self["DolbyActive"].show()
1185 self["DolbyActive"].hide()
1187 def checkCrypted(self, service):
1188 info = service.info()
1189 if info is not None:
1190 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1191 self["CryptActive"].show()
1193 self["CryptActive"].hide()
1195 def gotServiceEvent(self, ev):
1196 service = self.session.nav.getCurrentService()
1197 if ev == iPlayableService.evUpdatedEventInfo:
1198 self.checkSubservices(service)
1199 self.checkFormat(service)
1200 elif ev == iPlayableService.evUpdatedInfo:
1201 self.checkCrypted(service)
1202 self.checkDolby(service)
1203 elif ev == iPlayableService.evEnd:
1204 self.hideSubServiceIndication()
1205 self["CryptActive"].hide()
1206 self["DolbyActive"].hide()
1207 self["FormatActive"].hide()
1209 class InfoBarNotifications:
1211 self.onExecBegin.append(self.checkNotifications)
1212 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1214 def checkNotificationsIfExecing(self):
1216 self.checkNotifications()
1218 def checkNotifications(self):
1219 if len(Notifications.notifications):
1220 n = Notifications.notifications[0]
1221 Notifications.notifications = Notifications.notifications[1:]
1225 self.session.openWithCallback(cb, *n[1:])
1227 self.session.open(*n[1:])
1229 class InfoBarServiceNotifications:
1231 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1233 iPlayableService.evEnd: self.serviceHasEnded
1236 def serviceHasEnded(self):
1237 print "service end!"
1240 self.setSeekState(self.SEEK_STATE_PLAY)
1244 class InfoBarCueSheetSupport:
1250 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1252 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1253 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1254 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1258 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1260 iPlayableService.evStart: self.__serviceStarted,
1263 def __serviceStarted(self):
1264 print "new service started! trying to download cuts!"
1265 self.downloadCuesheet()
1267 def __getSeekable(self):
1268 service = self.session.nav.getCurrentService()
1271 return service.seek()
1273 def cueGetCurrentPosition(self):
1274 seek = self.__getSeekable()
1277 r = seek.getPlayPosition()
1282 def jumpPreviousNextMark(self, cmp, alternative=None):
1283 current_pos = self.cueGetCurrentPosition()
1284 if current_pos is None:
1286 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1287 if mark is not None:
1289 elif alternative is not None:
1294 seekable = self.__getSeekable()
1295 if seekable is not None:
1296 seekable.seekTo(pts)
1298 def jumpPreviousMark(self):
1299 # we add 2 seconds, so if the play position is <2s after
1300 # the mark, the mark before will be used
1301 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1303 def jumpNextMark(self):
1304 self.jumpPreviousNextMark(lambda x: x)
1306 def getNearestCutPoint(self, pts, cmp=abs):
1309 for cp in self.cut_list:
1310 diff = cmp(cp[0] - pts)
1311 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1315 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1316 current_pos = self.cueGetCurrentPosition()
1317 if current_pos is None:
1318 print "not seekable"
1321 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1323 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1325 return nearest_cutpoint
1327 self.removeMark(nearest_cutpoint)
1328 elif not onlyremove and not onlyreturn:
1329 self.addMark((current_pos, self.CUT_TYPE_MARK))
1334 def addMark(self, point):
1335 bisect.insort(self.cut_list, point)
1336 self.uploadCuesheet()
1338 def removeMark(self, point):
1339 self.cut_list.remove(point)
1340 self.uploadCuesheet()
1342 def __getCuesheet(self):
1343 service = self.session.nav.getCurrentService()
1346 return service.cueSheet()
1348 def uploadCuesheet(self):
1349 cue = self.__getCuesheet()
1352 print "upload failed, no cuesheet interface"
1354 cue.setCutList(self.cut_list)
1356 def downloadCuesheet(self):
1357 cue = self.__getCuesheet()
1360 print "upload failed, no cuesheet interface"
1362 self.cut_list = cue.getCutList()
1364 class InfoBarSummary(Screen):
1366 <screen position="0,0" size="132,64">
1367 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1368 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1371 def __init__(self, session, parent):
1372 Screen.__init__(self, session)
1373 self["CurrentService"] = ServiceName(self.session.nav)
1374 self["Clock"] = Clock()
1376 class InfoBarSummarySupport:
1380 def createSummary(self):
1381 return InfoBarSummary
1383 class InfoBarTeletextPlugin:
1385 self.teletext_plugin = None
1387 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1388 self.teletext_plugin = p
1390 if self.teletext_plugin is not None:
1391 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1393 "startTeletext": (self.startTeletext, "View teletext...")
1396 print "no teletext plugin found!"
1398 def startTeletext(self):
1399 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())