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
19 from Components.TunerInfo import TunerInfo
21 from EpgSelection import EPGSelection
22 from Plugins.Plugin import PluginDescriptor
24 from Screen import Screen
25 from Screens.ChoiceBox import ChoiceBox
26 from Screens.Dish import Dish
27 from Screens.EventView import EventViewEPGSelect, EventViewSimple
28 from Screens.InputBox import InputBox
29 from Screens.MessageBox import MessageBox
30 from Screens.MinuteInput import MinuteInput
31 from Screens.TimerSelection import TimerSelection
32 from Screens.PictureInPicture import PictureInPicture
33 from ServiceReference import ServiceReference
35 from Tools import Notifications
36 from Tools.Directories import *
38 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
45 from Components.config import config, currentConfigSelectionElement
48 from Menu import MainMenu, mdom
52 self.dishDialog = self.session.instantiateDialog(Dish)
53 self.onLayoutFinish.append(self.dishDialog.show)
55 class InfoBarShowHide:
56 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
64 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
66 "toggleShow": self.toggleShow,
70 self.__state = self.STATE_SHOWN
73 self.onExecBegin.append(self.show)
75 self.hideTimer = eTimer()
76 self.hideTimer.timeout.get().append(self.doTimerHide)
77 self.hideTimer.start(5000, True)
79 self.onShow.append(self.__onShow)
80 self.onHide.append(self.__onHide)
83 self.__state = self.STATE_SHOWN
86 def startHideTimer(self):
87 if self.__state == self.STATE_SHOWN and not self.__locked:
88 self.hideTimer.start(5000, True)
91 self.__state = self.STATE_HIDDEN
97 def doTimerHide(self):
99 if self.__state == self.STATE_SHOWN:
102 def toggleShow(self):
103 if self.__state == self.STATE_SHOWN:
105 self.hideTimer.stop()
106 elif self.__state == self.STATE_HIDDEN:
110 self.__locked = self.__locked + 1
113 self.hideTimer.stop()
115 def unlockShow(self):
116 self.__locked = self.__locked - 1
118 self.startHideTimer()
120 # def startShow(self):
121 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
122 # self.__state = self.STATE_SHOWN
124 # def startHide(self):
125 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
126 # self.__state = self.STATE_HIDDEN
128 class NumberZap(Screen):
135 self.close(int(self["number"].getText()))
137 def keyNumberGlobal(self, number):
138 self.Timer.start(3000, True) #reset timer
139 self.field = self.field + str(number)
140 self["number"].setText(self.field)
141 if len(self.field) >= 4:
144 def __init__(self, session, number):
145 Screen.__init__(self, session)
146 self.field = str(number)
148 self["channel"] = Label(_("Channel:"))
150 self["number"] = Label(self.field)
152 self["actions"] = NumberActionMap( [ "SetupActions" ],
156 "1": self.keyNumberGlobal,
157 "2": self.keyNumberGlobal,
158 "3": self.keyNumberGlobal,
159 "4": self.keyNumberGlobal,
160 "5": self.keyNumberGlobal,
161 "6": self.keyNumberGlobal,
162 "7": self.keyNumberGlobal,
163 "8": self.keyNumberGlobal,
164 "9": self.keyNumberGlobal,
165 "0": self.keyNumberGlobal
168 self.Timer = eTimer()
169 self.Timer.timeout.get().append(self.keyOK)
170 self.Timer.start(3000, True)
172 class InfoBarNumberZap:
173 """ Handles an initial number for NumberZapping """
175 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
177 "1": self.keyNumberGlobal,
178 "2": self.keyNumberGlobal,
179 "3": self.keyNumberGlobal,
180 "4": self.keyNumberGlobal,
181 "5": self.keyNumberGlobal,
182 "6": self.keyNumberGlobal,
183 "7": self.keyNumberGlobal,
184 "8": self.keyNumberGlobal,
185 "9": self.keyNumberGlobal,
186 "0": self.keyNumberGlobal,
189 def keyNumberGlobal(self, number):
190 # print "You pressed number " + str(number)
192 self.servicelist.recallPrevService()
195 self.session.openWithCallback(self.numberEntered, NumberZap, number)
197 def numberEntered(self, retval):
198 # print self.servicelist
200 self.zapToNumber(retval)
202 def searchNumberHelper(self, serviceHandler, num, bouquet):
203 servicelist = serviceHandler.list(bouquet)
204 if not servicelist is None:
206 serviceIterator = servicelist.getNext()
207 if not serviceIterator.valid(): #check end of list
209 if serviceIterator.flags: #assume normal dvb service have no flags set
212 if not num: #found service with searched number ?
213 return serviceIterator, 0
216 def zapToNumber(self, number):
217 bouquet = self.servicelist.bouquet_root
219 serviceHandler = eServiceCenter.getInstance()
220 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
221 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
223 bouquetlist = serviceHandler.list(bouquet)
224 if not bouquetlist is None:
226 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
227 if not bouquet.valid(): #check end of list
229 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
231 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
232 if not service is None:
233 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
234 self.servicelist.clearPath()
235 if self.servicelist.bouquet_root != bouquet:
236 self.servicelist.enterPath(self.servicelist.bouquet_root)
237 self.servicelist.enterPath(bouquet)
238 self.servicelist.setCurrentSelection(service) #select the service in servicelist
239 self.servicelist.zap()
241 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
243 class InfoBarChannelSelection:
244 """ ChannelSelection - handles the channelSelection dialog and the initial
245 channelChange actions which open the channelSelection dialog """
248 self.servicelist = self.session.instantiateDialog(ChannelSelection)
250 if config.misc.initialchannelselection.value == 1:
251 self.onShown.append(self.firstRun)
253 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
255 "switchChannelUp": self.switchChannelUp,
256 "switchChannelDown": self.switchChannelDown,
257 "zapUp": (self.zapUp, _("previous channel")),
258 "zapDown": (self.zapDown, _("next channel")),
259 "historyBack": (self.historyBack, _("previous channel in history")),
260 "historyNext": (self.historyNext, _("next channel in history"))
264 self.onShown.remove(self.firstRun)
265 config.misc.initialchannelselection.value = 0
266 config.misc.initialchannelselection.save()
267 self.switchChannelDown()
269 def historyBack(self):
270 self.servicelist.historyBack()
272 def historyNext(self):
273 self.servicelist.historyNext()
275 def switchChannelUp(self):
276 self.servicelist.moveUp()
277 self.session.execDialog(self.servicelist)
279 def switchChannelDown(self):
280 self.servicelist.moveDown()
281 self.session.execDialog(self.servicelist)
284 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
285 if self.servicelist.inBouquet() and self.servicelist.atBegin():
286 self.servicelist.prevBouquet()
287 self.servicelist.moveUp()
288 self.servicelist.zap()
292 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
293 self.servicelist.nextBouquet()
295 self.servicelist.moveDown()
296 self.servicelist.zap()
300 """ Handles a menu action, to open the (main) menu """
302 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
304 "mainMenu": (self.mainMenu, "Enter main menu..."),
308 print "loading mainmenu XML..."
309 menu = mdom.childNodes[0]
310 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
311 self.session.open(MainMenu, menu, menu.childNodes)
313 class InfoBarSimpleEventView:
314 """ Opens the Eventview for now/next """
316 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
318 "showEventInfo": (self.openEventView, _("show event details")),
321 def openEventView(self):
323 service = self.session.nav.getCurrentService()
324 ref = self.session.nav.getCurrentlyPlayingServiceReference()
325 info = service.info()
328 self.epglist.append(ptr)
331 self.epglist.append(ptr)
332 if len(self.epglist) > 0:
333 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
335 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
336 if len(self.epglist) > 1:
337 tmp = self.epglist[0]
338 self.epglist[0]=self.epglist[1]
340 setEvent(self.epglist[0])
343 """ EPG - Opens an EPG list when the showEPGList action fires """
345 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
347 "showEventInfo": (self.openEventView, _("show EPG...")),
350 def zapToService(self, service):
351 if not service is None:
352 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
353 self.servicelist.clearPath()
354 if self.servicelist.bouquet_root != self.epg_bouquet:
355 self.servicelist.enterPath(self.servicelist.bouquet_root)
356 self.servicelist.enterPath(self.epg_bouquet)
357 self.servicelist.setCurrentSelection(service) #select the service in servicelist
358 self.servicelist.zap()
360 def openBouquetEPG(self, bouquet, withCallback=True):
361 ptr=eEPGCache.getInstance()
363 servicelist = eServiceCenter.getInstance().list(bouquet)
364 if not servicelist is None:
366 service = servicelist.getNext()
367 if not service.valid(): #check if end of list
369 if service.flags: #ignore non playable services
371 services.append(ServiceReference(service))
373 self.epg_bouquet = bouquet
375 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
377 self.session.open(EPGSelection, services, self.zapToService)
379 def closed(self, ret):
383 def openMultiServiceEPG(self, withCallback=True):
384 bouquets = self.servicelist.getBouquetList()
389 if cnt > 1: # show bouquet list
391 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
393 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
395 self.openBouquetEPG(bouquets[0][1], withCallback)
397 def openSingleServiceEPG(self):
398 ref=self.session.nav.getCurrentlyPlayingServiceReference()
399 ptr=eEPGCache.getInstance()
400 self.session.openWithCallback(self.closed, EPGSelection, ref)
402 def openEventView(self):
404 service = self.session.nav.getCurrentService()
405 ref = self.session.nav.getCurrentlyPlayingServiceReference()
406 info = service.info()
409 self.epglist.append(ptr)
412 self.epglist.append(ptr)
413 if len(self.epglist) == 0:
414 epg = eEPGCache.getInstance()
415 ptr = epg.lookupEventTime(ref, -1)
417 self.epglist.append(ptr)
418 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
420 self.epglist.append(ptr)
421 if len(self.epglist) > 0:
422 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
424 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
425 self.openMultiServiceEPG(False)
427 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
428 if len(self.epglist) > 1:
429 tmp = self.epglist[0]
430 self.epglist[0]=self.epglist[1]
432 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"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
441 self["agc_percent"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
442 self["ber_count"] = TunerInfo(TunerInfo.BER_VALUE, servicefkt = self.session.nav.getCurrentService)
443 self["snr_progress"] = TunerInfo(TunerInfo.SNR_BAR, servicefkt = self.session.nav.getCurrentService)
444 self["agc_progress"] = TunerInfo(TunerInfo.AGC_BAR, servicefkt = self.session.nav.getCurrentService)
445 self["ber_progress"] = TunerInfo(TunerInfo.BER_BAR, servicefkt = self.session.nav.getCurrentService)
446 self.timer = eTimer()
447 self.timer.timeout.get().append(self.updateTunerInfo)
448 self.timer.start(1000)
450 def updateTunerInfo(self):
451 if self.instance.isVisible():
452 self["snr_percent"].update()
453 self["agc_percent"].update()
454 self["ber_count"].update()
455 self["snr_progress"].update()
456 self["agc_progress"].update()
457 self["ber_progress"].update()
460 """provides a current/next event info display"""
462 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
463 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
465 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
466 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
468 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
469 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
471 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
473 class InfoBarServiceName:
475 self["ServiceName"] = ServiceName(self.session.nav)
478 """handles actions like seeking, pause"""
480 # ispause, isff, issm
481 SEEK_STATE_PLAY = (0, 0, 0, ">")
482 SEEK_STATE_PAUSE = (1, 0, 0, "||")
483 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
484 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
485 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
486 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
487 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
488 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
490 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
491 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
492 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
493 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
495 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
496 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
497 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
500 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
502 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
503 iPlayableService.evStart: self.__serviceStarted,
505 iPlayableService.evEOF: self.__evEOF,
506 iPlayableService.evSOF: self.__evSOF,
509 class InfoBarSeekActionMap(HelpableActionMap):
510 def __init__(self, screen, *args, **kwargs):
511 HelpableActionMap.__init__(self, screen, *args, **kwargs)
514 def action(self, contexts, action):
515 if action[:5] == "seek:":
516 time = int(action[5:])
517 self.screen.seekRelative(time * 90000)
520 return HelpableActionMap.action(self, contexts, action)
522 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
524 "pauseService": (self.pauseService, "pause"),
525 "unPauseService": (self.unPauseService, "continue"),
527 "seekFwd": (self.seekFwd, "skip forward"),
528 "seekFwdDown": self.seekFwdDown,
529 "seekFwdUp": self.seekFwdUp,
530 "seekBack": (self.seekBack, "skip backward"),
531 "seekBackDown": self.seekBackDown,
532 "seekBackUp": self.seekBackUp,
534 # give them a little more priority to win over color buttons
536 self.seekstate = self.SEEK_STATE_PLAY
537 self.onClose.append(self.delTimer)
539 self.fwdtimer = False
540 self.fwdKeyTimer = eTimer()
541 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
543 self.rwdtimer = False
544 self.rwdKeyTimer = eTimer()
545 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
547 self.onPlayStateChanged = [ ]
549 self.lockedBecauseOfSkipping = False
562 service = self.session.nav.getCurrentService()
566 seek = service.seek()
568 if seek is None or not seek.isCurrentlySeekable():
573 def isSeekable(self):
574 if self.getSeek() is None:
578 def __seekableStatusChanged(self):
579 print "seekable status changed!"
580 if not self.isSeekable():
581 self["SeekActions"].setEnabled(False)
582 print "not seekable, return to play"
583 self.setSeekState(self.SEEK_STATE_PLAY)
585 self["SeekActions"].setEnabled(True)
588 def __serviceStarted(self):
589 self.seekstate = self.SEEK_STATE_PLAY
591 def setSeekState(self, state):
592 service = self.session.nav.getCurrentService()
597 if not self.isSeekable():
598 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
599 state = self.SEEK_STATE_PLAY
601 pauseable = service.pause()
603 if pauseable is None:
604 print "not pauseable."
605 state = self.SEEK_STATE_PLAY
607 oldstate = self.seekstate
608 self.seekstate = state
611 if oldstate[i] != self.seekstate[i]:
612 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
614 for c in self.onPlayStateChanged:
617 self.checkSkipShowHideLock()
621 def pauseService(self):
622 if self.seekstate == self.SEEK_STATE_PAUSE:
623 print "pause, but in fact unpause"
624 self.unPauseService()
626 if self.seekstate == self.SEEK_STATE_PLAY:
627 print "yes, playing."
629 print "no", self.seekstate
631 self.setSeekState(self.SEEK_STATE_PAUSE);
633 def unPauseService(self):
635 self.setSeekState(self.SEEK_STATE_PLAY);
637 def doSeek(self, seektime):
638 print "doseek", seektime
639 service = self.session.nav.getCurrentService()
643 seekable = self.getSeek()
647 seekable.seekTo(90 * seektime)
649 def seekFwdDown(self):
650 print "start fwd timer"
652 self.fwdKeyTimer.start(1000)
654 def seekBackDown(self):
655 print "start rewind timer"
657 self.rwdKeyTimer.start(1000)
662 self.fwdKeyTimer.stop()
663 self.fwdtimer = False
668 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
669 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
670 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
671 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
672 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
673 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
674 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
675 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
676 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
677 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
678 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
679 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
680 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
681 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
682 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
684 self.setSeekState(lookup[self.seekstate])
686 def seekBackUp(self):
689 self.rwdKeyTimer.stop()
690 self.rwdtimer = False
695 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
696 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
697 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
698 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
699 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
700 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
701 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
702 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
703 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
704 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
705 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
706 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
707 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
708 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
709 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
711 self.setSeekState(lookup[self.seekstate])
713 if self.seekstate == self.SEEK_STATE_PAUSE:
714 seekable = self.getSeek()
715 if seekable is not None:
716 seekable.seekRelative(-1, 3)
718 def fwdTimerFire(self):
719 print "Display seek fwd"
720 self.fwdKeyTimer.stop()
721 self.fwdtimer = False
722 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
724 def fwdSeekTo(self, minutes):
725 print "Seek", minutes, "minutes forward"
727 seekable = self.getSeek()
728 if seekable is not None:
729 seekable.seekRelative(1, minutes * 60 * 90000)
731 def rwdTimerFire(self):
733 self.rwdKeyTimer.stop()
734 self.rwdtimer = False
735 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
737 def rwdSeekTo(self, minutes):
739 self.fwdSeekTo(0 - minutes)
741 def checkSkipShowHideLock(self):
742 wantlock = self.seekstate != self.SEEK_STATE_PLAY
744 if self.lockedBecauseOfSkipping and not wantlock:
746 self.lockedBecauseOfSkipping = False
748 if wantlock and not self.lockedBecauseOfSkipping:
750 self.lockedBecauseOfSkipping = True
753 if self.seekstate != self.SEEK_STATE_PLAY:
754 self.setSeekState(self.SEEK_STATE_PAUSE)
756 #self.getSeek().seekRelative(1, -90000)
757 self.setSeekState(self.SEEK_STATE_PLAY)
759 self.setSeekState(self.SEEK_STATE_PAUSE)
762 self.setSeekState(self.SEEK_STATE_PLAY)
765 def seekRelative(self, diff):
766 seekable = self.getSeek()
767 if seekable is not None:
768 seekable.seekRelative(1, diff)
770 from Screens.PVRState import PVRState, TimeshiftState
772 class InfoBarPVRState:
773 def __init__(self, screen=PVRState):
774 self.onPlayStateChanged.append(self.__playStateChanged)
775 self.pvrStateDialog = self.session.instantiateDialog(screen)
776 self.onShow.append(self.__mayShow)
777 self.onHide.append(self.pvrStateDialog.hide)
780 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
781 self.pvrStateDialog.show()
783 def __playStateChanged(self, state):
784 playstateString = state[3]
785 self.pvrStateDialog["state"].setText(playstateString)
788 class InfoBarTimeshiftState(InfoBarPVRState):
790 InfoBarPVRState.__init__(self, screen=TimeshiftState)
793 class InfoBarShowMovies:
795 # i don't really like this class.
796 # it calls a not further specified "movie list" on up/down/movieList,
797 # so this is not more than an action map
799 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
801 "movieList": (self.showMovies, "movie list"),
802 "up": (self.showMovies, "movie list"),
803 "down": (self.showMovies, "movie list")
806 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
810 # Timeshift works the following way:
811 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
812 # - normal playback TUNER unused PLAY enable disable disable
813 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
814 # - user presess pause again FILE record PLAY enable disable enable
815 # - user fast forwards FILE record FF enable disable enable
816 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
817 # - user backwards FILE record BACK # !! enable disable enable
821 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
822 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
823 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
824 # - the user can now PVR around
825 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
826 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
828 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
829 # - if the user rewinds, or press pause, timeshift will be activated again
831 # note that a timeshift can be enabled ("recording") and
832 # activated (currently time-shifting).
834 class InfoBarTimeshift:
836 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
838 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
839 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
841 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
843 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
844 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
845 }, prio=-1) # priority over record
847 self.timeshift_enabled = 0
848 self.timeshift_state = 0
849 self.ts_pause_timer = eTimer()
850 self.ts_pause_timer.timeout.get().append(self.pauseService)
852 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
854 iPlayableService.evStart: self.__serviceStarted,
855 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
858 def getTimeshift(self):
859 service = self.session.nav.getCurrentService()
860 return service.timeshift()
862 def startTimeshift(self):
863 print "enable timeshift"
864 ts = self.getTimeshift()
866 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
867 print "no ts interface"
870 if self.timeshift_enabled:
871 print "hu, timeshift already enabled?"
873 if not ts.startTimeshift():
875 self.timeshift_enabled = 1
876 self.pvrStateDialog["timeshift"].setRelative(time.time())
879 self.setSeekState(self.SEEK_STATE_PAUSE)
881 # enable the "TimeshiftEnableActions", which will override
882 # the startTimeshift actions
883 self.__seekableStatusChanged()
885 print "timeshift failed"
887 def stopTimeshift(self):
888 if not self.timeshift_enabled:
890 print "disable timeshift"
891 ts = self.getTimeshift()
894 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
896 def stopTimeshiftConfirmed(self, confirmed):
900 ts = self.getTimeshift()
905 self.timeshift_enabled = 0
908 self.__seekableStatusChanged()
910 # activates timeshift, and seeks to (almost) the end
911 def activateTimeshiftEnd(self):
912 ts = self.getTimeshift()
917 if ts.isTimeshiftActive():
918 print "!! activate timeshift called - but shouldn't this be a normal pause?"
921 self.setSeekState(self.SEEK_STATE_PLAY)
922 ts.activateTimeshift()
925 # same as activateTimeshiftEnd, but pauses afterwards.
926 def activateTimeshiftEndAndPause(self):
927 state = self.seekstate
928 self.activateTimeshiftEnd()
930 # well, this is "andPause", but it could be pressed from pause,
931 # when pausing on the (fake-)"live" picture, so an un-pause
934 print "now, pauseService"
935 if state == self.SEEK_STATE_PLAY:
936 print "is PLAYING, start pause timer"
937 self.ts_pause_timer.start(200, 1)
940 self.unPauseService()
942 def __seekableStatusChanged(self):
945 print "self.isSeekable", self.isSeekable()
946 print "self.timeshift_enabled", self.timeshift_enabled
948 # when this service is not seekable, but timeshift
949 # is enabled, this means we can activate
951 if not self.isSeekable() and self.timeshift_enabled:
954 print "timeshift activate:", enabled
955 self["TimeshiftActivateActions"].setEnabled(enabled)
957 def __serviceStarted(self):
958 self.timeshift_enabled = False
959 self.__seekableStatusChanged()
961 class InfoBarExtensions:
963 self.pipshown = False
965 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
967 "extensions": (self.extensions, "Extensions..."),
970 def extensions(self):
972 if self.pipshown == False:
973 list.append((_("Activate Picture in Picture"), "pipon"))
974 elif self.pipshown == True:
975 list.append((_("Disable Picture in Picture"), "pipoff"))
976 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
978 def extensionCallback(self, answer):
979 if answer[1] == "pipon":
980 self.pip = self.session.instantiateDialog(PictureInPicture)
983 print "would show PiP now"
984 elif answer[1] == "pipoff":
987 self.pipshown = False
989 from RecordTimer import parseEvent
991 class InfoBarInstantRecord:
992 """Instant Record - handles the instantRecord action in order to
993 start/stop instant records"""
995 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
997 "instantRecord": (self.instantRecord, "Instant Record..."),
1000 self["BlinkingPoint"] = BlinkingPixmapConditional()
1001 self["BlinkingPoint"].hide()
1002 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1004 def stopCurrentRecording(self, entry = -1):
1005 if entry is not None and entry != -1:
1006 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1007 self.recording.remove(self.recording[entry])
1009 def startInstantRecording(self, limitEvent = False):
1010 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1012 # try to get event info
1015 service = self.session.nav.getCurrentService()
1016 epg = eEPGCache.getInstance()
1017 event = epg.lookupEventTime(serviceref, -1, 0)
1019 info = service.info()
1020 ev = info.getEvent(0)
1026 end = time.time() + 3600 * 10
1027 name = "instant record"
1031 if event is not None:
1032 curEvent = parseEvent(event)
1034 description = curEvent[3]
1035 eventid = curEvent[4]
1040 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1042 data = (begin, end, name, description, eventid)
1044 recording = self.session.nav.recordWithTimer(serviceref, *data)
1045 recording.dontSave = True
1046 self.recording.append(recording)
1048 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1050 def isInstantRecordRunning(self):
1051 print "self.recording:", self.recording
1052 if len(self.recording) > 0:
1053 for x in self.recording:
1058 def recordQuestionCallback(self, answer):
1059 if answer is None or answer[1] == "no":
1062 for x in self.recording:
1064 list.append(TimerEntryComponent(x, False))
1066 if answer[1] == "changeduration":
1067 if len(self.recording) == 1:
1068 self.changeDuration(0)
1070 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1071 elif answer[1] == "stop":
1072 if len(self.recording) == 1:
1073 self.stopCurrentRecording(0)
1075 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1076 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1078 if answer[1] == "event":
1080 if answer[1] == "manualduration":
1081 self.selectedEntry = len(self.recording)
1082 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1083 self.startInstantRecording(limitEvent = limitEvent)
1085 def changeDuration(self, entry):
1086 if entry is not None:
1087 self.selectedEntry = entry
1088 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1090 def inputCallback(self, value):
1091 if value is not None:
1092 print "stopping recording after", int(value), "minutes."
1093 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1094 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1096 def instantRecord(self):
1098 stat = os.stat(resolveFilename(SCOPE_HDD))
1100 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1103 if self.isInstantRecordRunning():
1104 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")])
1106 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")])
1108 from Screens.AudioSelection import AudioSelection
1110 class InfoBarAudioSelection:
1112 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1114 "audioSelection": (self.audioSelection, "Audio Options..."),
1117 def audioSelection(self):
1118 service = self.session.nav.getCurrentService()
1119 audio = service.audioTracks()
1120 n = audio.getNumberOfTracks()
1122 self.session.open(AudioSelection, audio)
1124 from Screens.SubserviceSelection import SubserviceSelection
1126 class InfoBarSubserviceSelection:
1128 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1130 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1133 def subserviceSelection(self):
1134 service = self.session.nav.getCurrentService()
1135 subservices = service.subServices()
1136 n = subservices.getNumberOfSubservices()
1138 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1140 def subserviceSelected(self, service):
1141 if not service is None:
1142 self.session.nav.playService(service)
1144 class InfoBarAdditionalInfo:
1146 self["DolbyActive"] = Pixmap()
1147 self["CryptActive"] = Pixmap()
1148 self["FormatActive"] = Pixmap()
1150 self["ButtonRed"] = PixmapConditional(withTimer = False)
1151 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1152 self.onLayoutFinish.append(self["ButtonRed"].update)
1153 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1154 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1155 self.onLayoutFinish.append(self["ButtonRedText"].update)
1157 self["ButtonGreen"] = Pixmap()
1158 self["ButtonGreenText"] = Label(_("Subservices"))
1160 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1161 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1162 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1163 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1164 self.onLayoutFinish.append(self["ButtonYellow"].update)
1165 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1167 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1168 self["ButtonBlue"].setConnect(lambda: True)
1169 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1170 self["ButtonBlueText"].setConnect(lambda: True)
1171 self.onLayoutFinish.append(self["ButtonBlue"].update)
1172 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1174 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1176 def hideSubServiceIndication(self):
1177 self["ButtonGreen"].hide()
1178 self["ButtonGreenText"].hide()
1180 def showSubServiceIndication(self):
1181 self["ButtonGreen"].show()
1182 self["ButtonGreenText"].show()
1184 def checkFormat(self, service):
1185 info = service.info()
1186 if info is not None:
1187 aspect = info.getInfo(iServiceInformation.sAspect)
1188 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1189 self["FormatActive"].show()
1191 self["FormatActive"].hide()
1193 def checkSubservices(self, service):
1194 if service.subServices().getNumberOfSubservices() > 0:
1195 self.showSubServiceIndication()
1197 self.hideSubServiceIndication()
1199 def checkDolby(self, service):
1202 audio = service.audioTracks()
1203 if audio is not None:
1204 n = audio.getNumberOfTracks()
1206 i = audio.getTrackInfo(x)
1207 description = i.getDescription();
1208 if description.find("AC3") != -1 or description.find("DTS") != -1:
1212 self["DolbyActive"].show()
1214 self["DolbyActive"].hide()
1216 def checkCrypted(self, service):
1217 info = service.info()
1218 if info is not None:
1219 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1220 self["CryptActive"].show()
1222 self["CryptActive"].hide()
1224 def gotServiceEvent(self, ev):
1225 service = self.session.nav.getCurrentService()
1226 if ev == iPlayableService.evUpdatedEventInfo:
1227 self.checkSubservices(service)
1228 self.checkFormat(service)
1229 elif ev == iPlayableService.evUpdatedInfo:
1230 self.checkCrypted(service)
1231 self.checkDolby(service)
1232 elif ev == iPlayableService.evEnd:
1233 self.hideSubServiceIndication()
1234 self["CryptActive"].hide()
1235 self["DolbyActive"].hide()
1236 self["FormatActive"].hide()
1238 class InfoBarNotifications:
1240 self.onExecBegin.append(self.checkNotifications)
1241 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1243 def checkNotificationsIfExecing(self):
1245 self.checkNotifications()
1247 def checkNotifications(self):
1248 if len(Notifications.notifications):
1249 n = Notifications.notifications[0]
1250 Notifications.notifications = Notifications.notifications[1:]
1254 self.session.openWithCallback(cb, *n[1:])
1256 self.session.open(*n[1:])
1258 class InfoBarServiceNotifications:
1260 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1262 iPlayableService.evEnd: self.serviceHasEnded
1265 def serviceHasEnded(self):
1266 print "service end!"
1269 self.setSeekState(self.SEEK_STATE_PLAY)
1273 class InfoBarCueSheetSupport:
1279 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1281 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1282 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1283 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1287 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1289 iPlayableService.evStart: self.__serviceStarted,
1292 def __serviceStarted(self):
1293 print "new service started! trying to download cuts!"
1294 self.downloadCuesheet()
1296 def __getSeekable(self):
1297 service = self.session.nav.getCurrentService()
1300 return service.seek()
1302 def cueGetCurrentPosition(self):
1303 seek = self.__getSeekable()
1306 r = seek.getPlayPosition()
1311 def jumpPreviousNextMark(self, cmp, alternative=None):
1312 current_pos = self.cueGetCurrentPosition()
1313 if current_pos is None:
1315 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1316 if mark is not None:
1318 elif alternative is not None:
1323 seekable = self.__getSeekable()
1324 if seekable is not None:
1325 seekable.seekTo(pts)
1327 def jumpPreviousMark(self):
1328 # we add 2 seconds, so if the play position is <2s after
1329 # the mark, the mark before will be used
1330 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1332 def jumpNextMark(self):
1333 self.jumpPreviousNextMark(lambda x: x)
1335 def getNearestCutPoint(self, pts, cmp=abs):
1338 for cp in self.cut_list:
1339 diff = cmp(cp[0] - pts)
1340 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1344 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1345 current_pos = self.cueGetCurrentPosition()
1346 if current_pos is None:
1347 print "not seekable"
1350 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1352 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1354 return nearest_cutpoint
1356 self.removeMark(nearest_cutpoint)
1357 elif not onlyremove and not onlyreturn:
1358 self.addMark((current_pos, self.CUT_TYPE_MARK))
1363 def addMark(self, point):
1364 bisect.insort(self.cut_list, point)
1365 self.uploadCuesheet()
1367 def removeMark(self, point):
1368 self.cut_list.remove(point)
1369 self.uploadCuesheet()
1371 def __getCuesheet(self):
1372 service = self.session.nav.getCurrentService()
1375 return service.cueSheet()
1377 def uploadCuesheet(self):
1378 cue = self.__getCuesheet()
1381 print "upload failed, no cuesheet interface"
1383 cue.setCutList(self.cut_list)
1385 def downloadCuesheet(self):
1386 cue = self.__getCuesheet()
1389 print "upload failed, no cuesheet interface"
1391 self.cut_list = cue.getCutList()
1393 class InfoBarSummary(Screen):
1395 <screen position="0,0" size="132,64">
1396 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1397 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1400 def __init__(self, session, parent):
1401 Screen.__init__(self, session)
1402 self["CurrentService"] = ServiceName(self.session.nav)
1403 self["Clock"] = Clock()
1405 class InfoBarSummarySupport:
1409 def createSummary(self):
1410 return InfoBarSummary
1412 class InfoBarTeletextPlugin:
1414 self.teletext_plugin = None
1416 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1417 self.teletext_plugin = p
1419 if self.teletext_plugin is not None:
1420 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1422 "startTeletext": (self.startTeletext, "View teletext...")
1425 print "no teletext plugin found!"
1427 def startTeletext(self):
1428 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())