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.session.nav.stopService()
981 self.pip = self.session.instantiateDialog(PictureInPicture)
984 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
985 self.pipservice = eServiceCenter.getInstance().play(newservice)
986 if self.pipservice and not self.pipservice.setTarget(1):
987 self.pipservice.start()
990 self.pipservice = None
993 elif answer[1] == "pipoff":
996 self.pipshown = False
998 from RecordTimer import parseEvent
1000 class InfoBarInstantRecord:
1001 """Instant Record - handles the instantRecord action in order to
1002 start/stop instant records"""
1004 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1006 "instantRecord": (self.instantRecord, "Instant Record..."),
1009 self["BlinkingPoint"] = BlinkingPixmapConditional()
1010 self["BlinkingPoint"].hide()
1011 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1013 def stopCurrentRecording(self, entry = -1):
1014 if entry is not None and entry != -1:
1015 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1016 self.recording.remove(self.recording[entry])
1018 def startInstantRecording(self, limitEvent = False):
1019 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1021 # try to get event info
1024 service = self.session.nav.getCurrentService()
1025 epg = eEPGCache.getInstance()
1026 event = epg.lookupEventTime(serviceref, -1, 0)
1028 info = service.info()
1029 ev = info.getEvent(0)
1035 end = time.time() + 3600 * 10
1036 name = "instant record"
1040 if event is not None:
1041 curEvent = parseEvent(event)
1043 description = curEvent[3]
1044 eventid = curEvent[4]
1049 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1051 data = (begin, end, name, description, eventid)
1053 recording = self.session.nav.recordWithTimer(serviceref, *data)
1054 recording.dontSave = True
1055 self.recording.append(recording)
1057 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1059 def isInstantRecordRunning(self):
1060 print "self.recording:", self.recording
1061 if len(self.recording) > 0:
1062 for x in self.recording:
1067 def recordQuestionCallback(self, answer):
1068 if answer is None or answer[1] == "no":
1071 for x in self.recording:
1073 list.append(TimerEntryComponent(x, False))
1075 if answer[1] == "changeduration":
1076 if len(self.recording) == 1:
1077 self.changeDuration(0)
1079 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1080 elif answer[1] == "stop":
1081 if len(self.recording) == 1:
1082 self.stopCurrentRecording(0)
1084 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1085 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1087 if answer[1] == "event":
1089 if answer[1] == "manualduration":
1090 self.selectedEntry = len(self.recording)
1091 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1092 self.startInstantRecording(limitEvent = limitEvent)
1094 def changeDuration(self, entry):
1095 if entry is not None:
1096 self.selectedEntry = entry
1097 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1099 def inputCallback(self, value):
1100 if value is not None:
1101 print "stopping recording after", int(value), "minutes."
1102 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1103 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1105 def instantRecord(self):
1107 stat = os.stat(resolveFilename(SCOPE_HDD))
1109 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1112 if self.isInstantRecordRunning():
1113 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")])
1115 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")])
1117 from Screens.AudioSelection import AudioSelection
1119 class InfoBarAudioSelection:
1121 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1123 "audioSelection": (self.audioSelection, "Audio Options..."),
1126 def audioSelection(self):
1127 service = self.session.nav.getCurrentService()
1128 audio = service.audioTracks()
1129 n = audio.getNumberOfTracks()
1131 self.session.open(AudioSelection, audio)
1133 from Screens.SubserviceSelection import SubserviceSelection
1135 class InfoBarSubserviceSelection:
1137 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1139 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1142 def subserviceSelection(self):
1143 service = self.session.nav.getCurrentService()
1144 subservices = service.subServices()
1145 n = subservices.getNumberOfSubservices()
1147 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1149 def subserviceSelected(self, service):
1150 if not service is None:
1151 self.session.nav.playService(service)
1153 class InfoBarAdditionalInfo:
1155 self["DolbyActive"] = Pixmap()
1156 self["CryptActive"] = Pixmap()
1157 self["FormatActive"] = Pixmap()
1159 self["ButtonRed"] = PixmapConditional(withTimer = False)
1160 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1161 self.onLayoutFinish.append(self["ButtonRed"].update)
1162 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1163 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1164 self.onLayoutFinish.append(self["ButtonRedText"].update)
1166 self["ButtonGreen"] = Pixmap()
1167 self["ButtonGreenText"] = Label(_("Subservices"))
1169 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1170 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1171 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1172 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1173 self.onLayoutFinish.append(self["ButtonYellow"].update)
1174 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1176 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1177 self["ButtonBlue"].setConnect(lambda: True)
1178 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1179 self["ButtonBlueText"].setConnect(lambda: True)
1180 self.onLayoutFinish.append(self["ButtonBlue"].update)
1181 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1183 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1185 def hideSubServiceIndication(self):
1186 self["ButtonGreen"].hide()
1187 self["ButtonGreenText"].hide()
1189 def showSubServiceIndication(self):
1190 self["ButtonGreen"].show()
1191 self["ButtonGreenText"].show()
1193 def checkFormat(self, service):
1194 info = service.info()
1195 if info is not None:
1196 aspect = info.getInfo(iServiceInformation.sAspect)
1197 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1198 self["FormatActive"].show()
1200 self["FormatActive"].hide()
1202 def checkSubservices(self, service):
1203 if service.subServices().getNumberOfSubservices() > 0:
1204 self.showSubServiceIndication()
1206 self.hideSubServiceIndication()
1208 def checkDolby(self, service):
1211 audio = service.audioTracks()
1212 if audio is not None:
1213 n = audio.getNumberOfTracks()
1215 i = audio.getTrackInfo(x)
1216 description = i.getDescription();
1217 if description.find("AC3") != -1 or description.find("DTS") != -1:
1221 self["DolbyActive"].show()
1223 self["DolbyActive"].hide()
1225 def checkCrypted(self, service):
1226 info = service.info()
1227 if info is not None:
1228 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1229 self["CryptActive"].show()
1231 self["CryptActive"].hide()
1233 def gotServiceEvent(self, ev):
1234 service = self.session.nav.getCurrentService()
1235 if ev == iPlayableService.evUpdatedEventInfo:
1236 self.checkSubservices(service)
1237 self.checkFormat(service)
1238 elif ev == iPlayableService.evUpdatedInfo:
1239 self.checkCrypted(service)
1240 self.checkDolby(service)
1241 elif ev == iPlayableService.evEnd:
1242 self.hideSubServiceIndication()
1243 self["CryptActive"].hide()
1244 self["DolbyActive"].hide()
1245 self["FormatActive"].hide()
1247 class InfoBarNotifications:
1249 self.onExecBegin.append(self.checkNotifications)
1250 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1252 def checkNotificationsIfExecing(self):
1254 self.checkNotifications()
1256 def checkNotifications(self):
1257 if len(Notifications.notifications):
1258 n = Notifications.notifications[0]
1259 Notifications.notifications = Notifications.notifications[1:]
1263 self.session.openWithCallback(cb, *n[1:])
1265 self.session.open(*n[1:])
1267 class InfoBarServiceNotifications:
1269 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1271 iPlayableService.evEnd: self.serviceHasEnded
1274 def serviceHasEnded(self):
1275 print "service end!"
1278 self.setSeekState(self.SEEK_STATE_PLAY)
1282 class InfoBarCueSheetSupport:
1288 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1290 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1291 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1292 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1296 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1298 iPlayableService.evStart: self.__serviceStarted,
1301 def __serviceStarted(self):
1302 print "new service started! trying to download cuts!"
1303 self.downloadCuesheet()
1305 def __getSeekable(self):
1306 service = self.session.nav.getCurrentService()
1309 return service.seek()
1311 def cueGetCurrentPosition(self):
1312 seek = self.__getSeekable()
1315 r = seek.getPlayPosition()
1320 def jumpPreviousNextMark(self, cmp, alternative=None):
1321 current_pos = self.cueGetCurrentPosition()
1322 if current_pos is None:
1324 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1325 if mark is not None:
1327 elif alternative is not None:
1332 seekable = self.__getSeekable()
1333 if seekable is not None:
1334 seekable.seekTo(pts)
1336 def jumpPreviousMark(self):
1337 # we add 2 seconds, so if the play position is <2s after
1338 # the mark, the mark before will be used
1339 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1341 def jumpNextMark(self):
1342 self.jumpPreviousNextMark(lambda x: x)
1344 def getNearestCutPoint(self, pts, cmp=abs):
1347 for cp in self.cut_list:
1348 diff = cmp(cp[0] - pts)
1349 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1353 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1354 current_pos = self.cueGetCurrentPosition()
1355 if current_pos is None:
1356 print "not seekable"
1359 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1361 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1363 return nearest_cutpoint
1365 self.removeMark(nearest_cutpoint)
1366 elif not onlyremove and not onlyreturn:
1367 self.addMark((current_pos, self.CUT_TYPE_MARK))
1372 def addMark(self, point):
1373 bisect.insort(self.cut_list, point)
1374 self.uploadCuesheet()
1376 def removeMark(self, point):
1377 self.cut_list.remove(point)
1378 self.uploadCuesheet()
1380 def __getCuesheet(self):
1381 service = self.session.nav.getCurrentService()
1384 return service.cueSheet()
1386 def uploadCuesheet(self):
1387 cue = self.__getCuesheet()
1390 print "upload failed, no cuesheet interface"
1392 cue.setCutList(self.cut_list)
1394 def downloadCuesheet(self):
1395 cue = self.__getCuesheet()
1398 print "upload failed, no cuesheet interface"
1400 self.cut_list = cue.getCutList()
1402 class InfoBarSummary(Screen):
1404 <screen position="0,0" size="132,64">
1405 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1406 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1409 def __init__(self, session, parent):
1410 Screen.__init__(self, session)
1411 self["CurrentService"] = ServiceName(self.session.nav)
1412 self["Clock"] = Clock()
1414 class InfoBarSummarySupport:
1418 def createSummary(self):
1419 return InfoBarSummary
1421 class InfoBarTeletextPlugin:
1423 self.teletext_plugin = None
1425 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1426 self.teletext_plugin = p
1428 if self.teletext_plugin is not None:
1429 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1431 "startTeletext": (self.startTeletext, "View teletext...")
1434 print "no teletext plugin found!"
1436 def startTeletext(self):
1437 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())