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 """
346 self.bouquetSel = None
347 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
349 "showEventInfo": (self.openEventView, _("show EPG...")),
352 def zapToService(self, service):
353 if not service is None:
354 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
355 self.servicelist.clearPath()
356 if self.servicelist.bouquet_root != self.epg_bouquet:
357 self.servicelist.enterPath(self.servicelist.bouquet_root)
358 self.servicelist.enterPath(self.epg_bouquet)
359 self.servicelist.setCurrentSelection(service) #select the service in servicelist
360 self.servicelist.zap()
362 def getBouquetServices(self, bouquet):
364 servicelist = eServiceCenter.getInstance().list(bouquet)
365 if not servicelist is None:
367 service = servicelist.getNext()
368 if not service.valid(): #check if end of list
370 if service.flags: #ignore non playable services
372 services.append(ServiceReference(service))
375 def openBouquetEPG(self, bouquet, withCallback=True):
376 services = self.getBouquetServices(bouquet)
378 self.epg_bouquet = bouquet
380 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
382 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
384 def changeBouquetCB(self, direction, epg):
387 self.bouquetSel.down()
390 bouquet = self.bouquetSel.getCurrent()
391 services = self.getBouquetServices(bouquet)
393 self.epg_bouquet = bouquet
394 epg.setServices(services)
396 def closed(self, ret=False):
397 closedScreen = self.dlg_stack.pop()
398 if self.bouquetSel and closedScreen == self.bouquetSel:
399 self.bouquetSel = None
401 dlgs=len(self.dlg_stack)
403 self.dlg_stack[dlgs-1].close(dlgs > 1)
405 def openMultiServiceEPG(self, withCallback=True):
406 bouquets = self.servicelist.getBouquetList()
411 if cnt > 1: # show bouquet list
413 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
414 self.dlg_stack.append(self.bouquetSel)
416 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
418 self.openBouquetEPG(bouquets[0][1], withCallback)
420 def openSingleServiceEPG(self):
421 ref=self.session.nav.getCurrentlyPlayingServiceReference()
422 self.session.open(EPGSelection, ref)
424 def openSimilarList(self, eventid, refstr):
425 self.session.open(EPGSelection, refstr, None, eventid)
427 def openEventView(self):
429 service = self.session.nav.getCurrentService()
430 ref = self.session.nav.getCurrentlyPlayingServiceReference()
431 info = service.info()
434 self.epglist.append(ptr)
437 self.epglist.append(ptr)
438 if len(self.epglist) == 0:
439 epg = eEPGCache.getInstance()
440 ptr = epg.lookupEventTime(ref, -1)
442 self.epglist.append(ptr)
443 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
445 self.epglist.append(ptr)
446 if len(self.epglist) > 0:
447 self.dlg_stack.append(self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList))
449 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
450 self.openMultiServiceEPG(False)
452 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
453 if len(self.epglist) > 1:
454 tmp = self.epglist[0]
455 self.epglist[0]=self.epglist[1]
457 setEvent(self.epglist[0])
460 """provides a snr/agc/ber display"""
462 self["snr"] = Label()
463 self["agc"] = Label()
464 self["ber"] = Label()
465 self["snr_percent"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
466 self["agc_percent"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
467 self["ber_count"] = TunerInfo(TunerInfo.BER_VALUE, servicefkt = self.session.nav.getCurrentService)
468 self["snr_progress"] = TunerInfo(TunerInfo.SNR_BAR, servicefkt = self.session.nav.getCurrentService)
469 self["agc_progress"] = TunerInfo(TunerInfo.AGC_BAR, servicefkt = self.session.nav.getCurrentService)
470 self["ber_progress"] = TunerInfo(TunerInfo.BER_BAR, servicefkt = self.session.nav.getCurrentService)
471 self.timer = eTimer()
472 self.timer.timeout.get().append(self.updateTunerInfo)
473 self.timer.start(1000)
475 def updateTunerInfo(self):
476 if self.instance.isVisible():
477 self["snr_percent"].update()
478 self["agc_percent"].update()
479 self["ber_count"].update()
480 self["snr_progress"].update()
481 self["agc_progress"].update()
482 self["ber_progress"].update()
485 """provides a current/next event info display"""
487 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
488 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
490 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
491 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
493 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
494 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
496 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
498 class InfoBarServiceName:
500 self["ServiceName"] = ServiceName(self.session.nav)
503 """handles actions like seeking, pause"""
505 # ispause, isff, issm
506 SEEK_STATE_PLAY = (0, 0, 0, ">")
507 SEEK_STATE_PAUSE = (1, 0, 0, "||")
508 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
509 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
510 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
511 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
512 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
513 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
515 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
516 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
517 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
518 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
520 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
521 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
522 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
525 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
527 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
528 iPlayableService.evStart: self.__serviceStarted,
530 iPlayableService.evEOF: self.__evEOF,
531 iPlayableService.evSOF: self.__evSOF,
534 class InfoBarSeekActionMap(HelpableActionMap):
535 def __init__(self, screen, *args, **kwargs):
536 HelpableActionMap.__init__(self, screen, *args, **kwargs)
539 def action(self, contexts, action):
540 if action[:5] == "seek:":
541 time = int(action[5:])
542 self.screen.seekRelative(time * 90000)
545 return HelpableActionMap.action(self, contexts, action)
547 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
549 "pauseService": (self.pauseService, "pause"),
550 "unPauseService": (self.unPauseService, "continue"),
552 "seekFwd": (self.seekFwd, "skip forward"),
553 "seekFwdDown": self.seekFwdDown,
554 "seekFwdUp": self.seekFwdUp,
555 "seekBack": (self.seekBack, "skip backward"),
556 "seekBackDown": self.seekBackDown,
557 "seekBackUp": self.seekBackUp,
559 # give them a little more priority to win over color buttons
561 self.seekstate = self.SEEK_STATE_PLAY
562 self.onClose.append(self.delTimer)
564 self.fwdtimer = False
565 self.fwdKeyTimer = eTimer()
566 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
568 self.rwdtimer = False
569 self.rwdKeyTimer = eTimer()
570 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
572 self.onPlayStateChanged = [ ]
574 self.lockedBecauseOfSkipping = False
587 service = self.session.nav.getCurrentService()
591 seek = service.seek()
593 if seek is None or not seek.isCurrentlySeekable():
598 def isSeekable(self):
599 if self.getSeek() is None:
603 def __seekableStatusChanged(self):
604 print "seekable status changed!"
605 if not self.isSeekable():
606 self["SeekActions"].setEnabled(False)
607 print "not seekable, return to play"
608 self.setSeekState(self.SEEK_STATE_PLAY)
610 self["SeekActions"].setEnabled(True)
613 def __serviceStarted(self):
614 self.seekstate = self.SEEK_STATE_PLAY
616 def setSeekState(self, state):
617 service = self.session.nav.getCurrentService()
622 if not self.isSeekable():
623 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
624 state = self.SEEK_STATE_PLAY
626 pauseable = service.pause()
628 if pauseable is None:
629 print "not pauseable."
630 state = self.SEEK_STATE_PLAY
632 oldstate = self.seekstate
633 self.seekstate = state
636 if oldstate[i] != self.seekstate[i]:
637 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
639 for c in self.onPlayStateChanged:
642 self.checkSkipShowHideLock()
646 def pauseService(self):
647 if self.seekstate == self.SEEK_STATE_PAUSE:
648 print "pause, but in fact unpause"
649 self.unPauseService()
651 if self.seekstate == self.SEEK_STATE_PLAY:
652 print "yes, playing."
654 print "no", self.seekstate
656 self.setSeekState(self.SEEK_STATE_PAUSE);
658 def unPauseService(self):
660 self.setSeekState(self.SEEK_STATE_PLAY);
662 def doSeek(self, seektime):
663 print "doseek", seektime
664 service = self.session.nav.getCurrentService()
668 seekable = self.getSeek()
672 seekable.seekTo(90 * seektime)
674 def seekFwdDown(self):
675 print "start fwd timer"
677 self.fwdKeyTimer.start(1000)
679 def seekBackDown(self):
680 print "start rewind timer"
682 self.rwdKeyTimer.start(1000)
687 self.fwdKeyTimer.stop()
688 self.fwdtimer = False
693 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
694 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
695 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
696 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
697 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
698 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
699 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
700 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
701 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
702 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
703 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
704 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
705 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
706 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
707 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
709 self.setSeekState(lookup[self.seekstate])
711 def seekBackUp(self):
714 self.rwdKeyTimer.stop()
715 self.rwdtimer = False
720 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
721 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
722 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
723 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
724 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
725 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
726 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
727 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
728 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
729 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
730 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
731 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
732 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
733 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
734 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
736 self.setSeekState(lookup[self.seekstate])
738 if self.seekstate == self.SEEK_STATE_PAUSE:
739 seekable = self.getSeek()
740 if seekable is not None:
741 seekable.seekRelative(-1, 3)
743 def fwdTimerFire(self):
744 print "Display seek fwd"
745 self.fwdKeyTimer.stop()
746 self.fwdtimer = False
747 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
749 def fwdSeekTo(self, minutes):
750 print "Seek", minutes, "minutes forward"
752 seekable = self.getSeek()
753 if seekable is not None:
754 seekable.seekRelative(1, minutes * 60 * 90000)
756 def rwdTimerFire(self):
758 self.rwdKeyTimer.stop()
759 self.rwdtimer = False
760 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
762 def rwdSeekTo(self, minutes):
764 self.fwdSeekTo(0 - minutes)
766 def checkSkipShowHideLock(self):
767 wantlock = self.seekstate != self.SEEK_STATE_PLAY
769 if self.lockedBecauseOfSkipping and not wantlock:
771 self.lockedBecauseOfSkipping = False
773 if wantlock and not self.lockedBecauseOfSkipping:
775 self.lockedBecauseOfSkipping = True
778 if self.seekstate != self.SEEK_STATE_PLAY:
779 self.setSeekState(self.SEEK_STATE_PAUSE)
781 #self.getSeek().seekRelative(1, -90000)
782 self.setSeekState(self.SEEK_STATE_PLAY)
784 self.setSeekState(self.SEEK_STATE_PAUSE)
787 self.setSeekState(self.SEEK_STATE_PLAY)
790 def seekRelative(self, diff):
791 seekable = self.getSeek()
792 if seekable is not None:
793 seekable.seekRelative(1, diff)
795 from Screens.PVRState import PVRState, TimeshiftState
797 class InfoBarPVRState:
798 def __init__(self, screen=PVRState):
799 self.onPlayStateChanged.append(self.__playStateChanged)
800 self.pvrStateDialog = self.session.instantiateDialog(screen)
801 self.onShow.append(self.__mayShow)
802 self.onHide.append(self.pvrStateDialog.hide)
805 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
806 self.pvrStateDialog.show()
808 def __playStateChanged(self, state):
809 playstateString = state[3]
810 self.pvrStateDialog["state"].setText(playstateString)
813 class InfoBarTimeshiftState(InfoBarPVRState):
815 InfoBarPVRState.__init__(self, screen=TimeshiftState)
818 class InfoBarShowMovies:
820 # i don't really like this class.
821 # it calls a not further specified "movie list" on up/down/movieList,
822 # so this is not more than an action map
824 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
826 "movieList": (self.showMovies, "movie list"),
827 "up": (self.showMovies, "movie list"),
828 "down": (self.showMovies, "movie list")
831 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
835 # Timeshift works the following way:
836 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
837 # - normal playback TUNER unused PLAY enable disable disable
838 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
839 # - user presess pause again FILE record PLAY enable disable enable
840 # - user fast forwards FILE record FF enable disable enable
841 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
842 # - user backwards FILE record BACK # !! enable disable enable
846 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
847 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
848 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
849 # - the user can now PVR around
850 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
851 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
853 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
854 # - if the user rewinds, or press pause, timeshift will be activated again
856 # note that a timeshift can be enabled ("recording") and
857 # activated (currently time-shifting).
859 class InfoBarTimeshift:
861 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
863 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
864 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
866 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
868 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
869 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
870 }, prio=-1) # priority over record
872 self.timeshift_enabled = 0
873 self.timeshift_state = 0
874 self.ts_pause_timer = eTimer()
875 self.ts_pause_timer.timeout.get().append(self.pauseService)
877 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
879 iPlayableService.evStart: self.__serviceStarted,
880 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
883 def getTimeshift(self):
884 service = self.session.nav.getCurrentService()
885 return service and service.timeshift()
887 def startTimeshift(self):
888 print "enable timeshift"
889 ts = self.getTimeshift()
891 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
892 print "no ts interface"
895 if self.timeshift_enabled:
896 print "hu, timeshift already enabled?"
898 if not ts.startTimeshift():
900 self.timeshift_enabled = 1
901 self.pvrStateDialog["timeshift"].setRelative(time.time())
904 self.setSeekState(self.SEEK_STATE_PAUSE)
906 # enable the "TimeshiftEnableActions", which will override
907 # the startTimeshift actions
908 self.__seekableStatusChanged()
910 print "timeshift failed"
912 def stopTimeshift(self):
913 if not self.timeshift_enabled:
915 print "disable timeshift"
916 ts = self.getTimeshift()
919 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
921 def stopTimeshiftConfirmed(self, confirmed):
925 ts = self.getTimeshift()
930 self.timeshift_enabled = 0
933 self.__seekableStatusChanged()
935 # activates timeshift, and seeks to (almost) the end
936 def activateTimeshiftEnd(self):
937 ts = self.getTimeshift()
942 if ts.isTimeshiftActive():
943 print "!! activate timeshift called - but shouldn't this be a normal pause?"
946 self.setSeekState(self.SEEK_STATE_PLAY)
947 ts.activateTimeshift()
950 # same as activateTimeshiftEnd, but pauses afterwards.
951 def activateTimeshiftEndAndPause(self):
952 state = self.seekstate
953 self.activateTimeshiftEnd()
955 # well, this is "andPause", but it could be pressed from pause,
956 # when pausing on the (fake-)"live" picture, so an un-pause
959 print "now, pauseService"
960 if state == self.SEEK_STATE_PLAY:
961 print "is PLAYING, start pause timer"
962 self.ts_pause_timer.start(200, 1)
965 self.unPauseService()
967 def __seekableStatusChanged(self):
970 print "self.isSeekable", self.isSeekable()
971 print "self.timeshift_enabled", self.timeshift_enabled
973 # when this service is not seekable, but timeshift
974 # is enabled, this means we can activate
976 if not self.isSeekable() and self.timeshift_enabled:
979 print "timeshift activate:", enabled
980 self["TimeshiftActivateActions"].setEnabled(enabled)
982 def __serviceStarted(self):
983 self.timeshift_enabled = False
984 self.__seekableStatusChanged()
986 class InfoBarExtensions:
988 self.pipshown = False
990 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
992 "extensions": (self.extensions, "Extensions..."),
995 def extensions(self):
997 if self.pipshown == False:
998 list.append((_("Activate Picture in Picture"), "pipon"))
999 elif self.pipshown == True:
1000 list.append((_("Disable Picture in Picture"), "pipoff"))
1001 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
1003 def extensionCallback(self, answer):
1004 if answer is not None:
1005 if answer[1] == "pipon":
1006 self.session.nav.stopService()
1007 self.pip = self.session.instantiateDialog(PictureInPicture)
1010 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1011 self.pipservice = eServiceCenter.getInstance().play(newservice)
1012 if self.pipservice and not self.pipservice.setTarget(1):
1013 self.pipservice.start()
1014 self.pipshown = True
1016 self.pipservice = None
1019 elif answer[1] == "pipoff":
1021 self.pipservice = None
1023 self.pipshown = False
1025 from RecordTimer import parseEvent
1027 class InfoBarInstantRecord:
1028 """Instant Record - handles the instantRecord action in order to
1029 start/stop instant records"""
1031 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1033 "instantRecord": (self.instantRecord, "Instant Record..."),
1036 self["BlinkingPoint"] = BlinkingPixmapConditional()
1037 self["BlinkingPoint"].hide()
1038 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1040 def stopCurrentRecording(self, entry = -1):
1041 if entry is not None and entry != -1:
1042 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1043 self.recording.remove(self.recording[entry])
1045 def startInstantRecording(self, limitEvent = False):
1046 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1048 # try to get event info
1051 service = self.session.nav.getCurrentService()
1052 epg = eEPGCache.getInstance()
1053 event = epg.lookupEventTime(serviceref, -1, 0)
1055 info = service.info()
1056 ev = info.getEvent(0)
1062 end = time.time() + 3600 * 10
1063 name = "instant record"
1067 if event is not None:
1068 curEvent = parseEvent(event)
1070 description = curEvent[3]
1071 eventid = curEvent[4]
1076 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1078 data = (begin, end, name, description, eventid)
1080 recording = self.session.nav.recordWithTimer(serviceref, *data)
1081 recording.dontSave = True
1082 self.recording.append(recording)
1084 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1086 def isInstantRecordRunning(self):
1087 print "self.recording:", self.recording
1088 if len(self.recording) > 0:
1089 for x in self.recording:
1094 def recordQuestionCallback(self, answer):
1095 print "pre:\n", self.recording
1097 if answer is None or answer[1] == "no":
1100 recording = self.recording[:]
1102 if not x in self.session.nav.RecordTimer.timer_list:
1103 self.recording.remove(x)
1104 elif x.dontSave and x.isRunning():
1105 list.append(TimerEntryComponent(x, False))
1107 if answer[1] == "changeduration":
1108 if len(self.recording) == 1:
1109 self.changeDuration(0)
1111 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1112 elif answer[1] == "stop":
1113 if len(self.recording) == 1:
1114 self.stopCurrentRecording(0)
1116 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1117 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1119 if answer[1] == "event":
1121 if answer[1] == "manualduration":
1122 self.selectedEntry = len(self.recording)
1123 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1124 self.startInstantRecording(limitEvent = limitEvent)
1126 print "after:\n", self.recording
1128 def changeDuration(self, entry):
1129 if entry is not None:
1130 self.selectedEntry = entry
1131 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1133 def inputCallback(self, value):
1134 if value is not None:
1135 print "stopping recording after", int(value), "minutes."
1136 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1137 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1139 def instantRecord(self):
1141 stat = os.stat(resolveFilename(SCOPE_HDD))
1143 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1146 if self.isInstantRecordRunning():
1147 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")])
1149 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")])
1151 from Screens.AudioSelection import AudioSelection
1153 class InfoBarAudioSelection:
1155 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1157 "audioSelection": (self.audioSelection, "Audio Options..."),
1160 def audioSelection(self):
1161 service = self.session.nav.getCurrentService()
1162 audio = service.audioTracks()
1163 n = audio.getNumberOfTracks()
1165 self.session.open(AudioSelection, audio)
1167 from Screens.SubserviceSelection import SubserviceSelection
1169 class InfoBarSubserviceSelection:
1171 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1173 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1176 def subserviceSelection(self):
1177 service = self.session.nav.getCurrentService()
1178 subservices = service.subServices()
1179 n = subservices.getNumberOfSubservices()
1181 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1183 def subserviceSelected(self, service):
1184 if not service is None:
1185 self.session.nav.playService(service)
1187 class InfoBarAdditionalInfo:
1189 self["DolbyActive"] = Pixmap()
1190 self["CryptActive"] = Pixmap()
1191 self["FormatActive"] = Pixmap()
1193 self["ButtonRed"] = PixmapConditional(withTimer = False)
1194 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1195 self.onLayoutFinish.append(self["ButtonRed"].update)
1196 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1197 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1198 self.onLayoutFinish.append(self["ButtonRedText"].update)
1200 self["ButtonGreen"] = Pixmap()
1201 self["ButtonGreenText"] = Label(_("Subservices"))
1203 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1204 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1205 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1206 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1207 self.onLayoutFinish.append(self["ButtonYellow"].update)
1208 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1210 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1211 self["ButtonBlue"].setConnect(lambda: True)
1212 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1213 self["ButtonBlueText"].setConnect(lambda: True)
1214 self.onLayoutFinish.append(self["ButtonBlue"].update)
1215 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1217 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1219 def hideSubServiceIndication(self):
1220 self["ButtonGreen"].hide()
1221 self["ButtonGreenText"].hide()
1223 def showSubServiceIndication(self):
1224 self["ButtonGreen"].show()
1225 self["ButtonGreenText"].show()
1227 def checkFormat(self, service):
1228 info = service.info()
1229 if info is not None:
1230 aspect = info.getInfo(iServiceInformation.sAspect)
1231 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1232 self["FormatActive"].show()
1234 self["FormatActive"].hide()
1236 def checkSubservices(self, service):
1237 if service.subServices().getNumberOfSubservices() > 0:
1238 self.showSubServiceIndication()
1240 self.hideSubServiceIndication()
1242 def checkDolby(self, service):
1245 audio = service.audioTracks()
1246 if audio is not None:
1247 n = audio.getNumberOfTracks()
1249 i = audio.getTrackInfo(x)
1250 description = i.getDescription();
1251 if description.find("AC3") != -1 or description.find("DTS") != -1:
1255 self["DolbyActive"].show()
1257 self["DolbyActive"].hide()
1259 def checkCrypted(self, service):
1260 info = service.info()
1261 if info is not None:
1262 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1263 self["CryptActive"].show()
1265 self["CryptActive"].hide()
1267 def gotServiceEvent(self, ev):
1268 service = self.session.nav.getCurrentService()
1269 if ev == iPlayableService.evUpdatedEventInfo:
1270 self.checkSubservices(service)
1271 self.checkFormat(service)
1272 elif ev == iPlayableService.evUpdatedInfo:
1273 self.checkCrypted(service)
1274 self.checkDolby(service)
1275 elif ev == iPlayableService.evEnd:
1276 self.hideSubServiceIndication()
1277 self["CryptActive"].hide()
1278 self["DolbyActive"].hide()
1279 self["FormatActive"].hide()
1281 class InfoBarNotifications:
1283 self.onExecBegin.append(self.checkNotifications)
1284 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1286 def checkNotificationsIfExecing(self):
1288 self.checkNotifications()
1290 def checkNotifications(self):
1291 if len(Notifications.notifications):
1292 n = Notifications.notifications[0]
1293 Notifications.notifications = Notifications.notifications[1:]
1297 self.session.openWithCallback(cb, *n[1:])
1299 self.session.open(*n[1:])
1301 class InfoBarServiceNotifications:
1303 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1305 iPlayableService.evEnd: self.serviceHasEnded
1308 def serviceHasEnded(self):
1309 print "service end!"
1312 self.setSeekState(self.SEEK_STATE_PLAY)
1316 class InfoBarCueSheetSupport:
1322 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1324 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1325 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1326 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1330 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1332 iPlayableService.evStart: self.__serviceStarted,
1335 def __serviceStarted(self):
1336 print "new service started! trying to download cuts!"
1337 self.downloadCuesheet()
1339 def __getSeekable(self):
1340 service = self.session.nav.getCurrentService()
1343 return service.seek()
1345 def cueGetCurrentPosition(self):
1346 seek = self.__getSeekable()
1349 r = seek.getPlayPosition()
1354 def jumpPreviousNextMark(self, cmp, alternative=None):
1355 current_pos = self.cueGetCurrentPosition()
1356 if current_pos is None:
1358 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1359 if mark is not None:
1361 elif alternative is not None:
1366 seekable = self.__getSeekable()
1367 if seekable is not None:
1368 seekable.seekTo(pts)
1370 def jumpPreviousMark(self):
1371 # we add 2 seconds, so if the play position is <2s after
1372 # the mark, the mark before will be used
1373 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1375 def jumpNextMark(self):
1376 self.jumpPreviousNextMark(lambda x: x)
1378 def getNearestCutPoint(self, pts, cmp=abs):
1381 for cp in self.cut_list:
1382 diff = cmp(cp[0] - pts)
1383 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1387 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1388 current_pos = self.cueGetCurrentPosition()
1389 if current_pos is None:
1390 print "not seekable"
1393 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1395 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1397 return nearest_cutpoint
1399 self.removeMark(nearest_cutpoint)
1400 elif not onlyremove and not onlyreturn:
1401 self.addMark((current_pos, self.CUT_TYPE_MARK))
1406 def addMark(self, point):
1407 bisect.insort(self.cut_list, point)
1408 self.uploadCuesheet()
1410 def removeMark(self, point):
1411 self.cut_list.remove(point)
1412 self.uploadCuesheet()
1414 def __getCuesheet(self):
1415 service = self.session.nav.getCurrentService()
1418 return service.cueSheet()
1420 def uploadCuesheet(self):
1421 cue = self.__getCuesheet()
1424 print "upload failed, no cuesheet interface"
1426 cue.setCutList(self.cut_list)
1428 def downloadCuesheet(self):
1429 cue = self.__getCuesheet()
1432 print "upload failed, no cuesheet interface"
1434 self.cut_list = cue.getCutList()
1436 class InfoBarSummary(Screen):
1438 <screen position="0,0" size="132,64">
1439 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1440 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1443 def __init__(self, session, parent):
1444 Screen.__init__(self, session)
1445 self["CurrentService"] = ServiceName(self.session.nav)
1446 self["Clock"] = Clock()
1448 class InfoBarSummarySupport:
1452 def createSummary(self):
1453 return InfoBarSummary
1455 class InfoBarTeletextPlugin:
1457 self.teletext_plugin = None
1459 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1460 self.teletext_plugin = p
1462 if self.teletext_plugin is not None:
1463 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1465 "startTeletext": (self.startTeletext, "View teletext...")
1468 print "no teletext plugin found!"
1470 def startTeletext(self):
1471 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())