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 print "pre:\n", self.recording
1070 if answer is None or answer[1] == "no":
1073 recording = self.recording[:]
1075 if not x in self.session.nav.RecordTimer.timer_list:
1076 self.recording.remove(x)
1077 elif x.dontSave and x.isRunning():
1078 list.append(TimerEntryComponent(x, False))
1080 if answer[1] == "changeduration":
1081 if len(self.recording) == 1:
1082 self.changeDuration(0)
1084 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1085 elif answer[1] == "stop":
1086 if len(self.recording) == 1:
1087 self.stopCurrentRecording(0)
1089 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1090 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1092 if answer[1] == "event":
1094 if answer[1] == "manualduration":
1095 self.selectedEntry = len(self.recording)
1096 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1097 self.startInstantRecording(limitEvent = limitEvent)
1099 print "after:\n", self.recording
1101 def changeDuration(self, entry):
1102 if entry is not None:
1103 self.selectedEntry = entry
1104 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1106 def inputCallback(self, value):
1107 if value is not None:
1108 print "stopping recording after", int(value), "minutes."
1109 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1110 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1112 def instantRecord(self):
1114 stat = os.stat(resolveFilename(SCOPE_HDD))
1116 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1119 if self.isInstantRecordRunning():
1120 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")])
1122 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")])
1124 from Screens.AudioSelection import AudioSelection
1126 class InfoBarAudioSelection:
1128 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1130 "audioSelection": (self.audioSelection, "Audio Options..."),
1133 def audioSelection(self):
1134 service = self.session.nav.getCurrentService()
1135 audio = service.audioTracks()
1136 n = audio.getNumberOfTracks()
1138 self.session.open(AudioSelection, audio)
1140 from Screens.SubserviceSelection import SubserviceSelection
1142 class InfoBarSubserviceSelection:
1144 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1146 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1149 def subserviceSelection(self):
1150 service = self.session.nav.getCurrentService()
1151 subservices = service.subServices()
1152 n = subservices.getNumberOfSubservices()
1154 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1156 def subserviceSelected(self, service):
1157 if not service is None:
1158 self.session.nav.playService(service)
1160 class InfoBarAdditionalInfo:
1162 self["DolbyActive"] = Pixmap()
1163 self["CryptActive"] = Pixmap()
1164 self["FormatActive"] = Pixmap()
1166 self["ButtonRed"] = PixmapConditional(withTimer = False)
1167 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1168 self.onLayoutFinish.append(self["ButtonRed"].update)
1169 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1170 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1171 self.onLayoutFinish.append(self["ButtonRedText"].update)
1173 self["ButtonGreen"] = Pixmap()
1174 self["ButtonGreenText"] = Label(_("Subservices"))
1176 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1177 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1178 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1179 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1180 self.onLayoutFinish.append(self["ButtonYellow"].update)
1181 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1183 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1184 self["ButtonBlue"].setConnect(lambda: True)
1185 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1186 self["ButtonBlueText"].setConnect(lambda: True)
1187 self.onLayoutFinish.append(self["ButtonBlue"].update)
1188 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1190 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1192 def hideSubServiceIndication(self):
1193 self["ButtonGreen"].hide()
1194 self["ButtonGreenText"].hide()
1196 def showSubServiceIndication(self):
1197 self["ButtonGreen"].show()
1198 self["ButtonGreenText"].show()
1200 def checkFormat(self, service):
1201 info = service.info()
1202 if info is not None:
1203 aspect = info.getInfo(iServiceInformation.sAspect)
1204 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1205 self["FormatActive"].show()
1207 self["FormatActive"].hide()
1209 def checkSubservices(self, service):
1210 if service.subServices().getNumberOfSubservices() > 0:
1211 self.showSubServiceIndication()
1213 self.hideSubServiceIndication()
1215 def checkDolby(self, service):
1218 audio = service.audioTracks()
1219 if audio is not None:
1220 n = audio.getNumberOfTracks()
1222 i = audio.getTrackInfo(x)
1223 description = i.getDescription();
1224 if description.find("AC3") != -1 or description.find("DTS") != -1:
1228 self["DolbyActive"].show()
1230 self["DolbyActive"].hide()
1232 def checkCrypted(self, service):
1233 info = service.info()
1234 if info is not None:
1235 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1236 self["CryptActive"].show()
1238 self["CryptActive"].hide()
1240 def gotServiceEvent(self, ev):
1241 service = self.session.nav.getCurrentService()
1242 if ev == iPlayableService.evUpdatedEventInfo:
1243 self.checkSubservices(service)
1244 self.checkFormat(service)
1245 elif ev == iPlayableService.evUpdatedInfo:
1246 self.checkCrypted(service)
1247 self.checkDolby(service)
1248 elif ev == iPlayableService.evEnd:
1249 self.hideSubServiceIndication()
1250 self["CryptActive"].hide()
1251 self["DolbyActive"].hide()
1252 self["FormatActive"].hide()
1254 class InfoBarNotifications:
1256 self.onExecBegin.append(self.checkNotifications)
1257 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1259 def checkNotificationsIfExecing(self):
1261 self.checkNotifications()
1263 def checkNotifications(self):
1264 if len(Notifications.notifications):
1265 n = Notifications.notifications[0]
1266 Notifications.notifications = Notifications.notifications[1:]
1270 self.session.openWithCallback(cb, *n[1:])
1272 self.session.open(*n[1:])
1274 class InfoBarServiceNotifications:
1276 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1278 iPlayableService.evEnd: self.serviceHasEnded
1281 def serviceHasEnded(self):
1282 print "service end!"
1285 self.setSeekState(self.SEEK_STATE_PLAY)
1289 class InfoBarCueSheetSupport:
1295 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1297 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1298 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1299 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1303 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1305 iPlayableService.evStart: self.__serviceStarted,
1308 def __serviceStarted(self):
1309 print "new service started! trying to download cuts!"
1310 self.downloadCuesheet()
1312 def __getSeekable(self):
1313 service = self.session.nav.getCurrentService()
1316 return service.seek()
1318 def cueGetCurrentPosition(self):
1319 seek = self.__getSeekable()
1322 r = seek.getPlayPosition()
1327 def jumpPreviousNextMark(self, cmp, alternative=None):
1328 current_pos = self.cueGetCurrentPosition()
1329 if current_pos is None:
1331 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1332 if mark is not None:
1334 elif alternative is not None:
1339 seekable = self.__getSeekable()
1340 if seekable is not None:
1341 seekable.seekTo(pts)
1343 def jumpPreviousMark(self):
1344 # we add 2 seconds, so if the play position is <2s after
1345 # the mark, the mark before will be used
1346 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1348 def jumpNextMark(self):
1349 self.jumpPreviousNextMark(lambda x: x)
1351 def getNearestCutPoint(self, pts, cmp=abs):
1354 for cp in self.cut_list:
1355 diff = cmp(cp[0] - pts)
1356 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1360 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1361 current_pos = self.cueGetCurrentPosition()
1362 if current_pos is None:
1363 print "not seekable"
1366 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1368 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1370 return nearest_cutpoint
1372 self.removeMark(nearest_cutpoint)
1373 elif not onlyremove and not onlyreturn:
1374 self.addMark((current_pos, self.CUT_TYPE_MARK))
1379 def addMark(self, point):
1380 bisect.insort(self.cut_list, point)
1381 self.uploadCuesheet()
1383 def removeMark(self, point):
1384 self.cut_list.remove(point)
1385 self.uploadCuesheet()
1387 def __getCuesheet(self):
1388 service = self.session.nav.getCurrentService()
1391 return service.cueSheet()
1393 def uploadCuesheet(self):
1394 cue = self.__getCuesheet()
1397 print "upload failed, no cuesheet interface"
1399 cue.setCutList(self.cut_list)
1401 def downloadCuesheet(self):
1402 cue = self.__getCuesheet()
1405 print "upload failed, no cuesheet interface"
1407 self.cut_list = cue.getCutList()
1409 class InfoBarSummary(Screen):
1411 <screen position="0,0" size="132,64">
1412 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1413 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1416 def __init__(self, session, parent):
1417 Screen.__init__(self, session)
1418 self["CurrentService"] = ServiceName(self.session.nav)
1419 self["Clock"] = Clock()
1421 class InfoBarSummarySupport:
1425 def createSummary(self):
1426 return InfoBarSummary
1428 class InfoBarTeletextPlugin:
1430 self.teletext_plugin = None
1432 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1433 self.teletext_plugin = p
1435 if self.teletext_plugin is not None:
1436 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1438 "startTeletext": (self.startTeletext, "View teletext...")
1441 print "no teletext plugin found!"
1443 def startTeletext(self):
1444 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())