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")
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)
644 return HelpableActionMap.action(self, contexts, action)
646 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
648 "playpauseService": (self.playpauseService, _("pause")),
649 "pauseService": (self.pauseService, _("pause")),
650 "unPauseService": (self.unPauseService, _("continue")),
652 "seekFwd": (self.seekFwd, _("skip forward")),
653 "seekFwdDown": self.seekFwdDown,
654 "seekFwdUp": self.seekFwdUp,
655 "seekBack": (self.seekBack, _("skip backward")),
656 "seekBackDown": self.seekBackDown,
657 "seekBackUp": self.seekBackUp,
659 # give them a little more priority to win over color buttons
661 self["SeekActions"].setEnabled(False)
663 self.seekstate = self.SEEK_STATE_PLAY
664 self.onClose.append(self.delTimer)
666 self.fwdtimer = False
667 self.fwdKeyTimer = eTimer()
668 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
670 self.rwdtimer = False
671 self.rwdKeyTimer = eTimer()
672 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
674 self.onPlayStateChanged = [ ]
676 self.lockedBecauseOfSkipping = False
689 service = self.session.nav.getCurrentService()
693 seek = service.seek()
695 if seek is None or not seek.isCurrentlySeekable():
700 def isSeekable(self):
701 if self.getSeek() is None:
705 def __seekableStatusChanged(self):
706 print "seekable status changed!"
707 if not self.isSeekable():
708 self["SeekActions"].setEnabled(False)
709 print "not seekable, return to play"
710 self.setSeekState(self.SEEK_STATE_PLAY)
712 self["SeekActions"].setEnabled(True)
715 def __serviceStarted(self):
716 self.seekstate = self.SEEK_STATE_PLAY
717 self.__seekableStatusChanged()
719 def setSeekState(self, state):
720 service = self.session.nav.getCurrentService()
725 if not self.isSeekable():
726 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
727 state = self.SEEK_STATE_PLAY
729 pauseable = service.pause()
731 if pauseable is None:
732 print "not pauseable."
733 state = self.SEEK_STATE_PLAY
735 oldstate = self.seekstate
736 self.seekstate = state
739 if oldstate[i] != self.seekstate[i]:
740 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
742 for c in self.onPlayStateChanged:
745 self.checkSkipShowHideLock()
749 def playpauseService(self):
750 if self.seekstate != self.SEEK_STATE_PLAY:
751 self.unPauseService()
755 def pauseService(self):
756 if self.seekstate == self.SEEK_STATE_PAUSE:
757 print "pause, but in fact unpause"
758 self.unPauseService()
760 if self.seekstate == self.SEEK_STATE_PLAY:
761 print "yes, playing."
763 print "no", self.seekstate
765 self.setSeekState(self.SEEK_STATE_PAUSE);
767 def unPauseService(self):
769 if self.seekstate == self.SEEK_STATE_PLAY:
771 self.setSeekState(self.SEEK_STATE_PLAY)
773 def doSeek(self, seektime):
774 print "doseek", seektime
775 service = self.session.nav.getCurrentService()
779 seekable = self.getSeek()
783 seekable.seekTo(90 * seektime)
785 def seekFwdDown(self):
786 print "start fwd timer"
788 self.fwdKeyTimer.start(1000)
790 def seekBackDown(self):
791 print "start rewind timer"
793 self.rwdKeyTimer.start(1000)
798 self.fwdKeyTimer.stop()
799 self.fwdtimer = False
804 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
805 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
806 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
807 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
808 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
809 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
810 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
811 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
812 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
813 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
814 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
815 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
816 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
817 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
818 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
819 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
821 self.setSeekState(lookup[self.seekstate])
823 def seekBackUp(self):
826 self.rwdKeyTimer.stop()
827 self.rwdtimer = False
832 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
833 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
834 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
835 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
836 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
837 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
838 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
839 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
840 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
841 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
842 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
843 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
844 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
845 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
846 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
847 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
849 self.setSeekState(lookup[self.seekstate])
851 if self.seekstate == self.SEEK_STATE_PAUSE:
852 seekable = self.getSeek()
853 if seekable is not None:
854 seekable.seekRelative(-1, 3)
856 def fwdTimerFire(self):
857 print "Display seek fwd"
858 self.fwdKeyTimer.stop()
859 self.fwdtimer = False
860 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
862 def fwdSeekTo(self, minutes):
863 print "Seek", minutes, "minutes forward"
865 seekable = self.getSeek()
866 if seekable is not None:
867 seekable.seekRelative(1, minutes * 60 * 90000)
869 def rwdTimerFire(self):
871 self.rwdKeyTimer.stop()
872 self.rwdtimer = False
873 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
875 def rwdSeekTo(self, minutes):
877 self.fwdSeekTo(0 - minutes)
879 def checkSkipShowHideLock(self):
880 wantlock = self.seekstate != self.SEEK_STATE_PLAY
882 if config.usage.show_infobar_on_zap.value:
883 if self.lockedBecauseOfSkipping and not wantlock:
885 self.lockedBecauseOfSkipping = False
887 if wantlock and not self.lockedBecauseOfSkipping:
889 self.lockedBecauseOfSkipping = True
892 if self.seekstate == self.SEEK_STATE_EOF:
894 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
895 print "end of stream while seeking back, ignoring."
898 # if we are seeking, we try to end up ~1s before the end, and pause there.
899 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
900 self.setSeekState(self.SEEK_STATE_EOF)
901 self.seekRelativeToEnd(-90000)
903 self.setSeekState(self.SEEK_STATE_EOF)
906 self.setSeekState(self.SEEK_STATE_PLAY)
909 def seekRelative(self, diff):
910 seekable = self.getSeek()
911 if seekable is not None:
912 print "seekRelative: res:", seekable.seekRelative(1, diff)
916 def seekRelativeToEnd(self, diff):
917 assert diff <= 0, "diff is expected to be negative!"
919 # might sound like an evil hack, but:
920 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
921 # and we don't get that by passing 0 here (it would seek to begin).
925 # relative-to-end seeking is implemented as absolutes seeks with negative time
926 self.seekAbsolute(diff)
928 def seekAbsolute(self, abs):
929 seekable = self.getSeek()
930 if seekable is not None:
933 from Screens.PVRState import PVRState, TimeshiftState
935 class InfoBarPVRState:
936 def __init__(self, screen=PVRState):
937 self.onPlayStateChanged.append(self.__playStateChanged)
938 self.pvrStateDialog = self.session.instantiateDialog(screen)
939 self.onShow.append(self._mayShow)
940 self.onHide.append(self.pvrStateDialog.hide)
943 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
944 self.pvrStateDialog.show()
946 def __playStateChanged(self, state):
947 playstateString = state[3]
948 self.pvrStateDialog["state"].setText(playstateString)
951 class InfoBarTimeshiftState(InfoBarPVRState):
953 InfoBarPVRState.__init__(self, screen=TimeshiftState)
956 if self.execing and self.timeshift_enabled:
957 self.pvrStateDialog.show()
959 class InfoBarShowMovies:
961 # i don't really like this class.
962 # it calls a not further specified "movie list" on up/down/movieList,
963 # so this is not more than an action map
965 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
967 "movieList": (self.showMovies, "movie list"),
968 "up": (self.showMovies, "movie list"),
969 "down": (self.showMovies, "movie list")
972 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
976 # Timeshift works the following way:
977 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
978 # - normal playback TUNER unused PLAY enable disable disable
979 # - user presses "yellow" button. FILE record PAUSE enable disable enable
980 # - user presess pause again FILE record PLAY enable disable enable
981 # - user fast forwards FILE record FF enable disable enable
982 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
983 # - user backwards FILE record BACK # !! enable disable enable
987 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
988 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
989 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
990 # - the user can now PVR around
991 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
992 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
994 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
995 # - if the user rewinds, or press pause, timeshift will be activated again
997 # note that a timeshift can be enabled ("recording") and
998 # activated (currently time-shifting).
1000 class InfoBarTimeshift:
1002 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1004 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1005 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1007 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1009 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1010 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1011 }, prio=-1) # priority over record
1013 self.timeshift_enabled = 0
1014 self.timeshift_state = 0
1015 self.ts_rewind_timer = eTimer()
1016 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1018 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1020 iPlayableService.evStart: self.__serviceStarted,
1021 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1024 def getTimeshift(self):
1025 service = self.session.nav.getCurrentService()
1026 return service and service.timeshift()
1028 def startTimeshift(self):
1029 print "enable timeshift"
1030 ts = self.getTimeshift()
1032 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1033 print "no ts interface"
1036 if self.timeshift_enabled:
1037 print "hu, timeshift already enabled?"
1039 if not ts.startTimeshift():
1040 self.timeshift_enabled = 1
1042 # we remove the "relative time" for now.
1043 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1046 #self.setSeekState(self.SEEK_STATE_PAUSE)
1047 self.activateTimeshiftEnd(False)
1049 # enable the "TimeshiftEnableActions", which will override
1050 # the startTimeshift actions
1051 self.__seekableStatusChanged()
1053 print "timeshift failed"
1055 def stopTimeshift(self):
1056 if not self.timeshift_enabled:
1058 print "disable timeshift"
1059 ts = self.getTimeshift()
1062 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1064 def stopTimeshiftConfirmed(self, confirmed):
1068 ts = self.getTimeshift()
1073 self.timeshift_enabled = 0
1076 self.__seekableStatusChanged()
1078 # activates timeshift, and seeks to (almost) the end
1079 def activateTimeshiftEnd(self, back = True):
1080 ts = self.getTimeshift()
1081 print "activateTimeshiftEnd"
1086 if ts.isTimeshiftActive():
1087 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1091 ts.activateTimeshift() # activate timeshift will automatically pause
1092 self.setSeekState(self.SEEK_STATE_PAUSE)
1093 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1096 self.ts_rewind_timer.start(200, 1)
1098 def rewindService(self):
1099 self.setSeekState(self.SEEK_STATE_BACK_16X)
1101 # same as activateTimeshiftEnd, but pauses afterwards.
1102 def activateTimeshiftEndAndPause(self):
1103 print "activateTimeshiftEndAndPause"
1104 #state = self.seekstate
1105 self.activateTimeshiftEnd(False)
1107 def __seekableStatusChanged(self):
1110 print "self.isSeekable", self.isSeekable()
1111 print "self.timeshift_enabled", self.timeshift_enabled
1113 # when this service is not seekable, but timeshift
1114 # is enabled, this means we can activate
1116 if not self.isSeekable() and self.timeshift_enabled:
1119 print "timeshift activate:", enabled
1120 self["TimeshiftActivateActions"].setEnabled(enabled)
1122 def __serviceStarted(self):
1123 self.timeshift_enabled = False
1124 self.__seekableStatusChanged()
1126 from Screens.PiPSetup import PiPSetup
1128 class InfoBarExtensions:
1129 EXTENSION_SINGLE = 0
1135 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1137 "extensions": (self.showExtensionSelection, _("view extensions...")),
1140 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1141 self.list.append((type, extension, key))
1143 def updateExtension(self, extension, key = None):
1144 self.extensionsList.append(extension)
1146 if self.extensionKeys.has_key(key):
1150 for x in self.availableKeys:
1151 if not self.extensionKeys.has_key(x):
1156 self.extensionKeys[key] = len(self.extensionsList) - 1
1158 def updateExtensions(self):
1159 self.extensionsList = []
1160 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1161 self.extensionKeys = {}
1163 if x[0] == self.EXTENSION_SINGLE:
1164 self.updateExtension(x[1], x[2])
1167 self.updateExtension(y[0], y[1])
1170 def showExtensionSelection(self):
1171 self.updateExtensions()
1172 extensionsList = self.extensionsList[:]
1175 for x in self.availableKeys:
1176 if self.extensionKeys.has_key(x):
1177 entry = self.extensionKeys[x]
1178 extension = self.extensionsList[entry]
1180 name = str(extension[0]())
1181 list.append((extension[0](), extension))
1183 extensionsList.remove(extension)
1185 extensionsList.remove(extension)
1186 for x in extensionsList:
1187 list.append((x[0](), x))
1188 keys += [""] * len(extensionsList)
1189 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1191 def extensionCallback(self, answer):
1192 if answer is not None:
1195 from Tools.BoundFunction import boundFunction
1197 # depends on InfoBarExtensions
1198 from Components.PluginComponent import plugins
1200 class InfoBarPlugins:
1202 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1204 def getPluginName(self, name):
1207 def getPluginList(self):
1209 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1210 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1213 def runPlugin(self, plugin):
1214 plugin(session = self.session)
1216 # depends on InfoBarExtensions
1217 class InfoBarSleepTimer:
1219 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1221 def available(self):
1224 def getSleepTimerName(self):
1225 return _("Sleep Timer")
1227 def showSleepTimerSetup(self):
1228 self.session.open(SleepTimerEdit)
1230 # depends on InfoBarExtensions
1233 self.session.pipshown = False
1235 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1236 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1237 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1239 def available(self):
1243 return self.session.pipshown
1245 def getShowHideName(self):
1246 if self.session.pipshown:
1247 return _("Disable Picture in Picture")
1249 return _("Activate Picture in Picture")
1251 def getSwapName(self):
1252 return _("Swap Services")
1254 def getMoveName(self):
1255 return _("Move Picture in Picture")
1258 if self.session.pipshown:
1259 del self.session.pip
1260 self.session.pipshown = False
1262 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1263 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1264 if self.session.pip.playService(newservice):
1265 self.session.pipshown = True
1266 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1268 self.session.pipshown = False
1269 del self.session.pip
1270 self.session.nav.playService(newservice)
1273 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1274 if self.session.pip.servicePath:
1275 servicepath = self.servicelist.getCurrentServicePath()
1276 ref=servicepath[len(servicepath)-1]
1277 pipref=self.session.pip.getCurrentService()
1278 self.session.pip.playService(swapservice)
1279 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1280 if pipref.toString() != ref.toString(): # is a subservice ?
1281 self.session.nav.stopService() # stop portal
1282 self.session.nav.playService(pipref) # start subservice
1283 self.session.pip.servicePath=servicepath
1286 self.session.open(PiPSetup, pip = self.session.pip)
1288 from RecordTimer import parseEvent
1290 class InfoBarInstantRecord:
1291 """Instant Record - handles the instantRecord action in order to
1292 start/stop instant records"""
1294 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1296 "instantRecord": (self.instantRecord, _("Instant Record...")),
1299 self["BlinkingPoint"] = BlinkingPixmapConditional()
1300 self["BlinkingPoint"].hide()
1301 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1303 def stopCurrentRecording(self, entry = -1):
1304 if entry is not None and entry != -1:
1305 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1306 self.recording.remove(self.recording[entry])
1308 def startInstantRecording(self, limitEvent = False):
1309 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1311 # try to get event info
1314 service = self.session.nav.getCurrentService()
1315 epg = eEPGCache.getInstance()
1316 event = epg.lookupEventTime(serviceref, -1, 0)
1318 info = service.info()
1319 ev = info.getEvent(0)
1325 end = time() + 3600 * 10
1326 name = "instant record"
1330 if event is not None:
1331 curEvent = parseEvent(event)
1333 description = curEvent[3]
1334 eventid = curEvent[4]
1339 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1341 data = (begin, end, name, description, eventid)
1343 recording = self.session.nav.recordWithTimer(serviceref, *data)
1344 recording.dontSave = True
1345 self.recording.append(recording)
1347 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1349 def isInstantRecordRunning(self):
1350 print "self.recording:", self.recording
1351 if len(self.recording) > 0:
1352 for x in self.recording:
1357 def recordQuestionCallback(self, answer):
1358 print "pre:\n", self.recording
1360 if answer is None or answer[1] == "no":
1363 recording = self.recording[:]
1365 if not x in self.session.nav.RecordTimer.timer_list:
1366 self.recording.remove(x)
1367 elif x.dontSave and x.isRunning():
1368 list.append(TimerEntryComponent(x, False))
1370 if answer[1] == "changeduration":
1371 if len(self.recording) == 1:
1372 self.changeDuration(0)
1374 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1375 elif answer[1] == "changeendtime":
1376 if len(self.recording) == 1:
1379 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1380 elif answer[1] == "stop":
1381 if len(self.recording) == 1:
1382 self.stopCurrentRecording(0)
1384 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1385 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1386 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1387 if answer[1] == "manualduration":
1388 self.changeDuration(len(self.recording)-1)
1389 elif answer[1] == "manualendtime":
1390 self.setEndtime(len(self.recording)-1)
1391 print "after:\n", self.recording
1393 def setEndtime(self, entry):
1394 if entry is not None:
1395 self.selectedEntry = entry
1396 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1397 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1398 dlg.setTitle(_("Please change recording endtime"))
1400 def TimeDateInputClosed(self, ret):
1403 localendtime = localtime(ret[1])
1404 print "stopping recording at", strftime("%c", localendtime)
1405 self.recording[self.selectedEntry].end = ret[1]
1406 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1408 def changeDuration(self, entry):
1409 if entry is not None:
1410 self.selectedEntry = entry
1411 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1413 def inputCallback(self, value):
1414 if value is not None:
1415 print "stopping recording after", int(value), "minutes."
1416 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1417 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1419 def instantRecord(self):
1421 stat = os_stat(resolveFilename(SCOPE_HDD))
1423 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1426 if self.isInstantRecordRunning():
1427 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1428 title=_("A recording is currently running.\nWhat do you want to do?"), \
1429 list=[(_("stop recording"), "stop"), \
1430 (_("change recording (duration)"), "changeduration"), \
1431 (_("change recording (endtime)"), "changeendtime"), \
1432 (_("add recording (indefinitely)"), "indefinitely"), \
1433 (_("add recording (stop after current event)"), "event"), \
1434 (_("add recording (enter recording duration)"), "manualduration"), \
1435 (_("add recording (enter recording endtime)"), "manualendtime"), \
1436 (_("do nothing"), "no")])
1438 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1439 title=_("Start recording?"), \
1440 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1441 (_("add recording (stop after current event)"), "event"), \
1442 (_("add recording (enter recording duration)"), "manualduration"), \
1443 (_("add recording (enter recording endtime)"), "manualendtime"), \
1444 (_("don't record"), "no")])
1446 from Tools.ISO639 import LanguageCodes
1448 class InfoBarAudioSelection:
1450 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1452 "audioSelection": (self.audioSelection, _("Audio Options...")),
1455 def audioSelection(self):
1456 service = self.session.nav.getCurrentService()
1457 audio = service and service.audioTracks()
1458 self.audioTracks = audio
1459 n = audio and audio.getNumberOfTracks() or 0
1460 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1462 print "tlist:", tlist
1464 self.audioChannel = service.audioChannel()
1467 i = audio.getTrackInfo(x)
1468 language = i.getLanguage()
1469 description = i.getDescription()
1471 if LanguageCodes.has_key(language):
1472 language = LanguageCodes[language][0]
1474 if len(description):
1475 description += " (" + language + ")"
1477 description = language
1479 tlist.append((description, x))
1481 selectedAudio = tlist[0][1]
1482 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1486 if x[1] != selectedAudio:
1491 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1492 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1494 del self.audioTracks
1496 def audioSelected(self, audio):
1497 if audio is not None:
1498 if isinstance(audio[1], str):
1499 if audio[1] == "mode":
1500 keys = ["red", "green", "yellow"]
1501 selection = self.audioChannel.getCurrentChannel()
1502 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1503 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1505 del self.audioChannel
1506 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1507 self.audioTracks.selectTrack(audio[1])
1509 del self.audioChannel
1510 del self.audioTracks
1512 def modeSelected(self, mode):
1513 if mode is not None:
1514 self.audioChannel.selectChannel(mode[1])
1515 del self.audioChannel
1517 class InfoBarSubserviceSelection:
1519 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1521 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1524 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1526 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1527 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1529 self["SubserviceQuickzapAction"].setEnabled(False)
1531 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1535 def checkSubservicesAvail(self, ev):
1536 if ev == iPlayableService.evUpdatedEventInfo:
1537 service = self.session.nav.getCurrentService()
1538 subservices = service and service.subServices()
1539 if not subservices or subservices.getNumberOfSubservices() == 0:
1540 self["SubserviceQuickzapAction"].setEnabled(False)
1542 def nextSubservice(self):
1543 self.changeSubservice(+1)
1545 def prevSubservice(self):
1546 self.changeSubservice(-1)
1548 def changeSubservice(self, direction):
1549 service = self.session.nav.getCurrentService()
1550 subservices = service and service.subServices()
1551 n = subservices and subservices.getNumberOfSubservices()
1554 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1556 if subservices.getSubservice(x).toString() == ref.toString():
1559 selection += direction
1564 newservice = subservices.getSubservice(selection)
1565 if newservice.valid():
1568 self.session.nav.playService(newservice)
1570 def subserviceSelection(self):
1571 service = self.session.nav.getCurrentService()
1572 subservices = service and service.subServices()
1573 self.bouquets = self.servicelist.getBouquetList()
1574 n = subservices and subservices.getNumberOfSubservices()
1577 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1580 i = subservices.getSubservice(x)
1581 if i.toString() == ref.toString():
1583 tlist.append((i.getName(), i))
1585 if self.bouquets and len(self.bouquets):
1586 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1587 if config.usage.multibouquet.value:
1588 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1590 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1593 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1594 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1597 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1599 def subserviceSelected(self, service):
1601 if not service is None:
1602 if isinstance(service[1], str):
1603 if service[1] == "quickzap":
1604 from Screens.SubservicesQuickzap import SubservicesQuickzap
1605 self.session.open(SubservicesQuickzap, service[2])
1607 self["SubserviceQuickzapAction"].setEnabled(True)
1608 self.session.nav.playService(service[1])
1610 def addSubserviceToBouquetCallback(self, service):
1611 if len(service) > 1 and isinstance(service[1], eServiceReference):
1612 self.selectedSubservice = service
1613 if self.bouquets is None:
1616 cnt = len(self.bouquets)
1617 if cnt > 1: # show bouquet list
1618 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1619 elif cnt == 1: # add to only one existing bouquet
1620 self.addSubserviceToBouquet(self.bouquets[0][1])
1621 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1623 def bouquetSelClosed(self, confirmed):
1625 del self.selectedSubservice
1627 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1629 def addSubserviceToBouquet(self, dest):
1630 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1632 self.bsel.close(True)
1634 del self.selectedSubservice
1636 class InfoBarAdditionalInfo:
1638 self["NimA"] = Pixmap()
1639 self["NimB"] = Pixmap()
1640 self["NimA_Active"] = Pixmap()
1641 self["NimB_Active"] = Pixmap()
1643 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1644 self["TimeshiftPossible"] = self["RecordingPossible"]
1645 self["ExtensionsAvailable"] = Boolean(fixed=1)
1647 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1648 res_mgr = eDVBResourceManager.getInstance()
1650 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1652 def tunerUseMaskChanged(self, mask):
1654 self["NimA_Active"].show()
1656 self["NimA_Active"].hide()
1658 self["NimB_Active"].show()
1660 self["NimB_Active"].hide()
1662 def checkTunerState(self, service):
1663 info = service and service.frontendInfo()
1664 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1665 if feNumber is None:
1675 def gotServiceEvent(self, ev):
1676 service = self.session.nav.getCurrentService()
1677 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1678 self.checkTunerState(service)
1680 class InfoBarNotifications:
1682 self.onExecBegin.append(self.checkNotifications)
1683 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1684 self.onClose.append(self.__removeNotification)
1686 def __removeNotification(self):
1687 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1689 def checkNotificationsIfExecing(self):
1691 self.checkNotifications()
1693 def checkNotifications(self):
1694 if len(Notifications.notifications):
1695 n = Notifications.notifications[0]
1697 Notifications.notifications = Notifications.notifications[1:]
1700 if n[3].has_key("onSessionOpenCallback"):
1701 n[3]["onSessionOpenCallback"]()
1702 del n[3]["onSessionOpenCallback"]
1705 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1707 dlg = self.session.open(n[1], *n[2], **n[3])
1709 # remember that this notification is currently active
1711 Notifications.current_notifications.append(d)
1712 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1714 def __notificationClosed(self, d):
1715 Notifications.current_notifications.remove(d)
1717 class InfoBarServiceNotifications:
1719 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1721 iPlayableService.evEnd: self.serviceHasEnded
1724 def serviceHasEnded(self):
1725 print "service end!"
1728 self.setSeekState(self.SEEK_STATE_PLAY)
1732 class InfoBarCueSheetSupport:
1738 ENABLE_RESUME_SUPPORT = False
1741 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1743 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1744 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1745 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1749 self.is_closing = False
1750 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1752 iPlayableService.evStart: self.__serviceStarted,
1755 def __serviceStarted(self):
1758 print "new service started! trying to download cuts!"
1759 self.downloadCuesheet()
1761 if self.ENABLE_RESUME_SUPPORT:
1764 for (pts, what) in self.cut_list:
1765 if what == self.CUT_TYPE_LAST:
1768 if last is not None:
1769 self.resume_point = last
1770 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1772 def playLastCB(self, answer):
1774 seekable = self.__getSeekable()
1775 if seekable is not None:
1776 seekable.seekTo(self.resume_point)
1778 def __getSeekable(self):
1779 service = self.session.nav.getCurrentService()
1782 return service.seek()
1784 def cueGetCurrentPosition(self):
1785 seek = self.__getSeekable()
1788 r = seek.getPlayPosition()
1793 def jumpPreviousNextMark(self, cmp, alternative=None):
1794 current_pos = self.cueGetCurrentPosition()
1795 if current_pos is None:
1797 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1798 if mark is not None:
1800 elif alternative is not None:
1805 seekable = self.__getSeekable()
1806 if seekable is not None:
1807 seekable.seekTo(pts)
1809 def jumpPreviousMark(self):
1810 # we add 2 seconds, so if the play position is <2s after
1811 # the mark, the mark before will be used
1812 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1814 def jumpNextMark(self):
1815 self.jumpPreviousNextMark(lambda x: x)
1817 def getNearestCutPoint(self, pts, cmp=abs):
1820 for cp in self.cut_list:
1821 diff = cmp(cp[0] - pts)
1822 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1826 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1827 current_pos = self.cueGetCurrentPosition()
1828 if current_pos is None:
1829 print "not seekable"
1832 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1834 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1836 return nearest_cutpoint
1838 self.removeMark(nearest_cutpoint)
1839 elif not onlyremove and not onlyreturn:
1840 self.addMark((current_pos, self.CUT_TYPE_MARK))
1845 def addMark(self, point):
1846 insort(self.cut_list, point)
1847 self.uploadCuesheet()
1849 def removeMark(self, point):
1850 self.cut_list.remove(point)
1851 self.uploadCuesheet()
1853 def __getCuesheet(self):
1854 service = self.session.nav.getCurrentService()
1857 return service.cueSheet()
1859 def uploadCuesheet(self):
1860 cue = self.__getCuesheet()
1863 print "upload failed, no cuesheet interface"
1865 cue.setCutList(self.cut_list)
1867 def downloadCuesheet(self):
1868 cue = self.__getCuesheet()
1871 print "upload failed, no cuesheet interface"
1873 self.cut_list = cue.getCutList()
1875 class InfoBarSummary(Screen):
1877 <screen position="0,0" size="132,64">
1878 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1879 <convert type="ClockToText">WithSeconds</convert>
1881 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1882 <convert type="ServiceName">Name</convert>
1886 def __init__(self, session, parent):
1887 Screen.__init__(self, session)
1888 self["CurrentService"] = CurrentService(self.session.nav)
1889 self["CurrentTime"] = Clock()
1891 class InfoBarSummarySupport:
1895 def createSummary(self):
1896 return InfoBarSummary
1898 class InfoBarTeletextPlugin:
1900 self.teletext_plugin = None
1902 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1903 self.teletext_plugin = p
1905 if self.teletext_plugin is not None:
1906 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1908 "startTeletext": (self.startTeletext, _("View teletext..."))
1911 print "no teletext plugin found!"
1913 def startTeletext(self):
1914 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1916 class InfoBarSubtitleSupport(object):
1918 object.__init__(self)
1919 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1920 self.__subtitles_enabled = False
1922 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1924 iPlayableService.evEnd: self.__serviceStopped,
1925 iPlayableService.evUpdatedInfo: self.__updatedInfo
1927 self.cached_subtitle_checked = False
1928 self.__selected_subtitle = None
1930 def __serviceStopped(self):
1931 self.subtitle_window.hide()
1932 self.__subtitles_enabled = False
1933 self.cached_subtitle_checked = False
1935 def __updatedInfo(self):
1936 if not self.cached_subtitle_checked:
1937 subtitle = self.getCurrentServiceSubtitle()
1938 self.cached_subtitle_checked = True
1939 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1940 if self.__selected_subtitle:
1941 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1942 self.subtitle_window.show()
1943 self.__subtitles_enabled = True
1945 def getCurrentServiceSubtitle(self):
1946 service = self.session.nav.getCurrentService()
1947 return service and service.subtitle()
1949 def setSubtitlesEnable(self, enable=True):
1950 subtitle = self.getCurrentServiceSubtitle()
1951 if enable and self.__selected_subtitle is not None:
1952 if subtitle and not self.__subtitles_enabled:
1953 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1954 self.subtitle_window.show()
1955 self.__subtitles_enabled = True
1958 subtitle.disableSubtitles(self.subtitle_window.instance)
1959 self.__subtitles_enabled = False
1960 self.subtitle_window.hide()
1962 def setSelectedSubtitle(self, subtitle):
1963 self.__selected_subtitle = subtitle
1965 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1966 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1968 class InfoBarServiceErrorPopupSupport:
1970 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1972 iPlayableService.evTuneFailed: self.__tuneFailed,
1973 iPlayableService.evStart: self.__serviceStarted
1975 self.__serviceStarted()
1977 def __serviceStarted(self):
1978 self.last_error = None
1979 Notifications.RemovePopup(id = "ZapError")
1981 def __tuneFailed(self):
1982 service = self.session.nav.getCurrentService()
1983 info = service and service.info()
1984 error = info and info.getInfo(iServiceInformation.sDVBState)
1986 if error == self.last_error:
1989 self.last_error = error
1992 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1993 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1994 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1995 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1996 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1997 eDVBServicePMTHandler.eventNewProgramInfo: None,
1998 eDVBServicePMTHandler.eventTuned: None,
1999 eDVBServicePMTHandler.eventSOF: None,
2000 eDVBServicePMTHandler.eventEOF: None
2003 error = errors.get(error) #this returns None when the key not exist in the dict
2005 if error is not None:
2006 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2008 Notifications.RemovePopup(id = "ZapError")