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,
74 iPlayableService.evUpdatedEventInfo: self.__eventInfoChanged
77 self.__state = self.STATE_SHOWN
80 self.hideTimer = eTimer()
81 self.hideTimer.timeout.get().append(self.doTimerHide)
82 self.hideTimer.start(5000, True)
84 self.onShow.append(self.__onShow)
85 self.onHide.append(self.__onHide)
86 self.current_begin_time=0
88 def __eventInfoChanged(self):
90 service = self.session.nav.getCurrentService()
91 old_begin_time = self.current_begin_time
92 info = service and service.info()
93 ptr = info and info.getEvent(0)
94 self.current_begin_time = ptr and ptr.getBeginTime() or 0
95 if config.usage.show_infobar_on_event_change.value:
96 if old_begin_time and old_begin_time != self.current_begin_time:
99 def __serviceStarted(self, force=False):
100 new = self.servicelist.newServicePlayed()
101 if self.execing or force:
102 self.current_begin_time=0
103 if config.usage.show_infobar_on_zap.value:
105 elif not self.__checkServiceStarted in self.onExecBegin and new:
106 self.onExecBegin.append(self.__checkServiceStarted)
108 def __checkServiceStarted(self):
109 self.__serviceStarted(True)
110 self.onExecBegin.remove(self.__checkServiceStarted)
113 self.__state = self.STATE_SHOWN
114 self.startHideTimer()
116 def startHideTimer(self):
117 if self.__state == self.STATE_SHOWN and not self.__locked:
118 idx = config.usage.infobar_timeout.index
120 self.hideTimer.start(idx*1000, True)
123 self.__state = self.STATE_HIDDEN
127 self.startHideTimer()
129 def doTimerHide(self):
130 self.hideTimer.stop()
131 if self.__state == self.STATE_SHOWN:
134 def toggleShow(self):
135 if self.__state == self.STATE_SHOWN:
137 self.hideTimer.stop()
138 elif self.__state == self.STATE_HIDDEN:
142 self.__locked = self.__locked + 1
145 self.hideTimer.stop()
147 def unlockShow(self):
148 self.__locked = self.__locked - 1
150 self.startHideTimer()
152 # def startShow(self):
153 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
154 # self.__state = self.STATE_SHOWN
156 # def startHide(self):
157 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
158 # self.__state = self.STATE_HIDDEN
160 class NumberZap(Screen):
167 self.close(int(self["number"].getText()))
169 def keyNumberGlobal(self, number):
170 self.Timer.start(3000, True) #reset timer
171 self.field = self.field + str(number)
172 self["number"].setText(self.field)
173 if len(self.field) >= 4:
176 def __init__(self, session, number):
177 Screen.__init__(self, session)
178 self.field = str(number)
180 self["channel"] = Label(_("Channel:"))
182 self["number"] = Label(self.field)
184 self["actions"] = NumberActionMap( [ "SetupActions" ],
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 self.Timer = eTimer()
201 self.Timer.timeout.get().append(self.keyOK)
202 self.Timer.start(3000, True)
204 class InfoBarNumberZap:
205 """ Handles an initial number for NumberZapping """
207 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
209 "1": self.keyNumberGlobal,
210 "2": self.keyNumberGlobal,
211 "3": self.keyNumberGlobal,
212 "4": self.keyNumberGlobal,
213 "5": self.keyNumberGlobal,
214 "6": self.keyNumberGlobal,
215 "7": self.keyNumberGlobal,
216 "8": self.keyNumberGlobal,
217 "9": self.keyNumberGlobal,
218 "0": self.keyNumberGlobal,
221 def keyNumberGlobal(self, number):
222 # print "You pressed number " + str(number)
224 self.servicelist.recallPrevService()
226 self.session.openWithCallback(self.numberEntered, NumberZap, number)
228 def numberEntered(self, retval):
229 # print self.servicelist
231 self.zapToNumber(retval)
233 def searchNumberHelper(self, serviceHandler, num, bouquet):
234 servicelist = serviceHandler.list(bouquet)
235 if not servicelist is None:
237 serviceIterator = servicelist.getNext()
238 if not serviceIterator.valid(): #check end of list
240 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
243 if not num: #found service with searched number ?
244 return serviceIterator, 0
247 def zapToNumber(self, number):
248 bouquet = self.servicelist.bouquet_root
250 serviceHandler = eServiceCenter.getInstance()
251 if not config.usage.multibouquet.value:
252 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
254 bouquetlist = serviceHandler.list(bouquet)
255 if not bouquetlist is None:
257 bouquet = bouquetlist.getNext()
258 if not bouquet.valid(): #check end of list
260 if bouquet.flags & eServiceReference.isDirectory:
261 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
262 if not service is None:
263 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
264 self.servicelist.clearPath()
265 if self.servicelist.bouquet_root != bouquet:
266 self.servicelist.enterPath(self.servicelist.bouquet_root)
267 self.servicelist.enterPath(bouquet)
268 self.servicelist.setCurrentSelection(service) #select the service in servicelist
269 self.servicelist.zap()
271 config.misc.initialchannelselection = ConfigBoolean(default = True)
273 class InfoBarChannelSelection:
274 """ ChannelSelection - handles the channelSelection dialog and the initial
275 channelChange actions which open the channelSelection dialog """
278 self.servicelist = self.session.instantiateDialog(ChannelSelection)
280 if config.misc.initialchannelselection.value:
281 self.onShown.append(self.firstRun)
283 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
285 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
286 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
287 "zapUp": (self.zapUp, _("previous channel")),
288 "zapDown": (self.zapDown, _("next channel")),
289 "historyBack": (self.historyBack, _("previous channel in history")),
290 "historyNext": (self.historyNext, _("next channel in history")),
291 "openServiceList": (self.openServiceList, _("open servicelist")),
294 def showTvChannelList(self, zap=False):
295 self.servicelist.setModeTv()
297 self.servicelist.zap()
298 self.session.execDialog(self.servicelist)
300 def showRadioChannelList(self, zap=False):
301 self.servicelist.setModeRadio()
303 self.servicelist.zap()
304 self.session.execDialog(self.servicelist)
307 self.onShown.remove(self.firstRun)
308 config.misc.initialchannelselection.value = False
309 config.misc.initialchannelselection.save()
310 self.switchChannelDown()
312 def historyBack(self):
313 self.servicelist.historyBack()
315 def historyNext(self):
316 self.servicelist.historyNext()
318 def switchChannelUp(self):
319 self.servicelist.moveUp()
320 self.session.execDialog(self.servicelist)
322 def switchChannelDown(self):
323 self.servicelist.moveDown()
324 self.session.execDialog(self.servicelist)
326 def openServiceList(self):
327 self.session.execDialog(self.servicelist)
330 if self.servicelist.inBouquet():
331 prev = self.servicelist.getCurrentSelection()
333 prev = prev.toString()
335 if config.usage.quickzap_bouquet_change.value:
336 if self.servicelist.atBegin():
337 self.servicelist.prevBouquet()
338 self.servicelist.moveUp()
339 cur = self.servicelist.getCurrentSelection()
340 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
343 self.servicelist.moveUp()
344 self.servicelist.zap()
347 if self.servicelist.inBouquet():
348 prev = self.servicelist.getCurrentSelection()
350 prev = prev.toString()
352 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
353 self.servicelist.nextBouquet()
355 self.servicelist.moveDown()
356 cur = self.servicelist.getCurrentSelection()
357 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
360 self.servicelist.moveDown()
361 self.servicelist.zap()
364 """ Handles a menu action, to open the (main) menu """
366 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
368 "mainMenu": (self.mainMenu, _("Enter main menu...")),
370 self.session.infobar = None
373 print "loading mainmenu XML..."
374 menu = mdom.childNodes[0]
375 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
377 self.session.infobar = self
378 # so we can access the currently active infobar from screens opened from within the mainmenu
379 # at the moment used from the SubserviceSelection
381 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
383 def mainMenuClosed(self, *val):
384 self.session.infobar = None
386 class InfoBarSimpleEventView:
387 """ Opens the Eventview for now/next """
389 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
391 "showEventInfo": (self.openEventView, _("show event details")),
394 def openEventView(self):
396 service = self.session.nav.getCurrentService()
397 ref = self.session.nav.getCurrentlyPlayingServiceReference()
398 info = service.info()
401 self.epglist.append(ptr)
404 self.epglist.append(ptr)
405 if len(self.epglist) > 0:
406 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
408 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
409 if len(self.epglist) > 1:
410 tmp = self.epglist[0]
411 self.epglist[0]=self.epglist[1]
413 setEvent(self.epglist[0])
416 """ EPG - Opens an EPG list when the showEPGList action fires """
418 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
420 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
423 self.is_now_next = False
425 self.bouquetSel = None
426 self.eventView = None
427 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
429 "showEventInfo": (self.openEventView, _("show EPG...")),
432 def zapToService(self, service):
433 if not service is None:
434 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
435 self.servicelist.clearPath()
436 if self.servicelist.bouquet_root != self.epg_bouquet:
437 self.servicelist.enterPath(self.servicelist.bouquet_root)
438 self.servicelist.enterPath(self.epg_bouquet)
439 self.servicelist.setCurrentSelection(service) #select the service in servicelist
440 self.servicelist.zap()
442 def getBouquetServices(self, bouquet):
444 servicelist = eServiceCenter.getInstance().list(bouquet)
445 if not servicelist is None:
447 service = servicelist.getNext()
448 if not service.valid(): #check if end of list
450 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
452 services.append(ServiceReference(service))
455 def openBouquetEPG(self, bouquet, withCallback=True):
456 services = self.getBouquetServices(bouquet)
458 self.epg_bouquet = bouquet
460 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
462 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
464 def changeBouquetCB(self, direction, epg):
467 self.bouquetSel.down()
470 bouquet = self.bouquetSel.getCurrent()
471 services = self.getBouquetServices(bouquet)
473 self.epg_bouquet = bouquet
474 epg.setServices(services)
476 def closed(self, ret=False):
477 closedScreen = self.dlg_stack.pop()
478 if self.bouquetSel and closedScreen == self.bouquetSel:
479 self.bouquetSel = None
480 elif self.eventView and closedScreen == self.eventView:
481 self.eventView = None
483 dlgs=len(self.dlg_stack)
485 self.dlg_stack[dlgs-1].close(dlgs > 1)
487 def openMultiServiceEPG(self, withCallback=True):
488 bouquets = self.servicelist.getBouquetList()
493 if cnt > 1: # show bouquet list
495 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
496 self.dlg_stack.append(self.bouquetSel)
498 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
500 self.openBouquetEPG(bouquets[0][1], withCallback)
502 def openSingleServiceEPG(self):
503 ref=self.session.nav.getCurrentlyPlayingServiceReference()
504 self.session.open(EPGSelection, ref)
506 def openSimilarList(self, eventid, refstr):
507 self.session.open(EPGSelection, refstr, None, eventid)
509 def getNowNext(self):
511 service = self.session.nav.getCurrentService()
512 info = service and service.info()
513 ptr = info and info.getEvent(0)
515 self.epglist.append(ptr)
516 ptr = info and info.getEvent(1)
518 self.epglist.append(ptr)
520 def __evEventInfoChanged(self):
521 if self.is_now_next and len(self.dlg_stack) == 1:
523 assert self.eventView
524 if len(self.epglist):
525 self.eventView.setEvent(self.epglist[0])
527 def openEventView(self):
528 ref = self.session.nav.getCurrentlyPlayingServiceReference()
530 if len(self.epglist) == 0:
531 self.is_now_next = False
532 epg = eEPGCache.getInstance()
533 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
535 self.epglist.append(ptr)
536 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
538 self.epglist.append(ptr)
540 self.is_now_next = True
541 if len(self.epglist) > 0:
542 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
543 self.dlg_stack.append(self.eventView)
545 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
546 self.openMultiServiceEPG(False)
548 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
549 if len(self.epglist) > 1:
550 tmp = self.epglist[0]
551 self.epglist[0]=self.epglist[1]
553 setEvent(self.epglist[0])
556 """provides a snr/agc/ber display"""
558 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
561 """provides a current/next event info display"""
563 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
564 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
566 class InfoBarRdsDecoder:
567 """provides RDS and Rass support/display"""
569 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
570 self.rass_interactive = None
572 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
574 iPlayableService.evEnd: self.__serviceStopped,
575 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
578 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
580 "startRassInteractive": self.startRassInteractive
583 self["RdsActions"].setEnabled(False)
585 self.onLayoutFinish.append(self.rds_display.show)
586 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
588 def RassInteractivePossibilityChanged(self, state):
589 self["RdsActions"].setEnabled(state)
591 def RassSlidePicChanged(self):
592 if not self.rass_interactive:
593 service = self.session.nav.getCurrentService()
594 decoder = service and service.rdsDecoder()
596 decoder.showRassSlidePicture()
598 def __serviceStopped(self):
599 if self.rass_interactive is not None:
600 rass_interactive = self.rass_interactive
601 self.rass_interactive = None
602 rass_interactive.close()
604 def startRassInteractive(self):
605 self.rds_display.hide()
606 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
608 def RassInteractiveClosed(self, *val):
609 if self.rass_interactive is not None:
610 self.rass_interactive = None
611 self.RassSlidePicChanged()
612 self.rds_display.show()
614 class InfoBarServiceName:
616 self["CurrentService"] = CurrentService(self.session.nav)
619 """handles actions like seeking, pause"""
621 # ispause, isff, issm
622 SEEK_STATE_PLAY = (0, 0, 0, ">")
623 SEEK_STATE_PAUSE = (1, 0, 0, "||")
624 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
625 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
626 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
627 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
628 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
629 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
631 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
632 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
633 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
634 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
636 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
637 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
638 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
640 SEEK_STATE_EOF = (1, 0, 0, "END")
643 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
645 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
646 iPlayableService.evStart: self.__serviceStarted,
648 iPlayableService.evEOF: self.__evEOF,
649 iPlayableService.evSOF: self.__evSOF,
652 class InfoBarSeekActionMap(HelpableActionMap):
653 def __init__(self, screen, *args, **kwargs):
654 HelpableActionMap.__init__(self, screen, *args, **kwargs)
657 def action(self, contexts, action):
658 print "action:", action
659 if action[:5] == "seek:":
660 time = int(action[5:])
661 self.screen.seekRelative(time * 90000)
665 return HelpableActionMap.action(self, contexts, action)
667 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
669 "playpauseService": (self.playpauseService, _("pause")),
670 "pauseService": (self.pauseService, _("pause")),
671 "unPauseService": (self.unPauseService, _("continue")),
673 "seekFwd": (self.seekFwd, _("skip forward")),
674 "seekFwdDown": self.seekFwdDown,
675 "seekFwdUp": self.seekFwdUp,
676 "seekBack": (self.seekBack, _("skip backward")),
677 "seekBackDown": self.seekBackDown,
678 "seekBackUp": self.seekBackUp,
680 # give them a little more priority to win over color buttons
682 self["SeekActions"].setEnabled(False)
684 self.seekstate = self.SEEK_STATE_PLAY
685 self.onClose.append(self.delTimer)
687 self.fwdtimer = False
688 self.fwdKeyTimer = eTimer()
689 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
691 self.rwdtimer = False
692 self.rwdKeyTimer = eTimer()
693 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
695 self.onPlayStateChanged = [ ]
697 self.lockedBecauseOfSkipping = False
710 service = self.session.nav.getCurrentService()
714 seek = service.seek()
716 if seek is None or not seek.isCurrentlySeekable():
721 def isSeekable(self):
722 if self.getSeek() is None:
726 def __seekableStatusChanged(self):
727 print "seekable status changed!"
728 if not self.isSeekable():
729 self["SeekActions"].setEnabled(False)
730 print "not seekable, return to play"
731 self.setSeekState(self.SEEK_STATE_PLAY)
733 self["SeekActions"].setEnabled(True)
736 def __serviceStarted(self):
737 self.seekstate = self.SEEK_STATE_PLAY
738 self.__seekableStatusChanged()
740 def setSeekState(self, state):
741 service = self.session.nav.getCurrentService()
746 if not self.isSeekable():
747 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
748 state = self.SEEK_STATE_PLAY
750 pauseable = service.pause()
752 if pauseable is None:
753 print "not pauseable."
754 state = self.SEEK_STATE_PLAY
756 oldstate = self.seekstate
757 self.seekstate = state
760 if oldstate[i] != self.seekstate[i]:
761 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
763 for c in self.onPlayStateChanged:
766 self.checkSkipShowHideLock()
770 def playpauseService(self):
771 if self.seekstate != self.SEEK_STATE_PLAY:
772 self.unPauseService()
776 def pauseService(self):
777 if self.seekstate == self.SEEK_STATE_PAUSE:
778 print "pause, but in fact unpause"
779 self.unPauseService()
781 if self.seekstate == self.SEEK_STATE_PLAY:
782 print "yes, playing."
784 print "no", self.seekstate
786 self.setSeekState(self.SEEK_STATE_PAUSE);
788 def unPauseService(self):
790 if self.seekstate == self.SEEK_STATE_PLAY:
792 self.setSeekState(self.SEEK_STATE_PLAY)
794 def doSeek(self, seektime):
795 print "doseek", seektime
796 service = self.session.nav.getCurrentService()
800 seekable = self.getSeek()
804 seekable.seekTo(90 * seektime)
806 def seekFwdDown(self):
807 print "start fwd timer"
809 self.fwdKeyTimer.start(1000)
811 def seekBackDown(self):
812 print "start rewind timer"
814 self.rwdKeyTimer.start(1000)
819 self.fwdKeyTimer.stop()
820 self.fwdtimer = False
825 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
826 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
827 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
828 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
829 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
830 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
831 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
832 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
833 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
834 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
835 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
836 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
837 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
838 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
839 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
840 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
842 self.setSeekState(lookup[self.seekstate])
844 def seekBackUp(self):
847 self.rwdKeyTimer.stop()
848 self.rwdtimer = False
853 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
854 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
855 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
856 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
857 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
858 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
859 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
860 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
861 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
862 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
863 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
864 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
865 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
866 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
867 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
868 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
870 self.setSeekState(lookup[self.seekstate])
872 if self.seekstate == self.SEEK_STATE_PAUSE:
873 seekable = self.getSeek()
874 if seekable is not None:
875 seekable.seekRelative(-1, 3)
877 def fwdTimerFire(self):
878 print "Display seek fwd"
879 self.fwdKeyTimer.stop()
880 self.fwdtimer = False
881 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
883 def fwdSeekTo(self, minutes):
884 print "Seek", minutes, "minutes forward"
886 seekable = self.getSeek()
887 if seekable is not None:
888 seekable.seekRelative(1, minutes * 60 * 90000)
890 def rwdTimerFire(self):
892 self.rwdKeyTimer.stop()
893 self.rwdtimer = False
894 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
896 def rwdSeekTo(self, minutes):
898 self.fwdSeekTo(0 - minutes)
900 def checkSkipShowHideLock(self):
901 wantlock = self.seekstate != self.SEEK_STATE_PLAY
903 if config.usage.show_infobar_on_zap.value:
904 if self.lockedBecauseOfSkipping and not wantlock:
906 self.lockedBecauseOfSkipping = False
908 if wantlock and not self.lockedBecauseOfSkipping:
910 self.lockedBecauseOfSkipping = True
913 if self.seekstate == self.SEEK_STATE_EOF:
915 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
916 print "end of stream while seeking back, ignoring."
919 # if we are seeking, we try to end up ~1s before the end, and pause there.
920 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
921 self.setSeekState(self.SEEK_STATE_EOF)
922 self.seekRelativeToEnd(-90000)
924 self.setSeekState(self.SEEK_STATE_EOF)
927 self.setSeekState(self.SEEK_STATE_PLAY)
930 def seekRelative(self, diff):
931 seekable = self.getSeek()
932 if seekable is not None:
933 print "seekRelative: res:", seekable.seekRelative(1, diff)
937 def seekRelativeToEnd(self, diff):
938 assert diff <= 0, "diff is expected to be negative!"
940 # might sound like an evil hack, but:
941 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
942 # and we don't get that by passing 0 here (it would seek to begin).
946 # relative-to-end seeking is implemented as absolutes seeks with negative time
947 self.seekAbsolute(diff)
949 def seekAbsolute(self, abs):
950 seekable = self.getSeek()
951 if seekable is not None:
954 from Screens.PVRState import PVRState, TimeshiftState
956 class InfoBarPVRState:
957 def __init__(self, screen=PVRState):
958 self.onPlayStateChanged.append(self.__playStateChanged)
959 self.pvrStateDialog = self.session.instantiateDialog(screen)
960 self.onShow.append(self._mayShow)
961 self.onHide.append(self.pvrStateDialog.hide)
964 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
965 self.pvrStateDialog.show()
967 def __playStateChanged(self, state):
968 playstateString = state[3]
969 self.pvrStateDialog["state"].setText(playstateString)
972 class InfoBarTimeshiftState(InfoBarPVRState):
974 InfoBarPVRState.__init__(self, screen=TimeshiftState)
977 if self.execing and self.timeshift_enabled:
978 self.pvrStateDialog.show()
980 class InfoBarShowMovies:
982 # i don't really like this class.
983 # it calls a not further specified "movie list" on up/down/movieList,
984 # so this is not more than an action map
986 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
988 "movieList": (self.showMovies, "movie list"),
989 "up": (self.showMovies, "movie list"),
990 "down": (self.showMovies, "movie list")
993 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
997 # Timeshift works the following way:
998 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
999 # - normal playback TUNER unused PLAY enable disable disable
1000 # - user presses "yellow" button. FILE record PAUSE enable disable enable
1001 # - user presess pause again FILE record PLAY enable disable enable
1002 # - user fast forwards FILE record FF enable disable enable
1003 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
1004 # - user backwards FILE record BACK # !! enable disable enable
1008 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1009 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1010 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1011 # - the user can now PVR around
1012 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1013 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1015 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1016 # - if the user rewinds, or press pause, timeshift will be activated again
1018 # note that a timeshift can be enabled ("recording") and
1019 # activated (currently time-shifting).
1021 class InfoBarTimeshift:
1023 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1025 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1026 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1028 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1030 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1031 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1032 }, prio=-1) # priority over record
1034 self.timeshift_enabled = 0
1035 self.timeshift_state = 0
1036 self.ts_rewind_timer = eTimer()
1037 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1039 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1041 iPlayableService.evStart: self.__serviceStarted,
1042 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1045 def getTimeshift(self):
1046 service = self.session.nav.getCurrentService()
1047 return service and service.timeshift()
1049 def startTimeshift(self):
1050 print "enable timeshift"
1051 ts = self.getTimeshift()
1053 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1054 print "no ts interface"
1057 if self.timeshift_enabled:
1058 print "hu, timeshift already enabled?"
1060 if not ts.startTimeshift():
1061 self.timeshift_enabled = 1
1063 # we remove the "relative time" for now.
1064 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1067 #self.setSeekState(self.SEEK_STATE_PAUSE)
1068 self.activateTimeshiftEnd(False)
1070 # enable the "TimeshiftEnableActions", which will override
1071 # the startTimeshift actions
1072 self.__seekableStatusChanged()
1074 print "timeshift failed"
1076 def stopTimeshift(self):
1077 if not self.timeshift_enabled:
1079 print "disable timeshift"
1080 ts = self.getTimeshift()
1083 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1085 def stopTimeshiftConfirmed(self, confirmed):
1089 ts = self.getTimeshift()
1094 self.timeshift_enabled = 0
1097 self.__seekableStatusChanged()
1099 # activates timeshift, and seeks to (almost) the end
1100 def activateTimeshiftEnd(self, back = True):
1101 ts = self.getTimeshift()
1102 print "activateTimeshiftEnd"
1107 if ts.isTimeshiftActive():
1108 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1112 ts.activateTimeshift() # activate timeshift will automatically pause
1113 self.setSeekState(self.SEEK_STATE_PAUSE)
1114 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1117 self.ts_rewind_timer.start(200, 1)
1119 def rewindService(self):
1120 self.setSeekState(self.SEEK_STATE_BACK_16X)
1122 # same as activateTimeshiftEnd, but pauses afterwards.
1123 def activateTimeshiftEndAndPause(self):
1124 print "activateTimeshiftEndAndPause"
1125 #state = self.seekstate
1126 self.activateTimeshiftEnd(False)
1128 def __seekableStatusChanged(self):
1131 print "self.isSeekable", self.isSeekable()
1132 print "self.timeshift_enabled", self.timeshift_enabled
1134 # when this service is not seekable, but timeshift
1135 # is enabled, this means we can activate
1137 if not self.isSeekable() and self.timeshift_enabled:
1140 print "timeshift activate:", enabled
1141 self["TimeshiftActivateActions"].setEnabled(enabled)
1143 def __serviceStarted(self):
1144 self.timeshift_enabled = False
1145 self.__seekableStatusChanged()
1147 from Screens.PiPSetup import PiPSetup
1149 class InfoBarExtensions:
1150 EXTENSION_SINGLE = 0
1156 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1158 "extensions": (self.showExtensionSelection, _("view extensions...")),
1161 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1162 self.list.append((type, extension, key))
1164 def updateExtension(self, extension, key = None):
1165 self.extensionsList.append(extension)
1167 if self.extensionKeys.has_key(key):
1171 for x in self.availableKeys:
1172 if not self.extensionKeys.has_key(x):
1177 self.extensionKeys[key] = len(self.extensionsList) - 1
1179 def updateExtensions(self):
1180 self.extensionsList = []
1181 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1182 self.extensionKeys = {}
1184 if x[0] == self.EXTENSION_SINGLE:
1185 self.updateExtension(x[1], x[2])
1188 self.updateExtension(y[0], y[1])
1191 def showExtensionSelection(self):
1192 self.updateExtensions()
1193 extensionsList = self.extensionsList[:]
1196 for x in self.availableKeys:
1197 if self.extensionKeys.has_key(x):
1198 entry = self.extensionKeys[x]
1199 extension = self.extensionsList[entry]
1201 name = str(extension[0]())
1202 list.append((extension[0](), extension))
1204 extensionsList.remove(extension)
1206 extensionsList.remove(extension)
1207 for x in extensionsList:
1208 list.append((x[0](), x))
1209 keys += [""] * len(extensionsList)
1210 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1212 def extensionCallback(self, answer):
1213 if answer is not None:
1216 from Tools.BoundFunction import boundFunction
1218 # depends on InfoBarExtensions
1219 from Components.PluginComponent import plugins
1221 class InfoBarPlugins:
1223 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1225 def getPluginName(self, name):
1228 def getPluginList(self):
1230 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1231 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1234 def runPlugin(self, plugin):
1235 plugin(session = self.session)
1237 # depends on InfoBarExtensions
1238 class InfoBarSleepTimer:
1240 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1242 def available(self):
1245 def getSleepTimerName(self):
1246 return _("Sleep Timer")
1248 def showSleepTimerSetup(self):
1249 self.session.open(SleepTimerEdit)
1251 # depends on InfoBarExtensions
1254 self.session.pipshown = False
1256 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1257 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1258 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1260 def available(self):
1264 return self.session.pipshown
1266 def getShowHideName(self):
1267 if self.session.pipshown:
1268 return _("Disable Picture in Picture")
1270 return _("Activate Picture in Picture")
1272 def getSwapName(self):
1273 return _("Swap Services")
1275 def getMoveName(self):
1276 return _("Move Picture in Picture")
1279 if self.session.pipshown:
1280 del self.session.pip
1281 self.session.pipshown = False
1283 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1284 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1285 if self.session.pip.playService(newservice):
1286 self.session.pipshown = True
1287 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1289 self.session.pipshown = False
1290 del self.session.pip
1291 self.session.nav.playService(newservice)
1294 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1295 if self.session.pip.servicePath:
1296 servicepath = self.servicelist.getCurrentServicePath()
1297 ref=servicepath[len(servicepath)-1]
1298 pipref=self.session.pip.getCurrentService()
1299 self.session.pip.playService(swapservice)
1300 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1301 if pipref.toString() != ref.toString(): # is a subservice ?
1302 self.session.nav.stopService() # stop portal
1303 self.session.nav.playService(pipref) # start subservice
1304 self.session.pip.servicePath=servicepath
1307 self.session.open(PiPSetup, pip = self.session.pip)
1309 from RecordTimer import parseEvent
1311 class InfoBarInstantRecord:
1312 """Instant Record - handles the instantRecord action in order to
1313 start/stop instant records"""
1315 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1317 "instantRecord": (self.instantRecord, _("Instant Record...")),
1320 self["BlinkingPoint"] = BlinkingPixmapConditional()
1321 self["BlinkingPoint"].hide()
1322 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1324 def stopCurrentRecording(self, entry = -1):
1325 if entry is not None and entry != -1:
1326 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1327 self.recording.remove(self.recording[entry])
1329 def startInstantRecording(self, limitEvent = False):
1330 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1332 # try to get event info
1335 service = self.session.nav.getCurrentService()
1336 epg = eEPGCache.getInstance()
1337 event = epg.lookupEventTime(serviceref, -1, 0)
1339 info = service.info()
1340 ev = info.getEvent(0)
1346 end = time() + 3600 * 10
1347 name = "instant record"
1351 if event is not None:
1352 curEvent = parseEvent(event)
1354 description = curEvent[3]
1355 eventid = curEvent[4]
1360 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1362 data = (begin, end, name, description, eventid)
1364 recording = self.session.nav.recordWithTimer(serviceref, *data)
1365 recording.dontSave = True
1366 self.recording.append(recording)
1368 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1370 def isInstantRecordRunning(self):
1371 print "self.recording:", self.recording
1372 if len(self.recording) > 0:
1373 for x in self.recording:
1378 def recordQuestionCallback(self, answer):
1379 print "pre:\n", self.recording
1381 if answer is None or answer[1] == "no":
1384 recording = self.recording[:]
1386 if not x in self.session.nav.RecordTimer.timer_list:
1387 self.recording.remove(x)
1388 elif x.dontSave and x.isRunning():
1389 list.append(TimerEntryComponent(x, False))
1391 if answer[1] == "changeduration":
1392 if len(self.recording) == 1:
1393 self.changeDuration(0)
1395 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1396 elif answer[1] == "changeendtime":
1397 if len(self.recording) == 1:
1400 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1401 elif answer[1] == "stop":
1402 if len(self.recording) == 1:
1403 self.stopCurrentRecording(0)
1405 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1406 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1407 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1408 if answer[1] == "manualduration":
1409 self.changeDuration(len(self.recording)-1)
1410 elif answer[1] == "manualendtime":
1411 self.setEndtime(len(self.recording)-1)
1412 print "after:\n", self.recording
1414 def setEndtime(self, entry):
1415 if entry is not None:
1416 self.selectedEntry = entry
1417 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1418 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1419 dlg.setTitle(_("Please change recording endtime"))
1421 def TimeDateInputClosed(self, ret):
1424 localendtime = localtime(ret[1])
1425 print "stopping recording at", strftime("%c", localendtime)
1426 self.recording[self.selectedEntry].end = ret[1]
1427 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1429 def changeDuration(self, entry):
1430 if entry is not None:
1431 self.selectedEntry = entry
1432 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1434 def inputCallback(self, value):
1435 if value is not None:
1436 print "stopping recording after", int(value), "minutes."
1437 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1438 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1440 def instantRecord(self):
1442 stat = os_stat(resolveFilename(SCOPE_HDD))
1444 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1447 if self.isInstantRecordRunning():
1448 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1449 title=_("A recording is currently running.\nWhat do you want to do?"), \
1450 list=[(_("stop recording"), "stop"), \
1451 (_("change recording (duration)"), "changeduration"), \
1452 (_("change recording (endtime)"), "changeendtime"), \
1453 (_("add recording (indefinitely)"), "indefinitely"), \
1454 (_("add recording (stop after current event)"), "event"), \
1455 (_("add recording (enter recording duration)"), "manualduration"), \
1456 (_("add recording (enter recording endtime)"), "manualendtime"), \
1457 (_("do nothing"), "no")])
1459 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1460 title=_("Start recording?"), \
1461 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1462 (_("add recording (stop after current event)"), "event"), \
1463 (_("add recording (enter recording duration)"), "manualduration"), \
1464 (_("add recording (enter recording endtime)"), "manualendtime"), \
1465 (_("don't record"), "no")])
1467 from Tools.ISO639 import LanguageCodes
1469 class InfoBarAudioSelection:
1471 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1473 "audioSelection": (self.audioSelection, _("Audio Options...")),
1476 def audioSelection(self):
1477 service = self.session.nav.getCurrentService()
1478 audio = service and service.audioTracks()
1479 self.audioTracks = audio
1480 n = audio and audio.getNumberOfTracks() or 0
1481 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1483 print "tlist:", tlist
1485 self.audioChannel = service.audioChannel()
1488 i = audio.getTrackInfo(x)
1489 language = i.getLanguage()
1490 description = i.getDescription()
1492 if LanguageCodes.has_key(language):
1493 language = LanguageCodes[language][0]
1495 if len(description):
1496 description += " (" + language + ")"
1498 description = language
1500 tlist.append((description, x))
1502 selectedAudio = tlist[0][1]
1503 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1507 if x[1] != selectedAudio:
1512 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1513 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1515 del self.audioTracks
1517 def audioSelected(self, audio):
1518 if audio is not None:
1519 if isinstance(audio[1], str):
1520 if audio[1] == "mode":
1521 keys = ["red", "green", "yellow"]
1522 selection = self.audioChannel.getCurrentChannel()
1523 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1524 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1526 del self.audioChannel
1527 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1528 self.audioTracks.selectTrack(audio[1])
1530 del self.audioChannel
1531 del self.audioTracks
1533 def modeSelected(self, mode):
1534 if mode is not None:
1535 self.audioChannel.selectChannel(mode[1])
1536 del self.audioChannel
1538 class InfoBarSubserviceSelection:
1540 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1542 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1545 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1547 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1548 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1550 self["SubserviceQuickzapAction"].setEnabled(False)
1552 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1556 def checkSubservicesAvail(self, ev):
1557 if ev == iPlayableService.evUpdatedEventInfo:
1558 service = self.session.nav.getCurrentService()
1559 subservices = service and service.subServices()
1560 if not subservices or subservices.getNumberOfSubservices() == 0:
1561 self["SubserviceQuickzapAction"].setEnabled(False)
1563 def nextSubservice(self):
1564 self.changeSubservice(+1)
1566 def prevSubservice(self):
1567 self.changeSubservice(-1)
1569 def changeSubservice(self, direction):
1570 service = self.session.nav.getCurrentService()
1571 subservices = service and service.subServices()
1572 n = subservices and subservices.getNumberOfSubservices()
1575 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1577 if subservices.getSubservice(x).toString() == ref.toString():
1580 selection += direction
1585 newservice = subservices.getSubservice(selection)
1586 if newservice.valid():
1589 self.session.nav.playService(newservice)
1591 def subserviceSelection(self):
1592 service = self.session.nav.getCurrentService()
1593 subservices = service and service.subServices()
1594 self.bouquets = self.servicelist.getBouquetList()
1595 n = subservices and subservices.getNumberOfSubservices()
1598 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1601 i = subservices.getSubservice(x)
1602 if i.toString() == ref.toString():
1604 tlist.append((i.getName(), i))
1606 if self.bouquets and len(self.bouquets):
1607 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1608 if config.usage.multibouquet.value:
1609 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1611 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1614 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1615 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1618 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1620 def subserviceSelected(self, service):
1622 if not service is None:
1623 if isinstance(service[1], str):
1624 if service[1] == "quickzap":
1625 from Screens.SubservicesQuickzap import SubservicesQuickzap
1626 self.session.open(SubservicesQuickzap, service[2])
1628 self["SubserviceQuickzapAction"].setEnabled(True)
1629 self.session.nav.playService(service[1])
1631 def addSubserviceToBouquetCallback(self, service):
1632 if len(service) > 1 and isinstance(service[1], eServiceReference):
1633 self.selectedSubservice = service
1634 if self.bouquets is None:
1637 cnt = len(self.bouquets)
1638 if cnt > 1: # show bouquet list
1639 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1640 elif cnt == 1: # add to only one existing bouquet
1641 self.addSubserviceToBouquet(self.bouquets[0][1])
1642 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1644 def bouquetSelClosed(self, confirmed):
1646 del self.selectedSubservice
1648 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1650 def addSubserviceToBouquet(self, dest):
1651 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1653 self.bsel.close(True)
1655 del self.selectedSubservice
1657 class InfoBarAdditionalInfo:
1659 self["NimA"] = Pixmap()
1660 self["NimB"] = Pixmap()
1661 self["NimA_Active"] = Pixmap()
1662 self["NimB_Active"] = Pixmap()
1664 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1665 self["TimeshiftPossible"] = self["RecordingPossible"]
1666 self["ExtensionsAvailable"] = Boolean(fixed=1)
1668 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1669 res_mgr = eDVBResourceManager.getInstance()
1671 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1673 def tunerUseMaskChanged(self, mask):
1675 self["NimA_Active"].show()
1677 self["NimA_Active"].hide()
1679 self["NimB_Active"].show()
1681 self["NimB_Active"].hide()
1683 def checkTunerState(self, service):
1684 info = service and service.frontendInfo()
1685 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1686 if feNumber is None:
1696 def gotServiceEvent(self, ev):
1697 service = self.session.nav.getCurrentService()
1698 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1699 self.checkTunerState(service)
1701 class InfoBarNotifications:
1703 self.onExecBegin.append(self.checkNotifications)
1704 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1705 self.onClose.append(self.__removeNotification)
1707 def __removeNotification(self):
1708 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1710 def checkNotificationsIfExecing(self):
1712 self.checkNotifications()
1714 def checkNotifications(self):
1715 if len(Notifications.notifications):
1716 n = Notifications.notifications[0]
1718 Notifications.notifications = Notifications.notifications[1:]
1721 if n[3].has_key("onSessionOpenCallback"):
1722 n[3]["onSessionOpenCallback"]()
1723 del n[3]["onSessionOpenCallback"]
1726 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1728 dlg = self.session.open(n[1], *n[2], **n[3])
1730 # remember that this notification is currently active
1732 Notifications.current_notifications.append(d)
1733 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1735 def __notificationClosed(self, d):
1736 Notifications.current_notifications.remove(d)
1738 class InfoBarServiceNotifications:
1740 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1742 iPlayableService.evEnd: self.serviceHasEnded
1745 def serviceHasEnded(self):
1746 print "service end!"
1749 self.setSeekState(self.SEEK_STATE_PLAY)
1753 class InfoBarCueSheetSupport:
1759 ENABLE_RESUME_SUPPORT = False
1762 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1764 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1765 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1766 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1770 self.is_closing = False
1771 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1773 iPlayableService.evStart: self.__serviceStarted,
1776 def __serviceStarted(self):
1779 print "new service started! trying to download cuts!"
1780 self.downloadCuesheet()
1782 if self.ENABLE_RESUME_SUPPORT:
1785 for (pts, what) in self.cut_list:
1786 if what == self.CUT_TYPE_LAST:
1789 if last is not None:
1790 self.resume_point = last
1791 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1793 def playLastCB(self, answer):
1795 seekable = self.__getSeekable()
1796 if seekable is not None:
1797 seekable.seekTo(self.resume_point)
1799 def __getSeekable(self):
1800 service = self.session.nav.getCurrentService()
1803 return service.seek()
1805 def cueGetCurrentPosition(self):
1806 seek = self.__getSeekable()
1809 r = seek.getPlayPosition()
1814 def jumpPreviousNextMark(self, cmp, alternative=None):
1815 current_pos = self.cueGetCurrentPosition()
1816 if current_pos is None:
1818 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1819 if mark is not None:
1821 elif alternative is not None:
1826 seekable = self.__getSeekable()
1827 if seekable is not None:
1828 seekable.seekTo(pts)
1830 def jumpPreviousMark(self):
1831 # we add 2 seconds, so if the play position is <2s after
1832 # the mark, the mark before will be used
1833 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1835 def jumpNextMark(self):
1836 self.jumpPreviousNextMark(lambda x: x)
1838 def getNearestCutPoint(self, pts, cmp=abs):
1841 for cp in self.cut_list:
1842 diff = cmp(cp[0] - pts)
1843 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1847 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1848 current_pos = self.cueGetCurrentPosition()
1849 if current_pos is None:
1850 print "not seekable"
1853 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1855 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1857 return nearest_cutpoint
1859 self.removeMark(nearest_cutpoint)
1860 elif not onlyremove and not onlyreturn:
1861 self.addMark((current_pos, self.CUT_TYPE_MARK))
1866 def addMark(self, point):
1867 insort(self.cut_list, point)
1868 self.uploadCuesheet()
1870 def removeMark(self, point):
1871 self.cut_list.remove(point)
1872 self.uploadCuesheet()
1874 def __getCuesheet(self):
1875 service = self.session.nav.getCurrentService()
1878 return service.cueSheet()
1880 def uploadCuesheet(self):
1881 cue = self.__getCuesheet()
1884 print "upload failed, no cuesheet interface"
1886 cue.setCutList(self.cut_list)
1888 def downloadCuesheet(self):
1889 cue = self.__getCuesheet()
1892 print "upload failed, no cuesheet interface"
1894 self.cut_list = cue.getCutList()
1896 class InfoBarSummary(Screen):
1898 <screen position="0,0" size="132,64">
1899 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1900 <convert type="ClockToText">WithSeconds</convert>
1902 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1903 <convert type="ServiceName">Name</convert>
1907 def __init__(self, session, parent):
1908 Screen.__init__(self, session)
1909 self["CurrentService"] = CurrentService(self.session.nav)
1910 self["CurrentTime"] = Clock()
1912 class InfoBarSummarySupport:
1916 def createSummary(self):
1917 return InfoBarSummary
1919 class InfoBarTeletextPlugin:
1921 self.teletext_plugin = None
1923 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1924 self.teletext_plugin = p
1926 if self.teletext_plugin is not None:
1927 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1929 "startTeletext": (self.startTeletext, _("View teletext..."))
1932 print "no teletext plugin found!"
1934 def startTeletext(self):
1935 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1937 class InfoBarSubtitleSupport(object):
1939 object.__init__(self)
1940 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1941 self.__subtitles_enabled = False
1943 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1945 iPlayableService.evEnd: self.__serviceStopped,
1946 iPlayableService.evUpdatedInfo: self.__updatedInfo
1948 self.cached_subtitle_checked = False
1949 self.__selected_subtitle = None
1951 def __serviceStopped(self):
1952 self.subtitle_window.hide()
1953 self.__subtitles_enabled = False
1954 self.cached_subtitle_checked = False
1956 def __updatedInfo(self):
1957 if not self.cached_subtitle_checked:
1958 subtitle = self.getCurrentServiceSubtitle()
1959 self.cached_subtitle_checked = True
1960 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1961 if self.__selected_subtitle:
1962 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1963 self.subtitle_window.show()
1964 self.__subtitles_enabled = True
1966 def getCurrentServiceSubtitle(self):
1967 service = self.session.nav.getCurrentService()
1968 return service and service.subtitle()
1970 def setSubtitlesEnable(self, enable=True):
1971 subtitle = self.getCurrentServiceSubtitle()
1972 if enable and self.__selected_subtitle is not None:
1973 if subtitle and not self.__subtitles_enabled:
1974 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1975 self.subtitle_window.show()
1976 self.__subtitles_enabled = True
1979 subtitle.disableSubtitles(self.subtitle_window.instance)
1980 self.__subtitles_enabled = False
1981 self.subtitle_window.hide()
1983 def setSelectedSubtitle(self, subtitle):
1984 self.__selected_subtitle = subtitle
1986 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1987 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1989 class InfoBarServiceErrorPopupSupport:
1991 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1993 iPlayableService.evTuneFailed: self.__tuneFailed,
1994 iPlayableService.evStart: self.__serviceStarted
1996 self.__serviceStarted()
1998 def __serviceStarted(self):
1999 self.last_error = None
2000 Notifications.RemovePopup(id = "ZapError")
2002 def __tuneFailed(self):
2003 service = self.session.nav.getCurrentService()
2004 info = service and service.info()
2005 error = info and info.getInfo(iServiceInformation.sDVBState)
2007 if error == self.last_error:
2010 self.last_error = error
2013 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2014 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2015 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2016 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2017 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2018 eDVBServicePMTHandler.eventNewProgramInfo: None,
2019 eDVBServicePMTHandler.eventTuned: None,
2020 eDVBServicePMTHandler.eventSOF: None,
2021 eDVBServicePMTHandler.eventEOF: None
2024 error = errors.get(error) #this returns None when the key not exist in the dict
2026 if error is not None:
2027 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2029 Notifications.RemovePopup(id = "ZapError")