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)
691 if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
692 return (0, -n * repeat, repeat, "<< %dx" % n)
694 return (0, -n, 0, "<< %dx" % n)
696 def makeStateSlowMotion(self, n):
697 return (0, 0, n, "/%d" % n)
699 def isStateForward(self, state):
702 def isStateBackward(self, state):
705 def isStateSlowMotion(self, state):
706 return state[1] == 0 and state[2] > 1
708 def getHigher(self, n, lst):
714 def getLower(self, n, lst):
722 def showAfterSeek(self):
723 if isinstance(self, InfoBarShowHide):
733 service = self.session.nav.getCurrentService()
737 seek = service.seek()
739 if seek is None or not seek.isCurrentlySeekable():
744 def isSeekable(self):
745 if self.getSeek() is None:
749 def __seekableStatusChanged(self):
750 print "seekable status changed!"
751 if not self.isSeekable():
752 self["SeekActions"].setEnabled(False)
753 print "not seekable, return to play"
754 self.setSeekState(self.SEEK_STATE_PLAY)
756 self["SeekActions"].setEnabled(True)
759 def __serviceStarted(self):
760 self.seekstate = self.SEEK_STATE_PLAY
761 self.__seekableStatusChanged()
762 if self.eofState != 0:
766 def setSeekState(self, state):
767 service = self.session.nav.getCurrentService()
772 if not self.isSeekable():
773 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
774 state = self.SEEK_STATE_PLAY
776 pauseable = service.pause()
778 if pauseable is None:
779 print "not pauseable."
780 state = self.SEEK_STATE_PLAY
782 oldstate = self.seekstate
783 self.seekstate = state
786 if oldstate[i] != self.seekstate[i]:
787 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
789 for c in self.onPlayStateChanged:
792 self.checkSkipShowHideLock()
796 def playpauseService(self):
797 if self.seekstate != self.SEEK_STATE_PLAY:
798 self.unPauseService()
802 def pauseService(self):
803 if self.seekstate == self.SEEK_STATE_PAUSE:
804 if config.seek.on_pause.value == "play":
805 self.unPauseService()
806 elif config.seek.on_pause.value == "step":
807 self.doSeekRelative(0)
808 elif config.seek.on_pause.value == "last":
809 self.setSeekState(self.lastseekstate)
810 self.lastseekstate = self.SEEK_STATE_PLAY
812 if self.seekstate != self.SEEK_STATE_EOF:
813 self.lastseekstate = self.seekstate
814 self.setSeekState(self.SEEK_STATE_PAUSE);
816 def unPauseService(self):
818 if self.seekstate == self.SEEK_STATE_PLAY:
820 self.setSeekState(self.SEEK_STATE_PLAY)
822 def doSeek(self, pts):
823 seekable = self.getSeek()
826 prevstate = self.seekstate
827 if self.eofState == 1:
830 if self.seekstate == self.SEEK_STATE_EOF:
831 if prevstate == self.SEEK_STATE_PAUSE:
832 self.setSeekState(self.SEEK_STATE_PAUSE)
834 self.setSeekState(self.SEEK_STATE_PLAY)
835 self.eofInhibitTimer.start(200, True)
838 def doSeekRelative(self, pts):
839 seekable = self.getSeek()
842 prevstate = self.seekstate
843 if self.eofState == 1:
846 if self.seekstate == self.SEEK_STATE_EOF:
847 if prevstate == self.SEEK_STATE_PAUSE:
848 self.setSeekState(self.SEEK_STATE_PAUSE)
850 self.setSeekState(self.SEEK_STATE_PLAY)
851 self.eofInhibitTimer.start(200, True)
852 seekable.seekRelative(pts<0 and -1 or 1, abs(pts))
853 if abs(pts) > 100 and config.usage.show_infobar_on_skip.value:
857 if self.seekstate == self.SEEK_STATE_PLAY:
858 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
859 elif self.seekstate == self.SEEK_STATE_PAUSE:
860 if len(config.seek.speeds_slowmotion.value):
861 self.setSeekState(self.makeStateSlowMotion(config.seek.speeds_slowmotion.value[-1]))
863 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
864 elif self.seekstate == self.SEEK_STATE_EOF:
866 elif self.isStateForward(self.seekstate):
867 speed = self.seekstate[1]
868 if self.seekstate[2]:
869 speed /= self.seekstate[2]
870 speed = self.getHigher(speed, config.seek.speeds_forward.value) or config.seek.speeds_forward.value[-1]
871 self.setSeekState(self.makeStateForward(speed))
872 elif self.isStateBackward(self.seekstate):
873 speed = -self.seekstate[1]
874 if self.seekstate[2]:
875 speed /= self.seekstate[2]
876 speed = self.getLower(speed, config.seek.speeds_backward.value)
878 self.setSeekState(self.makeStateBackward(speed))
880 self.setSeekState(self.SEEK_STATE_PLAY)
881 elif self.isStateSlowMotion(self.seekstate):
882 speed = self.getLower(self.seekstate[2], config.seek.speeds_slowmotion.value) or config.seek.speeds_slowmotion.value[0]
883 self.setSeekState(self.makeStateSlowMotion(speed))
886 if self.seekstate == self.SEEK_STATE_PLAY:
887 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
888 elif self.seekstate == self.SEEK_STATE_EOF:
889 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
890 self.doSeekRelative(-6)
891 elif self.seekstate == self.SEEK_STATE_PAUSE:
892 self.doSeekRelative(-3)
893 elif self.isStateForward(self.seekstate):
894 speed = self.seekstate[1]
895 if self.seekstate[2]:
896 speed /= self.seekstate[2]
897 speed = self.getLower(speed, config.seek.speeds_forward.value)
899 self.setSeekState(self.makeStateForward(speed))
901 self.setSeekState(self.SEEK_STATE_PLAY)
902 elif self.isStateBackward(self.seekstate):
903 speed = -self.seekstate[1]
904 if self.seekstate[2]:
905 speed /= self.seekstate[2]
906 speed = self.getHigher(speed, config.seek.speeds_backward.value) or config.seek.speeds_backward.value[-1]
907 self.setSeekState(self.makeStateBackward(speed))
908 elif self.isStateSlowMotion(self.seekstate):
909 speed = self.getHigher(self.seekstate[2], config.seek.speeds_slowmotion.value)
911 self.setSeekState(self.makeStateSlowMotion(speed))
913 self.setSeekState(self.SEEK_STATE_PAUSE)
915 def seekFwdManual(self):
916 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
918 def fwdSeekTo(self, minutes):
919 print "Seek", minutes, "minutes forward"
920 self.doSeekRelative(minutes * 60 * 90000)
922 def seekBackManual(self):
923 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
925 def rwdSeekTo(self, minutes):
927 self.doSeekRelative(-minutes * 60 * 90000)
929 def checkSkipShowHideLock(self):
930 wantlock = self.seekstate != self.SEEK_STATE_PLAY
932 if config.usage.show_infobar_on_skip.value:
933 if self.lockedBecauseOfSkipping and not wantlock:
935 self.lockedBecauseOfSkipping = False
937 if wantlock and not self.lockedBecauseOfSkipping:
939 self.lockedBecauseOfSkipping = True
941 def calcRemainingTime(self):
942 seekable = self.getSeek()
943 if seekable is not None:
944 len = seekable.getLength()
946 tmp = self.cueGetEndCutPosition()
951 pos = seekable.getPlayPosition()
952 speednom = self.seekstate[1] or 1
953 speedden = self.seekstate[2] or 1
954 if not len[0] and not pos[0]:
957 time = (len[1] - pos[1])*speedden/(90*speednom)
962 if self.eofState == 0 and self.seekstate != self.SEEK_STATE_EOF:
964 time = self.calcRemainingTime()
966 time = 3000 # Failed to calc, use default
968 time = 300 # Passed end, shortest wait
970 self.eofState = -2 # Too long, block eof
973 time += 1000 # Add margin
974 self.eofTimer.start(time, True)
976 def inhibitEof(self):
977 if self.eofState >= 1:
978 self.eofState = -self.eofState
983 if self.seekstate == self.SEEK_STATE_EOF:
985 if self.eofState == -2 or self.isStateBackward(self.seekstate):
989 # if we are seeking, we try to end up ~1s before the end, and pause there.
990 eofstate = self.eofState
991 seekstate = self.seekstate
993 if not self.seekstate == self.SEEK_STATE_PAUSE:
994 self.setSeekState(self.SEEK_STATE_EOF)
995 if eofstate == -1 or not seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
996 seekable = self.getSeek()
997 if seekable is not None:
999 if eofstate == 1 and seekstate == self.SEEK_STATE_PLAY:
1000 self.doEofInternal(True)
1002 self.doEofInternal(False)
1004 def doEofInternal(self, playing):
1005 pass # Defined in subclasses
1008 self.setSeekState(self.SEEK_STATE_PLAY)
1011 from Screens.PVRState import PVRState, TimeshiftState
1013 class InfoBarPVRState:
1014 def __init__(self, screen=PVRState):
1015 self.onPlayStateChanged.append(self.__playStateChanged)
1016 self.pvrStateDialog = self.session.instantiateDialog(screen)
1017 self.onShow.append(self._mayShow)
1018 self.onHide.append(self.pvrStateDialog.hide)
1021 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
1022 self.pvrStateDialog.show()
1024 def __playStateChanged(self, state):
1025 playstateString = state[3]
1026 self.pvrStateDialog["state"].setText(playstateString)
1029 class InfoBarTimeshiftState(InfoBarPVRState):
1031 InfoBarPVRState.__init__(self, screen=TimeshiftState)
1034 if self.execing and self.timeshift_enabled:
1035 self.pvrStateDialog.show()
1037 class InfoBarShowMovies:
1039 # i don't really like this class.
1040 # it calls a not further specified "movie list" on up/down/movieList,
1041 # so this is not more than an action map
1043 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
1045 "movieList": (self.showMovies, _("movie list")),
1046 "up": (self.showMovies, _("movie list")),
1047 "down": (self.showMovies, _("movie list"))
1050 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
1054 # Timeshift works the following way:
1055 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
1056 # - normal playback TUNER unused PLAY enable disable disable
1057 # - user presses "yellow" button. FILE record PAUSE enable disable enable
1058 # - user presess pause again FILE record PLAY enable disable enable
1059 # - user fast forwards FILE record FF enable disable enable
1060 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
1061 # - user backwards FILE record BACK # !! enable disable enable
1065 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1066 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1067 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1068 # - the user can now PVR around
1069 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1070 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1072 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1073 # - if the user rewinds, or press pause, timeshift will be activated again
1075 # note that a timeshift can be enabled ("recording") and
1076 # activated (currently time-shifting).
1078 class InfoBarTimeshift:
1080 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1082 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1083 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1085 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1087 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1088 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1089 }, prio=-1) # priority over record
1091 self.timeshift_enabled = 0
1092 self.timeshift_state = 0
1093 self.ts_rewind_timer = eTimer()
1094 self.ts_rewind_timer.callback.append(self.rewindService)
1096 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1098 iPlayableService.evStart: self.__serviceStarted,
1099 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1102 def getTimeshift(self):
1103 service = self.session.nav.getCurrentService()
1104 return service and service.timeshift()
1106 def startTimeshift(self):
1107 print "enable timeshift"
1108 ts = self.getTimeshift()
1110 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1111 print "no ts interface"
1114 if self.timeshift_enabled:
1115 print "hu, timeshift already enabled?"
1117 if not ts.startTimeshift():
1118 self.timeshift_enabled = 1
1120 # we remove the "relative time" for now.
1121 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1124 #self.setSeekState(self.SEEK_STATE_PAUSE)
1125 self.activateTimeshiftEnd(False)
1127 # enable the "TimeshiftEnableActions", which will override
1128 # the startTimeshift actions
1129 self.__seekableStatusChanged()
1131 print "timeshift failed"
1133 def stopTimeshift(self):
1134 if not self.timeshift_enabled:
1136 print "disable timeshift"
1137 ts = self.getTimeshift()
1140 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1142 def stopTimeshiftConfirmed(self, confirmed):
1146 ts = self.getTimeshift()
1151 self.timeshift_enabled = 0
1154 self.__seekableStatusChanged()
1156 # activates timeshift, and seeks to (almost) the end
1157 def activateTimeshiftEnd(self, back = True):
1158 ts = self.getTimeshift()
1159 print "activateTimeshiftEnd"
1164 if ts.isTimeshiftActive():
1165 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1169 ts.activateTimeshift() # activate timeshift will automatically pause
1170 self.setSeekState(self.SEEK_STATE_PAUSE)
1173 self.doSeek(-5) # seek some gops before end
1174 self.ts_rewind_timer.start(200, 1)
1176 self.doSeek(-1) # seek 1 gop before end
1178 def rewindService(self):
1179 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1181 # same as activateTimeshiftEnd, but pauses afterwards.
1182 def activateTimeshiftEndAndPause(self):
1183 print "activateTimeshiftEndAndPause"
1184 #state = self.seekstate
1185 self.activateTimeshiftEnd(False)
1187 def __seekableStatusChanged(self):
1190 print "self.isSeekable", self.isSeekable()
1191 print "self.timeshift_enabled", self.timeshift_enabled
1193 # when this service is not seekable, but timeshift
1194 # is enabled, this means we can activate
1196 if not self.isSeekable() and self.timeshift_enabled:
1199 print "timeshift activate:", enabled
1200 self["TimeshiftActivateActions"].setEnabled(enabled)
1202 def __serviceStarted(self):
1203 self.timeshift_enabled = False
1204 self.__seekableStatusChanged()
1206 from Screens.PiPSetup import PiPSetup
1208 class InfoBarExtensions:
1209 EXTENSION_SINGLE = 0
1215 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1217 "extensions": (self.showExtensionSelection, _("view extensions...")),
1220 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1221 self.list.append((type, extension, key))
1223 def updateExtension(self, extension, key = None):
1224 self.extensionsList.append(extension)
1226 if self.extensionKeys.has_key(key):
1230 for x in self.availableKeys:
1231 if not self.extensionKeys.has_key(x):
1236 self.extensionKeys[key] = len(self.extensionsList) - 1
1238 def updateExtensions(self):
1239 self.extensionsList = []
1240 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1241 self.extensionKeys = {}
1243 if x[0] == self.EXTENSION_SINGLE:
1244 self.updateExtension(x[1], x[2])
1247 self.updateExtension(y[0], y[1])
1250 def showExtensionSelection(self):
1251 self.updateExtensions()
1252 extensionsList = self.extensionsList[:]
1255 for x in self.availableKeys:
1256 if self.extensionKeys.has_key(x):
1257 entry = self.extensionKeys[x]
1258 extension = self.extensionsList[entry]
1260 name = str(extension[0]())
1261 list.append((extension[0](), extension))
1263 extensionsList.remove(extension)
1265 extensionsList.remove(extension)
1266 for x in extensionsList:
1267 list.append((x[0](), x))
1268 keys += [""] * len(extensionsList)
1269 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1271 def extensionCallback(self, answer):
1272 if answer is not None:
1275 from Tools.BoundFunction import boundFunction
1277 # depends on InfoBarExtensions
1278 from Components.PluginComponent import plugins
1280 class InfoBarPlugins:
1282 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1284 def getPluginName(self, name):
1287 def getPluginList(self):
1289 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1290 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1293 def runPlugin(self, plugin):
1294 plugin(session = self.session, servicelist = self.servicelist)
1296 # depends on InfoBarExtensions
1297 class InfoBarSleepTimer:
1299 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1301 def available(self):
1304 def getSleepTimerName(self):
1305 return _("Sleep Timer")
1307 def showSleepTimerSetup(self):
1308 self.session.open(SleepTimerEdit)
1310 # depends on InfoBarExtensions
1313 self.session.pipshown = False
1314 if SystemInfo.get("NumVideoDecoders", 1) > 1:
1315 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1316 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1317 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1319 def available(self):
1320 return SystemInfo.get("NumVideoDecoders", 1) > 1
1323 return self.session.pipshown
1325 def pipHandles0Action(self):
1326 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1328 def getShowHideName(self):
1329 if self.session.pipshown:
1330 return _("Disable Picture in Picture")
1332 return _("Activate Picture in Picture")
1334 def getSwapName(self):
1335 return _("Swap Services")
1337 def getMoveName(self):
1338 return _("Move Picture in Picture")
1341 if self.session.pipshown:
1342 del self.session.pip
1343 self.session.pipshown = False
1345 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1346 self.session.pip.show()
1347 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1348 if self.session.pip.playService(newservice):
1349 self.session.pipshown = True
1350 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1352 self.session.pipshown = False
1353 del self.session.pip
1354 self.session.nav.playService(newservice)
1357 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1358 if self.session.pip.servicePath:
1359 servicepath = self.servicelist.getCurrentServicePath()
1360 ref=servicepath[len(servicepath)-1]
1361 pipref=self.session.pip.getCurrentService()
1362 self.session.pip.playService(swapservice)
1363 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1364 if pipref.toString() != ref.toString(): # is a subservice ?
1365 self.session.nav.stopService() # stop portal
1366 self.session.nav.playService(pipref) # start subservice
1367 self.session.pip.servicePath=servicepath
1370 self.session.open(PiPSetup, pip = self.session.pip)
1372 def pipDoHandle0Action(self):
1373 use = config.usage.pip_zero_button.value
1376 elif "swapstop" == use:
1382 from RecordTimer import parseEvent
1384 class InfoBarInstantRecord:
1385 """Instant Record - handles the instantRecord action in order to
1386 start/stop instant records"""
1388 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1390 "instantRecord": (self.instantRecord, _("Instant Record...")),
1393 #### DEPRECATED CODE ####
1394 self["BlinkingPoint"] = BlinkingPixmapConditional()
1395 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1396 self["BlinkingPoint"].deprecationInfo = (
1397 "session.RecordState source, Pixmap renderer and "
1398 "ConditionalShowHide/Blink Converter", "2008-02")
1399 #########################
1401 def stopCurrentRecording(self, entry = -1):
1402 if entry is not None and entry != -1:
1403 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1404 self.recording.remove(self.recording[entry])
1406 def startInstantRecording(self, limitEvent = False):
1407 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1409 # try to get event info
1412 service = self.session.nav.getCurrentService()
1413 epg = eEPGCache.getInstance()
1414 event = epg.lookupEventTime(serviceref, -1, 0)
1416 info = service.info()
1417 ev = info.getEvent(0)
1423 end = time() + 3600 * 10
1424 name = "instant record"
1428 if event is not None:
1429 curEvent = parseEvent(event)
1431 description = curEvent[3]
1432 eventid = curEvent[4]
1437 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1439 data = (begin, end, name, description, eventid)
1441 recording = self.session.nav.recordWithTimer(serviceref, *data)
1442 recording.dontSave = True
1443 self.recording.append(recording)
1445 #### DEPRECATED CODE ####
1446 self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1447 #########################
1449 def isInstantRecordRunning(self):
1450 print "self.recording:", self.recording
1451 if len(self.recording) > 0:
1452 for x in self.recording:
1457 def recordQuestionCallback(self, answer):
1458 print "pre:\n", self.recording
1460 if answer is None or answer[1] == "no":
1463 recording = self.recording[:]
1465 if not x in self.session.nav.RecordTimer.timer_list:
1466 self.recording.remove(x)
1467 elif x.dontSave and x.isRunning():
1468 list.append((x, False))
1470 if answer[1] == "changeduration":
1471 if len(self.recording) == 1:
1472 self.changeDuration(0)
1474 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1475 elif answer[1] == "changeendtime":
1476 if len(self.recording) == 1:
1479 self.session.openWithCallback(self.setEndtime, TimerSelection, list)
1480 elif answer[1] == "stop":
1481 if len(self.recording) == 1:
1482 self.stopCurrentRecording(0)
1484 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1485 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1486 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1487 if answer[1] == "manualduration":
1488 self.changeDuration(len(self.recording)-1)
1489 elif answer[1] == "manualendtime":
1490 self.setEndtime(len(self.recording)-1)
1491 print "after:\n", self.recording
1493 def setEndtime(self, entry):
1494 if entry is not None:
1495 self.selectedEntry = entry
1496 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1497 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1498 dlg.setTitle(_("Please change recording endtime"))
1500 def TimeDateInputClosed(self, ret):
1503 localendtime = localtime(ret[1])
1504 print "stopping recording at", strftime("%c", localendtime)
1505 self.recording[self.selectedEntry].end = ret[1]
1506 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1508 def changeDuration(self, entry):
1509 if entry is not None:
1510 self.selectedEntry = entry
1511 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1513 def inputCallback(self, value):
1514 if value is not None:
1515 print "stopping recording after", int(value), "minutes."
1516 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1517 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1519 def instantRecord(self):
1521 stat = os_stat(resolveFilename(SCOPE_HDD))
1523 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1526 if self.isInstantRecordRunning():
1527 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1528 title=_("A recording is currently running.\nWhat do you want to do?"), \
1529 list=[(_("stop recording"), "stop"), \
1530 (_("change recording (duration)"), "changeduration"), \
1531 (_("change recording (endtime)"), "changeendtime"), \
1532 (_("add recording (indefinitely)"), "indefinitely"), \
1533 (_("add recording (stop after current event)"), "event"), \
1534 (_("add recording (enter recording duration)"), "manualduration"), \
1535 (_("add recording (enter recording endtime)"), "manualendtime"), \
1536 (_("do nothing"), "no")])
1538 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1539 title=_("Start recording?"), \
1540 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1541 (_("add recording (stop after current event)"), "event"), \
1542 (_("add recording (enter recording duration)"), "manualduration"), \
1543 (_("add recording (enter recording endtime)"), "manualendtime"), \
1544 (_("don't record"), "no")])
1546 from Tools.ISO639 import LanguageCodes
1548 class InfoBarAudioSelection:
1550 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1552 "audioSelection": (self.audioSelection, _("Audio Options...")),
1555 def audioSelection(self):
1556 service = self.session.nav.getCurrentService()
1557 audio = service and service.audioTracks()
1558 self.audioTracks = audio
1559 n = audio and audio.getNumberOfTracks() or 0
1560 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1563 self.audioChannel = service.audioChannel()
1566 i = audio.getTrackInfo(x)
1567 language = i.getLanguage()
1568 description = i.getDescription()
1570 if LanguageCodes.has_key(language):
1571 language = LanguageCodes[language][0]
1573 if len(description):
1574 description += " (" + language + ")"
1576 description = language
1578 tlist.append((description, x))
1580 selectedAudio = audio.getCurrentTrack()
1581 tlist.sort(key=lambda x: x[0])
1585 if x[1] != selectedAudio:
1590 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1591 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1593 del self.audioTracks
1595 def audioSelected(self, audio):
1596 if audio is not None:
1597 if isinstance(audio[1], str):
1598 if audio[1] == "mode":
1599 keys = ["red", "green", "yellow"]
1600 selection = self.audioChannel.getCurrentChannel()
1601 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1602 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1604 del self.audioChannel
1605 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1606 self.audioTracks.selectTrack(audio[1])
1608 del self.audioChannel
1609 del self.audioTracks
1611 def modeSelected(self, mode):
1612 if mode is not None:
1613 self.audioChannel.selectChannel(mode[1])
1614 del self.audioChannel
1616 class InfoBarSubserviceSelection:
1618 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1620 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1623 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1625 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1626 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1628 self["SubserviceQuickzapAction"].setEnabled(False)
1630 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1634 def checkSubservicesAvail(self, ev):
1635 if ev == iPlayableService.evUpdatedEventInfo:
1636 service = self.session.nav.getCurrentService()
1637 subservices = service and service.subServices()
1638 if not subservices or subservices.getNumberOfSubservices() == 0:
1639 self["SubserviceQuickzapAction"].setEnabled(False)
1641 def nextSubservice(self):
1642 self.changeSubservice(+1)
1644 def prevSubservice(self):
1645 self.changeSubservice(-1)
1647 def changeSubservice(self, direction):
1648 service = self.session.nav.getCurrentService()
1649 subservices = service and service.subServices()
1650 n = subservices and subservices.getNumberOfSubservices()
1653 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1655 if subservices.getSubservice(x).toString() == ref.toString():
1658 selection += direction
1663 newservice = subservices.getSubservice(selection)
1664 if newservice.valid():
1667 self.session.nav.playService(newservice)
1669 def subserviceSelection(self):
1670 service = self.session.nav.getCurrentService()
1671 subservices = service and service.subServices()
1672 self.bouquets = self.servicelist.getBouquetList()
1673 n = subservices and subservices.getNumberOfSubservices()
1676 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1679 i = subservices.getSubservice(x)
1680 if i.toString() == ref.toString():
1682 tlist.append((i.getName(), i))
1684 if self.bouquets and len(self.bouquets):
1685 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1686 if config.usage.multibouquet.value:
1687 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1689 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1692 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1693 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1696 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1698 def subserviceSelected(self, service):
1700 if not service is None:
1701 if isinstance(service[1], str):
1702 if service[1] == "quickzap":
1703 from Screens.SubservicesQuickzap import SubservicesQuickzap
1704 self.session.open(SubservicesQuickzap, service[2])
1706 self["SubserviceQuickzapAction"].setEnabled(True)
1707 self.session.nav.playService(service[1])
1709 def addSubserviceToBouquetCallback(self, service):
1710 if len(service) > 1 and isinstance(service[1], eServiceReference):
1711 self.selectedSubservice = service
1712 if self.bouquets is None:
1715 cnt = len(self.bouquets)
1716 if cnt > 1: # show bouquet list
1717 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1718 elif cnt == 1: # add to only one existing bouquet
1719 self.addSubserviceToBouquet(self.bouquets[0][1])
1720 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1722 def bouquetSelClosed(self, confirmed):
1724 del self.selectedSubservice
1726 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1728 def addSubserviceToBouquet(self, dest):
1729 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1731 self.bsel.close(True)
1733 del self.selectedSubservice
1735 class InfoBarAdditionalInfo:
1738 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1739 self["TimeshiftPossible"] = self["RecordingPossible"]
1740 self["ExtensionsAvailable"] = Boolean(fixed=1)
1742 ######### DEPRECATED CODE ##########
1743 self["NimA"] = Pixmap()
1744 self["NimA"].deprecationInfo = (
1745 "session.TunerInfo source, Pixmap renderer, TunerInfo/UseMask Converter"
1746 ", ValueBitTest(1) Converter and ConditionalShowHide Converter", "2008-02")
1747 self["NimB"] = Pixmap()
1748 self["NimB"].deprecationInfo = (
1749 "session.TunerInfo source, Pixmap renderer, TunerInfo/UseMask Converter"
1750 ", ValueBitTest(2) Converter and ConditionalShowHide Converter", "2008-02")
1751 self["NimA_Active"] = Pixmap()
1752 self["NimA_Active"].deprecationInfo = (
1753 "session.FrontendInfo source, Pixmap renderer, FrontendInfo/NUMBER Converter"
1754 ", ValueRange(1,1) Converter and ConditionalShowHide Converter", "2008-02")
1755 self["NimB_Active"] = Pixmap()
1756 self["NimB_Active"].deprecationInfo = (
1757 "session.FrontendInfo source, Pixmap renderer, FrontendInfo/NUMBER Converter"
1758 ", ValueRange(1,1) Converter and ConditionalShowHide Converter", "2008-02")
1760 res_mgr = eDVBResourceManager.getInstance()
1762 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1764 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1766 def tunerUseMaskChanged(self, mask):
1768 self["NimA_Active"].show()
1770 self["NimA_Active"].hide()
1772 self["NimB_Active"].show()
1774 self["NimB_Active"].hide()
1776 def checkTunerState(self, service):
1777 info = service and service.frontendInfo()
1778 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1779 if feNumber is None:
1789 def gotServiceEvent(self, ev):
1790 service = self.session.nav.getCurrentService()
1791 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1792 self.checkTunerState(service)
1793 ####################################
1795 class InfoBarNotifications:
1797 self.onExecBegin.append(self.checkNotifications)
1798 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1799 self.onClose.append(self.__removeNotification)
1801 def __removeNotification(self):
1802 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1804 def checkNotificationsIfExecing(self):
1806 self.checkNotifications()
1808 def checkNotifications(self):
1809 if len(Notifications.notifications):
1810 n = Notifications.notifications[0]
1812 Notifications.notifications = Notifications.notifications[1:]
1815 if n[3].has_key("onSessionOpenCallback"):
1816 n[3]["onSessionOpenCallback"]()
1817 del n[3]["onSessionOpenCallback"]
1820 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1822 dlg = self.session.open(n[1], *n[2], **n[3])
1824 # remember that this notification is currently active
1826 Notifications.current_notifications.append(d)
1827 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1829 def __notificationClosed(self, d):
1830 Notifications.current_notifications.remove(d)
1832 class InfoBarServiceNotifications:
1834 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1836 iPlayableService.evEnd: self.serviceHasEnded
1839 def serviceHasEnded(self):
1840 print "service end!"
1843 self.setSeekState(self.SEEK_STATE_PLAY)
1847 class InfoBarCueSheetSupport:
1853 ENABLE_RESUME_SUPPORT = False
1855 def __init__(self, actionmap = "InfobarCueSheetActions"):
1856 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1858 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1859 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1860 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1864 self.is_closing = False
1865 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1867 iPlayableService.evStart: self.__serviceStarted,
1870 def __serviceStarted(self):
1873 print "new service started! trying to download cuts!"
1874 self.downloadCuesheet()
1876 if self.ENABLE_RESUME_SUPPORT:
1879 for (pts, what) in self.cut_list:
1880 if what == self.CUT_TYPE_LAST:
1883 if last is not None:
1884 self.resume_point = last
1885 if config.usage.on_movie_start.value == "ask":
1886 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1887 elif config.usage.on_movie_start.value == "resume":
1888 # TRANSLATORS: The string "Resuming playback" flashes for a moment
1889 # TRANSLATORS: at the start of a movie, when the user has selected
1890 # TRANSLATORS: "Resume from last position" as start behavior.
1891 # TRANSLATORS: The purpose is to notify the user that the movie starts
1892 # TRANSLATORS: in the middle somewhere and not from the beginning.
1893 # TRANSLATORS: (Some translators seem to have interpreted it as a
1894 # TRANSLATORS: question or a choice, but it is a statement.)
1895 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Resuming playback"), timeout=2, type=MessageBox.TYPE_INFO)
1897 def playLastCB(self, answer):
1899 self.doSeek(self.resume_point)
1900 self.hideAfterResume()
1902 def hideAfterResume(self):
1903 if isinstance(self, InfoBarShowHide):
1906 def __getSeekable(self):
1907 service = self.session.nav.getCurrentService()
1910 return service.seek()
1912 def cueGetCurrentPosition(self):
1913 seek = self.__getSeekable()
1916 r = seek.getPlayPosition()
1921 def cueGetEndCutPosition(self):
1924 for cp in self.cut_list:
1925 if cp[1] == self.CUT_TYPE_OUT:
1929 elif cp[1] == self.CUT_TYPE_IN:
1933 def jumpPreviousNextMark(self, cmp, start=False):
1934 current_pos = self.cueGetCurrentPosition()
1935 if current_pos is None:
1937 mark = self.getNearestCutPoint(current_pos, cmp=cmp, start=start)
1938 if mark is not None:
1946 def jumpPreviousMark(self):
1947 # we add 2 seconds, so if the play position is <2s after
1948 # the mark, the mark before will be used
1949 self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
1951 def jumpNextMark(self):
1952 if not self.jumpPreviousNextMark(lambda x: x):
1955 def getNearestCutPoint(self, pts, cmp=abs, start=False):
1961 bestdiff = cmp(0 - pts)
1963 nearest = [0, False]
1964 for cp in self.cut_list:
1965 if beforecut and cp[1] in [self.CUT_TYPE_IN, self.CUT_TYPE_OUT]:
1967 if cp[1] == self.CUT_TYPE_IN: # Start is here, disregard previous marks
1968 diff = cmp(cp[0] - pts)
1974 if cp[1] in [self.CUT_TYPE_MARK, self.CUT_TYPE_LAST]:
1975 diff = cmp(cp[0] - pts)
1976 if diff >= 0 and (nearest is None or bestdiff > diff):
1981 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1982 current_pos = self.cueGetCurrentPosition()
1983 if current_pos is None:
1984 print "not seekable"
1987 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1989 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1991 return nearest_cutpoint
1993 self.removeMark(nearest_cutpoint)
1994 elif not onlyremove and not onlyreturn:
1995 self.addMark((current_pos, self.CUT_TYPE_MARK))
2000 def addMark(self, point):
2001 insort(self.cut_list, point)
2002 self.uploadCuesheet()
2003 self.showAfterCuesheetOperation()
2005 def removeMark(self, point):
2006 self.cut_list.remove(point)
2007 self.uploadCuesheet()
2008 self.showAfterCuesheetOperation()
2010 def showAfterCuesheetOperation(self):
2011 if isinstance(self, InfoBarShowHide):
2014 def __getCuesheet(self):
2015 service = self.session.nav.getCurrentService()
2018 return service.cueSheet()
2020 def uploadCuesheet(self):
2021 cue = self.__getCuesheet()
2024 print "upload failed, no cuesheet interface"
2026 cue.setCutList(self.cut_list)
2028 def downloadCuesheet(self):
2029 cue = self.__getCuesheet()
2032 print "download failed, no cuesheet interface"
2035 self.cut_list = cue.getCutList()
2037 class InfoBarSummary(Screen):
2039 <screen position="0,0" size="132,64">
2040 <widget source="global.CurrentTime" render="Label" position="62,46" size="82,18" font="Regular;16" >
2041 <convert type="ClockToText">WithSeconds</convert>
2043 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="82,18" zPosition="1" >
2044 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2045 <convert type="ConditionalShowHide">Blink</convert>
2047 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2048 <convert type="ServiceName">Name</convert>
2050 <widget source="session.Event_Now" render="Progress" position="6,46" size="46,18" borderWidth="1" >
2051 <convert type="EventTime">Progress</convert>
2055 # for picon: (path="piconlcd" will use LCD picons)
2056 # <widget source="session.CurrentService" render="Picon" position="6,0" size="120,64" path="piconlcd" >
2057 # <convert type="ServiceName">Reference</convert>
2060 def __init__(self, session, parent):
2061 Screen.__init__(self, session, parent = parent)
2063 class InfoBarSummarySupport:
2067 def createSummary(self):
2068 return InfoBarSummary
2070 class InfoBarMoviePlayerSummary(Screen):
2072 <screen position="0,0" size="132,64">
2073 <widget source="global.CurrentTime" render="Label" position="62,46" size="64,18" font="Regular;16" halign="right" >
2074 <convert type="ClockToText">WithSeconds</convert>
2076 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="64,18" zPosition="1" >
2077 <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2078 <convert type="ConditionalShowHide">Blink</convert>
2080 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2081 <convert type="ServiceName">Name</convert>
2083 <widget source="session.CurrentService" render="Progress" position="6,46" size="56,18" borderWidth="1" >
2084 <convert type="ServicePosition">Position</convert>
2088 def __init__(self, session, parent):
2089 Screen.__init__(self, session)
2091 class InfoBarMoviePlayerSummarySupport:
2095 def createSummary(self):
2096 return InfoBarMoviePlayerSummary
2098 class InfoBarTeletextPlugin:
2100 self.teletext_plugin = None
2102 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
2103 self.teletext_plugin = p
2105 if self.teletext_plugin is not None:
2106 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
2108 "startTeletext": (self.startTeletext, _("View teletext..."))
2111 print "no teletext plugin found!"
2113 def startTeletext(self):
2114 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
2116 class InfoBarSubtitleSupport(object):
2118 object.__init__(self)
2119 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
2120 self.__subtitles_enabled = False
2122 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2124 iPlayableService.evEnd: self.__serviceStopped,
2125 iPlayableService.evUpdatedInfo: self.__updatedInfo
2127 self.cached_subtitle_checked = False
2128 self.__selected_subtitle = None
2130 def __serviceStopped(self):
2131 self.subtitle_window.hide()
2132 self.__subtitles_enabled = False
2133 self.cached_subtitle_checked = False
2135 def __updatedInfo(self):
2136 if not self.cached_subtitle_checked:
2137 subtitle = self.getCurrentServiceSubtitle()
2138 self.cached_subtitle_checked = True
2139 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
2140 if self.__selected_subtitle:
2141 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2142 self.subtitle_window.show()
2143 self.__subtitles_enabled = True
2145 def getCurrentServiceSubtitle(self):
2146 service = self.session.nav.getCurrentService()
2147 return service and service.subtitle()
2149 def setSubtitlesEnable(self, enable=True):
2150 subtitle = self.getCurrentServiceSubtitle()
2151 if enable and self.__selected_subtitle is not None:
2152 if subtitle and not self.__subtitles_enabled:
2153 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2154 self.subtitle_window.show()
2155 self.__subtitles_enabled = True
2158 subtitle.disableSubtitles(self.subtitle_window.instance)
2159 self.__subtitles_enabled = False
2160 self.subtitle_window.hide()
2162 def setSelectedSubtitle(self, subtitle):
2163 self.__selected_subtitle = subtitle
2165 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
2166 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
2168 class InfoBarServiceErrorPopupSupport:
2170 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2172 iPlayableService.evTuneFailed: self.__tuneFailed,
2173 iPlayableService.evStart: self.__serviceStarted
2175 self.__serviceStarted()
2177 def __serviceStarted(self):
2178 self.last_error = None
2179 Notifications.RemovePopup(id = "ZapError")
2181 def __tuneFailed(self):
2182 service = self.session.nav.getCurrentService()
2183 info = service and service.info()
2184 error = info and info.getInfo(iServiceInformation.sDVBState)
2186 if error == self.last_error:
2189 self.last_error = error
2192 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2193 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2194 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2195 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2196 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2197 eDVBServicePMTHandler.eventNewProgramInfo: None,
2198 eDVBServicePMTHandler.eventTuned: None,
2199 eDVBServicePMTHandler.eventSOF: None,
2200 eDVBServicePMTHandler.eventEOF: None,
2201 eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
2204 error = errors.get(error) #this returns None when the key not exist in the dict
2206 if error is not None:
2207 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2209 Notifications.RemovePopup(id = "ZapError")