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
18 from Components.TimerList import TimerEntryComponent
20 from EpgSelection import EPGSelection
21 from Plugins.Plugin import PluginDescriptor
23 from Screen import Screen
24 from Screens.ChoiceBox import ChoiceBox
25 from Screens.Dish import Dish
26 from Screens.EventView import EventViewEPGSelect, EventViewSimple
27 from Screens.InputBox import InputBox
28 from Screens.MessageBox import MessageBox
29 from Screens.MinuteInput import MinuteInput
30 from Screens.TimerSelection import TimerSelection
31 from ServiceReference import ServiceReference
33 from Tools import Notifications
34 from Tools.Directories import *
36 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
43 from Components.config import config, currentConfigSelectionElement
46 from Menu import MainMenu, mdom
50 self.dishDialog = self.session.instantiateDialog(Dish)
51 self.onLayoutFinish.append(self.dishDialog.show)
53 class InfoBarShowHide:
54 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
62 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
64 "toggleShow": self.toggleShow,
68 self.__state = self.STATE_SHOWN
71 self.onExecBegin.append(self.show)
73 self.hideTimer = eTimer()
74 self.hideTimer.timeout.get().append(self.doTimerHide)
75 self.hideTimer.start(5000, True)
77 self.onShow.append(self.__onShow)
78 self.onHide.append(self.__onHide)
81 self.__state = self.STATE_SHOWN
84 def startHideTimer(self):
85 if self.__state == self.STATE_SHOWN and not self.__locked:
86 self.hideTimer.start(5000, True)
89 self.__state = self.STATE_HIDDEN
95 def doTimerHide(self):
97 if self.__state == self.STATE_SHOWN:
100 def toggleShow(self):
101 if self.__state == self.STATE_SHOWN:
103 self.hideTimer.stop()
104 elif self.__state == self.STATE_HIDDEN:
108 self.__locked = self.__locked + 1
111 self.hideTimer.stop()
113 def unlockShow(self):
114 self.__locked = self.__locked - 1
116 self.startHideTimer()
118 # def startShow(self):
119 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
120 # self.__state = self.STATE_SHOWN
122 # def startHide(self):
123 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
124 # self.__state = self.STATE_HIDDEN
126 class NumberZap(Screen):
133 self.close(int(self["number"].getText()))
135 def keyNumberGlobal(self, number):
136 self.Timer.start(3000, True) #reset timer
137 self.field = self.field + str(number)
138 self["number"].setText(self.field)
139 if len(self.field) >= 4:
142 def __init__(self, session, number):
143 Screen.__init__(self, session)
144 self.field = str(number)
146 self["channel"] = Label(_("Channel:"))
148 self["number"] = Label(self.field)
150 self["actions"] = NumberActionMap( [ "SetupActions" ],
154 "1": self.keyNumberGlobal,
155 "2": self.keyNumberGlobal,
156 "3": self.keyNumberGlobal,
157 "4": self.keyNumberGlobal,
158 "5": self.keyNumberGlobal,
159 "6": self.keyNumberGlobal,
160 "7": self.keyNumberGlobal,
161 "8": self.keyNumberGlobal,
162 "9": self.keyNumberGlobal,
163 "0": self.keyNumberGlobal
166 self.Timer = eTimer()
167 self.Timer.timeout.get().append(self.keyOK)
168 self.Timer.start(3000, True)
170 class InfoBarNumberZap:
171 """ Handles an initial number for NumberZapping """
173 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
175 "1": self.keyNumberGlobal,
176 "2": self.keyNumberGlobal,
177 "3": self.keyNumberGlobal,
178 "4": self.keyNumberGlobal,
179 "5": self.keyNumberGlobal,
180 "6": self.keyNumberGlobal,
181 "7": self.keyNumberGlobal,
182 "8": self.keyNumberGlobal,
183 "9": self.keyNumberGlobal,
184 "0": self.keyNumberGlobal,
187 def keyNumberGlobal(self, number):
188 # print "You pressed number " + str(number)
190 self.servicelist.recallPrevService()
193 self.session.openWithCallback(self.numberEntered, NumberZap, number)
195 def numberEntered(self, retval):
196 # print self.servicelist
198 self.zapToNumber(retval)
200 def searchNumberHelper(self, serviceHandler, num, bouquet):
201 servicelist = serviceHandler.list(bouquet)
202 if not servicelist is None:
204 serviceIterator = servicelist.getNext()
205 if not serviceIterator.valid(): #check end of list
207 if serviceIterator.flags: #assume normal dvb service have no flags set
210 if not num: #found service with searched number ?
211 return serviceIterator, 0
214 def zapToNumber(self, number):
215 bouquet = self.servicelist.bouquet_root
217 serviceHandler = eServiceCenter.getInstance()
218 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
219 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
221 bouquetlist = serviceHandler.list(bouquet)
222 if not bouquetlist is None:
224 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
225 if not bouquet.valid(): #check end of list
227 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
229 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
230 if not service is None:
231 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
232 self.servicelist.clearPath()
233 if self.servicelist.bouquet_root != bouquet:
234 self.servicelist.enterPath(self.servicelist.bouquet_root)
235 self.servicelist.enterPath(bouquet)
236 self.servicelist.setCurrentSelection(service) #select the service in servicelist
237 self.servicelist.zap()
239 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
241 class InfoBarChannelSelection:
242 """ ChannelSelection - handles the channelSelection dialog and the initial
243 channelChange actions which open the channelSelection dialog """
246 self.servicelist = self.session.instantiateDialog(ChannelSelection)
248 if config.misc.initialchannelselection.value == 1:
249 self.onShown.append(self.firstRun)
251 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
253 "switchChannelUp": self.switchChannelUp,
254 "switchChannelDown": self.switchChannelDown,
255 "zapUp": (self.zapUp, _("previous channel")),
256 "zapDown": (self.zapDown, _("next channel")),
257 "historyBack": (self.historyBack, _("previous channel in history")),
258 "historyNext": (self.historyNext, _("next channel in history"))
262 self.onShown.remove(self.firstRun)
263 config.misc.initialchannelselection.value = 0
264 config.misc.initialchannelselection.save()
265 self.switchChannelDown()
267 def historyBack(self):
268 self.servicelist.historyBack()
270 def historyNext(self):
271 self.servicelist.historyNext()
273 def switchChannelUp(self):
274 self.servicelist.moveUp()
275 self.session.execDialog(self.servicelist)
277 def switchChannelDown(self):
278 self.servicelist.moveDown()
279 self.session.execDialog(self.servicelist)
282 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
283 if self.servicelist.inBouquet() and self.servicelist.atBegin():
284 self.servicelist.prevBouquet()
285 self.servicelist.moveUp()
286 self.servicelist.zap()
290 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
291 self.servicelist.nextBouquet()
293 self.servicelist.moveDown()
294 self.servicelist.zap()
298 """ Handles a menu action, to open the (main) menu """
300 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
302 "mainMenu": (self.mainMenu, "Enter main menu..."),
306 print "loading mainmenu XML..."
307 menu = mdom.childNodes[0]
308 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
309 self.session.open(MainMenu, menu, menu.childNodes)
311 class InfoBarSimpleEventView:
312 """ Opens the Eventview for now/next """
314 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
316 "showEventInfo": (self.openEventView, _("show event details")),
319 def openEventView(self):
321 service = self.session.nav.getCurrentService()
322 ref = self.session.nav.getCurrentlyPlayingServiceReference()
323 info = service.info()
326 self.epglist.append(ptr)
329 self.epglist.append(ptr)
330 if len(self.epglist) > 0:
331 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
333 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
334 if len(self.epglist) > 1:
335 tmp = self.epglist[0]
336 self.epglist[0]=self.epglist[1]
338 setEvent(self.epglist[0])
341 """ EPG - Opens an EPG list when the showEPGList action fires """
343 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
345 "showEventInfo": (self.openEventView, _("show EPG...")),
348 def zapToService(self, service):
349 if not service is None:
350 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
351 self.servicelist.clearPath()
352 if self.servicelist.bouquet_root != self.epg_bouquet:
353 self.servicelist.enterPath(self.servicelist.bouquet_root)
354 self.servicelist.enterPath(self.epg_bouquet)
355 self.servicelist.setCurrentSelection(service) #select the service in servicelist
356 self.servicelist.zap()
358 def openBouquetEPG(self, bouquet, withCallback=True):
359 ptr=eEPGCache.getInstance()
361 servicelist = eServiceCenter.getInstance().list(bouquet)
362 if not servicelist is None:
364 service = servicelist.getNext()
365 if not service.valid(): #check if end of list
367 if service.flags: #ignore non playable services
369 services.append(ServiceReference(service))
371 self.epg_bouquet = bouquet
373 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
375 self.session.open(EPGSelection, services, self.zapToService)
377 def closed(self, ret):
381 def openMultiServiceEPG(self, withCallback=True):
382 bouquets = self.servicelist.getBouquetList()
387 if cnt > 1: # show bouquet list
389 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
391 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
393 self.openBouquetEPG(bouquets[0][1], withCallback)
395 def openSingleServiceEPG(self):
396 ref=self.session.nav.getCurrentlyPlayingServiceReference()
397 ptr=eEPGCache.getInstance()
398 self.session.openWithCallback(self.closed, EPGSelection, ref)
400 def openEventView(self):
402 service = self.session.nav.getCurrentService()
403 ref = self.session.nav.getCurrentlyPlayingServiceReference()
404 info = service.info()
407 self.epglist.append(ptr)
410 self.epglist.append(ptr)
411 if len(self.epglist) == 0:
412 epg = eEPGCache.getInstance()
413 ptr = epg.lookupEventTime(ref, -1)
415 self.epglist.append(ptr)
416 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
418 self.epglist.append(ptr)
419 if len(self.epglist) > 0:
420 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
422 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
423 self.openMultiServiceEPG(False)
425 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
426 if len(self.epglist) > 1:
427 tmp = self.epglist[0]
428 self.epglist[0]=self.epglist[1]
430 setEvent(self.epglist[0])
435 """provides a snr/agc/ber display"""
437 self["snr"] = Label()
438 self["agc"] = Label()
439 self["ber"] = Label()
440 self["snr_percent"] = Label()
441 self["agc_percent"] = Label()
442 self["ber_count"] = Label()
443 self["snr_progress"] = ProgressBar()
444 self["agc_progress"] = ProgressBar()
445 self["ber_progress"] = ProgressBar()
446 self.timer = eTimer()
447 self.timer.timeout.get().append(self.updateTunerInfo)
448 self.timer.start(1000)
454 return (long)(log(val)/log(2))
457 def updateTunerInfo(self):
458 if self.instance.isVisible():
459 service = self.session.nav.getCurrentService()
463 if service is not None:
464 feinfo = service.frontendStatusInfo()
465 if feinfo is not None:
466 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
467 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
468 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
469 self["snr_percent"].setText("%d%%"%(snr))
470 self["agc_percent"].setText("%d%%"%(agc))
471 self["ber_count"].setText("%d"%(ber))
472 self["snr_progress"].setValue(snr)
473 self["agc_progress"].setValue(agc)
474 self["ber_progress"].setValue(self.calc(ber))
477 """provides a current/next event info display"""
479 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
480 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
482 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
483 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
485 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
486 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
488 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
490 class InfoBarServiceName:
492 self["ServiceName"] = ServiceName(self.session.nav)
495 """handles actions like seeking, pause"""
497 # ispause, isff, issm
498 SEEK_STATE_PLAY = (0, 0, 0, ">")
499 SEEK_STATE_PAUSE = (1, 0, 0, "||")
500 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
501 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
502 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
503 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
504 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
505 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
507 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
508 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
509 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
510 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
512 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
513 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
514 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
517 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
519 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
520 iPlayableService.evStart: self.__serviceStarted,
522 iPlayableService.evEOF: self.__evEOF,
523 iPlayableService.evSOF: self.__evSOF,
526 class InfoBarSeekActionMap(HelpableActionMap):
527 def __init__(self, screen, *args, **kwargs):
528 HelpableActionMap.__init__(self, screen, *args, **kwargs)
531 def action(self, contexts, action):
532 if action[:5] == "seek:":
533 time = int(action[5:])
534 self.screen.seekRelative(time * 90000)
537 return HelpableActionMap.action(self, contexts, action)
539 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
541 "pauseService": (self.pauseService, "pause"),
542 "unPauseService": (self.unPauseService, "continue"),
544 "seekFwd": (self.seekFwd, "skip forward"),
545 "seekFwdDown": self.seekFwdDown,
546 "seekFwdUp": self.seekFwdUp,
547 "seekBack": (self.seekBack, "skip backward"),
548 "seekBackDown": self.seekBackDown,
549 "seekBackUp": self.seekBackUp,
551 # give them a little more priority to win over color buttons
553 self.seekstate = self.SEEK_STATE_PLAY
554 self.onClose.append(self.delTimer)
556 self.fwdtimer = False
557 self.fwdKeyTimer = eTimer()
558 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
560 self.rwdtimer = False
561 self.rwdKeyTimer = eTimer()
562 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
564 self.onPlayStateChanged = [ ]
566 self.lockedBecauseOfSkipping = False
579 service = self.session.nav.getCurrentService()
583 seek = service.seek()
585 if seek is None or not seek.isCurrentlySeekable():
590 def isSeekable(self):
591 if self.getSeek() is None:
595 def __seekableStatusChanged(self):
596 print "seekable status changed!"
597 if not self.isSeekable():
598 self["SeekActions"].setEnabled(False)
599 print "not seekable, return to play"
600 self.setSeekState(self.SEEK_STATE_PLAY)
602 self["SeekActions"].setEnabled(True)
605 def __serviceStarted(self):
606 self.seekstate = self.SEEK_STATE_PLAY
608 def setSeekState(self, state):
609 service = self.session.nav.getCurrentService()
614 if not self.isSeekable():
615 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
616 state = self.SEEK_STATE_PLAY
618 pauseable = service.pause()
620 if pauseable is None:
621 print "not pauseable."
622 state = self.SEEK_STATE_PLAY
624 oldstate = self.seekstate
625 self.seekstate = state
628 if oldstate[i] != self.seekstate[i]:
629 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
631 for c in self.onPlayStateChanged:
634 self.checkSkipShowHideLock()
638 def pauseService(self):
639 if self.seekstate == self.SEEK_STATE_PAUSE:
640 print "pause, but in fact unpause"
641 self.unPauseService()
643 if self.seekstate == self.SEEK_STATE_PLAY:
644 print "yes, playing."
646 print "no", self.seekstate
648 self.setSeekState(self.SEEK_STATE_PAUSE);
650 def unPauseService(self):
652 self.setSeekState(self.SEEK_STATE_PLAY);
654 def doSeek(self, seektime):
655 print "doseek", seektime
656 service = self.session.nav.getCurrentService()
660 seekable = self.getSeek()
664 seekable.seekTo(90 * seektime)
666 def seekFwdDown(self):
667 print "start fwd timer"
669 self.fwdKeyTimer.start(1000)
671 def seekBackDown(self):
672 print "start rewind timer"
674 self.rwdKeyTimer.start(1000)
679 self.fwdKeyTimer.stop()
680 self.fwdtimer = False
685 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
686 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
687 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
688 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
689 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
690 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
691 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
692 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
693 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
694 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
695 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
696 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
697 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
698 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
699 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
701 self.setSeekState(lookup[self.seekstate])
703 def seekBackUp(self):
706 self.rwdKeyTimer.stop()
707 self.rwdtimer = False
712 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
713 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
714 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
715 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
716 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
717 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
718 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
719 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
720 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
721 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
722 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
723 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
724 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
725 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
726 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
728 self.setSeekState(lookup[self.seekstate])
730 if self.seekstate == self.SEEK_STATE_PAUSE:
731 seekable = self.getSeek()
732 if seekable is not None:
733 seekable.seekRelative(-1, 3)
735 def fwdTimerFire(self):
736 print "Display seek fwd"
737 self.fwdKeyTimer.stop()
738 self.fwdtimer = False
739 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
741 def fwdSeekTo(self, minutes):
742 print "Seek", minutes, "minutes forward"
744 seekable = self.getSeek()
745 if seekable is not None:
746 seekable.seekRelative(1, minutes * 60 * 90000)
748 def rwdTimerFire(self):
750 self.rwdKeyTimer.stop()
751 self.rwdtimer = False
752 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
754 def rwdSeekTo(self, minutes):
756 self.fwdSeekTo(0 - minutes)
758 def checkSkipShowHideLock(self):
759 wantlock = self.seekstate != self.SEEK_STATE_PLAY
761 if self.lockedBecauseOfSkipping and not wantlock:
763 self.lockedBecauseOfSkipping = False
765 if wantlock and not self.lockedBecauseOfSkipping:
767 self.lockedBecauseOfSkipping = True
770 if self.seekstate != self.SEEK_STATE_PLAY:
771 self.setSeekState(self.SEEK_STATE_PAUSE)
773 #self.getSeek().seekRelative(1, -90000)
774 self.setSeekState(self.SEEK_STATE_PLAY)
776 self.setSeekState(self.SEEK_STATE_PAUSE)
779 self.setSeekState(self.SEEK_STATE_PLAY)
782 def seekRelative(self, diff):
783 seekable = self.getSeek()
784 if seekable is not None:
785 seekable.seekRelative(1, diff)
787 from Screens.PVRState import PVRState, TimeshiftState
789 class InfoBarPVRState:
790 def __init__(self, screen=PVRState):
791 self.onPlayStateChanged.append(self.__playStateChanged)
792 self.pvrStateDialog = self.session.instantiateDialog(screen)
793 self.onShow.append(self.__mayShow)
794 self.onHide.append(self.pvrStateDialog.hide)
797 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
798 self.pvrStateDialog.show()
800 def __playStateChanged(self, state):
801 playstateString = state[3]
802 self.pvrStateDialog["state"].setText(playstateString)
805 class InfoBarTimeshiftState(InfoBarPVRState):
807 InfoBarPVRState.__init__(self, screen=TimeshiftState)
810 class InfoBarShowMovies:
812 # i don't really like this class.
813 # it calls a not further specified "movie list" on up/down/movieList,
814 # so this is not more than an action map
816 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
818 "movieList": (self.showMovies, "movie list"),
819 "up": (self.showMovies, "movie list"),
820 "down": (self.showMovies, "movie list")
823 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
827 # Timeshift works the following way:
828 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
829 # - normal playback TUNER unused PLAY enable disable disable
830 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
831 # - user presess pause again FILE record PLAY enable disable enable
832 # - user fast forwards FILE record FF enable disable enable
833 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
834 # - user backwards FILE record BACK # !! enable disable enable
838 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
839 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
840 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
841 # - the user can now PVR around
842 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
843 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
845 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
846 # - if the user rewinds, or press pause, timeshift will be activated again
848 # note that a timeshift can be enabled ("recording") and
849 # activated (currently time-shifting).
851 class InfoBarTimeshift:
853 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
855 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
856 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
858 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
860 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
861 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
862 }, prio=-1) # priority over record
864 self.timeshift_enabled = 0
865 self.timeshift_state = 0
866 self.ts_pause_timer = eTimer()
867 self.ts_pause_timer.timeout.get().append(self.pauseService)
869 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
871 iPlayableService.evStart: self.__serviceStarted,
872 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
875 def getTimeshift(self):
876 service = self.session.nav.getCurrentService()
877 return service.timeshift()
879 def startTimeshift(self):
880 print "enable timeshift"
881 ts = self.getTimeshift()
883 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
884 print "no ts interface"
887 if self.timeshift_enabled:
888 print "hu, timeshift already enabled?"
890 if not ts.startTimeshift():
892 self.timeshift_enabled = 1
893 self.pvrStateDialog["timeshift"].setRelative(time.time())
896 self.setSeekState(self.SEEK_STATE_PAUSE)
898 # enable the "TimeshiftEnableActions", which will override
899 # the startTimeshift actions
900 self.__seekableStatusChanged()
902 print "timeshift failed"
904 def stopTimeshift(self):
905 if not self.timeshift_enabled:
907 print "disable timeshift"
908 ts = self.getTimeshift()
911 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
913 def stopTimeshiftConfirmed(self, confirmed):
917 ts = self.getTimeshift()
922 self.timeshift_enabled = 0
925 self.__seekableStatusChanged()
927 # activates timeshift, and seeks to (almost) the end
928 def activateTimeshiftEnd(self):
929 ts = self.getTimeshift()
934 if ts.isTimeshiftActive():
935 print "!! activate timeshift called - but shouldn't this be a normal pause?"
938 self.setSeekState(self.SEEK_STATE_PLAY)
939 ts.activateTimeshift()
942 # same as activateTimeshiftEnd, but pauses afterwards.
943 def activateTimeshiftEndAndPause(self):
944 state = self.seekstate
945 self.activateTimeshiftEnd()
947 # well, this is "andPause", but it could be pressed from pause,
948 # when pausing on the (fake-)"live" picture, so an un-pause
951 print "now, pauseService"
952 if state == self.SEEK_STATE_PLAY:
953 print "is PLAYING, start pause timer"
954 self.ts_pause_timer.start(200, 1)
957 self.unPauseService()
959 def __seekableStatusChanged(self):
962 print "self.isSeekable", self.isSeekable()
963 print "self.timeshift_enabled", self.timeshift_enabled
965 # when this service is not seekable, but timeshift
966 # is enabled, this means we can activate
968 if not self.isSeekable() and self.timeshift_enabled:
971 print "timeshift activate:", enabled
972 self["TimeshiftActivateActions"].setEnabled(enabled)
974 def __serviceStarted(self):
975 self.timeshift_enabled = False
976 self.__seekableStatusChanged()
978 from RecordTimer import parseEvent
980 class InfoBarInstantRecord:
981 """Instant Record - handles the instantRecord action in order to
982 start/stop instant records"""
984 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
986 "instantRecord": (self.instantRecord, "Instant Record..."),
989 self["BlinkingPoint"] = BlinkingPixmapConditional()
990 self["BlinkingPoint"].hide()
991 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
993 def stopCurrentRecording(self, entry = -1):
994 if entry is not None and entry != -1:
995 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
996 self.recording.remove(self.recording[entry])
998 def startInstantRecording(self, limitEvent = False):
999 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1001 # try to get event info
1004 service = self.session.nav.getCurrentService()
1005 epg = eEPGCache.getInstance()
1006 event = epg.lookupEventTime(serviceref, -1, 0)
1008 info = service.info()
1009 ev = info.getEvent(0)
1015 end = time.time() + 3600 * 10
1016 name = "instant record"
1020 if event is not None:
1021 curEvent = parseEvent(event)
1023 description = curEvent[3]
1024 eventid = curEvent[4]
1029 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1031 data = (begin, end, name, description, eventid)
1033 recording = self.session.nav.recordWithTimer(serviceref, *data)
1034 recording.dontSave = True
1035 self.recording.append(recording)
1037 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1039 def isInstantRecordRunning(self):
1040 print "self.recording:", self.recording
1041 if len(self.recording) > 0:
1042 for x in self.recording:
1047 def recordQuestionCallback(self, answer):
1048 if answer is None or answer[1] == "no":
1051 for x in self.recording:
1053 list.append(TimerEntryComponent(x, False))
1055 if answer[1] == "changeduration":
1056 if len(self.recording) == 1:
1057 self.changeDuration(0)
1059 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1060 elif answer[1] == "stop":
1061 if len(self.recording) == 1:
1062 self.stopCurrentRecording(0)
1064 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1065 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1067 if answer[1] == "event":
1069 if answer[1] == "manualduration":
1070 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1071 self.startInstantRecording(limitEvent = limitEvent)
1073 def changeDuration(self, entry):
1074 if entry is not None:
1075 self.selectedEntry = entry
1076 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1078 def inputCallback(self, value):
1079 if value is not None:
1080 print "stopping recording after", int(value), "minutes."
1081 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1082 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1084 def instantRecord(self):
1086 stat = os.stat(resolveFilename(SCOPE_HDD))
1088 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1091 if self.isInstantRecordRunning():
1092 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("A recording is currently running.\nWhat do you want to do?"), list=[(_("stop recording"), "stop"), (_("change recording (duration)"), "changeduration"), (_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"), (_("do nothing"), "no")])
1094 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Start recording?"), list=[(_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"),(_("don't record"), "no")])
1096 from Screens.AudioSelection import AudioSelection
1098 class InfoBarAudioSelection:
1100 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1102 "audioSelection": (self.audioSelection, "Audio Options..."),
1105 def audioSelection(self):
1106 service = self.session.nav.getCurrentService()
1107 audio = service.audioTracks()
1108 n = audio.getNumberOfTracks()
1110 self.session.open(AudioSelection, audio)
1112 from Screens.SubserviceSelection import SubserviceSelection
1114 class InfoBarSubserviceSelection:
1116 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1118 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1121 def subserviceSelection(self):
1122 service = self.session.nav.getCurrentService()
1123 subservices = service.subServices()
1124 n = subservices.getNumberOfSubservices()
1126 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1128 def subserviceSelected(self, service):
1129 if not service is None:
1130 self.session.nav.playService(service)
1132 class InfoBarAdditionalInfo:
1134 self["DolbyActive"] = Pixmap()
1135 self["CryptActive"] = Pixmap()
1136 self["FormatActive"] = Pixmap()
1138 self["ButtonRed"] = PixmapConditional(withTimer = False)
1139 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1140 self.onLayoutFinish.append(self["ButtonRed"].update)
1141 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1142 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1143 self.onLayoutFinish.append(self["ButtonRedText"].update)
1145 self["ButtonGreen"] = Pixmap()
1146 self["ButtonGreenText"] = Label(_("Subservices"))
1148 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1149 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1150 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1151 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1152 self.onLayoutFinish.append(self["ButtonYellow"].update)
1153 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1155 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1156 self["ButtonBlue"].setConnect(lambda: False)
1157 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1158 self["ButtonBlueText"].setConnect(lambda: False)
1159 self.onLayoutFinish.append(self["ButtonBlue"].update)
1160 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1162 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1164 def hideSubServiceIndication(self):
1165 self["ButtonGreen"].hide()
1166 self["ButtonGreenText"].hide()
1168 def showSubServiceIndication(self):
1169 self["ButtonGreen"].show()
1170 self["ButtonGreenText"].show()
1172 def checkFormat(self, service):
1173 info = service.info()
1174 if info is not None:
1175 aspect = info.getInfo(iServiceInformation.sAspect)
1176 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1177 self["FormatActive"].show()
1179 self["FormatActive"].hide()
1181 def checkSubservices(self, service):
1182 if service.subServices().getNumberOfSubservices() > 0:
1183 self.showSubServiceIndication()
1185 self.hideSubServiceIndication()
1187 def checkDolby(self, service):
1190 audio = service.audioTracks()
1191 if audio is not None:
1192 n = audio.getNumberOfTracks()
1194 i = audio.getTrackInfo(x)
1195 description = i.getDescription();
1196 if description.find("AC3") != -1 or description.find("DTS") != -1:
1200 self["DolbyActive"].show()
1202 self["DolbyActive"].hide()
1204 def checkCrypted(self, service):
1205 info = service.info()
1206 if info is not None:
1207 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1208 self["CryptActive"].show()
1210 self["CryptActive"].hide()
1212 def gotServiceEvent(self, ev):
1213 service = self.session.nav.getCurrentService()
1214 if ev == iPlayableService.evUpdatedEventInfo:
1215 self.checkSubservices(service)
1216 self.checkFormat(service)
1217 elif ev == iPlayableService.evUpdatedInfo:
1218 self.checkCrypted(service)
1219 self.checkDolby(service)
1220 elif ev == iPlayableService.evEnd:
1221 self.hideSubServiceIndication()
1222 self["CryptActive"].hide()
1223 self["DolbyActive"].hide()
1224 self["FormatActive"].hide()
1226 class InfoBarNotifications:
1228 self.onExecBegin.append(self.checkNotifications)
1229 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1231 def checkNotificationsIfExecing(self):
1233 self.checkNotifications()
1235 def checkNotifications(self):
1236 if len(Notifications.notifications):
1237 n = Notifications.notifications[0]
1238 Notifications.notifications = Notifications.notifications[1:]
1242 self.session.openWithCallback(cb, *n[1:])
1244 self.session.open(*n[1:])
1246 class InfoBarServiceNotifications:
1248 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1250 iPlayableService.evEnd: self.serviceHasEnded
1253 def serviceHasEnded(self):
1254 print "service end!"
1257 self.setSeekState(self.SEEK_STATE_PLAY)
1261 class InfoBarCueSheetSupport:
1267 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1269 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1270 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1271 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1275 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1277 iPlayableService.evStart: self.__serviceStarted,
1280 def __serviceStarted(self):
1281 print "new service started! trying to download cuts!"
1282 self.downloadCuesheet()
1284 def __getSeekable(self):
1285 service = self.session.nav.getCurrentService()
1288 return service.seek()
1290 def cueGetCurrentPosition(self):
1291 seek = self.__getSeekable()
1294 r = seek.getPlayPosition()
1299 def jumpPreviousNextMark(self, cmp, alternative=None):
1300 current_pos = self.cueGetCurrentPosition()
1301 if current_pos is None:
1303 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1304 if mark is not None:
1306 elif alternative is not None:
1311 seekable = self.__getSeekable()
1312 if seekable is not None:
1313 seekable.seekTo(pts)
1315 def jumpPreviousMark(self):
1316 # we add 2 seconds, so if the play position is <2s after
1317 # the mark, the mark before will be used
1318 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1320 def jumpNextMark(self):
1321 self.jumpPreviousNextMark(lambda x: x)
1323 def getNearestCutPoint(self, pts, cmp=abs):
1326 for cp in self.cut_list:
1327 diff = cmp(cp[0] - pts)
1328 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1332 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1333 current_pos = self.cueGetCurrentPosition()
1334 if current_pos is None:
1335 print "not seekable"
1338 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1340 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1342 return nearest_cutpoint
1344 self.removeMark(nearest_cutpoint)
1345 elif not onlyremove and not onlyreturn:
1346 self.addMark((current_pos, self.CUT_TYPE_MARK))
1351 def addMark(self, point):
1352 bisect.insort(self.cut_list, point)
1353 self.uploadCuesheet()
1355 def removeMark(self, point):
1356 self.cut_list.remove(point)
1357 self.uploadCuesheet()
1359 def __getCuesheet(self):
1360 service = self.session.nav.getCurrentService()
1363 return service.cueSheet()
1365 def uploadCuesheet(self):
1366 cue = self.__getCuesheet()
1369 print "upload failed, no cuesheet interface"
1371 cue.setCutList(self.cut_list)
1373 def downloadCuesheet(self):
1374 cue = self.__getCuesheet()
1377 print "upload failed, no cuesheet interface"
1379 self.cut_list = cue.getCutList()
1381 class InfoBarSummary(Screen):
1383 <screen position="0,0" size="132,64">
1384 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1385 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1388 def __init__(self, session, parent):
1389 Screen.__init__(self, session)
1390 self["CurrentService"] = ServiceName(self.session.nav)
1391 self["Clock"] = Clock()
1393 class InfoBarSummarySupport:
1397 def createSummary(self):
1398 return InfoBarSummary
1400 class InfoBarTeletextPlugin:
1402 self.teletext_plugin = None
1404 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1405 self.teletext_plugin = p
1407 if self.teletext_plugin is not None:
1408 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1410 "startTeletext": (self.startTeletext, "View teletext...")
1413 print "no teletext plugin found!"
1415 def startTeletext(self):
1416 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())