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 *
9 from Components.Pixmap import Pixmap, PixmapConditional
10 from Components.PluginComponent import plugins
11 from Components.ProgressBar import *
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.Sources.CurrentService import CurrentService
14 from Components.Sources.EventInfo import EventInfo
15 from Components.Sources.FrontendStatus import FrontendStatus
16 from Components.Sources.Boolean import Boolean
17 from Components.Sources.Clock import Clock
18 from Components.TimerList import TimerEntryComponent
19 from Components.config import config, ConfigBoolean, ConfigClock
20 from EpgSelection import EPGSelection
21 from Plugins.Plugin import PluginDescriptor
23 from Screen import Screen
24 from Screens.ChoiceBox import ChoiceBox
25 from Screens.Dish import Dish
26 from Screens.EventView import EventViewEPGSelect, EventViewSimple
27 from Screens.InputBox import InputBox
28 from Screens.MessageBox import MessageBox
29 from Screens.MinuteInput import MinuteInput
30 from Screens.TimerSelection import TimerSelection
31 from Screens.PictureInPicture import PictureInPicture
32 from Screens.SubtitleDisplay import SubtitleDisplay
33 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
34 from Screens.SleepTimerEdit import SleepTimerEdit
35 from Screens.TimeDateInput import TimeDateInput
36 from ServiceReference import ServiceReference
38 from Tools import Notifications
39 from Tools.Directories import SCOPE_HDD, resolveFilename
41 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
42 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
44 from time import time, localtime, strftime
45 from os import stat as os_stat
46 from bisect import insort
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
69 }, 1) # lower prio to make it possible to override ok and cancel..
71 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
73 iPlayableService.evStart: self.serviceStarted,
76 self.__state = self.STATE_SHOWN
79 self.hideTimer = eTimer()
80 self.hideTimer.timeout.get().append(self.doTimerHide)
81 self.hideTimer.start(5000, True)
83 self.onShow.append(self.__onShow)
84 self.onHide.append(self.__onHide)
86 def serviceStarted(self):
88 if config.usage.show_infobar_on_zap.value:
92 self.__state = self.STATE_SHOWN
95 def startHideTimer(self):
96 if self.__state == self.STATE_SHOWN and not self.__locked:
97 idx = config.usage.infobar_timeout.index
99 self.hideTimer.start(idx*1000, True)
102 self.__state = self.STATE_HIDDEN
106 self.startHideTimer()
108 def doTimerHide(self):
109 self.hideTimer.stop()
110 if self.__state == self.STATE_SHOWN:
113 def toggleShow(self):
114 if self.__state == self.STATE_SHOWN:
116 self.hideTimer.stop()
117 elif self.__state == self.STATE_HIDDEN:
121 self.__locked = self.__locked + 1
124 self.hideTimer.stop()
126 def unlockShow(self):
127 self.__locked = self.__locked - 1
129 self.startHideTimer()
131 # def startShow(self):
132 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
133 # self.__state = self.STATE_SHOWN
135 # def startHide(self):
136 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
137 # self.__state = self.STATE_HIDDEN
139 class NumberZap(Screen):
146 self.close(int(self["number"].getText()))
148 def keyNumberGlobal(self, number):
149 self.Timer.start(3000, True) #reset timer
150 self.field = self.field + str(number)
151 self["number"].setText(self.field)
152 if len(self.field) >= 4:
155 def __init__(self, session, number):
156 Screen.__init__(self, session)
157 self.field = str(number)
159 self["channel"] = Label(_("Channel:"))
161 self["number"] = Label(self.field)
163 self["actions"] = NumberActionMap( [ "SetupActions" ],
167 "1": self.keyNumberGlobal,
168 "2": self.keyNumberGlobal,
169 "3": self.keyNumberGlobal,
170 "4": self.keyNumberGlobal,
171 "5": self.keyNumberGlobal,
172 "6": self.keyNumberGlobal,
173 "7": self.keyNumberGlobal,
174 "8": self.keyNumberGlobal,
175 "9": self.keyNumberGlobal,
176 "0": self.keyNumberGlobal
179 self.Timer = eTimer()
180 self.Timer.timeout.get().append(self.keyOK)
181 self.Timer.start(3000, True)
183 class InfoBarNumberZap:
184 """ Handles an initial number for NumberZapping """
186 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
188 "1": self.keyNumberGlobal,
189 "2": self.keyNumberGlobal,
190 "3": self.keyNumberGlobal,
191 "4": self.keyNumberGlobal,
192 "5": self.keyNumberGlobal,
193 "6": self.keyNumberGlobal,
194 "7": self.keyNumberGlobal,
195 "8": self.keyNumberGlobal,
196 "9": self.keyNumberGlobal,
197 "0": self.keyNumberGlobal,
200 def keyNumberGlobal(self, number):
201 # print "You pressed number " + str(number)
203 self.servicelist.recallPrevService()
205 self.session.openWithCallback(self.numberEntered, NumberZap, number)
207 def numberEntered(self, retval):
208 # print self.servicelist
210 self.zapToNumber(retval)
212 def searchNumberHelper(self, serviceHandler, num, bouquet):
213 servicelist = serviceHandler.list(bouquet)
214 if not servicelist is None:
216 serviceIterator = servicelist.getNext()
217 if not serviceIterator.valid(): #check end of list
219 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
222 if not num: #found service with searched number ?
223 return serviceIterator, 0
226 def zapToNumber(self, number):
227 bouquet = self.servicelist.bouquet_root
229 serviceHandler = eServiceCenter.getInstance()
230 if not config.usage.multibouquet.value:
231 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
233 bouquetlist = serviceHandler.list(bouquet)
234 if not bouquetlist is None:
236 bouquet = bouquetlist.getNext()
237 if not bouquet.valid(): #check end of list
239 if bouquet.flags & eServiceReference.isDirectory:
240 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
241 if not service is None:
242 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
243 self.servicelist.clearPath()
244 if self.servicelist.bouquet_root != bouquet:
245 self.servicelist.enterPath(self.servicelist.bouquet_root)
246 self.servicelist.enterPath(bouquet)
247 self.servicelist.setCurrentSelection(service) #select the service in servicelist
248 self.servicelist.zap()
250 config.misc.initialchannelselection = ConfigBoolean(default = True)
252 class InfoBarChannelSelection:
253 """ ChannelSelection - handles the channelSelection dialog and the initial
254 channelChange actions which open the channelSelection dialog """
257 self.servicelist = self.session.instantiateDialog(ChannelSelection)
259 if config.misc.initialchannelselection.value:
260 self.onShown.append(self.firstRun)
262 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
264 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
265 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
266 "zapUp": (self.zapUp, _("previous channel")),
267 "zapDown": (self.zapDown, _("next channel")),
268 "historyBack": (self.historyBack, _("previous channel in history")),
269 "historyNext": (self.historyNext, _("next channel in history")),
270 "openServiceList": (self.openServiceList, _("open servicelist")),
273 def showTvChannelList(self, zap=False):
274 self.servicelist.setModeTv()
276 self.servicelist.zap()
277 self.session.execDialog(self.servicelist)
279 def showRadioChannelList(self, zap=False):
280 self.servicelist.setModeRadio()
282 self.servicelist.zap()
283 self.session.execDialog(self.servicelist)
286 self.onShown.remove(self.firstRun)
287 config.misc.initialchannelselection.value = False
288 config.misc.initialchannelselection.save()
289 self.switchChannelDown()
291 def historyBack(self):
292 self.servicelist.historyBack()
294 def historyNext(self):
295 self.servicelist.historyNext()
297 def switchChannelUp(self):
298 self.servicelist.moveUp()
299 self.session.execDialog(self.servicelist)
301 def switchChannelDown(self):
302 self.servicelist.moveDown()
303 self.session.execDialog(self.servicelist)
305 def openServiceList(self):
306 self.session.execDialog(self.servicelist)
309 if self.servicelist.inBouquet():
310 prev = self.servicelist.getCurrentSelection()
312 prev = prev.toString()
314 if config.usage.quickzap_bouquet_change.value:
315 if self.servicelist.atBegin():
316 self.servicelist.prevBouquet()
317 self.servicelist.moveUp()
318 cur = self.servicelist.getCurrentSelection()
319 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
322 self.servicelist.moveUp()
323 self.servicelist.zap()
326 if self.servicelist.inBouquet():
327 prev = self.servicelist.getCurrentSelection()
329 prev = prev.toString()
331 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
332 self.servicelist.nextBouquet()
334 self.servicelist.moveDown()
335 cur = self.servicelist.getCurrentSelection()
336 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
339 self.servicelist.moveDown()
340 self.servicelist.zap()
343 """ Handles a menu action, to open the (main) menu """
345 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
347 "mainMenu": (self.mainMenu, _("Enter main menu...")),
349 self.session.infobar = None
352 print "loading mainmenu XML..."
353 menu = mdom.childNodes[0]
354 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
356 self.session.infobar = self
357 # so we can access the currently active infobar from screens opened from within the mainmenu
358 # at the moment used from the SubserviceSelection
360 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
362 def mainMenuClosed(self, *val):
363 self.session.infobar = None
365 class InfoBarSimpleEventView:
366 """ Opens the Eventview for now/next """
368 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
370 "showEventInfo": (self.openEventView, _("show event details")),
373 def openEventView(self):
375 service = self.session.nav.getCurrentService()
376 ref = self.session.nav.getCurrentlyPlayingServiceReference()
377 info = service.info()
380 self.epglist.append(ptr)
383 self.epglist.append(ptr)
384 if len(self.epglist) > 0:
385 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
387 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
388 if len(self.epglist) > 1:
389 tmp = self.epglist[0]
390 self.epglist[0]=self.epglist[1]
392 setEvent(self.epglist[0])
395 """ EPG - Opens an EPG list when the showEPGList action fires """
397 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
399 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
402 self.is_now_next = False
404 self.bouquetSel = None
405 self.eventView = None
406 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
408 "showEventInfo": (self.openEventView, _("show EPG...")),
411 def zapToService(self, service):
412 if not service is None:
413 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
414 self.servicelist.clearPath()
415 if self.servicelist.bouquet_root != self.epg_bouquet:
416 self.servicelist.enterPath(self.servicelist.bouquet_root)
417 self.servicelist.enterPath(self.epg_bouquet)
418 self.servicelist.setCurrentSelection(service) #select the service in servicelist
419 self.servicelist.zap()
421 def getBouquetServices(self, bouquet):
423 servicelist = eServiceCenter.getInstance().list(bouquet)
424 if not servicelist is None:
426 service = servicelist.getNext()
427 if not service.valid(): #check if end of list
429 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
431 services.append(ServiceReference(service))
434 def openBouquetEPG(self, bouquet, withCallback=True):
435 services = self.getBouquetServices(bouquet)
437 self.epg_bouquet = bouquet
439 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
441 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
443 def changeBouquetCB(self, direction, epg):
446 self.bouquetSel.down()
449 bouquet = self.bouquetSel.getCurrent()
450 services = self.getBouquetServices(bouquet)
452 self.epg_bouquet = bouquet
453 epg.setServices(services)
455 def closed(self, ret=False):
456 closedScreen = self.dlg_stack.pop()
457 if self.bouquetSel and closedScreen == self.bouquetSel:
458 self.bouquetSel = None
459 elif self.eventView and closedScreen == self.eventView:
460 self.eventView = None
462 dlgs=len(self.dlg_stack)
464 self.dlg_stack[dlgs-1].close(dlgs > 1)
466 def openMultiServiceEPG(self, withCallback=True):
467 bouquets = self.servicelist.getBouquetList()
472 if cnt > 1: # show bouquet list
474 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
475 self.dlg_stack.append(self.bouquetSel)
477 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
479 self.openBouquetEPG(bouquets[0][1], withCallback)
481 def openSingleServiceEPG(self):
482 ref=self.session.nav.getCurrentlyPlayingServiceReference()
483 self.session.open(EPGSelection, ref)
485 def openSimilarList(self, eventid, refstr):
486 self.session.open(EPGSelection, refstr, None, eventid)
488 def getNowNext(self):
490 service = self.session.nav.getCurrentService()
491 info = service and service.info()
492 ptr = info and info.getEvent(0)
494 self.epglist.append(ptr)
495 ptr = info and info.getEvent(1)
497 self.epglist.append(ptr)
499 def __evEventInfoChanged(self):
500 if self.is_now_next and len(self.dlg_stack) == 1:
502 assert self.eventView
503 if len(self.epglist):
504 self.eventView.setEvent(self.epglist[0])
506 def openEventView(self):
507 ref = self.session.nav.getCurrentlyPlayingServiceReference()
509 if len(self.epglist) == 0:
510 self.is_now_next = False
511 epg = eEPGCache.getInstance()
512 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
514 self.epglist.append(ptr)
515 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
517 self.epglist.append(ptr)
519 self.is_now_next = True
520 if len(self.epglist) > 0:
521 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
522 self.dlg_stack.append(self.eventView)
524 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
525 self.openMultiServiceEPG(False)
527 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
528 if len(self.epglist) > 1:
529 tmp = self.epglist[0]
530 self.epglist[0]=self.epglist[1]
532 setEvent(self.epglist[0])
535 """provides a snr/agc/ber display"""
537 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
540 """provides a current/next event info display"""
542 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
543 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
545 class InfoBarRdsDecoder:
546 """provides RDS and Rass support/display"""
548 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
549 self.rass_interactive = None
551 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
553 iPlayableService.evEnd: self.__serviceStopped,
554 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
557 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
559 "startRassInteractive": self.startRassInteractive
562 self["RdsActions"].setEnabled(False)
564 self.onLayoutFinish.append(self.rds_display.show)
565 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
567 def RassInteractivePossibilityChanged(self, state):
568 self["RdsActions"].setEnabled(state)
570 def RassSlidePicChanged(self):
571 if not self.rass_interactive:
572 service = self.session.nav.getCurrentService()
573 decoder = service and service.rdsDecoder()
575 decoder.showRassSlidePicture()
577 def __serviceStopped(self):
578 if self.rass_interactive is not None:
579 rass_interactive = self.rass_interactive
580 self.rass_interactive = None
581 rass_interactive.close()
583 def startRassInteractive(self):
584 self.rds_display.hide()
585 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
587 def RassInteractiveClosed(self, *val):
588 if self.rass_interactive is not None:
589 self.rass_interactive = None
590 self.RassSlidePicChanged()
591 self.rds_display.show()
593 class InfoBarServiceName:
595 self["CurrentService"] = CurrentService(self.session.nav)
598 """handles actions like seeking, pause"""
600 # ispause, isff, issm
601 SEEK_STATE_PLAY = (0, 0, 0, ">")
602 SEEK_STATE_PAUSE = (1, 0, 0, "||")
603 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
604 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
605 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
606 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
607 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
608 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
610 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
611 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
612 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
613 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
615 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
616 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
617 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
619 SEEK_STATE_EOF = (1, 0, 0, "END")
621 def __init__(self, actionmap = "InfobarSeekActions"):
622 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
624 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
625 iPlayableService.evStart: self.__serviceStarted,
627 iPlayableService.evEOF: self.__evEOF,
628 iPlayableService.evSOF: self.__evSOF,
631 class InfoBarSeekActionMap(HelpableActionMap):
632 def __init__(self, screen, *args, **kwargs):
633 HelpableActionMap.__init__(self, screen, *args, **kwargs)
636 def action(self, contexts, action):
637 print "action:", action
638 if action[:5] == "seek:":
639 time = int(action[5:])
640 self.screen.seekRelative(time * 90000)
641 self.screen.showAfterSeek()
644 return HelpableActionMap.action(self, contexts, action)
646 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
648 "playpauseService": (self.playpauseService, _("pause")),
649 "pauseService": (self.pauseService, _("pause")),
650 "unPauseService": (self.unPauseService, _("continue")),
652 "seekFwd": (self.seekFwd, _("skip forward")),
653 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
654 "seekBack": (self.seekBack, _("skip backward")),
655 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
657 # give them a little more priority to win over color buttons
659 self["SeekActions"].setEnabled(False)
661 self.seekstate = self.SEEK_STATE_PLAY
663 self.onPlayStateChanged = [ ]
665 self.lockedBecauseOfSkipping = False
667 self.__seekableStatusChanged()
669 def showAfterSeek(self):
670 if isinstance(self, InfoBarShowHide):
680 service = self.session.nav.getCurrentService()
684 seek = service.seek()
686 if seek is None or not seek.isCurrentlySeekable():
691 def isSeekable(self):
692 if self.getSeek() is None:
696 def __seekableStatusChanged(self):
697 print "seekable status changed!"
698 if not self.isSeekable():
699 self["SeekActions"].setEnabled(False)
700 print "not seekable, return to play"
701 self.setSeekState(self.SEEK_STATE_PLAY)
703 self["SeekActions"].setEnabled(True)
706 def __serviceStarted(self):
707 self.seekstate = self.SEEK_STATE_PLAY
708 self.__seekableStatusChanged()
710 def setSeekState(self, state):
711 service = self.session.nav.getCurrentService()
716 if not self.isSeekable():
717 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
718 state = self.SEEK_STATE_PLAY
720 pauseable = service.pause()
722 if pauseable is None:
723 print "not pauseable."
724 state = self.SEEK_STATE_PLAY
726 oldstate = self.seekstate
727 self.seekstate = state
730 if oldstate[i] != self.seekstate[i]:
731 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
733 for c in self.onPlayStateChanged:
736 self.checkSkipShowHideLock()
740 def playpauseService(self):
741 if self.seekstate != self.SEEK_STATE_PLAY:
742 self.unPauseService()
746 def pauseService(self):
747 if self.seekstate == self.SEEK_STATE_PAUSE:
748 print "pause, but in fact unpause"
749 self.unPauseService()
751 if self.seekstate == self.SEEK_STATE_PLAY:
752 print "yes, playing."
754 print "no", self.seekstate
756 self.setSeekState(self.SEEK_STATE_PAUSE);
758 def unPauseService(self):
760 if self.seekstate == self.SEEK_STATE_PLAY:
762 self.setSeekState(self.SEEK_STATE_PLAY)
764 def doSeek(self, seektime):
765 print "doseek", seektime
766 service = self.session.nav.getCurrentService()
770 seekable = self.getSeek()
774 seekable.seekTo(90 * seektime)
778 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
779 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
780 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
781 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
782 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
783 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
784 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
785 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
786 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
787 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
788 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
789 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
790 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
791 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
792 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
793 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
795 self.setSeekState(lookup[self.seekstate])
799 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
800 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
801 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
802 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
803 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
804 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
805 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
806 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
807 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
808 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
809 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
810 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
811 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
812 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
813 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
814 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
816 self.setSeekState(lookup[self.seekstate])
818 if self.seekstate == self.SEEK_STATE_PAUSE:
819 seekable = self.getSeek()
820 if seekable is not None:
821 seekable.seekRelative(-1, 3)
823 def seekFwdManual(self):
824 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
826 def fwdSeekTo(self, minutes):
827 print "Seek", minutes, "minutes forward"
829 seekable = self.getSeek()
830 if seekable is not None:
831 seekable.seekRelative(1, minutes * 60 * 90000)
833 def seekBackManual(self):
834 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
836 def rwdSeekTo(self, minutes):
838 self.fwdSeekTo(0 - minutes)
840 def checkSkipShowHideLock(self):
841 wantlock = self.seekstate != self.SEEK_STATE_PLAY
843 if config.usage.show_infobar_on_zap.value:
844 if self.lockedBecauseOfSkipping and not wantlock:
846 self.lockedBecauseOfSkipping = False
848 if wantlock and not self.lockedBecauseOfSkipping:
850 self.lockedBecauseOfSkipping = True
853 if self.seekstate == self.SEEK_STATE_EOF:
855 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
856 print "end of stream while seeking back, ignoring."
859 # if we are seeking, we try to end up ~1s before the end, and pause there.
860 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
861 self.setSeekState(self.SEEK_STATE_EOF)
862 self.seekRelativeToEnd(-90000)
864 self.setSeekState(self.SEEK_STATE_EOF)
867 self.setSeekState(self.SEEK_STATE_PLAY)
870 def seekRelative(self, diff):
871 seekable = self.getSeek()
872 if seekable is not None:
873 print "seekRelative: res:", seekable.seekRelative(1, diff)
877 def seekRelativeToEnd(self, diff):
878 assert diff <= 0, "diff is expected to be negative!"
880 # might sound like an evil hack, but:
881 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
882 # and we don't get that by passing 0 here (it would seek to begin).
886 # relative-to-end seeking is implemented as absolutes seeks with negative time
887 self.seekAbsolute(diff)
889 def seekAbsolute(self, abs):
890 seekable = self.getSeek()
891 if seekable is not None:
894 from Screens.PVRState import PVRState, TimeshiftState
896 class InfoBarPVRState:
897 def __init__(self, screen=PVRState):
898 self.onPlayStateChanged.append(self.__playStateChanged)
899 self.pvrStateDialog = self.session.instantiateDialog(screen)
900 self.onShow.append(self._mayShow)
901 self.onHide.append(self.pvrStateDialog.hide)
904 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
905 self.pvrStateDialog.show()
907 def __playStateChanged(self, state):
908 playstateString = state[3]
909 self.pvrStateDialog["state"].setText(playstateString)
912 class InfoBarTimeshiftState(InfoBarPVRState):
914 InfoBarPVRState.__init__(self, screen=TimeshiftState)
917 if self.execing and self.timeshift_enabled:
918 self.pvrStateDialog.show()
920 class InfoBarShowMovies:
922 # i don't really like this class.
923 # it calls a not further specified "movie list" on up/down/movieList,
924 # so this is not more than an action map
926 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
928 "movieList": (self.showMovies, _("movie list")),
929 "up": (self.showMovies, _("movie list")),
930 "down": (self.showMovies, _("movie list"))
933 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
937 # Timeshift works the following way:
938 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
939 # - normal playback TUNER unused PLAY enable disable disable
940 # - user presses "yellow" button. FILE record PAUSE enable disable enable
941 # - user presess pause again FILE record PLAY enable disable enable
942 # - user fast forwards FILE record FF enable disable enable
943 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
944 # - user backwards FILE record BACK # !! enable disable enable
948 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
949 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
950 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
951 # - the user can now PVR around
952 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
953 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
955 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
956 # - if the user rewinds, or press pause, timeshift will be activated again
958 # note that a timeshift can be enabled ("recording") and
959 # activated (currently time-shifting).
961 class InfoBarTimeshift:
963 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
965 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
966 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
968 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
970 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
971 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
972 }, prio=-1) # priority over record
974 self.timeshift_enabled = 0
975 self.timeshift_state = 0
976 self.ts_rewind_timer = eTimer()
977 self.ts_rewind_timer.timeout.get().append(self.rewindService)
979 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
981 iPlayableService.evStart: self.__serviceStarted,
982 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
985 def getTimeshift(self):
986 service = self.session.nav.getCurrentService()
987 return service and service.timeshift()
989 def startTimeshift(self):
990 print "enable timeshift"
991 ts = self.getTimeshift()
993 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
994 print "no ts interface"
997 if self.timeshift_enabled:
998 print "hu, timeshift already enabled?"
1000 if not ts.startTimeshift():
1001 self.timeshift_enabled = 1
1003 # we remove the "relative time" for now.
1004 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1007 #self.setSeekState(self.SEEK_STATE_PAUSE)
1008 self.activateTimeshiftEnd(False)
1010 # enable the "TimeshiftEnableActions", which will override
1011 # the startTimeshift actions
1012 self.__seekableStatusChanged()
1014 print "timeshift failed"
1016 def stopTimeshift(self):
1017 if not self.timeshift_enabled:
1019 print "disable timeshift"
1020 ts = self.getTimeshift()
1023 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1025 def stopTimeshiftConfirmed(self, confirmed):
1029 ts = self.getTimeshift()
1034 self.timeshift_enabled = 0
1037 self.__seekableStatusChanged()
1039 # activates timeshift, and seeks to (almost) the end
1040 def activateTimeshiftEnd(self, back = True):
1041 ts = self.getTimeshift()
1042 print "activateTimeshiftEnd"
1047 if ts.isTimeshiftActive():
1048 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1052 ts.activateTimeshift() # activate timeshift will automatically pause
1053 self.setSeekState(self.SEEK_STATE_PAUSE)
1054 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1057 self.ts_rewind_timer.start(200, 1)
1059 def rewindService(self):
1060 self.setSeekState(self.SEEK_STATE_BACK_16X)
1062 # same as activateTimeshiftEnd, but pauses afterwards.
1063 def activateTimeshiftEndAndPause(self):
1064 print "activateTimeshiftEndAndPause"
1065 #state = self.seekstate
1066 self.activateTimeshiftEnd(False)
1068 def __seekableStatusChanged(self):
1071 print "self.isSeekable", self.isSeekable()
1072 print "self.timeshift_enabled", self.timeshift_enabled
1074 # when this service is not seekable, but timeshift
1075 # is enabled, this means we can activate
1077 if not self.isSeekable() and self.timeshift_enabled:
1080 print "timeshift activate:", enabled
1081 self["TimeshiftActivateActions"].setEnabled(enabled)
1083 def __serviceStarted(self):
1084 self.timeshift_enabled = False
1085 self.__seekableStatusChanged()
1087 from Screens.PiPSetup import PiPSetup
1089 class InfoBarExtensions:
1090 EXTENSION_SINGLE = 0
1096 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1098 "extensions": (self.showExtensionSelection, _("view extensions...")),
1101 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1102 self.list.append((type, extension, key))
1104 def updateExtension(self, extension, key = None):
1105 self.extensionsList.append(extension)
1107 if self.extensionKeys.has_key(key):
1111 for x in self.availableKeys:
1112 if not self.extensionKeys.has_key(x):
1117 self.extensionKeys[key] = len(self.extensionsList) - 1
1119 def updateExtensions(self):
1120 self.extensionsList = []
1121 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1122 self.extensionKeys = {}
1124 if x[0] == self.EXTENSION_SINGLE:
1125 self.updateExtension(x[1], x[2])
1128 self.updateExtension(y[0], y[1])
1131 def showExtensionSelection(self):
1132 self.updateExtensions()
1133 extensionsList = self.extensionsList[:]
1136 for x in self.availableKeys:
1137 if self.extensionKeys.has_key(x):
1138 entry = self.extensionKeys[x]
1139 extension = self.extensionsList[entry]
1141 name = str(extension[0]())
1142 list.append((extension[0](), extension))
1144 extensionsList.remove(extension)
1146 extensionsList.remove(extension)
1147 for x in extensionsList:
1148 list.append((x[0](), x))
1149 keys += [""] * len(extensionsList)
1150 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1152 def extensionCallback(self, answer):
1153 if answer is not None:
1156 from Tools.BoundFunction import boundFunction
1158 # depends on InfoBarExtensions
1159 from Components.PluginComponent import plugins
1161 class InfoBarPlugins:
1163 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1165 def getPluginName(self, name):
1168 def getPluginList(self):
1170 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1171 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1174 def runPlugin(self, plugin):
1175 plugin(session = self.session)
1177 # depends on InfoBarExtensions
1178 class InfoBarSleepTimer:
1180 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1182 def available(self):
1185 def getSleepTimerName(self):
1186 return _("Sleep Timer")
1188 def showSleepTimerSetup(self):
1189 self.session.open(SleepTimerEdit)
1191 # depends on InfoBarExtensions
1194 self.session.pipshown = False
1196 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1197 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1198 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1200 def available(self):
1204 return self.session.pipshown
1206 def getShowHideName(self):
1207 if self.session.pipshown:
1208 return _("Disable Picture in Picture")
1210 return _("Activate Picture in Picture")
1212 def getSwapName(self):
1213 return _("Swap Services")
1215 def getMoveName(self):
1216 return _("Move Picture in Picture")
1219 if self.session.pipshown:
1220 del self.session.pip
1221 self.session.pipshown = False
1223 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1224 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1225 if self.session.pip.playService(newservice):
1226 self.session.pipshown = True
1227 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1229 self.session.pipshown = False
1230 del self.session.pip
1231 self.session.nav.playService(newservice)
1234 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1235 if self.session.pip.servicePath:
1236 servicepath = self.servicelist.getCurrentServicePath()
1237 ref=servicepath[len(servicepath)-1]
1238 pipref=self.session.pip.getCurrentService()
1239 self.session.pip.playService(swapservice)
1240 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1241 if pipref.toString() != ref.toString(): # is a subservice ?
1242 self.session.nav.stopService() # stop portal
1243 self.session.nav.playService(pipref) # start subservice
1244 self.session.pip.servicePath=servicepath
1247 self.session.open(PiPSetup, pip = self.session.pip)
1249 from RecordTimer import parseEvent
1251 class InfoBarInstantRecord:
1252 """Instant Record - handles the instantRecord action in order to
1253 start/stop instant records"""
1255 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1257 "instantRecord": (self.instantRecord, _("Instant Record...")),
1260 self["BlinkingPoint"] = BlinkingPixmapConditional()
1261 self["BlinkingPoint"].hide()
1262 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1264 def stopCurrentRecording(self, entry = -1):
1265 if entry is not None and entry != -1:
1266 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1267 self.recording.remove(self.recording[entry])
1269 def startInstantRecording(self, limitEvent = False):
1270 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1272 # try to get event info
1275 service = self.session.nav.getCurrentService()
1276 epg = eEPGCache.getInstance()
1277 event = epg.lookupEventTime(serviceref, -1, 0)
1279 info = service.info()
1280 ev = info.getEvent(0)
1286 end = time() + 3600 * 10
1287 name = "instant record"
1291 if event is not None:
1292 curEvent = parseEvent(event)
1294 description = curEvent[3]
1295 eventid = curEvent[4]
1300 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1302 data = (begin, end, name, description, eventid)
1304 recording = self.session.nav.recordWithTimer(serviceref, *data)
1305 recording.dontSave = True
1306 self.recording.append(recording)
1308 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1310 def isInstantRecordRunning(self):
1311 print "self.recording:", self.recording
1312 if len(self.recording) > 0:
1313 for x in self.recording:
1318 def recordQuestionCallback(self, answer):
1319 print "pre:\n", self.recording
1321 if answer is None or answer[1] == "no":
1324 recording = self.recording[:]
1326 if not x in self.session.nav.RecordTimer.timer_list:
1327 self.recording.remove(x)
1328 elif x.dontSave and x.isRunning():
1329 list.append(TimerEntryComponent(x, False))
1331 if answer[1] == "changeduration":
1332 if len(self.recording) == 1:
1333 self.changeDuration(0)
1335 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1336 elif answer[1] == "changeendtime":
1337 if len(self.recording) == 1:
1340 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1341 elif answer[1] == "stop":
1342 if len(self.recording) == 1:
1343 self.stopCurrentRecording(0)
1345 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1346 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1347 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1348 if answer[1] == "manualduration":
1349 self.changeDuration(len(self.recording)-1)
1350 elif answer[1] == "manualendtime":
1351 self.setEndtime(len(self.recording)-1)
1352 print "after:\n", self.recording
1354 def setEndtime(self, entry):
1355 if entry is not None:
1356 self.selectedEntry = entry
1357 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1358 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1359 dlg.setTitle(_("Please change recording endtime"))
1361 def TimeDateInputClosed(self, ret):
1364 localendtime = localtime(ret[1])
1365 print "stopping recording at", strftime("%c", localendtime)
1366 self.recording[self.selectedEntry].end = ret[1]
1367 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1369 def changeDuration(self, entry):
1370 if entry is not None:
1371 self.selectedEntry = entry
1372 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1374 def inputCallback(self, value):
1375 if value is not None:
1376 print "stopping recording after", int(value), "minutes."
1377 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1378 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1380 def instantRecord(self):
1382 stat = os_stat(resolveFilename(SCOPE_HDD))
1384 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1387 if self.isInstantRecordRunning():
1388 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1389 title=_("A recording is currently running.\nWhat do you want to do?"), \
1390 list=[(_("stop recording"), "stop"), \
1391 (_("change recording (duration)"), "changeduration"), \
1392 (_("change recording (endtime)"), "changeendtime"), \
1393 (_("add recording (indefinitely)"), "indefinitely"), \
1394 (_("add recording (stop after current event)"), "event"), \
1395 (_("add recording (enter recording duration)"), "manualduration"), \
1396 (_("add recording (enter recording endtime)"), "manualendtime"), \
1397 (_("do nothing"), "no")])
1399 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1400 title=_("Start recording?"), \
1401 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1402 (_("add recording (stop after current event)"), "event"), \
1403 (_("add recording (enter recording duration)"), "manualduration"), \
1404 (_("add recording (enter recording endtime)"), "manualendtime"), \
1405 (_("don't record"), "no")])
1407 from Tools.ISO639 import LanguageCodes
1409 class InfoBarAudioSelection:
1411 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1413 "audioSelection": (self.audioSelection, _("Audio Options...")),
1416 def audioSelection(self):
1417 service = self.session.nav.getCurrentService()
1418 audio = service and service.audioTracks()
1419 self.audioTracks = audio
1420 n = audio and audio.getNumberOfTracks() or 0
1421 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1423 print "tlist:", tlist
1425 self.audioChannel = service.audioChannel()
1428 i = audio.getTrackInfo(x)
1429 language = i.getLanguage()
1430 description = i.getDescription()
1432 if LanguageCodes.has_key(language):
1433 language = LanguageCodes[language][0]
1435 if len(description):
1436 description += " (" + language + ")"
1438 description = language
1440 tlist.append((description, x))
1442 selectedAudio = tlist[0][1]
1443 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1447 if x[1] != selectedAudio:
1452 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1453 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1455 del self.audioTracks
1457 def audioSelected(self, audio):
1458 if audio is not None:
1459 if isinstance(audio[1], str):
1460 if audio[1] == "mode":
1461 keys = ["red", "green", "yellow"]
1462 selection = self.audioChannel.getCurrentChannel()
1463 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1464 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1466 del self.audioChannel
1467 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1468 self.audioTracks.selectTrack(audio[1])
1470 del self.audioChannel
1471 del self.audioTracks
1473 def modeSelected(self, mode):
1474 if mode is not None:
1475 self.audioChannel.selectChannel(mode[1])
1476 del self.audioChannel
1478 class InfoBarSubserviceSelection:
1480 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1482 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1485 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1487 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1488 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1490 self["SubserviceQuickzapAction"].setEnabled(False)
1492 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1496 def checkSubservicesAvail(self, ev):
1497 if ev == iPlayableService.evUpdatedEventInfo:
1498 service = self.session.nav.getCurrentService()
1499 subservices = service and service.subServices()
1500 if not subservices or subservices.getNumberOfSubservices() == 0:
1501 self["SubserviceQuickzapAction"].setEnabled(False)
1503 def nextSubservice(self):
1504 self.changeSubservice(+1)
1506 def prevSubservice(self):
1507 self.changeSubservice(-1)
1509 def changeSubservice(self, direction):
1510 service = self.session.nav.getCurrentService()
1511 subservices = service and service.subServices()
1512 n = subservices and subservices.getNumberOfSubservices()
1515 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1517 if subservices.getSubservice(x).toString() == ref.toString():
1520 selection += direction
1525 newservice = subservices.getSubservice(selection)
1526 if newservice.valid():
1529 self.session.nav.playService(newservice)
1531 def subserviceSelection(self):
1532 service = self.session.nav.getCurrentService()
1533 subservices = service and service.subServices()
1534 self.bouquets = self.servicelist.getBouquetList()
1535 n = subservices and subservices.getNumberOfSubservices()
1538 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1541 i = subservices.getSubservice(x)
1542 if i.toString() == ref.toString():
1544 tlist.append((i.getName(), i))
1546 if self.bouquets and len(self.bouquets):
1547 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1548 if config.usage.multibouquet.value:
1549 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1551 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1554 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1555 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1558 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1560 def subserviceSelected(self, service):
1562 if not service is None:
1563 if isinstance(service[1], str):
1564 if service[1] == "quickzap":
1565 from Screens.SubservicesQuickzap import SubservicesQuickzap
1566 self.session.open(SubservicesQuickzap, service[2])
1568 self["SubserviceQuickzapAction"].setEnabled(True)
1569 self.session.nav.playService(service[1])
1571 def addSubserviceToBouquetCallback(self, service):
1572 if len(service) > 1 and isinstance(service[1], eServiceReference):
1573 self.selectedSubservice = service
1574 if self.bouquets is None:
1577 cnt = len(self.bouquets)
1578 if cnt > 1: # show bouquet list
1579 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1580 elif cnt == 1: # add to only one existing bouquet
1581 self.addSubserviceToBouquet(self.bouquets[0][1])
1582 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1584 def bouquetSelClosed(self, confirmed):
1586 del self.selectedSubservice
1588 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1590 def addSubserviceToBouquet(self, dest):
1591 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1593 self.bsel.close(True)
1595 del self.selectedSubservice
1597 class InfoBarAdditionalInfo:
1599 self["NimA"] = Pixmap()
1600 self["NimB"] = Pixmap()
1601 self["NimA_Active"] = Pixmap()
1602 self["NimB_Active"] = Pixmap()
1604 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1605 self["TimeshiftPossible"] = self["RecordingPossible"]
1606 self["ExtensionsAvailable"] = Boolean(fixed=1)
1608 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1609 res_mgr = eDVBResourceManager.getInstance()
1611 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1613 def tunerUseMaskChanged(self, mask):
1615 self["NimA_Active"].show()
1617 self["NimA_Active"].hide()
1619 self["NimB_Active"].show()
1621 self["NimB_Active"].hide()
1623 def checkTunerState(self, service):
1624 info = service and service.frontendInfo()
1625 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1626 if feNumber is None:
1636 def gotServiceEvent(self, ev):
1637 service = self.session.nav.getCurrentService()
1638 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1639 self.checkTunerState(service)
1641 class InfoBarNotifications:
1643 self.onExecBegin.append(self.checkNotifications)
1644 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1645 self.onClose.append(self.__removeNotification)
1647 def __removeNotification(self):
1648 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1650 def checkNotificationsIfExecing(self):
1652 self.checkNotifications()
1654 def checkNotifications(self):
1655 if len(Notifications.notifications):
1656 n = Notifications.notifications[0]
1658 Notifications.notifications = Notifications.notifications[1:]
1661 if n[3].has_key("onSessionOpenCallback"):
1662 n[3]["onSessionOpenCallback"]()
1663 del n[3]["onSessionOpenCallback"]
1666 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1668 dlg = self.session.open(n[1], *n[2], **n[3])
1670 # remember that this notification is currently active
1672 Notifications.current_notifications.append(d)
1673 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1675 def __notificationClosed(self, d):
1676 Notifications.current_notifications.remove(d)
1678 class InfoBarServiceNotifications:
1680 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1682 iPlayableService.evEnd: self.serviceHasEnded
1685 def serviceHasEnded(self):
1686 print "service end!"
1689 self.setSeekState(self.SEEK_STATE_PLAY)
1693 class InfoBarCueSheetSupport:
1699 ENABLE_RESUME_SUPPORT = False
1702 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1704 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to next marked position")),
1705 "jumpNextMark": (self.jumpNextMark, _("jump to previous marked position")),
1706 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1710 self.is_closing = False
1711 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1713 iPlayableService.evStart: self.__serviceStarted,
1716 def __serviceStarted(self):
1719 print "new service started! trying to download cuts!"
1720 self.downloadCuesheet()
1722 if self.ENABLE_RESUME_SUPPORT:
1725 for (pts, what) in self.cut_list:
1726 if what == self.CUT_TYPE_LAST:
1729 if last is not None:
1730 self.resume_point = last
1731 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1733 def playLastCB(self, answer):
1735 seekable = self.__getSeekable()
1736 if seekable is not None:
1737 seekable.seekTo(self.resume_point)
1739 def __getSeekable(self):
1740 service = self.session.nav.getCurrentService()
1743 return service.seek()
1745 def cueGetCurrentPosition(self):
1746 seek = self.__getSeekable()
1749 r = seek.getPlayPosition()
1754 def jumpPreviousNextMark(self, cmp, alternative=None):
1755 current_pos = self.cueGetCurrentPosition()
1756 if current_pos is None:
1758 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1759 if mark is not None:
1761 elif alternative is not None:
1766 seekable = self.__getSeekable()
1767 if seekable is not None:
1768 seekable.seekTo(pts)
1770 def jumpPreviousMark(self):
1771 # we add 2 seconds, so if the play position is <2s after
1772 # the mark, the mark before will be used
1773 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1775 def jumpNextMark(self):
1776 self.jumpPreviousNextMark(lambda x: x)
1778 def getNearestCutPoint(self, pts, cmp=abs):
1781 for cp in self.cut_list:
1782 diff = cmp(cp[0] - pts)
1783 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1787 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1788 current_pos = self.cueGetCurrentPosition()
1789 if current_pos is None:
1790 print "not seekable"
1793 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1795 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1797 return nearest_cutpoint
1799 self.removeMark(nearest_cutpoint)
1800 elif not onlyremove and not onlyreturn:
1801 self.addMark((current_pos, self.CUT_TYPE_MARK))
1806 def showAfterCuesheetOperation(self):
1807 if isinstance(self, InfoBarShowHide):
1810 def addMark(self, point):
1811 insort(self.cut_list, point)
1812 self.uploadCuesheet()
1813 self.showAfterCuesheetOperation()
1815 def removeMark(self, point):
1816 self.cut_list.remove(point)
1817 self.uploadCuesheet()
1818 self.showAfterCuesheetOperation()
1820 def showAfterCuesheetOperation(self):
1821 if isinstance(self, InfoBarShowHide):
1824 def __getCuesheet(self):
1825 service = self.session.nav.getCurrentService()
1828 return service.cueSheet()
1830 def uploadCuesheet(self):
1831 cue = self.__getCuesheet()
1834 print "upload failed, no cuesheet interface"
1836 cue.setCutList(self.cut_list)
1838 def downloadCuesheet(self):
1839 cue = self.__getCuesheet()
1842 print "download failed, no cuesheet interface"
1845 self.cut_list = cue.getCutList()
1847 class InfoBarSummary(Screen):
1849 <screen position="0,0" size="132,64">
1850 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1851 <convert type="ClockToText">WithSeconds</convert>
1853 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1854 <convert type="ServiceName">Name</convert>
1858 def __init__(self, session, parent):
1859 Screen.__init__(self, session)
1860 self["CurrentService"] = CurrentService(self.session.nav)
1861 self["CurrentTime"] = Clock()
1863 class InfoBarSummarySupport:
1867 def createSummary(self):
1868 return InfoBarSummary
1870 class InfoBarTeletextPlugin:
1872 self.teletext_plugin = None
1874 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1875 self.teletext_plugin = p
1877 if self.teletext_plugin is not None:
1878 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1880 "startTeletext": (self.startTeletext, _("View teletext..."))
1883 print "no teletext plugin found!"
1885 def startTeletext(self):
1886 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1888 class InfoBarSubtitleSupport(object):
1890 object.__init__(self)
1891 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1892 self.__subtitles_enabled = False
1894 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1896 iPlayableService.evEnd: self.__serviceStopped,
1897 iPlayableService.evUpdatedInfo: self.__updatedInfo
1899 self.cached_subtitle_checked = False
1900 self.__selected_subtitle = None
1902 def __serviceStopped(self):
1903 self.subtitle_window.hide()
1904 self.__subtitles_enabled = False
1905 self.cached_subtitle_checked = False
1907 def __updatedInfo(self):
1908 if not self.cached_subtitle_checked:
1909 subtitle = self.getCurrentServiceSubtitle()
1910 self.cached_subtitle_checked = True
1911 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1912 if self.__selected_subtitle:
1913 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1914 self.subtitle_window.show()
1915 self.__subtitles_enabled = True
1917 def getCurrentServiceSubtitle(self):
1918 service = self.session.nav.getCurrentService()
1919 return service and service.subtitle()
1921 def setSubtitlesEnable(self, enable=True):
1922 subtitle = self.getCurrentServiceSubtitle()
1923 if enable and self.__selected_subtitle is not None:
1924 if subtitle and not self.__subtitles_enabled:
1925 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1926 self.subtitle_window.show()
1927 self.__subtitles_enabled = True
1930 subtitle.disableSubtitles(self.subtitle_window.instance)
1931 self.__subtitles_enabled = False
1932 self.subtitle_window.hide()
1934 def setSelectedSubtitle(self, subtitle):
1935 self.__selected_subtitle = subtitle
1937 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1938 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1940 class InfoBarServiceErrorPopupSupport:
1942 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1944 iPlayableService.evTuneFailed: self.__tuneFailed,
1945 iPlayableService.evStart: self.__serviceStarted
1947 self.__serviceStarted()
1949 def __serviceStarted(self):
1950 self.last_error = None
1951 Notifications.RemovePopup(id = "ZapError")
1953 def __tuneFailed(self):
1954 service = self.session.nav.getCurrentService()
1955 info = service and service.info()
1956 error = info and info.getInfo(iServiceInformation.sDVBState)
1958 if error == self.last_error:
1961 self.last_error = error
1964 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1965 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1966 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1967 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1968 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1969 eDVBServicePMTHandler.eventNewProgramInfo: None,
1970 eDVBServicePMTHandler.eventTuned: None,
1971 eDVBServicePMTHandler.eventSOF: None,
1972 eDVBServicePMTHandler.eventEOF: None
1975 error = errors.get(error) #this returns None when the key not exist in the dict
1977 if error is not None:
1978 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1980 Notifications.RemovePopup(id = "ZapError")