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.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import Label
9 from Components.Pixmap import Pixmap
10 from Components.PluginComponent import plugins
11 from Components.ServiceEventTracker import ServiceEventTracker
12 from Components.Sources.Source import ObsoleteSource
13 from Components.Sources.Boolean import Boolean
14 from Components.config import config, ConfigBoolean, ConfigClock
15 from Components.SystemInfo import SystemInfo
16 from EpgSelection import EPGSelection
17 from Plugins.Plugin import PluginDescriptor
19 from Screen import Screen
20 from Screens.ChoiceBox import ChoiceBox
21 from Screens.Dish import Dish
22 from Screens.EventView import EventViewEPGSelect, EventViewSimple
23 from Screens.InputBox import InputBox
24 from Screens.MessageBox import MessageBox
25 from Screens.MinuteInput import MinuteInput
26 from Screens.TimerSelection import TimerSelection
27 from Screens.PictureInPicture import PictureInPicture
28 from Screens.SubtitleDisplay import SubtitleDisplay
29 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
30 from Screens.SleepTimerEdit import SleepTimerEdit
31 from Screens.TimeDateInput import TimeDateInput
32 from ServiceReference import ServiceReference
34 from Tools import Notifications
35 from Tools.Directories import SCOPE_HDD, resolveFilename
37 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
38 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
40 from time import time, localtime, strftime
41 from os import stat as os_stat
42 from bisect import insort
45 from Menu import MainMenu, mdom
49 self.dishDialog = self.session.instantiateDialog(Dish)
51 class InfoBarShowHide:
52 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
60 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
62 "toggleShow": self.toggleShow,
64 }, 1) # lower prio to make it possible to override ok and cancel..
66 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
68 iPlayableService.evStart: self.serviceStarted,
71 self.__state = self.STATE_SHOWN
74 self.hideTimer = eTimer()
75 self.hideTimer.callback.append(self.doTimerHide)
76 self.hideTimer.start(5000, True)
78 self.onShow.append(self.__onShow)
79 self.onHide.append(self.__onHide)
81 def serviceStarted(self):
83 if config.usage.show_infobar_on_zap.value:
87 self.__state = self.STATE_SHOWN
90 def startHideTimer(self):
91 if self.__state == self.STATE_SHOWN and not self.__locked:
92 idx = config.usage.infobar_timeout.index
94 self.hideTimer.start(idx*1000, True)
97 self.__state = self.STATE_HIDDEN
101 self.startHideTimer()
103 def doTimerHide(self):
104 self.hideTimer.stop()
105 if self.__state == self.STATE_SHOWN:
108 def toggleShow(self):
109 if self.__state == self.STATE_SHOWN:
111 self.hideTimer.stop()
112 elif self.__state == self.STATE_HIDDEN:
116 self.__locked = self.__locked + 1
119 self.hideTimer.stop()
121 def unlockShow(self):
122 self.__locked = self.__locked - 1
124 self.startHideTimer()
126 # def startShow(self):
127 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
128 # self.__state = self.STATE_SHOWN
130 # def startHide(self):
131 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
132 # self.__state = self.STATE_HIDDEN
134 class NumberZap(Screen):
141 self.close(int(self["number"].getText()))
143 def keyNumberGlobal(self, number):
144 self.Timer.start(3000, True) #reset timer
145 self.field = self.field + str(number)
146 self["number"].setText(self.field)
147 if len(self.field) >= 4:
150 def __init__(self, session, number):
151 Screen.__init__(self, session)
152 self.field = str(number)
154 self["channel"] = Label(_("Channel:"))
156 self["number"] = Label(self.field)
158 self["actions"] = NumberActionMap( [ "SetupActions" ],
162 "1": self.keyNumberGlobal,
163 "2": self.keyNumberGlobal,
164 "3": self.keyNumberGlobal,
165 "4": self.keyNumberGlobal,
166 "5": self.keyNumberGlobal,
167 "6": self.keyNumberGlobal,
168 "7": self.keyNumberGlobal,
169 "8": self.keyNumberGlobal,
170 "9": self.keyNumberGlobal,
171 "0": self.keyNumberGlobal
174 self.Timer = eTimer()
175 self.Timer.callback.append(self.keyOK)
176 self.Timer.start(3000, True)
178 class InfoBarNumberZap:
179 """ Handles an initial number for NumberZapping """
181 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
183 "1": self.keyNumberGlobal,
184 "2": self.keyNumberGlobal,
185 "3": self.keyNumberGlobal,
186 "4": self.keyNumberGlobal,
187 "5": self.keyNumberGlobal,
188 "6": self.keyNumberGlobal,
189 "7": self.keyNumberGlobal,
190 "8": self.keyNumberGlobal,
191 "9": self.keyNumberGlobal,
192 "0": self.keyNumberGlobal,
195 def keyNumberGlobal(self, number):
196 # print "You pressed number " + str(number)
198 if isinstance(self, InfoBarPiP) and self.pipHandles0Action():
199 self.pipDoHandle0Action()
201 self.servicelist.recallPrevService()
203 if self.has_key("TimeshiftActions") and not self.timeshift_enabled:
204 self.session.openWithCallback(self.numberEntered, NumberZap, number)
206 def numberEntered(self, retval):
207 # print self.servicelist
209 self.zapToNumber(retval)
211 def searchNumberHelper(self, serviceHandler, num, bouquet):
212 servicelist = serviceHandler.list(bouquet)
213 if not servicelist is None:
215 serviceIterator = servicelist.getNext()
216 if not serviceIterator.valid(): #check end of list
218 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
221 if not num: #found service with searched number ?
222 return serviceIterator, 0
225 def zapToNumber(self, number):
226 bouquet = self.servicelist.bouquet_root
228 serviceHandler = eServiceCenter.getInstance()
229 if not config.usage.multibouquet.value:
230 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
232 bouquetlist = serviceHandler.list(bouquet)
233 if not bouquetlist is None:
235 bouquet = bouquetlist.getNext()
236 if not bouquet.valid(): #check end of list
238 if bouquet.flags & eServiceReference.isDirectory:
239 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
240 if not service is None:
241 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
242 self.servicelist.clearPath()
243 if self.servicelist.bouquet_root != bouquet:
244 self.servicelist.enterPath(self.servicelist.bouquet_root)
245 self.servicelist.enterPath(bouquet)
246 self.servicelist.setCurrentSelection(service) #select the service in servicelist
247 self.servicelist.zap()
249 config.misc.initialchannelselection = ConfigBoolean(default = True)
251 class InfoBarChannelSelection:
252 """ ChannelSelection - handles the channelSelection dialog and the initial
253 channelChange actions which open the channelSelection dialog """
256 self.servicelist = self.session.instantiateDialog(ChannelSelection)
258 if config.misc.initialchannelselection.value:
259 self.onShown.append(self.firstRun)
261 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
263 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
264 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
265 "zapUp": (self.zapUp, _("previous channel")),
266 "zapDown": (self.zapDown, _("next channel")),
267 "historyBack": (self.historyBack, _("previous channel in history")),
268 "historyNext": (self.historyNext, _("next channel in history")),
269 "openServiceList": (self.openServiceList, _("open servicelist")),
272 def showTvChannelList(self, zap=False):
273 self.servicelist.setModeTv()
275 self.servicelist.zap()
276 self.session.execDialog(self.servicelist)
278 def showRadioChannelList(self, zap=False):
279 self.servicelist.setModeRadio()
281 self.servicelist.zap()
282 self.session.execDialog(self.servicelist)
285 self.onShown.remove(self.firstRun)
286 config.misc.initialchannelselection.value = False
287 config.misc.initialchannelselection.save()
288 self.switchChannelDown()
290 def historyBack(self):
291 self.servicelist.historyBack()
293 def historyNext(self):
294 self.servicelist.historyNext()
296 def switchChannelUp(self):
297 self.servicelist.moveUp()
298 self.session.execDialog(self.servicelist)
300 def switchChannelDown(self):
301 self.servicelist.moveDown()
302 self.session.execDialog(self.servicelist)
304 def openServiceList(self):
305 self.session.execDialog(self.servicelist)
308 if self.servicelist.inBouquet():
309 prev = self.servicelist.getCurrentSelection()
311 prev = prev.toString()
313 if config.usage.quickzap_bouquet_change.value:
314 if self.servicelist.atBegin():
315 self.servicelist.prevBouquet()
316 self.servicelist.moveUp()
317 cur = self.servicelist.getCurrentSelection()
318 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
321 self.servicelist.moveUp()
322 self.servicelist.zap()
325 if self.servicelist.inBouquet():
326 prev = self.servicelist.getCurrentSelection()
328 prev = prev.toString()
330 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
331 self.servicelist.nextBouquet()
333 self.servicelist.moveDown()
334 cur = self.servicelist.getCurrentSelection()
335 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
338 self.servicelist.moveDown()
339 self.servicelist.zap()
342 """ Handles a menu action, to open the (main) menu """
344 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
346 "mainMenu": (self.mainMenu, _("Enter main menu...")),
348 self.session.infobar = None
351 print "loading mainmenu XML..."
352 menu = mdom.childNodes[0]
353 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
355 self.session.infobar = self
356 # so we can access the currently active infobar from screens opened from within the mainmenu
357 # at the moment used from the SubserviceSelection
359 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
361 def mainMenuClosed(self, *val):
362 self.session.infobar = None
364 class InfoBarSimpleEventView:
365 """ Opens the Eventview for now/next """
367 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
369 "showEventInfo": (self.openEventView, _("show event details")),
372 def openEventView(self):
374 service = self.session.nav.getCurrentService()
375 ref = self.session.nav.getCurrentlyPlayingServiceReference()
376 info = service.info()
379 self.epglist.append(ptr)
382 self.epglist.append(ptr)
383 if len(self.epglist) > 0:
384 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
386 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
387 if len(self.epglist) > 1:
388 tmp = self.epglist[0]
389 self.epglist[0]=self.epglist[1]
391 setEvent(self.epglist[0])
394 """ EPG - Opens an EPG list when the showEPGList action fires """
396 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
398 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
401 self.is_now_next = False
403 self.bouquetSel = None
404 self.eventView = None
405 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
407 "showEventInfo": (self.openEventView, _("show EPG...")),
408 "showSingleServiceEPG": (self.openSingleServiceEPG, _("show single service EPG...")),
409 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
412 def showEventInfoWhenNotVisible(self):
419 def zapToService(self, service):
420 if not service is None:
421 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
422 self.servicelist.clearPath()
423 if self.servicelist.bouquet_root != self.epg_bouquet:
424 self.servicelist.enterPath(self.servicelist.bouquet_root)
425 self.servicelist.enterPath(self.epg_bouquet)
426 self.servicelist.setCurrentSelection(service) #select the service in servicelist
427 self.servicelist.zap()
429 def getBouquetServices(self, bouquet):
431 servicelist = eServiceCenter.getInstance().list(bouquet)
432 if not servicelist is None:
434 service = servicelist.getNext()
435 if not service.valid(): #check if end of list
437 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
439 services.append(ServiceReference(service))
442 def openBouquetEPG(self, bouquet, withCallback=True):
443 services = self.getBouquetServices(bouquet)
445 self.epg_bouquet = bouquet
447 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
449 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
451 def changeBouquetCB(self, direction, epg):
454 self.bouquetSel.down()
457 bouquet = self.bouquetSel.getCurrent()
458 services = self.getBouquetServices(bouquet)
460 self.epg_bouquet = bouquet
461 epg.setServices(services)
463 def closed(self, ret=False):
464 closedScreen = self.dlg_stack.pop()
465 if self.bouquetSel and closedScreen == self.bouquetSel:
466 self.bouquetSel = None
467 elif self.eventView and closedScreen == self.eventView:
468 self.eventView = None
470 dlgs=len(self.dlg_stack)
472 self.dlg_stack[dlgs-1].close(dlgs > 1)
474 def openMultiServiceEPG(self, withCallback=True):
475 bouquets = self.servicelist.getBouquetList()
480 if cnt > 1: # show bouquet list
482 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
483 self.dlg_stack.append(self.bouquetSel)
485 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
487 self.openBouquetEPG(bouquets[0][1], withCallback)
489 def openSingleServiceEPG(self):
490 ref=self.session.nav.getCurrentlyPlayingServiceReference()
491 self.session.open(EPGSelection, ref)
493 def openSimilarList(self, eventid, refstr):
494 self.session.open(EPGSelection, refstr, None, eventid)
496 def getNowNext(self):
498 service = self.session.nav.getCurrentService()
499 info = service and service.info()
500 ptr = info and info.getEvent(0)
502 self.epglist.append(ptr)
503 ptr = info and info.getEvent(1)
505 self.epglist.append(ptr)
507 def __evEventInfoChanged(self):
508 if self.is_now_next and len(self.dlg_stack) == 1:
510 assert self.eventView
511 if len(self.epglist):
512 self.eventView.setEvent(self.epglist[0])
514 def openEventView(self):
515 ref = self.session.nav.getCurrentlyPlayingServiceReference()
517 if len(self.epglist) == 0:
518 self.is_now_next = False
519 epg = eEPGCache.getInstance()
520 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
522 self.epglist.append(ptr)
523 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
525 self.epglist.append(ptr)
527 self.is_now_next = True
528 if len(self.epglist) > 0:
529 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
530 self.dlg_stack.append(self.eventView)
532 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
533 self.openMultiServiceEPG(False)
535 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
536 if len(self.epglist) > 1:
537 tmp = self.epglist[0]
538 self.epglist[0]=self.epglist[1]
540 setEvent(self.epglist[0])
543 """provides a snr/agc/ber display"""
545 self["FrontendStatus"] = ObsoleteSource(new_source = "session.FrontendStatus", removal_date = "2008-01")
548 """provides a current/next event info display"""
550 self["Event_Now"] = ObsoleteSource(new_source = "session.Event_Now", removal_date = "2008-01")
551 self["Event_Next"] = ObsoleteSource(new_source = "session.Event_Next", removal_date = "2008-01")
553 class InfoBarRdsDecoder:
554 """provides RDS and Rass support/display"""
556 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
557 self.rass_interactive = None
559 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
561 iPlayableService.evEnd: self.__serviceStopped,
562 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
565 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
567 "startRassInteractive": self.startRassInteractive
570 self["RdsActions"].setEnabled(False)
572 self.onLayoutFinish.append(self.rds_display.show)
573 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
575 def RassInteractivePossibilityChanged(self, state):
576 self["RdsActions"].setEnabled(state)
578 def RassSlidePicChanged(self):
579 if not self.rass_interactive:
580 service = self.session.nav.getCurrentService()
581 decoder = service and service.rdsDecoder()
583 decoder.showRassSlidePicture()
585 def __serviceStopped(self):
586 if self.rass_interactive is not None:
587 rass_interactive = self.rass_interactive
588 self.rass_interactive = None
589 rass_interactive.close()
591 def startRassInteractive(self):
592 self.rds_display.hide()
593 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
595 def RassInteractiveClosed(self, *val):
596 if self.rass_interactive is not None:
597 self.rass_interactive = None
598 self.RassSlidePicChanged()
599 self.rds_display.show()
601 class InfoBarServiceName:
603 self["CurrentService"] = ObsoleteSource(new_source = "session.CurrentService", removal_date = "2008-01")
606 """handles actions like seeking, pause"""
608 SEEK_STATE_PLAY = (0, 0, 0, ">")
609 SEEK_STATE_PAUSE = (1, 0, 0, "||")
610 SEEK_STATE_EOF = (1, 0, 0, "END")
612 def __init__(self, actionmap = "InfobarSeekActions"):
613 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
615 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
616 iPlayableService.evStart: self.__serviceStarted,
618 iPlayableService.evEOF: self.__evEOF,
619 iPlayableService.evSOF: self.__evSOF,
622 self.eofTimer = eTimer()
623 self.eofTimer.timeout.get().append(self.doEof)
624 self.eofInhibitTimer = eTimer()
625 self.eofInhibitTimer.timeout.get().append(self.inhibitEof)
627 self.minSpeedBackward = 16
629 class InfoBarSeekActionMap(HelpableActionMap):
630 def __init__(self, screen, *args, **kwargs):
631 HelpableActionMap.__init__(self, screen, *args, **kwargs)
634 def action(self, contexts, action):
635 print "action:", action
636 if action[:5] == "seek:":
637 time = int(action[5:])
638 self.screen.doSeekRelative(time * 90000)
640 elif action[:8] == "seekdef:":
641 key = int(action[8:])
642 time = [-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
643 -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
644 -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value][key-1]
645 self.screen.doSeekRelative(time * 90000)
648 return HelpableActionMap.action(self, contexts, action)
650 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
652 "playpauseService": self.playpauseService,
653 "pauseService": (self.pauseService, _("pause")),
654 "unPauseService": (self.unPauseService, _("continue")),
656 "seekFwd": (self.seekFwd, _("skip forward")),
657 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
658 "seekBack": (self.seekBack, _("skip backward")),
659 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)"))
661 # give them a little more priority to win over color buttons
663 self["SeekActions"].setEnabled(False)
665 self.seekstate = self.SEEK_STATE_PLAY
666 self.lastseekstate = self.SEEK_STATE_PLAY
668 self.onPlayStateChanged = [ ]
670 self.lockedBecauseOfSkipping = False
672 self.__seekableStatusChanged()
674 def makeStateForward(self, n):
675 minspeed = config.seek.stepwise_minspeed.value
676 repeat = int(config.seek.stepwise_repeat.value)
677 if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
678 return (0, n * repeat, repeat, ">> %dx" % n)
680 return (0, n, 0, ">> %dx" % n)
682 def makeStateBackward(self, n):
683 minspeed = config.seek.stepwise_minspeed.value
684 repeat = int(config.seek.stepwise_repeat.value)
685 if n < self.minSpeedBackward:
686 r = (self.minSpeedBackward - 1)/ n + 1
687 if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
689 return (0, -n * r, r, "<< %dx" % n)
690 elif minspeed != "Never" and n >= int(minspeed) and repeat > 1:
691 return (0, -n * repeat, repeat, "<< %dx" % n)
693 return (0, -n, 0, "<< %dx" % n)
695 def makeStateSlowMotion(self, n):
696 return (0, 0, n, "/%d" % n)
698 def isStateForward(self, state):
701 def isStateBackward(self, state):
704 def isStateSlowMotion(self, state):
705 return state[1] == 0 and state[2] > 1
707 def getHigher(self, n, lst):
713 def getLower(self, n, lst):
721 def showAfterSeek(self):
722 if isinstance(self, InfoBarShowHide):
732 service = self.session.nav.getCurrentService()
736 seek = service.seek()
738 if seek is None or not seek.isCurrentlySeekable():
743 def isSeekable(self):
744 if self.getSeek() is None:
748 def __seekableStatusChanged(self):
749 print "seekable status changed!"
750 if not self.isSeekable():
751 self["SeekActions"].setEnabled(False)
752 print "not seekable, return to play"
753 self.setSeekState(self.SEEK_STATE_PLAY)
755 self["SeekActions"].setEnabled(True)
758 def __serviceStarted(self):
759 self.seekstate = self.SEEK_STATE_PLAY
760 self.__seekableStatusChanged()
761 if self.eofState != 0:
765 def setSeekState(self, state):
766 service = self.session.nav.getCurrentService()
771 if not self.isSeekable():
772 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
773 state = self.SEEK_STATE_PLAY
775 pauseable = service.pause()
777 if pauseable is None:
778 print "not pauseable."
779 state = self.SEEK_STATE_PLAY
781 oldstate = self.seekstate
782 self.seekstate = state
785 if oldstate[i] != self.seekstate[i]:
786 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
788 for c in self.onPlayStateChanged:
791 self.checkSkipShowHideLock()
795 def playpauseService(self):
796 if self.seekstate != self.SEEK_STATE_PLAY:
797 self.unPauseService()
801 def pauseService(self):
802 if self.seekstate == self.SEEK_STATE_PAUSE:
803 if config.seek.on_pause.value == "play":
804 self.unPauseService()
805 elif config.seek.on_pause.value == "step":
806 self.doSeekRelative(0)
807 elif config.seek.on_pause.value == "last":
808 self.setSeekState(self.lastseekstate)
809 self.lastseekstate = self.SEEK_STATE_PLAY
811 if self.seekstate != self.SEEK_STATE_EOF:
812 self.lastseekstate = self.seekstate
813 self.setSeekState(self.SEEK_STATE_PAUSE);
815 def unPauseService(self):
817 if self.seekstate == self.SEEK_STATE_PLAY:
819 self.setSeekState(self.SEEK_STATE_PLAY)
821 def doSeek(self, pts):
822 seekable = self.getSeek()
825 prevstate = self.seekstate
826 if self.eofState == 1:
829 if self.seekstate == self.SEEK_STATE_EOF:
830 if prevstate == self.SEEK_STATE_PAUSE:
831 self.setSeekState(self.SEEK_STATE_PAUSE)
833 self.setSeekState(self.SEEK_STATE_PLAY)
834 self.eofInhibitTimer.start(200, True)
837 def doSeekRelative(self, pts):
838 seekable = self.getSeek()
841 prevstate = self.seekstate
842 if self.eofState == 1:
845 if self.seekstate == self.SEEK_STATE_EOF:
846 if prevstate == self.SEEK_STATE_PAUSE:
847 self.setSeekState(self.SEEK_STATE_PAUSE)
849 self.setSeekState(self.SEEK_STATE_PLAY)
850 self.eofInhibitTimer.start(200, True)
851 seekable.seekRelative(pts<0 and -1 or 1, abs(pts))
852 if abs(pts) > 100 and config.usage.show_infobar_on_skip.value:
856 if self.seekstate == self.SEEK_STATE_PLAY:
857 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
858 elif self.seekstate == self.SEEK_STATE_PAUSE:
859 if config.seek.speeds_slowmotion:
860 self.setSeekState(self.makeStateSlowMotion(config.seek.speeds_slowmotion.value[-1]))
862 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
863 elif self.seekstate == self.SEEK_STATE_EOF:
865 elif self.isStateForward(self.seekstate):
866 speed = self.seekstate[1]
867 if self.seekstate[2]:
868 speed /= self.seekstate[2]
869 speed = self.getHigher(speed, config.seek.speeds_forward.value) or config.seek.speeds_forward.value[-1]
870 self.setSeekState(self.makeStateForward(speed))
871 elif self.isStateBackward(self.seekstate):
872 speed = -self.seekstate[1]
873 if self.seekstate[2]:
874 speed /= self.seekstate[2]
875 speed = self.getLower(speed, config.seek.speeds_backward.value)
877 self.setSeekState(self.makeStateBackward(speed))
879 self.setSeekState(self.SEEK_STATE_PLAY)
880 elif self.isStateSlowMotion(self.seekstate):
881 speed = self.getLower(self.seekstate[2], config.seek.speeds_slowmotion.value) or config.seek.speeds_slowmotion.value[0]
882 self.setSeekState(self.makeStateSlowMotion(speed))
885 if self.seekstate == self.SEEK_STATE_PLAY:
886 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
887 elif self.seekstate == self.SEEK_STATE_EOF:
888 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
889 self.doSeekRelative(-6)
890 elif self.seekstate == self.SEEK_STATE_PAUSE:
891 self.doSeekRelative(-3)
892 elif self.isStateForward(self.seekstate):
893 speed = self.seekstate[1]
894 if self.seekstate[2]:
895 speed /= self.seekstate[2]
896 speed = self.getLower(speed, config.seek.speeds_forward.value)
898 self.setSeekState(self.makeStateForward(speed))
900 self.setSeekState(self.SEEK_STATE_PLAY)
901 elif self.isStateBackward(self.seekstate):
902 speed = -self.seekstate[1]
903 if self.seekstate[2]:
904 speed /= self.seekstate[2]
905 speed = self.getHigher(speed, config.seek.speeds_backward.value) or config.seek.speeds_backward.value[-1]
906 self.setSeekState(self.makeStateBackward(speed))
907 elif self.isStateSlowMotion(self.seekstate):
908 speed = self.getHigher(self.seekstate[2], config.seek.speeds_slowmotion.value)
910 self.setSeekState(self.makeStateSlowMotion(speed))
912 self.setSeekState(self.SEEK_STATE_PAUSE)
914 def seekFwdManual(self):
915 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
917 def fwdSeekTo(self, minutes):
918 print "Seek", minutes, "minutes forward"
919 self.doSeekRelative(minutes * 60 * 90000)
921 def seekBackManual(self):
922 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
924 def rwdSeekTo(self, minutes):
926 self.doSeekRelative(-minutes * 60 * 90000)
928 def checkSkipShowHideLock(self):
929 wantlock = self.seekstate != self.SEEK_STATE_PLAY
931 if config.usage.show_infobar_on_skip.value:
932 if self.lockedBecauseOfSkipping and not wantlock:
934 self.lockedBecauseOfSkipping = False
936 if wantlock and not self.lockedBecauseOfSkipping:
938 self.lockedBecauseOfSkipping = True
940 def calcRemainingTime(self):
941 seekable = self.getSeek()
942 if seekable is not None:
943 len = seekable.getLength()
945 tmp = self.cueGetEndCutPosition()
950 pos = seekable.getPlayPosition()
951 speednom = self.seekstate[1] or 1
952 speedden = self.seekstate[2] or 1
953 if not len[0] and not pos[0]:
956 time = (len[1] - pos[1])*speedden/(90*speednom)
961 if self.eofState == 0 and self.seekstate != self.SEEK_STATE_EOF:
963 time = self.calcRemainingTime()
965 time = 3000 # Failed to calc, use default
967 time = 300 # Passed end, shortest wait
969 self.eofState = -2 # Too long, block eof
972 time += 1000 # Add margin
973 self.eofTimer.start(time, True)
975 def inhibitEof(self):
976 if self.eofState >= 1:
977 self.eofState = -self.eofState
982 if self.seekstate == self.SEEK_STATE_EOF:
984 if self.eofState == -2 or self.isStateBackward(self.seekstate):
988 # if we are seeking, we try to end up ~1s before the end, and pause there.
989 eofstate = self.eofState
990 seekstate = self.seekstate
992 if not self.seekstate == self.SEEK_STATE_PAUSE:
993 self.setSeekState(self.SEEK_STATE_EOF)
994 if eofstate == -1 or not seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
995 seekable = self.getSeek()
996 if seekable is not None:
998 if eofstate == 1 and seekstate == self.SEEK_STATE_PLAY:
999 self.doEofInternal(True)
1001 self.doEofInternal(False)
1003 def doEofInternal(self, playing):
1004 pass # Defined in subclasses
1007 self.setSeekState(self.SEEK_STATE_PLAY)
1010 from Screens.PVRState import PVRState, TimeshiftState
1012 class InfoBarPVRState:
1013 def __init__(self, screen=PVRState):
1014 self.onPlayStateChanged.append(self.__playStateChanged)
1015 self.pvrStateDialog = self.session.instantiateDialog(screen)
1016 self.onShow.append(self._mayShow)
1017 self.onHide.append(self.pvrStateDialog.hide)
1020 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
1021 self.pvrStateDialog.show()
1023 def __playStateChanged(self, state):
1024 playstateString = state[3]
1025 self.pvrStateDialog["state"].setText(playstateString)
1028 class InfoBarTimeshiftState(InfoBarPVRState):
1030 InfoBarPVRState.__init__(self, screen=TimeshiftState)
1033 if self.execing and self.timeshift_enabled:
1034 self.pvrStateDialog.show()
1036 class InfoBarShowMovies:
1038 # i don't really like this class.
1039 # it calls a not further specified "movie list" on up/down/movieList,
1040 # so this is not more than an action map
1042 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
1044 "movieList": (self.showMovies, _("movie list")),
1045 "up": (self.showMovies, _("movie list")),
1046 "down": (self.showMovies, _("movie list"))
1049 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
1053 # Timeshift works the following way:
1054 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
1055 # - normal playback TUNER unused PLAY enable disable disable
1056 # - user presses "yellow" button. FILE record PAUSE enable disable enable
1057 # - user presess pause again FILE record PLAY enable disable enable
1058 # - user fast forwards FILE record FF enable disable enable
1059 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
1060 # - user backwards FILE record BACK # !! enable disable enable
1064 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1065 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1066 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1067 # - the user can now PVR around
1068 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1069 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1071 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1072 # - if the user rewinds, or press pause, timeshift will be activated again
1074 # note that a timeshift can be enabled ("recording") and
1075 # activated (currently time-shifting).
1077 class InfoBarTimeshift:
1079 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1081 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1082 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1084 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1086 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1087 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1088 }, prio=-1) # priority over record
1090 self.timeshift_enabled = 0
1091 self.timeshift_state = 0
1092 self.ts_rewind_timer = eTimer()
1093 self.ts_rewind_timer.callback.append(self.rewindService)
1095 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1097 iPlayableService.evStart: self.__serviceStarted,
1098 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1101 def getTimeshift(self):
1102 service = self.session.nav.getCurrentService()
1103 return service and service.timeshift()
1105 def startTimeshift(self):
1106 print "enable timeshift"
1107 ts = self.getTimeshift()
1109 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1110 print "no ts interface"
1113 if self.timeshift_enabled:
1114 print "hu, timeshift already enabled?"
1116 if not ts.startTimeshift():
1117 self.timeshift_enabled = 1
1119 # we remove the "relative time" for now.
1120 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1123 #self.setSeekState(self.SEEK_STATE_PAUSE)
1124 self.activateTimeshiftEnd(False)
1126 # enable the "TimeshiftEnableActions", which will override
1127 # the startTimeshift actions
1128 self.__seekableStatusChanged()
1130 print "timeshift failed"
1132 def stopTimeshift(self):
1133 if not self.timeshift_enabled:
1135 print "disable timeshift"
1136 ts = self.getTimeshift()
1139 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1141 def stopTimeshiftConfirmed(self, confirmed):
1145 ts = self.getTimeshift()
1150 self.timeshift_enabled = 0
1153 self.__seekableStatusChanged()
1155 # activates timeshift, and seeks to (almost) the end
1156 def activateTimeshiftEnd(self, back = True):
1157 ts = self.getTimeshift()
1158 print "activateTimeshiftEnd"
1163 if ts.isTimeshiftActive():
1164 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1168 ts.activateTimeshift() # activate timeshift will automatically pause
1169 self.setSeekState(self.SEEK_STATE_PAUSE)
1172 self.doSeek(-5) # seek some gops before end
1173 self.ts_rewind_timer.start(200, 1)
1175 self.doSeek(-1) # seek 1 gop before end
1177 def rewindService(self):
1178 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1180 # same as activateTimeshiftEnd, but pauses afterwards.
1181 def activateTimeshiftEndAndPause(self):
1182 print "activateTimeshiftEndAndPause"
1183 #state = self.seekstate
1184 self.activateTimeshiftEnd(False)
1186 def __seekableStatusChanged(self):
1189 print "self.isSeekable", self.isSeekable()
1190 print "self.timeshift_enabled", self.timeshift_enabled
1192 # when this service is not seekable, but timeshift
1193 # is enabled, this means we can activate
1195 if not self.isSeekable() and self.timeshift_enabled:
1198 print "timeshift activate:", enabled
1199 self["TimeshiftActivateActions"].setEnabled(enabled)
1201 def __serviceStarted(self):
1202 self.timeshift_enabled = False
1203 self.__seekableStatusChanged()
1205 from Screens.PiPSetup import PiPSetup
1207 class InfoBarExtensions:
1208 EXTENSION_SINGLE = 0
1214 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1216 "extensions": (self.showExtensionSelection, _("view extensions...")),
1219 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1220 self.list.append((type, extension, key))
1222 def updateExtension(self, extension, key = None):
1223 self.extensionsList.append(extension)
1225 if self.extensionKeys.has_key(key):
1229 for x in self.availableKeys:
1230 if not self.extensionKeys.has_key(x):
1235 self.extensionKeys[key] = len(self.extensionsList) - 1
1237 def updateExtensions(self):
1238 self.extensionsList = []
1239 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1240 self.extensionKeys = {}
1242 if x[0] == self.EXTENSION_SINGLE:
1243 self.updateExtension(x[1], x[2])
1246 self.updateExtension(y[0], y[1])
1249 def showExtensionSelection(self):
1250 self.updateExtensions()
1251 extensionsList = self.extensionsList[:]
1254 for x in self.availableKeys:
1255 if self.extensionKeys.has_key(x):
1256 entry = self.extensionKeys[x]
1257 extension = self.extensionsList[entry]
1259 name = str(extension[0]())
1260 list.append((extension[0](), extension))
1262 extensionsList.remove(extension)
1264 extensionsList.remove(extension)
1265 for x in extensionsList:
1266 list.append((x[0](), x))
1267 keys += [""] * len(extensionsList)
1268 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1270 def extensionCallback(self, answer):
1271 if answer is not None:
1274 from Tools.BoundFunction import boundFunction
1276 # depends on InfoBarExtensions
1277 from Components.PluginComponent import plugins
1279 class InfoBarPlugins:
1281 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1283 def getPluginName(self, name):
1286 def getPluginList(self):
1288 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1289 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1292 def runPlugin(self, plugin):
1293 plugin(session = self.session, servicelist = self.servicelist)
1295 # depends on InfoBarExtensions
1296 class InfoBarSleepTimer:
1298 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1300 def available(self):
1303 def getSleepTimerName(self):
1304 return _("Sleep Timer")
1306 def showSleepTimerSetup(self):
1307 self.session.open(SleepTimerEdit)
1309 # depends on InfoBarExtensions
1312 self.session.pipshown = False
1313 if SystemInfo.get("NumVideoDecoders", 1) > 1:
1314 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1315 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1316 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1318 def available(self):
1319 return SystemInfo.get("NumVideoDecoders", 1) > 1
1322 return self.session.pipshown
1324 def pipHandles0Action(self):
1325 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1327 def getShowHideName(self):
1328 if self.session.pipshown:
1329 return _("Disable Picture in Picture")
1331 return _("Activate Picture in Picture")
1333 def getSwapName(self):
1334 return _("Swap Services")
1336 def getMoveName(self):
1337 return _("Move Picture in Picture")
1340 if self.session.pipshown:
1341 del self.session.pip
1342 self.session.pipshown = False
1344 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1345 self.session.pip.show()
1346 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1347 if self.session.pip.playService(newservice):
1348 self.session.pipshown = True
1349 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1351 self.session.pipshown = False
1352 del self.session.pip
1353 self.session.nav.playService(newservice)
1356 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1357 if self.session.pip.servicePath:
1358 servicepath = self.servicelist.getCurrentServicePath()
1359 ref=servicepath[len(servicepath)-1]
1360 pipref=self.session.pip.getCurrentService()
1361 self.session.pip.playService(swapservice)
1362 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1363 if pipref.toString() != ref.toString(): # is a subservice ?
1364 self.session.nav.stopService() # stop portal
1365 self.session.nav.playService(pipref) # start subservice
1366 self.session.pip.servicePath=servicepath
1369 self.session.open(PiPSetup, pip = self.session.pip)
1371 def pipDoHandle0Action(self):
1372 use = config.usage.pip_zero_button.value
1375 elif "swapstop" == use:
1381 from RecordTimer import parseEvent
1383 class InfoBarInstantRecord:
1384 """Instant Record - handles the instantRecord action in order to
1385 start/stop instant records"""
1387 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1389 "instantRecord": (self.instantRecord, _("Instant Record...")),
1392 #### DEPRECATED CODE ####
1393 self["BlinkingPoint"] = BlinkingPixmapConditional()
1394 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1395 self["BlinkingPoint"].deprecationInfo = (
1396 "session.RecordState source, Pixmap renderer and "
1397 "ConditionalShowHide/Blink Converter", "2008-02")
1398 #########################
1400 def stopCurrentRecording(self, entry = -1):
1401 if entry is not None and entry != -1:
1402 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1403 self.recording.remove(self.recording[entry])
1405 def startInstantRecording(self, limitEvent = False):
1406 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1408 # try to get event info
1411 service = self.session.nav.getCurrentService()
1412 epg = eEPGCache.getInstance()
1413 event = epg.lookupEventTime(serviceref, -1, 0)
1415 info = service.info()
1416 ev = info.getEvent(0)
1422 end = time() + 3600 * 10
1423 name = "instant record"
1427 if event is not None:
1428 curEvent = parseEvent(event)
1430 description = curEvent[3]
1431 eventid = curEvent[4]
1436 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1438 data = (begin, end, name, description, eventid)
1440 recording = self.session.nav.recordWithTimer(serviceref, *data)
1441 recording.dontSave = True
1442 self.recording.append(recording)
1444 #### DEPRECATED CODE ####
1445 self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1446 #########################
1448 def isInstantRecordRunning(self):
1449 print "self.recording:", self.recording
1450 if len(self.recording) > 0:
1451 for x in self.recording:
1456 def recordQuestionCallback(self, answer):
1457 print "pre:\n", self.recording
1459 if answer is None or answer[1] == "no":
1462 recording = self.recording[:]
1464 if not x in self.session.nav.RecordTimer.timer_list:
1465 self.recording.remove(x)
1466 elif x.dontSave and x.isRunning():
1467 list.append((x, False))
1469 if answer[1] == "changeduration":
1470 if len(self.recording) == 1:
1471 self.changeDuration(0)
1473 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1474 elif answer[1] == "changeendtime":
1475 if len(self.recording) == 1:
1478 self.session.openWithCallback(self.setEndtime, TimerSelection, list)
1479 elif answer[1] == "stop":
1480 if len(self.recording) == 1:
1481 self.stopCurrentRecording(0)
1483 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1484 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1485 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1486 if answer[1] == "manualduration":
1487 self.changeDuration(len(self.recording)-1)
1488 elif answer[1] == "manualendtime":
1489 self.setEndtime(len(self.recording)-1)
1490 print "after:\n", self.recording
1492 def setEndtime(self, entry):
1493 if entry is not None:
1494 self.selectedEntry = entry
1495 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1496 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1497 dlg.setTitle(_("Please change recording endtime"))
1499 def TimeDateInputClosed(self, ret):
1502 localendtime = localtime(ret[1])
1503 print "stopping recording at", strftime("%c", localendtime)
1504 self.recording[self.selectedEntry].end = ret[1]
1505 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1507 def changeDuration(self, entry):
1508 if entry is not None:
1509 self.selectedEntry = entry
1510 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1512 def inputCallback(self, value):
1513 if value is not None:
1514 print "stopping recording after", int(value), "minutes."
1515 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1516 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1518 def instantRecord(self):
1520 stat = os_stat(resolveFilename(SCOPE_HDD))
1522 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1525 if self.isInstantRecordRunning():
1526 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1527 title=_("A recording is currently running.\nWhat do you want to do?"), \
1528 list=[(_("stop recording"), "stop"), \
1529 (_("change recording (duration)"), "changeduration"), \
1530 (_("change recording (endtime)"), "changeendtime"), \
1531 (_("add recording (indefinitely)"), "indefinitely"), \
1532 (_("add recording (stop after current event)"), "event"), \
1533 (_("add recording (enter recording duration)"), "manualduration"), \
1534 (_("add recording (enter recording endtime)"), "manualendtime"), \
1535 (_("do nothing"), "no")])
1537 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1538 title=_("Start recording?"), \
1539 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1540 (_("add recording (stop after current event)"), "event"), \
1541 (_("add recording (enter recording duration)"), "manualduration"), \
1542 (_("add recording (enter recording endtime)"), "manualendtime"), \
1543 (_("don't record"), "no")])
1545 from Tools.ISO639 import LanguageCodes
1547 class InfoBarAudioSelection:
1549 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1551 "audioSelection": (self.audioSelection, _("Audio Options...")),
1554 def audioSelection(self):
1555 service = self.session.nav.getCurrentService()
1556 audio = service and service.audioTracks()
1557 self.audioTracks = audio
1558 n = audio and audio.getNumberOfTracks() or 0
1559 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1562 self.audioChannel = service.audioChannel()
1565 i = audio.getTrackInfo(x)
1566 language = i.getLanguage()
1567 description = i.getDescription()
1569 if LanguageCodes.has_key(language):
1570 language = LanguageCodes[language][0]
1572 if len(description):
1573 description += " (" + language + ")"
1575 description = language
1577 tlist.append((description, x))
1579 selectedAudio = audio.getCurrentTrack()
1580 tlist.sort(key=lambda x: x[0])
1584 if x[1] != selectedAudio:
1589 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1590 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1592 del self.audioTracks
1594 def audioSelected(self, audio):
1595 if audio is not None:
1596 if isinstance(audio[1], str):
1597 if audio[1] == "mode":
1598 keys = ["red", "green", "yellow"]
1599 selection = self.audioChannel.getCurrentChannel()
1600 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1601 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1603 del self.audioChannel
1604 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1605 self.audioTracks.selectTrack(audio[1])
1607 del self.audioChannel
1608 del self.audioTracks
1610 def modeSelected(self, mode):
1611 if mode is not None:
1612 self.audioChannel.selectChannel(mode[1])
1613 del self.audioChannel
1615 class InfoBarSubserviceSelection:
1617 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1619 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1622 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1624 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1625 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1627 self["SubserviceQuickzapAction"].setEnabled(False)
1629 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1633 def checkSubservicesAvail(self, ev):
1634 if ev == iPlayableService.evUpdatedEventInfo:
1635 service = self.session.nav.getCurrentService()
1636 subservices = service and service.subServices()
1637 if not subservices or subservices.getNumberOfSubservices() == 0:
1638 self["SubserviceQuickzapAction"].setEnabled(False)
1640 def nextSubservice(self):
1641 self.changeSubservice(+1)
1643 def prevSubservice(self):
1644 self.changeSubservice(-1)
1646 def changeSubservice(self, direction):
1647 service = self.session.nav.getCurrentService()
1648 subservices = service and service.subServices()
1649 n = subservices and subservices.getNumberOfSubservices()
1652 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1654 if subservices.getSubservice(x).toString() == ref.toString():
1657 selection += direction
1662 newservice = subservices.getSubservice(selection)
1663 if newservice.valid():
1666 self.session.nav.playService(newservice)
1668 def subserviceSelection(self):
1669 service = self.session.nav.getCurrentService()
1670 subservices = service and service.subServices()
1671 self.bouquets = self.servicelist.getBouquetList()
1672 n = subservices and subservices.getNumberOfSubservices()
1675 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1678 i = subservices.getSubservice(x)
1679 if i.toString() == ref.toString():
1681 tlist.append((i.getName(), i))
1683 if self.bouquets and len(self.bouquets):
1684 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1685 if config.usage.multibouquet.value:
1686 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1688 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1691 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1692 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1695 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1697 def subserviceSelected(self, service):
1699 if not service is None:
1700 if isinstance(service[1], str):
1701 if service[1] == "quickzap":
1702 from Screens.SubservicesQuickzap import SubservicesQuickzap
1703 self.session.open(SubservicesQuickzap, service[2])
1705 self["SubserviceQuickzapAction"].setEnabled(True)
1706 self.session.nav.playService(service[1])
1708 def addSubserviceToBouquetCallback(self, service):
1709 if len(service) > 1 and isinstance(service[1], eServiceReference):
1710 self.selectedSubservice = service
1711 if self.bouquets is None:
1714 cnt = len(self.bouquets)
1715 if cnt > 1: # show bouquet list
1716 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1717 elif cnt == 1: # add to only one existing bouquet
1718 self.addSubserviceToBouquet(self.bouquets[0][1])
1719 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1721 def bouquetSelClosed(self, confirmed):
1723 del self.selectedSubservice
1725 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1727 def addSubserviceToBouquet(self, dest):
1728 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1730 self.bsel.close(True)
1732 del self.selectedSubservice
1734 class InfoBarAdditionalInfo:
1737 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1738 self["TimeshiftPossible"] = self["RecordingPossible"]
1739 self["ExtensionsAvailable"] = Boolean(fixed=1)
1741 ######### DEPRECATED CODE ##########
1742 self["NimA"] = Pixmap()
1743 self["NimA"].deprecationInfo = (
1744 "session.TunerInfo source, Pixmap renderer, TunerInfo/UseMask Converter"
1745 ", ValueBitTest(1) Converter and ConditionalShowHide Converter", "2008-02")
1746 self["NimB"] = Pixmap()
1747 self["NimB"].deprecationInfo = (
1748 "session.TunerInfo source, Pixmap renderer, TunerInfo/UseMask Converter"
1749 ", ValueBitTest(2) Converter and ConditionalShowHide Converter", "2008-02")
1750 self["NimA_Active"] = Pixmap()
1751 self["NimA_Active"].deprecationInfo = (
1752 "session.FrontendInfo source, Pixmap renderer, FrontendInfo/NUMBER Converter"
1753 ", ValueRange(1,1) Converter and ConditionalShowHide Converter", "2008-02")
1754 self["NimB_Active"] = Pixmap()
1755 self["NimB_Active"].deprecationInfo = (
1756 "session.FrontendInfo source, Pixmap renderer, FrontendInfo/NUMBER Converter"
1757 ", ValueRange(1,1) Converter and ConditionalShowHide Converter", "2008-02")
1759 res_mgr = eDVBResourceManager.getInstance()
1761 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1763 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1765 def tunerUseMaskChanged(self, mask):
1767 self["NimA_Active"].show()
1769 self["NimA_Active"].hide()
1771 self["NimB_Active"].show()
1773 self["NimB_Active"].hide()
1775 def checkTunerState(self, service):
1776 info = service and service.frontendInfo()
1777 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1778 if feNumber is None:
1788 def gotServiceEvent(self, ev):
1789 service = self.session.nav.getCurrentService()
1790 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1791 self.checkTunerState(service)
1792 ####################################
1794 class InfoBarNotifications:
1796 self.onExecBegin.append(self.checkNotifications)
1797 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1798 self.onClose.append(self.__removeNotification)
1800 def __removeNotification(self):
1801 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1803 def checkNotificationsIfExecing(self):
1805 self.checkNotifications()
1807 def checkNotifications(self):
1808 if len(Notifications.notifications):
1809 n = Notifications.notifications[0]
1811 Notifications.notifications = Notifications.notifications[1:]
1814 if n[3].has_key("onSessionOpenCallback"):
1815 n[3]["onSessionOpenCallback"]()
1816 del n[3]["onSessionOpenCallback"]
1819 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1821 dlg = self.session.open(n[1], *n[2], **n[3])
1823 # remember that this notification is currently active
1825 Notifications.current_notifications.append(d)
1826 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1828 def __notificationClosed(self, d):
1829 Notifications.current_notifications.remove(d)
1831 class InfoBarServiceNotifications:
1833 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1835 iPlayableService.evEnd: self.serviceHasEnded
1838 def serviceHasEnded(self):
1839 print "service end!"
1842 self.setSeekState(self.SEEK_STATE_PLAY)
1846 class InfoBarCueSheetSupport:
1852 ENABLE_RESUME_SUPPORT = False
1854 def __init__(self, actionmap = "InfobarCueSheetActions"):
1855 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1857 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1858 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1859 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1863 self.is_closing = False
1864 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1866 iPlayableService.evStart: self.__serviceStarted,
1869 def __serviceStarted(self):
1872 print "new service started! trying to download cuts!"
1873 self.downloadCuesheet()
1875 if self.ENABLE_RESUME_SUPPORT:
1878 for (pts, what) in self.cut_list:
1879 if what == self.CUT_TYPE_LAST:
1882 if last is not None:
1883 self.resume_point = last
1884 if config.usage.on_movie_start.value == "ask":
1885 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1886 elif config.usage.on_movie_start.value == "resume":
1887 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Resuming playback"), timeout=2, type=MessageBox.TYPE_INFO)
1889 def playLastCB(self, answer):
1891 self.doSeek(self.resume_point)
1892 self.hideAfterResume()
1894 def hideAfterResume(self):
1895 if isinstance(self, InfoBarShowHide):
1898 def __getSeekable(self):
1899 service = self.session.nav.getCurrentService()
1902 return service.seek()
1904 def cueGetCurrentPosition(self):
1905 seek = self.__getSeekable()
1908 r = seek.getPlayPosition()
1913 def cueGetEndCutPosition(self):
1916 for cp in self.cut_list:
1917 if cp[1] == self.CUT_TYPE_OUT:
1921 elif cp[1] == self.CUT_TYPE_IN:
1925 def jumpPreviousNextMark(self, cmp, start=False):
1926 current_pos = self.cueGetCurrentPosition()
1927 if current_pos is None:
1929 mark = self.getNearestCutPoint(current_pos, cmp=cmp, start=start)
1930 if mark is not None:
1938 def jumpPreviousMark(self):
1939 # we add 2 seconds, so if the play position is <2s after
1940 # the mark, the mark before will be used
1941 self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
1943 def jumpNextMark(self):
1944 if not self.jumpPreviousNextMark(lambda x: x):
1947 def getNearestCutPoint(self, pts, cmp=abs, start=False):
1953 bestdiff = cmp(0 - pts)
1955 nearest = [0, False]
1956 for cp in self.cut_list:
1957 if beforecut and cp[1] in [self.CUT_TYPE_IN, self.CUT_TYPE_OUT]:
1959 if cp[1] == self.CUT_TYPE_IN: # Start is here, disregard previous marks
1960 diff = cmp(cp[0] - pts)
1966 if cp[1] in [self.CUT_TYPE_MARK, self.CUT_TYPE_LAST]:
1967 diff = cmp(cp[0] - pts)
1968 if diff >= 0 and (nearest is None or bestdiff > diff):
1973 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1974 current_pos = self.cueGetCurrentPosition()
1975 if current_pos is None:
1976 print "not seekable"
1979 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1981 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1983 return nearest_cutpoint
1985 self.removeMark(nearest_cutpoint)
1986 elif not onlyremove and not onlyreturn:
1987 self.addMark((current_pos, self.CUT_TYPE_MARK))
1992 def addMark(self, point):
1993 insort(self.cut_list, point)
1994 self.uploadCuesheet()
1995 self.showAfterCuesheetOperation()
1997 def removeMark(self, point):
1998 self.cut_list.remove(point)
1999 self.uploadCuesheet()
2000 self.showAfterCuesheetOperation()
2002 def showAfterCuesheetOperation(self):
2003 if isinstance(self, InfoBarShowHide):
2006 def __getCuesheet(self):
2007 service = self.session.nav.getCurrentService()
2010 return service.cueSheet()
2012 def uploadCuesheet(self):
2013 cue = self.__getCuesheet()
2016 print "upload failed, no cuesheet interface"
2018 cue.setCutList(self.cut_list)
2020 def downloadCuesheet(self):
2021 cue = self.__getCuesheet()
2024 print "download failed, no cuesheet interface"
2027 self.cut_list = cue.getCutList()
2029 class InfoBarSummary(Screen):
2031 <screen position="0,0" size="132,64">
2032 <widget source="global.CurrentTime" render="Label" position="62,46" size="82,18" font="Regular;16" >
2033 <convert type="ClockToText">WithSeconds</convert>
2035 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="82,18" zPosition="1" >
2036 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2037 <convert type="ConditionalShowHide">Blink</convert>
2039 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2040 <convert type="ServiceName">Name</convert>
2042 <widget source="session.Event_Now" render="Progress" position="6,46" size="46,18" borderWidth="1" >
2043 <convert type="EventTime">Progress</convert>
2047 # for picon: (path="piconlcd" will use LCD picons)
2048 # <widget source="session.CurrentService" render="Picon" position="6,0" size="120,64" path="piconlcd" >
2049 # <convert type="ServiceName">Reference</convert>
2052 def __init__(self, session, parent):
2053 Screen.__init__(self, session, parent = parent)
2055 class InfoBarSummarySupport:
2059 def createSummary(self):
2060 return InfoBarSummary
2062 class InfoBarMoviePlayerSummary(Screen):
2064 <screen position="0,0" size="132,64">
2065 <widget source="global.CurrentTime" render="Label" position="62,46" size="64,18" font="Regular;16" halign="right" >
2066 <convert type="ClockToText">WithSeconds</convert>
2068 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="64,18" zPosition="1" >
2069 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2070 <convert type="ConditionalShowHide">Blink</convert>
2072 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2073 <convert type="ServiceName">Name</convert>
2075 <widget source="session.CurrentService" render="Progress" position="6,46" size="56,18" borderWidth="1" >
2076 <convert type="ServicePosition">Position</convert>
2080 def __init__(self, session, parent):
2081 Screen.__init__(self, session)
2083 class InfoBarMoviePlayerSummarySupport:
2087 def createSummary(self):
2088 return InfoBarMoviePlayerSummary
2090 class InfoBarTeletextPlugin:
2092 self.teletext_plugin = None
2094 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
2095 self.teletext_plugin = p
2097 if self.teletext_plugin is not None:
2098 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
2100 "startTeletext": (self.startTeletext, _("View teletext..."))
2103 print "no teletext plugin found!"
2105 def startTeletext(self):
2106 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
2108 class InfoBarSubtitleSupport(object):
2110 object.__init__(self)
2111 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
2112 self.__subtitles_enabled = False
2114 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2116 iPlayableService.evEnd: self.__serviceStopped,
2117 iPlayableService.evUpdatedInfo: self.__updatedInfo
2119 self.cached_subtitle_checked = False
2120 self.__selected_subtitle = None
2122 def __serviceStopped(self):
2123 self.subtitle_window.hide()
2124 self.__subtitles_enabled = False
2125 self.cached_subtitle_checked = False
2127 def __updatedInfo(self):
2128 if not self.cached_subtitle_checked:
2129 subtitle = self.getCurrentServiceSubtitle()
2130 self.cached_subtitle_checked = True
2131 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
2132 if self.__selected_subtitle:
2133 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2134 self.subtitle_window.show()
2135 self.__subtitles_enabled = True
2137 def getCurrentServiceSubtitle(self):
2138 service = self.session.nav.getCurrentService()
2139 return service and service.subtitle()
2141 def setSubtitlesEnable(self, enable=True):
2142 subtitle = self.getCurrentServiceSubtitle()
2143 if enable and self.__selected_subtitle is not None:
2144 if subtitle and not self.__subtitles_enabled:
2145 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2146 self.subtitle_window.show()
2147 self.__subtitles_enabled = True
2150 subtitle.disableSubtitles(self.subtitle_window.instance)
2151 self.__subtitles_enabled = False
2152 self.subtitle_window.hide()
2154 def setSelectedSubtitle(self, subtitle):
2155 self.__selected_subtitle = subtitle
2157 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
2158 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
2160 class InfoBarServiceErrorPopupSupport:
2162 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2164 iPlayableService.evTuneFailed: self.__tuneFailed,
2165 iPlayableService.evStart: self.__serviceStarted
2167 self.__serviceStarted()
2169 def __serviceStarted(self):
2170 self.last_error = None
2171 Notifications.RemovePopup(id = "ZapError")
2173 def __tuneFailed(self):
2174 service = self.session.nav.getCurrentService()
2175 info = service and service.info()
2176 error = info and info.getInfo(iServiceInformation.sDVBState)
2178 if error == self.last_error:
2181 self.last_error = error
2184 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2185 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2186 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2187 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2188 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2189 eDVBServicePMTHandler.eventNewProgramInfo: None,
2190 eDVBServicePMTHandler.eventTuned: None,
2191 eDVBServicePMTHandler.eventSOF: None,
2192 eDVBServicePMTHandler.eventEOF: None,
2193 eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
2196 error = errors.get(error) #this returns None when the key not exist in the dict
2198 if error is not None:
2199 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2201 Notifications.RemovePopup(id = "ZapError")