1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import Label
9 from Components.Pixmap import Pixmap
10 from Components.PluginComponent import plugins
11 from Components.ServiceEventTracker import ServiceEventTracker
12 from Components.Sources.CurrentService import CurrentService
13 from Components.Sources.EventInfo import EventInfo
14 from Components.Sources.FrontendStatus import FrontendStatus
15 from Components.Sources.Boolean import Boolean
16 from Components.Sources.Clock import Clock
17 from Components.TimerList import TimerEntryComponent
18 from Components.config import config, ConfigBoolean, ConfigClock
19 from EpgSelection import EPGSelection
20 from Plugins.Plugin import PluginDescriptor
22 from Screen import Screen
23 from Screens.ChoiceBox import ChoiceBox
24 from Screens.Dish import Dish
25 from Screens.EventView import EventViewEPGSelect, EventViewSimple
26 from Screens.InputBox import InputBox
27 from Screens.MessageBox import MessageBox
28 from Screens.MinuteInput import MinuteInput
29 from Screens.TimerSelection import TimerSelection
30 from Screens.PictureInPicture import PictureInPicture
31 from Screens.SubtitleDisplay import SubtitleDisplay
32 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
33 from Screens.SleepTimerEdit import SleepTimerEdit
34 from Screens.TimeDateInput import TimeDateInput
35 from ServiceReference import ServiceReference
37 from Tools import Notifications
38 from Tools.Directories import SCOPE_HDD, resolveFilename
40 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
41 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
43 from time import time, localtime, strftime
44 from os import stat as os_stat
45 from bisect import insort
48 from Menu import MainMenu, mdom
52 self.dishDialog = self.session.instantiateDialog(Dish)
53 self.onLayoutFinish.append(self.dishDialog.show)
55 class InfoBarShowHide:
56 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
64 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
66 "toggleShow": self.toggleShow,
68 }, 1) # lower prio to make it possible to override ok and cancel..
70 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
72 iPlayableService.evStart: self.serviceStarted,
75 self.__state = self.STATE_SHOWN
78 self.hideTimer = eTimer()
79 self.hideTimer.timeout.get().append(self.doTimerHide)
80 self.hideTimer.start(5000, True)
82 self.onShow.append(self.__onShow)
83 self.onHide.append(self.__onHide)
85 def serviceStarted(self):
87 if config.usage.show_infobar_on_zap.value:
91 self.__state = self.STATE_SHOWN
94 def startHideTimer(self):
95 if self.__state == self.STATE_SHOWN and not self.__locked:
96 idx = config.usage.infobar_timeout.index
98 self.hideTimer.start(idx*1000, True)
101 self.__state = self.STATE_HIDDEN
105 self.startHideTimer()
107 def doTimerHide(self):
108 self.hideTimer.stop()
109 if self.__state == self.STATE_SHOWN:
112 def toggleShow(self):
113 if self.__state == self.STATE_SHOWN:
115 self.hideTimer.stop()
116 elif self.__state == self.STATE_HIDDEN:
120 self.__locked = self.__locked + 1
123 self.hideTimer.stop()
125 def unlockShow(self):
126 self.__locked = self.__locked - 1
128 self.startHideTimer()
130 # def startShow(self):
131 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
132 # self.__state = self.STATE_SHOWN
134 # def startHide(self):
135 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
136 # self.__state = self.STATE_HIDDEN
138 class NumberZap(Screen):
145 self.close(int(self["number"].getText()))
147 def keyNumberGlobal(self, number):
148 self.Timer.start(3000, True) #reset timer
149 self.field = self.field + str(number)
150 self["number"].setText(self.field)
151 if len(self.field) >= 4:
154 def __init__(self, session, number):
155 Screen.__init__(self, session)
156 self.field = str(number)
158 self["channel"] = Label(_("Channel:"))
160 self["number"] = Label(self.field)
162 self["actions"] = NumberActionMap( [ "SetupActions" ],
166 "1": self.keyNumberGlobal,
167 "2": self.keyNumberGlobal,
168 "3": self.keyNumberGlobal,
169 "4": self.keyNumberGlobal,
170 "5": self.keyNumberGlobal,
171 "6": self.keyNumberGlobal,
172 "7": self.keyNumberGlobal,
173 "8": self.keyNumberGlobal,
174 "9": self.keyNumberGlobal,
175 "0": self.keyNumberGlobal
178 self.Timer = eTimer()
179 self.Timer.timeout.get().append(self.keyOK)
180 self.Timer.start(3000, True)
182 class InfoBarNumberZap:
183 """ Handles an initial number for NumberZapping """
185 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
187 "1": self.keyNumberGlobal,
188 "2": self.keyNumberGlobal,
189 "3": self.keyNumberGlobal,
190 "4": self.keyNumberGlobal,
191 "5": self.keyNumberGlobal,
192 "6": self.keyNumberGlobal,
193 "7": self.keyNumberGlobal,
194 "8": self.keyNumberGlobal,
195 "9": self.keyNumberGlobal,
196 "0": self.keyNumberGlobal,
199 def keyNumberGlobal(self, number):
200 # print "You pressed number " + str(number)
202 self.servicelist.recallPrevService()
204 self.session.openWithCallback(self.numberEntered, NumberZap, number)
206 def numberEntered(self, retval):
207 # print self.servicelist
209 self.zapToNumber(retval)
211 def searchNumberHelper(self, serviceHandler, num, bouquet):
212 servicelist = serviceHandler.list(bouquet)
213 if not servicelist is None:
215 serviceIterator = servicelist.getNext()
216 if not serviceIterator.valid(): #check end of list
218 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
221 if not num: #found service with searched number ?
222 return serviceIterator, 0
225 def zapToNumber(self, number):
226 bouquet = self.servicelist.bouquet_root
228 serviceHandler = eServiceCenter.getInstance()
229 if not config.usage.multibouquet.value:
230 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
232 bouquetlist = serviceHandler.list(bouquet)
233 if not bouquetlist is None:
235 bouquet = bouquetlist.getNext()
236 if not bouquet.valid(): #check end of list
238 if bouquet.flags & eServiceReference.isDirectory:
239 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
240 if not service is None:
241 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
242 self.servicelist.clearPath()
243 if self.servicelist.bouquet_root != bouquet:
244 self.servicelist.enterPath(self.servicelist.bouquet_root)
245 self.servicelist.enterPath(bouquet)
246 self.servicelist.setCurrentSelection(service) #select the service in servicelist
247 self.servicelist.zap()
249 config.misc.initialchannelselection = ConfigBoolean(default = True)
251 class InfoBarChannelSelection:
252 """ ChannelSelection - handles the channelSelection dialog and the initial
253 channelChange actions which open the channelSelection dialog """
256 self.servicelist = self.session.instantiateDialog(ChannelSelection)
258 if config.misc.initialchannelselection.value:
259 self.onShown.append(self.firstRun)
261 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
263 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
264 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
265 "zapUp": (self.zapUp, _("previous channel")),
266 "zapDown": (self.zapDown, _("next channel")),
267 "historyBack": (self.historyBack, _("previous channel in history")),
268 "historyNext": (self.historyNext, _("next channel in history")),
269 "openServiceList": (self.openServiceList, _("open servicelist")),
272 def showTvChannelList(self, zap=False):
273 self.servicelist.setModeTv()
275 self.servicelist.zap()
276 self.session.execDialog(self.servicelist)
278 def showRadioChannelList(self, zap=False):
279 self.servicelist.setModeRadio()
281 self.servicelist.zap()
282 self.session.execDialog(self.servicelist)
285 self.onShown.remove(self.firstRun)
286 config.misc.initialchannelselection.value = False
287 config.misc.initialchannelselection.save()
288 self.switchChannelDown()
290 def historyBack(self):
291 self.servicelist.historyBack()
293 def historyNext(self):
294 self.servicelist.historyNext()
296 def switchChannelUp(self):
297 self.servicelist.moveUp()
298 self.session.execDialog(self.servicelist)
300 def switchChannelDown(self):
301 self.servicelist.moveDown()
302 self.session.execDialog(self.servicelist)
304 def openServiceList(self):
305 self.session.execDialog(self.servicelist)
308 if self.servicelist.inBouquet():
309 prev = self.servicelist.getCurrentSelection()
311 prev = prev.toString()
313 if config.usage.quickzap_bouquet_change.value:
314 if self.servicelist.atBegin():
315 self.servicelist.prevBouquet()
316 self.servicelist.moveUp()
317 cur = self.servicelist.getCurrentSelection()
318 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
321 self.servicelist.moveUp()
322 self.servicelist.zap()
325 if self.servicelist.inBouquet():
326 prev = self.servicelist.getCurrentSelection()
328 prev = prev.toString()
330 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
331 self.servicelist.nextBouquet()
333 self.servicelist.moveDown()
334 cur = self.servicelist.getCurrentSelection()
335 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
338 self.servicelist.moveDown()
339 self.servicelist.zap()
342 """ Handles a menu action, to open the (main) menu """
344 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
346 "mainMenu": (self.mainMenu, _("Enter main menu...")),
348 self.session.infobar = None
351 print "loading mainmenu XML..."
352 menu = mdom.childNodes[0]
353 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
355 self.session.infobar = self
356 # so we can access the currently active infobar from screens opened from within the mainmenu
357 # at the moment used from the SubserviceSelection
359 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
361 def mainMenuClosed(self, *val):
362 self.session.infobar = None
364 class InfoBarSimpleEventView:
365 """ Opens the Eventview for now/next """
367 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
369 "showEventInfo": (self.openEventView, _("show event details")),
372 def openEventView(self):
374 service = self.session.nav.getCurrentService()
375 ref = self.session.nav.getCurrentlyPlayingServiceReference()
376 info = service.info()
379 self.epglist.append(ptr)
382 self.epglist.append(ptr)
383 if len(self.epglist) > 0:
384 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
386 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
387 if len(self.epglist) > 1:
388 tmp = self.epglist[0]
389 self.epglist[0]=self.epglist[1]
391 setEvent(self.epglist[0])
394 """ EPG - Opens an EPG list when the showEPGList action fires """
396 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
398 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
401 self.is_now_next = False
403 self.bouquetSel = None
404 self.eventView = None
405 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
407 "showEventInfo": (self.openEventView, _("show EPG...")),
408 "showSingleServiceEPG": (self.openSingleServiceEPG, _("show single service EPG...")),
409 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
412 def showEventInfoWhenNotVisible(self):
419 def zapToService(self, service):
420 if not service is None:
421 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
422 self.servicelist.clearPath()
423 if self.servicelist.bouquet_root != self.epg_bouquet:
424 self.servicelist.enterPath(self.servicelist.bouquet_root)
425 self.servicelist.enterPath(self.epg_bouquet)
426 self.servicelist.setCurrentSelection(service) #select the service in servicelist
427 self.servicelist.zap()
429 def getBouquetServices(self, bouquet):
431 servicelist = eServiceCenter.getInstance().list(bouquet)
432 if not servicelist is None:
434 service = servicelist.getNext()
435 if not service.valid(): #check if end of list
437 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
439 services.append(ServiceReference(service))
442 def openBouquetEPG(self, bouquet, withCallback=True):
443 services = self.getBouquetServices(bouquet)
445 self.epg_bouquet = bouquet
447 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
449 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
451 def changeBouquetCB(self, direction, epg):
454 self.bouquetSel.down()
457 bouquet = self.bouquetSel.getCurrent()
458 services = self.getBouquetServices(bouquet)
460 self.epg_bouquet = bouquet
461 epg.setServices(services)
463 def closed(self, ret=False):
464 closedScreen = self.dlg_stack.pop()
465 if self.bouquetSel and closedScreen == self.bouquetSel:
466 self.bouquetSel = None
467 elif self.eventView and closedScreen == self.eventView:
468 self.eventView = None
470 dlgs=len(self.dlg_stack)
472 self.dlg_stack[dlgs-1].close(dlgs > 1)
474 def openMultiServiceEPG(self, withCallback=True):
475 bouquets = self.servicelist.getBouquetList()
480 if cnt > 1: # show bouquet list
482 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
483 self.dlg_stack.append(self.bouquetSel)
485 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
487 self.openBouquetEPG(bouquets[0][1], withCallback)
489 def openSingleServiceEPG(self):
490 ref=self.session.nav.getCurrentlyPlayingServiceReference()
491 self.session.open(EPGSelection, ref)
493 def openSimilarList(self, eventid, refstr):
494 self.session.open(EPGSelection, refstr, None, eventid)
496 def getNowNext(self):
498 service = self.session.nav.getCurrentService()
499 info = service and service.info()
500 ptr = info and info.getEvent(0)
502 self.epglist.append(ptr)
503 ptr = info and info.getEvent(1)
505 self.epglist.append(ptr)
507 def __evEventInfoChanged(self):
508 if self.is_now_next and len(self.dlg_stack) == 1:
510 assert self.eventView
511 if len(self.epglist):
512 self.eventView.setEvent(self.epglist[0])
514 def openEventView(self):
515 ref = self.session.nav.getCurrentlyPlayingServiceReference()
517 if len(self.epglist) == 0:
518 self.is_now_next = False
519 epg = eEPGCache.getInstance()
520 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
522 self.epglist.append(ptr)
523 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
525 self.epglist.append(ptr)
527 self.is_now_next = True
528 if len(self.epglist) > 0:
529 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
530 self.dlg_stack.append(self.eventView)
532 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
533 self.openMultiServiceEPG(False)
535 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
536 if len(self.epglist) > 1:
537 tmp = self.epglist[0]
538 self.epglist[0]=self.epglist[1]
540 setEvent(self.epglist[0])
543 """provides a snr/agc/ber display"""
545 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
548 """provides a current/next event info display"""
550 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
551 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
553 class InfoBarRdsDecoder:
554 """provides RDS and Rass support/display"""
556 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
557 self.rass_interactive = None
559 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
561 iPlayableService.evEnd: self.__serviceStopped,
562 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
565 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
567 "startRassInteractive": self.startRassInteractive
570 self["RdsActions"].setEnabled(False)
572 self.onLayoutFinish.append(self.rds_display.show)
573 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
575 def RassInteractivePossibilityChanged(self, state):
576 self["RdsActions"].setEnabled(state)
578 def RassSlidePicChanged(self):
579 if not self.rass_interactive:
580 service = self.session.nav.getCurrentService()
581 decoder = service and service.rdsDecoder()
583 decoder.showRassSlidePicture()
585 def __serviceStopped(self):
586 if self.rass_interactive is not None:
587 rass_interactive = self.rass_interactive
588 self.rass_interactive = None
589 rass_interactive.close()
591 def startRassInteractive(self):
592 self.rds_display.hide()
593 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
595 def RassInteractiveClosed(self, *val):
596 if self.rass_interactive is not None:
597 self.rass_interactive = None
598 self.RassSlidePicChanged()
599 self.rds_display.show()
601 class InfoBarServiceName:
603 self["CurrentService"] = CurrentService(self.session.nav)
606 """handles actions like seeking, pause"""
608 # ispause, isff, issm
609 SEEK_STATE_PLAY = (0, 0, 0, ">")
610 SEEK_STATE_PAUSE = (1, 0, 0, "||")
611 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
612 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
613 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
614 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
615 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
616 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
618 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
619 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
620 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
621 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
623 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
624 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
625 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
627 SEEK_STATE_EOF = (1, 0, 0, "END")
629 def __init__(self, actionmap = "InfobarSeekActions"):
630 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
632 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
633 iPlayableService.evStart: self.__serviceStarted,
635 iPlayableService.evEOF: self.__evEOF,
636 iPlayableService.evSOF: self.__evSOF,
639 class InfoBarSeekActionMap(HelpableActionMap):
640 def __init__(self, screen, *args, **kwargs):
641 HelpableActionMap.__init__(self, screen, *args, **kwargs)
644 def action(self, contexts, action):
645 print "action:", action
646 if action[:5] == "seek:":
647 time = int(action[5:])
648 self.screen.seekRelative(time * 90000)
649 self.screen.showAfterSeek()
652 return HelpableActionMap.action(self, contexts, action)
654 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
656 "playpauseService": self.playpauseService,
657 "pauseService": (self.pauseService, _("pause")),
658 "unPauseService": (self.unPauseService, _("continue")),
660 "seekFwd": (self.seekFwd, _("skip forward")),
661 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
662 "seekBack": (self.seekBack, _("skip backward")),
663 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
665 "seekFwdDef": (self.seekFwdDef, _("skip forward (self defined)")),
666 "seekBackDef": (self.seekBackDef, _("skip backward (self defined)"))
668 # give them a little more priority to win over color buttons
670 self["SeekActions"].setEnabled(False)
672 self.seekstate = self.SEEK_STATE_PLAY
674 self.seek_flag = True
676 self.onPlayStateChanged = [ ]
678 self.lockedBecauseOfSkipping = False
680 self.__seekableStatusChanged()
682 def showAfterSeek(self):
683 if isinstance(self, InfoBarShowHide):
693 service = self.session.nav.getCurrentService()
697 seek = service.seek()
699 if seek is None or not seek.isCurrentlySeekable():
704 def isSeekable(self):
705 if self.getSeek() is None:
709 def __seekableStatusChanged(self):
710 print "seekable status changed!"
711 if not self.isSeekable():
712 self["SeekActions"].setEnabled(False)
713 print "not seekable, return to play"
714 self.setSeekState(self.SEEK_STATE_PLAY)
716 self["SeekActions"].setEnabled(True)
719 def __serviceStarted(self):
720 self.seekstate = self.SEEK_STATE_PLAY
721 self.__seekableStatusChanged()
723 def setSeekState(self, state):
724 service = self.session.nav.getCurrentService()
729 if not self.isSeekable():
730 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
731 state = self.SEEK_STATE_PLAY
733 pauseable = service.pause()
735 if pauseable is None:
736 print "not pauseable."
737 state = self.SEEK_STATE_PLAY
739 oldstate = self.seekstate
740 self.seekstate = state
743 if oldstate[i] != self.seekstate[i]:
744 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
746 for c in self.onPlayStateChanged:
749 self.checkSkipShowHideLock()
753 def playpauseService(self):
754 if self.seekstate != self.SEEK_STATE_PLAY:
755 self.unPauseService()
759 def pauseService(self):
760 if self.seekstate == self.SEEK_STATE_PAUSE:
761 print "pause, but in fact unpause"
762 self.unPauseService()
764 if self.seekstate == self.SEEK_STATE_PLAY:
765 print "yes, playing."
767 print "no", self.seekstate
769 self.setSeekState(self.SEEK_STATE_PAUSE);
771 def unPauseService(self):
773 if self.seekstate == self.SEEK_STATE_PLAY:
775 self.setSeekState(self.SEEK_STATE_PLAY)
777 def doSeek(self, seektime):
778 print "doseek", seektime
779 service = self.session.nav.getCurrentService()
783 seekable = self.getSeek()
787 seekable.seekTo(90 * seektime)
791 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
792 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
793 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
794 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
795 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
796 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
797 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
798 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
799 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
800 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
801 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
802 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
803 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
804 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
805 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
806 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
808 self.setSeekState(lookup[self.seekstate])
812 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
813 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
814 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
815 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
816 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
817 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
818 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
819 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
820 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
821 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
822 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
823 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
824 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
825 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
826 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
827 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
829 self.setSeekState(lookup[self.seekstate])
831 if self.seekstate == self.SEEK_STATE_PAUSE:
832 seekable = self.getSeek()
833 if seekable is not None:
834 seekable.seekRelative(-1, 3)
836 def seekFwdDef(self):
837 self.seek_flag = False
838 seconds = config.usage.self_defined_seek.value
839 print "Seek", seconds, "seconds self defined forward"
840 seekable = self.getSeek()
841 if seekable is not None:
842 seekable.seekRelative(1, seconds * 90000)
844 def seekBackDef(self):
845 self.seek_flag = False
846 seconds = config.usage.self_defined_seek.value
847 print "Seek", seconds, "seconds self defined backward"
848 seekable = self.getSeek()
849 if seekable is not None:
850 seekable.seekRelative(1, 0 - seconds * 90000)
852 def seekFwdManual(self):
853 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
855 def fwdSeekTo(self, minutes):
856 print "Seek", minutes, "minutes forward"
858 seekable = self.getSeek()
859 if seekable is not None:
860 seekable.seekRelative(1, minutes * 60 * 90000)
862 def seekBackManual(self):
863 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
865 def rwdSeekTo(self, minutes):
867 self.fwdSeekTo(0 - minutes)
869 def checkSkipShowHideLock(self):
870 wantlock = self.seekstate != self.SEEK_STATE_PLAY
872 if config.usage.show_infobar_on_zap.value:
873 if self.lockedBecauseOfSkipping and not wantlock:
875 self.lockedBecauseOfSkipping = False
877 if wantlock and not self.lockedBecauseOfSkipping:
879 self.lockedBecauseOfSkipping = True
882 if self.seekstate == self.SEEK_STATE_EOF:
884 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
885 print "end of stream while seeking back, ignoring."
888 # if we are seeking, we try to end up ~1s before the end, and pause there.
889 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
890 self.setSeekState(self.SEEK_STATE_EOF)
891 self.seekRelativeToEnd(-90000)
893 self.setSeekState(self.SEEK_STATE_EOF)
896 self.setSeekState(self.SEEK_STATE_PLAY)
899 def seekRelative(self, diff):
900 if self.seek_flag == True:
901 seekable = self.getSeek()
902 if seekable is not None:
903 print "seekRelative: res:", seekable.seekRelative(1, diff)
907 self.seek_flag = True
909 def seekRelativeToEnd(self, diff):
910 assert diff <= 0, "diff is expected to be negative!"
912 # might sound like an evil hack, but:
913 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
914 # and we don't get that by passing 0 here (it would seek to begin).
918 # relative-to-end seeking is implemented as absolutes seeks with negative time
919 self.seekAbsolute(diff)
921 def seekAbsolute(self, abs):
922 seekable = self.getSeek()
923 if seekable is not None:
926 from Screens.PVRState import PVRState, TimeshiftState
928 class InfoBarPVRState:
929 def __init__(self, screen=PVRState):
930 self.onPlayStateChanged.append(self.__playStateChanged)
931 self.pvrStateDialog = self.session.instantiateDialog(screen)
932 self.onShow.append(self._mayShow)
933 self.onHide.append(self.pvrStateDialog.hide)
936 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
937 self.pvrStateDialog.show()
939 def __playStateChanged(self, state):
940 playstateString = state[3]
941 self.pvrStateDialog["state"].setText(playstateString)
944 class InfoBarTimeshiftState(InfoBarPVRState):
946 InfoBarPVRState.__init__(self, screen=TimeshiftState)
949 if self.execing and self.timeshift_enabled:
950 self.pvrStateDialog.show()
952 class InfoBarShowMovies:
954 # i don't really like this class.
955 # it calls a not further specified "movie list" on up/down/movieList,
956 # so this is not more than an action map
958 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
960 "movieList": (self.showMovies, _("movie list")),
961 "up": (self.showMovies, _("movie list")),
962 "down": (self.showMovies, _("movie list"))
965 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
969 # Timeshift works the following way:
970 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
971 # - normal playback TUNER unused PLAY enable disable disable
972 # - user presses "yellow" button. FILE record PAUSE enable disable enable
973 # - user presess pause again FILE record PLAY enable disable enable
974 # - user fast forwards FILE record FF enable disable enable
975 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
976 # - user backwards FILE record BACK # !! enable disable enable
980 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
981 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
982 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
983 # - the user can now PVR around
984 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
985 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
987 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
988 # - if the user rewinds, or press pause, timeshift will be activated again
990 # note that a timeshift can be enabled ("recording") and
991 # activated (currently time-shifting).
993 class InfoBarTimeshift:
995 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
997 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
998 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1000 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1002 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1003 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1004 }, prio=-1) # priority over record
1006 self.timeshift_enabled = 0
1007 self.timeshift_state = 0
1008 self.ts_rewind_timer = eTimer()
1009 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1011 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1013 iPlayableService.evStart: self.__serviceStarted,
1014 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1017 def getTimeshift(self):
1018 service = self.session.nav.getCurrentService()
1019 return service and service.timeshift()
1021 def startTimeshift(self):
1022 print "enable timeshift"
1023 ts = self.getTimeshift()
1025 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1026 print "no ts interface"
1029 if self.timeshift_enabled:
1030 print "hu, timeshift already enabled?"
1032 if not ts.startTimeshift():
1033 self.timeshift_enabled = 1
1035 # we remove the "relative time" for now.
1036 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1039 #self.setSeekState(self.SEEK_STATE_PAUSE)
1040 self.activateTimeshiftEnd(False)
1042 # enable the "TimeshiftEnableActions", which will override
1043 # the startTimeshift actions
1044 self.__seekableStatusChanged()
1046 print "timeshift failed"
1048 def stopTimeshift(self):
1049 if not self.timeshift_enabled:
1051 print "disable timeshift"
1052 ts = self.getTimeshift()
1055 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1057 def stopTimeshiftConfirmed(self, confirmed):
1061 ts = self.getTimeshift()
1066 self.timeshift_enabled = 0
1069 self.__seekableStatusChanged()
1071 # activates timeshift, and seeks to (almost) the end
1072 def activateTimeshiftEnd(self, back = True):
1073 ts = self.getTimeshift()
1074 print "activateTimeshiftEnd"
1079 if ts.isTimeshiftActive():
1080 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1084 ts.activateTimeshift() # activate timeshift will automatically pause
1085 self.setSeekState(self.SEEK_STATE_PAUSE)
1086 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1089 self.ts_rewind_timer.start(200, 1)
1091 def rewindService(self):
1092 self.setSeekState(self.SEEK_STATE_BACK_16X)
1094 # same as activateTimeshiftEnd, but pauses afterwards.
1095 def activateTimeshiftEndAndPause(self):
1096 print "activateTimeshiftEndAndPause"
1097 #state = self.seekstate
1098 self.activateTimeshiftEnd(False)
1100 def __seekableStatusChanged(self):
1103 print "self.isSeekable", self.isSeekable()
1104 print "self.timeshift_enabled", self.timeshift_enabled
1106 # when this service is not seekable, but timeshift
1107 # is enabled, this means we can activate
1109 if not self.isSeekable() and self.timeshift_enabled:
1112 print "timeshift activate:", enabled
1113 self["TimeshiftActivateActions"].setEnabled(enabled)
1115 def __serviceStarted(self):
1116 self.timeshift_enabled = False
1117 self.__seekableStatusChanged()
1119 from Screens.PiPSetup import PiPSetup
1121 class InfoBarExtensions:
1122 EXTENSION_SINGLE = 0
1128 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1130 "extensions": (self.showExtensionSelection, _("view extensions...")),
1133 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1134 self.list.append((type, extension, key))
1136 def updateExtension(self, extension, key = None):
1137 self.extensionsList.append(extension)
1139 if self.extensionKeys.has_key(key):
1143 for x in self.availableKeys:
1144 if not self.extensionKeys.has_key(x):
1149 self.extensionKeys[key] = len(self.extensionsList) - 1
1151 def updateExtensions(self):
1152 self.extensionsList = []
1153 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1154 self.extensionKeys = {}
1156 if x[0] == self.EXTENSION_SINGLE:
1157 self.updateExtension(x[1], x[2])
1160 self.updateExtension(y[0], y[1])
1163 def showExtensionSelection(self):
1164 self.updateExtensions()
1165 extensionsList = self.extensionsList[:]
1168 for x in self.availableKeys:
1169 if self.extensionKeys.has_key(x):
1170 entry = self.extensionKeys[x]
1171 extension = self.extensionsList[entry]
1173 name = str(extension[0]())
1174 list.append((extension[0](), extension))
1176 extensionsList.remove(extension)
1178 extensionsList.remove(extension)
1179 for x in extensionsList:
1180 list.append((x[0](), x))
1181 keys += [""] * len(extensionsList)
1182 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1184 def extensionCallback(self, answer):
1185 if answer is not None:
1188 from Tools.BoundFunction import boundFunction
1190 # depends on InfoBarExtensions
1191 from Components.PluginComponent import plugins
1193 class InfoBarPlugins:
1195 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1197 def getPluginName(self, name):
1200 def getPluginList(self):
1202 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1203 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1206 def runPlugin(self, plugin):
1207 self.session.servicelist = self.servicelist
1208 plugin(session = self.session)
1209 del self.session.servicelist
1211 # depends on InfoBarExtensions
1212 class InfoBarSleepTimer:
1214 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1216 def available(self):
1219 def getSleepTimerName(self):
1220 return _("Sleep Timer")
1222 def showSleepTimerSetup(self):
1223 self.session.open(SleepTimerEdit)
1225 # depends on InfoBarExtensions
1228 self.session.pipshown = False
1230 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1231 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1232 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1234 def available(self):
1238 return self.session.pipshown
1240 def getShowHideName(self):
1241 if self.session.pipshown:
1242 return _("Disable Picture in Picture")
1244 return _("Activate Picture in Picture")
1246 def getSwapName(self):
1247 return _("Swap Services")
1249 def getMoveName(self):
1250 return _("Move Picture in Picture")
1253 if self.session.pipshown:
1254 del self.session.pip
1255 self.session.pipshown = False
1257 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1258 self.session.pip.show()
1259 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1260 if self.session.pip.playService(newservice):
1261 self.session.pipshown = True
1262 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1264 self.session.pipshown = False
1265 del self.session.pip
1266 self.session.nav.playService(newservice)
1269 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1270 if self.session.pip.servicePath:
1271 servicepath = self.servicelist.getCurrentServicePath()
1272 ref=servicepath[len(servicepath)-1]
1273 pipref=self.session.pip.getCurrentService()
1274 self.session.pip.playService(swapservice)
1275 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1276 if pipref.toString() != ref.toString(): # is a subservice ?
1277 self.session.nav.stopService() # stop portal
1278 self.session.nav.playService(pipref) # start subservice
1279 self.session.pip.servicePath=servicepath
1282 self.session.open(PiPSetup, pip = self.session.pip)
1284 from RecordTimer import parseEvent
1286 class InfoBarInstantRecord:
1287 """Instant Record - handles the instantRecord action in order to
1288 start/stop instant records"""
1290 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1292 "instantRecord": (self.instantRecord, _("Instant Record...")),
1295 self["BlinkingPoint"] = BlinkingPixmapConditional()
1296 self["BlinkingPoint"].hide()
1297 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1299 def stopCurrentRecording(self, entry = -1):
1300 if entry is not None and entry != -1:
1301 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1302 self.recording.remove(self.recording[entry])
1304 def startInstantRecording(self, limitEvent = False):
1305 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1307 # try to get event info
1310 service = self.session.nav.getCurrentService()
1311 epg = eEPGCache.getInstance()
1312 event = epg.lookupEventTime(serviceref, -1, 0)
1314 info = service.info()
1315 ev = info.getEvent(0)
1321 end = time() + 3600 * 10
1322 name = "instant record"
1326 if event is not None:
1327 curEvent = parseEvent(event)
1329 description = curEvent[3]
1330 eventid = curEvent[4]
1335 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1337 data = (begin, end, name, description, eventid)
1339 recording = self.session.nav.recordWithTimer(serviceref, *data)
1340 recording.dontSave = True
1341 self.recording.append(recording)
1343 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1345 def isInstantRecordRunning(self):
1346 print "self.recording:", self.recording
1347 if len(self.recording) > 0:
1348 for x in self.recording:
1353 def recordQuestionCallback(self, answer):
1354 print "pre:\n", self.recording
1356 if answer is None or answer[1] == "no":
1359 recording = self.recording[:]
1361 if not x in self.session.nav.RecordTimer.timer_list:
1362 self.recording.remove(x)
1363 elif x.dontSave and x.isRunning():
1364 list.append(TimerEntryComponent(x, False))
1366 if answer[1] == "changeduration":
1367 if len(self.recording) == 1:
1368 self.changeDuration(0)
1370 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1371 elif answer[1] == "changeendtime":
1372 if len(self.recording) == 1:
1375 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1376 elif answer[1] == "stop":
1377 if len(self.recording) == 1:
1378 self.stopCurrentRecording(0)
1380 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1381 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1382 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1383 if answer[1] == "manualduration":
1384 self.changeDuration(len(self.recording)-1)
1385 elif answer[1] == "manualendtime":
1386 self.setEndtime(len(self.recording)-1)
1387 print "after:\n", self.recording
1389 def setEndtime(self, entry):
1390 if entry is not None:
1391 self.selectedEntry = entry
1392 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1393 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1394 dlg.setTitle(_("Please change recording endtime"))
1396 def TimeDateInputClosed(self, ret):
1399 localendtime = localtime(ret[1])
1400 print "stopping recording at", strftime("%c", localendtime)
1401 self.recording[self.selectedEntry].end = ret[1]
1402 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1404 def changeDuration(self, entry):
1405 if entry is not None:
1406 self.selectedEntry = entry
1407 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1409 def inputCallback(self, value):
1410 if value is not None:
1411 print "stopping recording after", int(value), "minutes."
1412 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1413 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1415 def instantRecord(self):
1417 stat = os_stat(resolveFilename(SCOPE_HDD))
1419 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1422 if self.isInstantRecordRunning():
1423 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1424 title=_("A recording is currently running.\nWhat do you want to do?"), \
1425 list=[(_("stop recording"), "stop"), \
1426 (_("change recording (duration)"), "changeduration"), \
1427 (_("change recording (endtime)"), "changeendtime"), \
1428 (_("add recording (indefinitely)"), "indefinitely"), \
1429 (_("add recording (stop after current event)"), "event"), \
1430 (_("add recording (enter recording duration)"), "manualduration"), \
1431 (_("add recording (enter recording endtime)"), "manualendtime"), \
1432 (_("do nothing"), "no")])
1434 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1435 title=_("Start recording?"), \
1436 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1437 (_("add recording (stop after current event)"), "event"), \
1438 (_("add recording (enter recording duration)"), "manualduration"), \
1439 (_("add recording (enter recording endtime)"), "manualendtime"), \
1440 (_("don't record"), "no")])
1442 from Tools.ISO639 import LanguageCodes
1444 class InfoBarAudioSelection:
1446 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1448 "audioSelection": (self.audioSelection, _("Audio Options...")),
1451 def audioSelection(self):
1452 service = self.session.nav.getCurrentService()
1453 audio = service and service.audioTracks()
1454 self.audioTracks = audio
1455 n = audio and audio.getNumberOfTracks() or 0
1456 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1458 print "tlist:", tlist
1460 self.audioChannel = service.audioChannel()
1463 i = audio.getTrackInfo(x)
1464 language = i.getLanguage()
1465 description = i.getDescription()
1467 if LanguageCodes.has_key(language):
1468 language = LanguageCodes[language][0]
1470 if len(description):
1471 description += " (" + language + ")"
1473 description = language
1475 tlist.append((description, x))
1477 selectedAudio = tlist[0][1]
1478 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1482 if x[1] != selectedAudio:
1487 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1488 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1490 del self.audioTracks
1492 def audioSelected(self, audio):
1493 if audio is not None:
1494 if isinstance(audio[1], str):
1495 if audio[1] == "mode":
1496 keys = ["red", "green", "yellow"]
1497 selection = self.audioChannel.getCurrentChannel()
1498 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1499 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1501 del self.audioChannel
1502 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1503 self.audioTracks.selectTrack(audio[1])
1505 del self.audioChannel
1506 del self.audioTracks
1508 def modeSelected(self, mode):
1509 if mode is not None:
1510 self.audioChannel.selectChannel(mode[1])
1511 del self.audioChannel
1513 class InfoBarSubserviceSelection:
1515 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1517 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1520 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1522 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1523 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1525 self["SubserviceQuickzapAction"].setEnabled(False)
1527 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1531 def checkSubservicesAvail(self, ev):
1532 if ev == iPlayableService.evUpdatedEventInfo:
1533 service = self.session.nav.getCurrentService()
1534 subservices = service and service.subServices()
1535 if not subservices or subservices.getNumberOfSubservices() == 0:
1536 self["SubserviceQuickzapAction"].setEnabled(False)
1538 def nextSubservice(self):
1539 self.changeSubservice(+1)
1541 def prevSubservice(self):
1542 self.changeSubservice(-1)
1544 def changeSubservice(self, direction):
1545 service = self.session.nav.getCurrentService()
1546 subservices = service and service.subServices()
1547 n = subservices and subservices.getNumberOfSubservices()
1550 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1552 if subservices.getSubservice(x).toString() == ref.toString():
1555 selection += direction
1560 newservice = subservices.getSubservice(selection)
1561 if newservice.valid():
1564 self.session.nav.playService(newservice)
1566 def subserviceSelection(self):
1567 service = self.session.nav.getCurrentService()
1568 subservices = service and service.subServices()
1569 self.bouquets = self.servicelist.getBouquetList()
1570 n = subservices and subservices.getNumberOfSubservices()
1573 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1576 i = subservices.getSubservice(x)
1577 if i.toString() == ref.toString():
1579 tlist.append((i.getName(), i))
1581 if self.bouquets and len(self.bouquets):
1582 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1583 if config.usage.multibouquet.value:
1584 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1586 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1589 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1590 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1593 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1595 def subserviceSelected(self, service):
1597 if not service is None:
1598 if isinstance(service[1], str):
1599 if service[1] == "quickzap":
1600 from Screens.SubservicesQuickzap import SubservicesQuickzap
1601 self.session.open(SubservicesQuickzap, service[2])
1603 self["SubserviceQuickzapAction"].setEnabled(True)
1604 self.session.nav.playService(service[1])
1606 def addSubserviceToBouquetCallback(self, service):
1607 if len(service) > 1 and isinstance(service[1], eServiceReference):
1608 self.selectedSubservice = service
1609 if self.bouquets is None:
1612 cnt = len(self.bouquets)
1613 if cnt > 1: # show bouquet list
1614 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1615 elif cnt == 1: # add to only one existing bouquet
1616 self.addSubserviceToBouquet(self.bouquets[0][1])
1617 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1619 def bouquetSelClosed(self, confirmed):
1621 del self.selectedSubservice
1623 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1625 def addSubserviceToBouquet(self, dest):
1626 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1628 self.bsel.close(True)
1630 del self.selectedSubservice
1632 class InfoBarAdditionalInfo:
1634 self["NimA"] = Pixmap()
1635 self["NimB"] = Pixmap()
1636 self["NimA_Active"] = Pixmap()
1637 self["NimB_Active"] = Pixmap()
1639 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1640 self["TimeshiftPossible"] = self["RecordingPossible"]
1641 self["ExtensionsAvailable"] = Boolean(fixed=1)
1643 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1644 res_mgr = eDVBResourceManager.getInstance()
1646 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1648 def tunerUseMaskChanged(self, mask):
1650 self["NimA_Active"].show()
1652 self["NimA_Active"].hide()
1654 self["NimB_Active"].show()
1656 self["NimB_Active"].hide()
1658 def checkTunerState(self, service):
1659 info = service and service.frontendInfo()
1660 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1661 if feNumber is None:
1671 def gotServiceEvent(self, ev):
1672 service = self.session.nav.getCurrentService()
1673 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1674 self.checkTunerState(service)
1676 class InfoBarNotifications:
1678 self.onExecBegin.append(self.checkNotifications)
1679 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1680 self.onClose.append(self.__removeNotification)
1682 def __removeNotification(self):
1683 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1685 def checkNotificationsIfExecing(self):
1687 self.checkNotifications()
1689 def checkNotifications(self):
1690 if len(Notifications.notifications):
1691 n = Notifications.notifications[0]
1693 Notifications.notifications = Notifications.notifications[1:]
1696 if n[3].has_key("onSessionOpenCallback"):
1697 n[3]["onSessionOpenCallback"]()
1698 del n[3]["onSessionOpenCallback"]
1701 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1703 dlg = self.session.open(n[1], *n[2], **n[3])
1705 # remember that this notification is currently active
1707 Notifications.current_notifications.append(d)
1708 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1710 def __notificationClosed(self, d):
1711 Notifications.current_notifications.remove(d)
1713 class InfoBarServiceNotifications:
1715 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1717 iPlayableService.evEnd: self.serviceHasEnded
1720 def serviceHasEnded(self):
1721 print "service end!"
1724 self.setSeekState(self.SEEK_STATE_PLAY)
1728 class InfoBarCueSheetSupport:
1734 ENABLE_RESUME_SUPPORT = False
1736 def __init__(self, actionmap = "InfobarCueSheetActions"):
1737 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1739 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1740 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1741 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1745 self.is_closing = False
1746 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1748 iPlayableService.evStart: self.__serviceStarted,
1751 def __serviceStarted(self):
1754 print "new service started! trying to download cuts!"
1755 self.downloadCuesheet()
1757 if self.ENABLE_RESUME_SUPPORT:
1760 for (pts, what) in self.cut_list:
1761 if what == self.CUT_TYPE_LAST:
1764 if last is not None:
1765 self.resume_point = last
1766 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1768 def playLastCB(self, answer):
1770 seekable = self.__getSeekable()
1771 if seekable is not None:
1772 seekable.seekTo(self.resume_point)
1773 self.hideAfterResume()
1775 def hideAfterResume(self):
1776 if isinstance(self, InfoBarShowHide):
1779 def __getSeekable(self):
1780 service = self.session.nav.getCurrentService()
1783 return service.seek()
1785 def cueGetCurrentPosition(self):
1786 seek = self.__getSeekable()
1789 r = seek.getPlayPosition()
1794 def jumpPreviousNextMark(self, cmp, alternative=None):
1795 current_pos = self.cueGetCurrentPosition()
1796 if current_pos is None:
1798 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1799 if mark is not None:
1801 elif alternative is not None:
1806 seekable = self.__getSeekable()
1807 if seekable is not None:
1808 seekable.seekTo(pts)
1810 def jumpPreviousMark(self):
1811 # we add 2 seconds, so if the play position is <2s after
1812 # the mark, the mark before will be used
1813 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1815 def jumpNextMark(self):
1816 self.jumpPreviousNextMark(lambda x: x)
1818 def getNearestCutPoint(self, pts, cmp=abs):
1821 for cp in self.cut_list:
1822 diff = cmp(cp[0] - pts)
1823 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1827 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1828 current_pos = self.cueGetCurrentPosition()
1829 if current_pos is None:
1830 print "not seekable"
1833 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1835 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1837 return nearest_cutpoint
1839 self.removeMark(nearest_cutpoint)
1840 elif not onlyremove and not onlyreturn:
1841 self.addMark((current_pos, self.CUT_TYPE_MARK))
1846 def addMark(self, point):
1847 insort(self.cut_list, point)
1848 self.uploadCuesheet()
1849 self.showAfterCuesheetOperation()
1851 def removeMark(self, point):
1852 self.cut_list.remove(point)
1853 self.uploadCuesheet()
1854 self.showAfterCuesheetOperation()
1856 def showAfterCuesheetOperation(self):
1857 if isinstance(self, InfoBarShowHide):
1860 def __getCuesheet(self):
1861 service = self.session.nav.getCurrentService()
1864 return service.cueSheet()
1866 def uploadCuesheet(self):
1867 cue = self.__getCuesheet()
1870 print "upload failed, no cuesheet interface"
1872 cue.setCutList(self.cut_list)
1874 def downloadCuesheet(self):
1875 cue = self.__getCuesheet()
1878 print "download failed, no cuesheet interface"
1881 self.cut_list = cue.getCutList()
1883 class InfoBarSummary(Screen):
1885 <screen position="0,0" size="132,64">
1886 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1887 <convert type="ClockToText">WithSeconds</convert>
1889 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1890 <convert type="ServiceName">Name</convert>
1894 def __init__(self, session, parent):
1895 Screen.__init__(self, session)
1896 self["CurrentService"] = CurrentService(self.session.nav)
1897 self["CurrentTime"] = Clock()
1899 class InfoBarSummarySupport:
1903 def createSummary(self):
1904 return InfoBarSummary
1906 class InfoBarTeletextPlugin:
1908 self.teletext_plugin = None
1910 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1911 self.teletext_plugin = p
1913 if self.teletext_plugin is not None:
1914 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1916 "startTeletext": (self.startTeletext, _("View teletext..."))
1919 print "no teletext plugin found!"
1921 def startTeletext(self):
1922 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1924 class InfoBarSubtitleSupport(object):
1926 object.__init__(self)
1927 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1928 self.__subtitles_enabled = False
1930 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1932 iPlayableService.evEnd: self.__serviceStopped,
1933 iPlayableService.evUpdatedInfo: self.__updatedInfo
1935 self.cached_subtitle_checked = False
1936 self.__selected_subtitle = None
1938 def __serviceStopped(self):
1939 self.subtitle_window.hide()
1940 self.__subtitles_enabled = False
1941 self.cached_subtitle_checked = False
1943 def __updatedInfo(self):
1944 if not self.cached_subtitle_checked:
1945 subtitle = self.getCurrentServiceSubtitle()
1946 self.cached_subtitle_checked = True
1947 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1948 if self.__selected_subtitle:
1949 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1950 self.subtitle_window.show()
1951 self.__subtitles_enabled = True
1953 def getCurrentServiceSubtitle(self):
1954 service = self.session.nav.getCurrentService()
1955 return service and service.subtitle()
1957 def setSubtitlesEnable(self, enable=True):
1958 subtitle = self.getCurrentServiceSubtitle()
1959 if enable and self.__selected_subtitle is not None:
1960 if subtitle and not self.__subtitles_enabled:
1961 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1962 self.subtitle_window.show()
1963 self.__subtitles_enabled = True
1966 subtitle.disableSubtitles(self.subtitle_window.instance)
1967 self.__subtitles_enabled = False
1968 self.subtitle_window.hide()
1970 def setSelectedSubtitle(self, subtitle):
1971 self.__selected_subtitle = subtitle
1973 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1974 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1976 class InfoBarServiceErrorPopupSupport:
1978 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1980 iPlayableService.evTuneFailed: self.__tuneFailed,
1981 iPlayableService.evStart: self.__serviceStarted
1983 self.__serviceStarted()
1985 def __serviceStarted(self):
1986 self.last_error = None
1987 Notifications.RemovePopup(id = "ZapError")
1989 def __tuneFailed(self):
1990 service = self.session.nav.getCurrentService()
1991 info = service and service.info()
1992 error = info and info.getInfo(iServiceInformation.sDVBState)
1994 if error == self.last_error:
1997 self.last_error = error
2000 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2001 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2002 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2003 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2004 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2005 eDVBServicePMTHandler.eventNewProgramInfo: None,
2006 eDVBServicePMTHandler.eventTuned: None,
2007 eDVBServicePMTHandler.eventSOF: None,
2008 eDVBServicePMTHandler.eventEOF: None
2011 error = errors.get(error) #this returns None when the key not exist in the dict
2013 if error is not None:
2014 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2016 Notifications.RemovePopup(id = "ZapError")