1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import *
9 from Components.Pixmap import Pixmap, PixmapConditional
10 from Components.PluginComponent import plugins
11 from Components.ProgressBar import *
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.Sources.CurrentService import CurrentService
14 from Components.Sources.EventInfo import EventInfo
15 from Components.Sources.FrontendStatus import FrontendStatus
16 from Components.Sources.Boolean import Boolean
17 from Components.Sources.Clock import Clock
18 from Components.TimerList import TimerEntryComponent
19 from Components.config import config, ConfigBoolean, ConfigClock
20 from EpgSelection import EPGSelection
21 from Plugins.Plugin import PluginDescriptor
23 from Screen import Screen
24 from Screens.ChoiceBox import ChoiceBox
25 from Screens.Dish import Dish
26 from Screens.EventView import EventViewEPGSelect, EventViewSimple
27 from Screens.InputBox import InputBox
28 from Screens.MessageBox import MessageBox
29 from Screens.MinuteInput import MinuteInput
30 from Screens.TimerSelection import TimerSelection
31 from Screens.PictureInPicture import PictureInPicture
32 from Screens.SubtitleDisplay import SubtitleDisplay
33 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
34 from Screens.SleepTimerEdit import SleepTimerEdit
35 from Screens.TimeDateInput import TimeDateInput
36 from ServiceReference import ServiceReference
38 from Tools import Notifications
39 from Tools.Directories import SCOPE_HDD, resolveFilename
41 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
42 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
44 from time import time, localtime, strftime
45 from os import stat as os_stat
46 from bisect import insort
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
69 }, 1) # lower prio to make it possible to override ok and cancel..
71 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
73 iPlayableService.evStart: self.serviceStarted,
76 self.__state = self.STATE_SHOWN
79 self.hideTimer = eTimer()
80 self.hideTimer.timeout.get().append(self.doTimerHide)
81 self.hideTimer.start(5000, True)
83 self.onShow.append(self.__onShow)
84 self.onHide.append(self.__onHide)
86 def serviceStarted(self):
88 if config.usage.show_infobar_on_zap.value:
92 self.__state = self.STATE_SHOWN
95 def startHideTimer(self):
96 if self.__state == self.STATE_SHOWN and not self.__locked:
97 idx = config.usage.infobar_timeout.index
99 self.hideTimer.start(idx*1000, True)
102 self.__state = self.STATE_HIDDEN
106 self.startHideTimer()
108 def doTimerHide(self):
109 self.hideTimer.stop()
110 if self.__state == self.STATE_SHOWN:
113 def toggleShow(self):
114 if self.__state == self.STATE_SHOWN:
116 self.hideTimer.stop()
117 elif self.__state == self.STATE_HIDDEN:
121 self.__locked = self.__locked + 1
124 self.hideTimer.stop()
126 def unlockShow(self):
127 self.__locked = self.__locked - 1
129 self.startHideTimer()
131 # def startShow(self):
132 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
133 # self.__state = self.STATE_SHOWN
135 # def startHide(self):
136 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
137 # self.__state = self.STATE_HIDDEN
139 class NumberZap(Screen):
146 self.close(int(self["number"].getText()))
148 def keyNumberGlobal(self, number):
149 self.Timer.start(3000, True) #reset timer
150 self.field = self.field + str(number)
151 self["number"].setText(self.field)
152 if len(self.field) >= 4:
155 def __init__(self, session, number):
156 Screen.__init__(self, session)
157 self.field = str(number)
159 self["channel"] = Label(_("Channel:"))
161 self["number"] = Label(self.field)
163 self["actions"] = NumberActionMap( [ "SetupActions" ],
167 "1": self.keyNumberGlobal,
168 "2": self.keyNumberGlobal,
169 "3": self.keyNumberGlobal,
170 "4": self.keyNumberGlobal,
171 "5": self.keyNumberGlobal,
172 "6": self.keyNumberGlobal,
173 "7": self.keyNumberGlobal,
174 "8": self.keyNumberGlobal,
175 "9": self.keyNumberGlobal,
176 "0": self.keyNumberGlobal
179 self.Timer = eTimer()
180 self.Timer.timeout.get().append(self.keyOK)
181 self.Timer.start(3000, True)
183 class InfoBarNumberZap:
184 """ Handles an initial number for NumberZapping """
186 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
188 "1": self.keyNumberGlobal,
189 "2": self.keyNumberGlobal,
190 "3": self.keyNumberGlobal,
191 "4": self.keyNumberGlobal,
192 "5": self.keyNumberGlobal,
193 "6": self.keyNumberGlobal,
194 "7": self.keyNumberGlobal,
195 "8": self.keyNumberGlobal,
196 "9": self.keyNumberGlobal,
197 "0": self.keyNumberGlobal,
200 def keyNumberGlobal(self, number):
201 # print "You pressed number " + str(number)
203 self.servicelist.recallPrevService()
205 self.session.openWithCallback(self.numberEntered, NumberZap, number)
207 def numberEntered(self, retval):
208 # print self.servicelist
210 self.zapToNumber(retval)
212 def searchNumberHelper(self, serviceHandler, num, bouquet):
213 servicelist = serviceHandler.list(bouquet)
214 if not servicelist is None:
216 serviceIterator = servicelist.getNext()
217 if not serviceIterator.valid(): #check end of list
219 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
222 if not num: #found service with searched number ?
223 return serviceIterator, 0
226 def zapToNumber(self, number):
227 bouquet = self.servicelist.bouquet_root
229 serviceHandler = eServiceCenter.getInstance()
230 if not config.usage.multibouquet.value:
231 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
233 bouquetlist = serviceHandler.list(bouquet)
234 if not bouquetlist is None:
236 bouquet = bouquetlist.getNext()
237 if not bouquet.valid(): #check end of list
239 if bouquet.flags & eServiceReference.isDirectory:
240 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
241 if not service is None:
242 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
243 self.servicelist.clearPath()
244 if self.servicelist.bouquet_root != bouquet:
245 self.servicelist.enterPath(self.servicelist.bouquet_root)
246 self.servicelist.enterPath(bouquet)
247 self.servicelist.setCurrentSelection(service) #select the service in servicelist
248 self.servicelist.zap()
250 config.misc.initialchannelselection = ConfigBoolean(default = True)
252 class InfoBarChannelSelection:
253 """ ChannelSelection - handles the channelSelection dialog and the initial
254 channelChange actions which open the channelSelection dialog """
257 self.servicelist = self.session.instantiateDialog(ChannelSelection)
259 if config.misc.initialchannelselection.value:
260 self.onShown.append(self.firstRun)
262 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
264 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
265 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
266 "zapUp": (self.zapUp, _("previous channel")),
267 "zapDown": (self.zapDown, _("next channel")),
268 "historyBack": (self.historyBack, _("previous channel in history")),
269 "historyNext": (self.historyNext, _("next channel in history")),
270 "openServiceList": (self.openServiceList, _("open servicelist")),
273 def showTvChannelList(self, zap=False):
274 self.servicelist.setModeTv()
276 self.servicelist.zap()
277 self.session.execDialog(self.servicelist)
279 def showRadioChannelList(self, zap=False):
280 self.servicelist.setModeRadio()
282 self.servicelist.zap()
283 self.session.execDialog(self.servicelist)
286 self.onShown.remove(self.firstRun)
287 config.misc.initialchannelselection.value = False
288 config.misc.initialchannelselection.save()
289 self.switchChannelDown()
291 def historyBack(self):
292 self.servicelist.historyBack()
294 def historyNext(self):
295 self.servicelist.historyNext()
297 def switchChannelUp(self):
298 self.servicelist.moveUp()
299 self.session.execDialog(self.servicelist)
301 def switchChannelDown(self):
302 self.servicelist.moveDown()
303 self.session.execDialog(self.servicelist)
305 def openServiceList(self):
306 self.session.execDialog(self.servicelist)
309 if self.servicelist.inBouquet():
310 prev = self.servicelist.getCurrentSelection()
312 prev = prev.toString()
314 if config.usage.quickzap_bouquet_change.value:
315 if self.servicelist.atBegin():
316 self.servicelist.prevBouquet()
317 self.servicelist.moveUp()
318 cur = self.servicelist.getCurrentSelection()
319 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
322 self.servicelist.moveUp()
323 self.servicelist.zap()
326 if self.servicelist.inBouquet():
327 prev = self.servicelist.getCurrentSelection()
329 prev = prev.toString()
331 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
332 self.servicelist.nextBouquet()
334 self.servicelist.moveDown()
335 cur = self.servicelist.getCurrentSelection()
336 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
339 self.servicelist.moveDown()
340 self.servicelist.zap()
343 """ Handles a menu action, to open the (main) menu """
345 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
347 "mainMenu": (self.mainMenu, _("Enter main menu...")),
349 self.session.infobar = None
352 print "loading mainmenu XML..."
353 menu = mdom.childNodes[0]
354 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
356 self.session.infobar = self
357 # so we can access the currently active infobar from screens opened from within the mainmenu
358 # at the moment used from the SubserviceSelection
360 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
362 def mainMenuClosed(self, *val):
363 self.session.infobar = None
365 class InfoBarSimpleEventView:
366 """ Opens the Eventview for now/next """
368 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
370 "showEventInfo": (self.openEventView, _("show event details")),
373 def openEventView(self):
375 service = self.session.nav.getCurrentService()
376 ref = self.session.nav.getCurrentlyPlayingServiceReference()
377 info = service.info()
380 self.epglist.append(ptr)
383 self.epglist.append(ptr)
384 if len(self.epglist) > 0:
385 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
387 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
388 if len(self.epglist) > 1:
389 tmp = self.epglist[0]
390 self.epglist[0]=self.epglist[1]
392 setEvent(self.epglist[0])
395 """ EPG - Opens an EPG list when the showEPGList action fires """
397 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
399 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
402 self.is_now_next = False
404 self.bouquetSel = None
405 self.eventView = None
406 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
408 "showEventInfo": (self.openEventView, _("show EPG...")),
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, _("pause")),
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 # give them a little more priority to win over color buttons
667 self["SeekActions"].setEnabled(False)
669 self.seekstate = self.SEEK_STATE_PLAY
671 self.onPlayStateChanged = [ ]
673 self.lockedBecauseOfSkipping = False
675 self.__seekableStatusChanged()
677 def showAfterSeek(self):
678 if isinstance(self, InfoBarShowHide):
688 service = self.session.nav.getCurrentService()
692 seek = service.seek()
694 if seek is None or not seek.isCurrentlySeekable():
699 def isSeekable(self):
700 if self.getSeek() is None:
704 def __seekableStatusChanged(self):
705 print "seekable status changed!"
706 if not self.isSeekable():
707 self["SeekActions"].setEnabled(False)
708 print "not seekable, return to play"
709 self.setSeekState(self.SEEK_STATE_PLAY)
711 self["SeekActions"].setEnabled(True)
714 def __serviceStarted(self):
715 self.seekstate = self.SEEK_STATE_PLAY
716 self.__seekableStatusChanged()
718 def setSeekState(self, state):
719 service = self.session.nav.getCurrentService()
724 if not self.isSeekable():
725 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
726 state = self.SEEK_STATE_PLAY
728 pauseable = service.pause()
730 if pauseable is None:
731 print "not pauseable."
732 state = self.SEEK_STATE_PLAY
734 oldstate = self.seekstate
735 self.seekstate = state
738 if oldstate[i] != self.seekstate[i]:
739 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
741 for c in self.onPlayStateChanged:
744 self.checkSkipShowHideLock()
748 def playpauseService(self):
749 if self.seekstate != self.SEEK_STATE_PLAY:
750 self.unPauseService()
754 def pauseService(self):
755 if self.seekstate == self.SEEK_STATE_PAUSE:
756 print "pause, but in fact unpause"
757 self.unPauseService()
759 if self.seekstate == self.SEEK_STATE_PLAY:
760 print "yes, playing."
762 print "no", self.seekstate
764 self.setSeekState(self.SEEK_STATE_PAUSE);
766 def unPauseService(self):
768 if self.seekstate == self.SEEK_STATE_PLAY:
770 self.setSeekState(self.SEEK_STATE_PLAY)
772 def doSeek(self, seektime):
773 print "doseek", seektime
774 service = self.session.nav.getCurrentService()
778 seekable = self.getSeek()
782 seekable.seekTo(90 * seektime)
786 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
787 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
788 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
789 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
790 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
791 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
792 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
793 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
794 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
795 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
796 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
797 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
798 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
799 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
800 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
801 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
803 self.setSeekState(lookup[self.seekstate])
807 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
808 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
809 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
810 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
811 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
812 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
813 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
814 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
815 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
816 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
817 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
818 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
819 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
820 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
821 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
822 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
824 self.setSeekState(lookup[self.seekstate])
826 if self.seekstate == self.SEEK_STATE_PAUSE:
827 seekable = self.getSeek()
828 if seekable is not None:
829 seekable.seekRelative(-1, 3)
831 def seekFwdManual(self):
832 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
834 def fwdSeekTo(self, minutes):
835 print "Seek", minutes, "minutes forward"
837 seekable = self.getSeek()
838 if seekable is not None:
839 seekable.seekRelative(1, minutes * 60 * 90000)
841 def seekBackManual(self):
842 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
844 def rwdSeekTo(self, minutes):
846 self.fwdSeekTo(0 - minutes)
848 def checkSkipShowHideLock(self):
849 wantlock = self.seekstate != self.SEEK_STATE_PLAY
851 if config.usage.show_infobar_on_zap.value:
852 if self.lockedBecauseOfSkipping and not wantlock:
854 self.lockedBecauseOfSkipping = False
856 if wantlock and not self.lockedBecauseOfSkipping:
858 self.lockedBecauseOfSkipping = True
861 if self.seekstate == self.SEEK_STATE_EOF:
863 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
864 print "end of stream while seeking back, ignoring."
867 # if we are seeking, we try to end up ~1s before the end, and pause there.
868 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
869 self.setSeekState(self.SEEK_STATE_EOF)
870 self.seekRelativeToEnd(-90000)
872 self.setSeekState(self.SEEK_STATE_EOF)
875 self.setSeekState(self.SEEK_STATE_PLAY)
878 def seekRelative(self, diff):
879 seekable = self.getSeek()
880 if seekable is not None:
881 print "seekRelative: res:", seekable.seekRelative(1, diff)
885 def seekRelativeToEnd(self, diff):
886 assert diff <= 0, "diff is expected to be negative!"
888 # might sound like an evil hack, but:
889 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
890 # and we don't get that by passing 0 here (it would seek to begin).
894 # relative-to-end seeking is implemented as absolutes seeks with negative time
895 self.seekAbsolute(diff)
897 def seekAbsolute(self, abs):
898 seekable = self.getSeek()
899 if seekable is not None:
902 from Screens.PVRState import PVRState, TimeshiftState
904 class InfoBarPVRState:
905 def __init__(self, screen=PVRState):
906 self.onPlayStateChanged.append(self.__playStateChanged)
907 self.pvrStateDialog = self.session.instantiateDialog(screen)
908 self.onShow.append(self._mayShow)
909 self.onHide.append(self.pvrStateDialog.hide)
912 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
913 self.pvrStateDialog.show()
915 def __playStateChanged(self, state):
916 playstateString = state[3]
917 self.pvrStateDialog["state"].setText(playstateString)
920 class InfoBarTimeshiftState(InfoBarPVRState):
922 InfoBarPVRState.__init__(self, screen=TimeshiftState)
925 if self.execing and self.timeshift_enabled:
926 self.pvrStateDialog.show()
928 class InfoBarShowMovies:
930 # i don't really like this class.
931 # it calls a not further specified "movie list" on up/down/movieList,
932 # so this is not more than an action map
934 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
936 "movieList": (self.showMovies, _("movie list")),
937 "up": (self.showMovies, _("movie list")),
938 "down": (self.showMovies, _("movie list"))
941 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
945 # Timeshift works the following way:
946 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
947 # - normal playback TUNER unused PLAY enable disable disable
948 # - user presses "yellow" button. FILE record PAUSE enable disable enable
949 # - user presess pause again FILE record PLAY enable disable enable
950 # - user fast forwards FILE record FF enable disable enable
951 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
952 # - user backwards FILE record BACK # !! enable disable enable
956 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
957 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
958 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
959 # - the user can now PVR around
960 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
961 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
963 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
964 # - if the user rewinds, or press pause, timeshift will be activated again
966 # note that a timeshift can be enabled ("recording") and
967 # activated (currently time-shifting).
969 class InfoBarTimeshift:
971 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
973 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
974 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
976 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
978 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
979 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
980 }, prio=-1) # priority over record
982 self.timeshift_enabled = 0
983 self.timeshift_state = 0
984 self.ts_rewind_timer = eTimer()
985 self.ts_rewind_timer.timeout.get().append(self.rewindService)
987 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
989 iPlayableService.evStart: self.__serviceStarted,
990 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
993 def getTimeshift(self):
994 service = self.session.nav.getCurrentService()
995 return service and service.timeshift()
997 def startTimeshift(self):
998 print "enable timeshift"
999 ts = self.getTimeshift()
1001 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1002 print "no ts interface"
1005 if self.timeshift_enabled:
1006 print "hu, timeshift already enabled?"
1008 if not ts.startTimeshift():
1009 self.timeshift_enabled = 1
1011 # we remove the "relative time" for now.
1012 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1015 #self.setSeekState(self.SEEK_STATE_PAUSE)
1016 self.activateTimeshiftEnd(False)
1018 # enable the "TimeshiftEnableActions", which will override
1019 # the startTimeshift actions
1020 self.__seekableStatusChanged()
1022 print "timeshift failed"
1024 def stopTimeshift(self):
1025 if not self.timeshift_enabled:
1027 print "disable timeshift"
1028 ts = self.getTimeshift()
1031 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1033 def stopTimeshiftConfirmed(self, confirmed):
1037 ts = self.getTimeshift()
1042 self.timeshift_enabled = 0
1045 self.__seekableStatusChanged()
1047 # activates timeshift, and seeks to (almost) the end
1048 def activateTimeshiftEnd(self, back = True):
1049 ts = self.getTimeshift()
1050 print "activateTimeshiftEnd"
1055 if ts.isTimeshiftActive():
1056 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1060 ts.activateTimeshift() # activate timeshift will automatically pause
1061 self.setSeekState(self.SEEK_STATE_PAUSE)
1062 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1065 self.ts_rewind_timer.start(200, 1)
1067 def rewindService(self):
1068 self.setSeekState(self.SEEK_STATE_BACK_16X)
1070 # same as activateTimeshiftEnd, but pauses afterwards.
1071 def activateTimeshiftEndAndPause(self):
1072 print "activateTimeshiftEndAndPause"
1073 #state = self.seekstate
1074 self.activateTimeshiftEnd(False)
1076 def __seekableStatusChanged(self):
1079 print "self.isSeekable", self.isSeekable()
1080 print "self.timeshift_enabled", self.timeshift_enabled
1082 # when this service is not seekable, but timeshift
1083 # is enabled, this means we can activate
1085 if not self.isSeekable() and self.timeshift_enabled:
1088 print "timeshift activate:", enabled
1089 self["TimeshiftActivateActions"].setEnabled(enabled)
1091 def __serviceStarted(self):
1092 self.timeshift_enabled = False
1093 self.__seekableStatusChanged()
1095 from Screens.PiPSetup import PiPSetup
1097 class InfoBarExtensions:
1098 EXTENSION_SINGLE = 0
1104 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1106 "extensions": (self.showExtensionSelection, _("view extensions...")),
1109 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1110 self.list.append((type, extension, key))
1112 def updateExtension(self, extension, key = None):
1113 self.extensionsList.append(extension)
1115 if self.extensionKeys.has_key(key):
1119 for x in self.availableKeys:
1120 if not self.extensionKeys.has_key(x):
1125 self.extensionKeys[key] = len(self.extensionsList) - 1
1127 def updateExtensions(self):
1128 self.extensionsList = []
1129 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1130 self.extensionKeys = {}
1132 if x[0] == self.EXTENSION_SINGLE:
1133 self.updateExtension(x[1], x[2])
1136 self.updateExtension(y[0], y[1])
1139 def showExtensionSelection(self):
1140 self.updateExtensions()
1141 extensionsList = self.extensionsList[:]
1144 for x in self.availableKeys:
1145 if self.extensionKeys.has_key(x):
1146 entry = self.extensionKeys[x]
1147 extension = self.extensionsList[entry]
1149 name = str(extension[0]())
1150 list.append((extension[0](), extension))
1152 extensionsList.remove(extension)
1154 extensionsList.remove(extension)
1155 for x in extensionsList:
1156 list.append((x[0](), x))
1157 keys += [""] * len(extensionsList)
1158 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1160 def extensionCallback(self, answer):
1161 if answer is not None:
1164 from Tools.BoundFunction import boundFunction
1166 # depends on InfoBarExtensions
1167 from Components.PluginComponent import plugins
1169 class InfoBarPlugins:
1171 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1173 def getPluginName(self, name):
1176 def getPluginList(self):
1178 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1179 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1182 def runPlugin(self, plugin):
1183 plugin(session = self.session)
1185 # depends on InfoBarExtensions
1186 class InfoBarSleepTimer:
1188 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1190 def available(self):
1193 def getSleepTimerName(self):
1194 return _("Sleep Timer")
1196 def showSleepTimerSetup(self):
1197 self.session.open(SleepTimerEdit)
1199 # depends on InfoBarExtensions
1202 self.session.pipshown = False
1204 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1205 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1206 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1208 def available(self):
1212 return self.session.pipshown
1214 def getShowHideName(self):
1215 if self.session.pipshown:
1216 return _("Disable Picture in Picture")
1218 return _("Activate Picture in Picture")
1220 def getSwapName(self):
1221 return _("Swap Services")
1223 def getMoveName(self):
1224 return _("Move Picture in Picture")
1227 if self.session.pipshown:
1228 del self.session.pip
1229 self.session.pipshown = False
1231 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1232 self.session.pip.show()
1233 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1234 if self.session.pip.playService(newservice):
1235 self.session.pipshown = True
1236 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1238 self.session.pipshown = False
1239 del self.session.pip
1240 self.session.nav.playService(newservice)
1243 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1244 if self.session.pip.servicePath:
1245 servicepath = self.servicelist.getCurrentServicePath()
1246 ref=servicepath[len(servicepath)-1]
1247 pipref=self.session.pip.getCurrentService()
1248 self.session.pip.playService(swapservice)
1249 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1250 if pipref.toString() != ref.toString(): # is a subservice ?
1251 self.session.nav.stopService() # stop portal
1252 self.session.nav.playService(pipref) # start subservice
1253 self.session.pip.servicePath=servicepath
1256 self.session.open(PiPSetup, pip = self.session.pip)
1258 from RecordTimer import parseEvent
1260 class InfoBarInstantRecord:
1261 """Instant Record - handles the instantRecord action in order to
1262 start/stop instant records"""
1264 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1266 "instantRecord": (self.instantRecord, _("Instant Record...")),
1269 self["BlinkingPoint"] = BlinkingPixmapConditional()
1270 self["BlinkingPoint"].hide()
1271 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1273 def stopCurrentRecording(self, entry = -1):
1274 if entry is not None and entry != -1:
1275 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1276 self.recording.remove(self.recording[entry])
1278 def startInstantRecording(self, limitEvent = False):
1279 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1281 # try to get event info
1284 service = self.session.nav.getCurrentService()
1285 epg = eEPGCache.getInstance()
1286 event = epg.lookupEventTime(serviceref, -1, 0)
1288 info = service.info()
1289 ev = info.getEvent(0)
1295 end = time() + 3600 * 10
1296 name = "instant record"
1300 if event is not None:
1301 curEvent = parseEvent(event)
1303 description = curEvent[3]
1304 eventid = curEvent[4]
1309 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1311 data = (begin, end, name, description, eventid)
1313 recording = self.session.nav.recordWithTimer(serviceref, *data)
1314 recording.dontSave = True
1315 self.recording.append(recording)
1317 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1319 def isInstantRecordRunning(self):
1320 print "self.recording:", self.recording
1321 if len(self.recording) > 0:
1322 for x in self.recording:
1327 def recordQuestionCallback(self, answer):
1328 print "pre:\n", self.recording
1330 if answer is None or answer[1] == "no":
1333 recording = self.recording[:]
1335 if not x in self.session.nav.RecordTimer.timer_list:
1336 self.recording.remove(x)
1337 elif x.dontSave and x.isRunning():
1338 list.append(TimerEntryComponent(x, False))
1340 if answer[1] == "changeduration":
1341 if len(self.recording) == 1:
1342 self.changeDuration(0)
1344 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1345 elif answer[1] == "changeendtime":
1346 if len(self.recording) == 1:
1349 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1350 elif answer[1] == "stop":
1351 if len(self.recording) == 1:
1352 self.stopCurrentRecording(0)
1354 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1355 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1356 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1357 if answer[1] == "manualduration":
1358 self.changeDuration(len(self.recording)-1)
1359 elif answer[1] == "manualendtime":
1360 self.setEndtime(len(self.recording)-1)
1361 print "after:\n", self.recording
1363 def setEndtime(self, entry):
1364 if entry is not None:
1365 self.selectedEntry = entry
1366 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1367 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1368 dlg.setTitle(_("Please change recording endtime"))
1370 def TimeDateInputClosed(self, ret):
1373 localendtime = localtime(ret[1])
1374 print "stopping recording at", strftime("%c", localendtime)
1375 self.recording[self.selectedEntry].end = ret[1]
1376 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1378 def changeDuration(self, entry):
1379 if entry is not None:
1380 self.selectedEntry = entry
1381 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1383 def inputCallback(self, value):
1384 if value is not None:
1385 print "stopping recording after", int(value), "minutes."
1386 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1387 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1389 def instantRecord(self):
1391 stat = os_stat(resolveFilename(SCOPE_HDD))
1393 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1396 if self.isInstantRecordRunning():
1397 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1398 title=_("A recording is currently running.\nWhat do you want to do?"), \
1399 list=[(_("stop recording"), "stop"), \
1400 (_("change recording (duration)"), "changeduration"), \
1401 (_("change recording (endtime)"), "changeendtime"), \
1402 (_("add recording (indefinitely)"), "indefinitely"), \
1403 (_("add recording (stop after current event)"), "event"), \
1404 (_("add recording (enter recording duration)"), "manualduration"), \
1405 (_("add recording (enter recording endtime)"), "manualendtime"), \
1406 (_("do nothing"), "no")])
1408 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1409 title=_("Start recording?"), \
1410 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1411 (_("add recording (stop after current event)"), "event"), \
1412 (_("add recording (enter recording duration)"), "manualduration"), \
1413 (_("add recording (enter recording endtime)"), "manualendtime"), \
1414 (_("don't record"), "no")])
1416 from Tools.ISO639 import LanguageCodes
1418 class InfoBarAudioSelection:
1420 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1422 "audioSelection": (self.audioSelection, _("Audio Options...")),
1425 def audioSelection(self):
1426 service = self.session.nav.getCurrentService()
1427 audio = service and service.audioTracks()
1428 self.audioTracks = audio
1429 n = audio and audio.getNumberOfTracks() or 0
1430 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1432 print "tlist:", tlist
1434 self.audioChannel = service.audioChannel()
1437 i = audio.getTrackInfo(x)
1438 language = i.getLanguage()
1439 description = i.getDescription()
1441 if LanguageCodes.has_key(language):
1442 language = LanguageCodes[language][0]
1444 if len(description):
1445 description += " (" + language + ")"
1447 description = language
1449 tlist.append((description, x))
1451 selectedAudio = tlist[0][1]
1452 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1456 if x[1] != selectedAudio:
1461 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1462 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1464 del self.audioTracks
1466 def audioSelected(self, audio):
1467 if audio is not None:
1468 if isinstance(audio[1], str):
1469 if audio[1] == "mode":
1470 keys = ["red", "green", "yellow"]
1471 selection = self.audioChannel.getCurrentChannel()
1472 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1473 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1475 del self.audioChannel
1476 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1477 self.audioTracks.selectTrack(audio[1])
1479 del self.audioChannel
1480 del self.audioTracks
1482 def modeSelected(self, mode):
1483 if mode is not None:
1484 self.audioChannel.selectChannel(mode[1])
1485 del self.audioChannel
1487 class InfoBarSubserviceSelection:
1489 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1491 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1494 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1496 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1497 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1499 self["SubserviceQuickzapAction"].setEnabled(False)
1501 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1505 def checkSubservicesAvail(self, ev):
1506 if ev == iPlayableService.evUpdatedEventInfo:
1507 service = self.session.nav.getCurrentService()
1508 subservices = service and service.subServices()
1509 if not subservices or subservices.getNumberOfSubservices() == 0:
1510 self["SubserviceQuickzapAction"].setEnabled(False)
1512 def nextSubservice(self):
1513 self.changeSubservice(+1)
1515 def prevSubservice(self):
1516 self.changeSubservice(-1)
1518 def changeSubservice(self, direction):
1519 service = self.session.nav.getCurrentService()
1520 subservices = service and service.subServices()
1521 n = subservices and subservices.getNumberOfSubservices()
1524 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1526 if subservices.getSubservice(x).toString() == ref.toString():
1529 selection += direction
1534 newservice = subservices.getSubservice(selection)
1535 if newservice.valid():
1538 self.session.nav.playService(newservice)
1540 def subserviceSelection(self):
1541 service = self.session.nav.getCurrentService()
1542 subservices = service and service.subServices()
1543 self.bouquets = self.servicelist.getBouquetList()
1544 n = subservices and subservices.getNumberOfSubservices()
1547 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1550 i = subservices.getSubservice(x)
1551 if i.toString() == ref.toString():
1553 tlist.append((i.getName(), i))
1555 if self.bouquets and len(self.bouquets):
1556 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1557 if config.usage.multibouquet.value:
1558 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1560 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1563 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1564 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1567 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1569 def subserviceSelected(self, service):
1571 if not service is None:
1572 if isinstance(service[1], str):
1573 if service[1] == "quickzap":
1574 from Screens.SubservicesQuickzap import SubservicesQuickzap
1575 self.session.open(SubservicesQuickzap, service[2])
1577 self["SubserviceQuickzapAction"].setEnabled(True)
1578 self.session.nav.playService(service[1])
1580 def addSubserviceToBouquetCallback(self, service):
1581 if len(service) > 1 and isinstance(service[1], eServiceReference):
1582 self.selectedSubservice = service
1583 if self.bouquets is None:
1586 cnt = len(self.bouquets)
1587 if cnt > 1: # show bouquet list
1588 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1589 elif cnt == 1: # add to only one existing bouquet
1590 self.addSubserviceToBouquet(self.bouquets[0][1])
1591 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1593 def bouquetSelClosed(self, confirmed):
1595 del self.selectedSubservice
1597 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1599 def addSubserviceToBouquet(self, dest):
1600 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1602 self.bsel.close(True)
1604 del self.selectedSubservice
1606 class InfoBarAdditionalInfo:
1608 self["NimA"] = Pixmap()
1609 self["NimB"] = Pixmap()
1610 self["NimA_Active"] = Pixmap()
1611 self["NimB_Active"] = Pixmap()
1613 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1614 self["TimeshiftPossible"] = self["RecordingPossible"]
1615 self["ExtensionsAvailable"] = Boolean(fixed=1)
1617 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1618 res_mgr = eDVBResourceManager.getInstance()
1620 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1622 def tunerUseMaskChanged(self, mask):
1624 self["NimA_Active"].show()
1626 self["NimA_Active"].hide()
1628 self["NimB_Active"].show()
1630 self["NimB_Active"].hide()
1632 def checkTunerState(self, service):
1633 info = service and service.frontendInfo()
1634 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1635 if feNumber is None:
1645 def gotServiceEvent(self, ev):
1646 service = self.session.nav.getCurrentService()
1647 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1648 self.checkTunerState(service)
1650 class InfoBarNotifications:
1652 self.onExecBegin.append(self.checkNotifications)
1653 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1654 self.onClose.append(self.__removeNotification)
1656 def __removeNotification(self):
1657 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1659 def checkNotificationsIfExecing(self):
1661 self.checkNotifications()
1663 def checkNotifications(self):
1664 if len(Notifications.notifications):
1665 n = Notifications.notifications[0]
1667 Notifications.notifications = Notifications.notifications[1:]
1670 if n[3].has_key("onSessionOpenCallback"):
1671 n[3]["onSessionOpenCallback"]()
1672 del n[3]["onSessionOpenCallback"]
1675 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1677 dlg = self.session.open(n[1], *n[2], **n[3])
1679 # remember that this notification is currently active
1681 Notifications.current_notifications.append(d)
1682 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1684 def __notificationClosed(self, d):
1685 Notifications.current_notifications.remove(d)
1687 class InfoBarServiceNotifications:
1689 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1691 iPlayableService.evEnd: self.serviceHasEnded
1694 def serviceHasEnded(self):
1695 print "service end!"
1698 self.setSeekState(self.SEEK_STATE_PLAY)
1702 class InfoBarCueSheetSupport:
1708 ENABLE_RESUME_SUPPORT = False
1711 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1713 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to next marked position")),
1714 "jumpNextMark": (self.jumpNextMark, _("jump to previous marked position")),
1715 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1719 self.is_closing = False
1720 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1722 iPlayableService.evStart: self.__serviceStarted,
1725 def __serviceStarted(self):
1728 print "new service started! trying to download cuts!"
1729 self.downloadCuesheet()
1731 if self.ENABLE_RESUME_SUPPORT:
1734 for (pts, what) in self.cut_list:
1735 if what == self.CUT_TYPE_LAST:
1738 if last is not None:
1739 self.resume_point = last
1740 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1742 def playLastCB(self, answer):
1744 seekable = self.__getSeekable()
1745 if seekable is not None:
1746 seekable.seekTo(self.resume_point)
1748 def __getSeekable(self):
1749 service = self.session.nav.getCurrentService()
1752 return service.seek()
1754 def cueGetCurrentPosition(self):
1755 seek = self.__getSeekable()
1758 r = seek.getPlayPosition()
1763 def jumpPreviousNextMark(self, cmp, alternative=None):
1764 current_pos = self.cueGetCurrentPosition()
1765 if current_pos is None:
1767 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1768 if mark is not None:
1770 elif alternative is not None:
1775 seekable = self.__getSeekable()
1776 if seekable is not None:
1777 seekable.seekTo(pts)
1779 def jumpPreviousMark(self):
1780 # we add 2 seconds, so if the play position is <2s after
1781 # the mark, the mark before will be used
1782 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1784 def jumpNextMark(self):
1785 self.jumpPreviousNextMark(lambda x: x)
1787 def getNearestCutPoint(self, pts, cmp=abs):
1790 for cp in self.cut_list:
1791 diff = cmp(cp[0] - pts)
1792 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1796 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1797 current_pos = self.cueGetCurrentPosition()
1798 if current_pos is None:
1799 print "not seekable"
1802 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1804 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1806 return nearest_cutpoint
1808 self.removeMark(nearest_cutpoint)
1809 elif not onlyremove and not onlyreturn:
1810 self.addMark((current_pos, self.CUT_TYPE_MARK))
1815 def showAfterCuesheetOperation(self):
1816 if isinstance(self, InfoBarShowHide):
1819 def addMark(self, point):
1820 insort(self.cut_list, point)
1821 self.uploadCuesheet()
1822 self.showAfterCuesheetOperation()
1824 def removeMark(self, point):
1825 self.cut_list.remove(point)
1826 self.uploadCuesheet()
1827 self.showAfterCuesheetOperation()
1829 def showAfterCuesheetOperation(self):
1830 if isinstance(self, InfoBarShowHide):
1833 def __getCuesheet(self):
1834 service = self.session.nav.getCurrentService()
1837 return service.cueSheet()
1839 def uploadCuesheet(self):
1840 cue = self.__getCuesheet()
1843 print "upload failed, no cuesheet interface"
1845 cue.setCutList(self.cut_list)
1847 def downloadCuesheet(self):
1848 cue = self.__getCuesheet()
1851 print "download failed, no cuesheet interface"
1854 self.cut_list = cue.getCutList()
1856 class InfoBarSummary(Screen):
1858 <screen position="0,0" size="132,64">
1859 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1860 <convert type="ClockToText">WithSeconds</convert>
1862 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1863 <convert type="ServiceName">Name</convert>
1867 def __init__(self, session, parent):
1868 Screen.__init__(self, session)
1869 self["CurrentService"] = CurrentService(self.session.nav)
1870 self["CurrentTime"] = Clock()
1872 class InfoBarSummarySupport:
1876 def createSummary(self):
1877 return InfoBarSummary
1879 class InfoBarTeletextPlugin:
1881 self.teletext_plugin = None
1883 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1884 self.teletext_plugin = p
1886 if self.teletext_plugin is not None:
1887 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1889 "startTeletext": (self.startTeletext, _("View teletext..."))
1892 print "no teletext plugin found!"
1894 def startTeletext(self):
1895 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1897 class InfoBarSubtitleSupport(object):
1899 object.__init__(self)
1900 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1901 self.__subtitles_enabled = False
1903 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1905 iPlayableService.evEnd: self.__serviceStopped,
1906 iPlayableService.evUpdatedInfo: self.__updatedInfo
1908 self.cached_subtitle_checked = False
1909 self.__selected_subtitle = None
1911 def __serviceStopped(self):
1912 self.subtitle_window.hide()
1913 self.__subtitles_enabled = False
1914 self.cached_subtitle_checked = False
1916 def __updatedInfo(self):
1917 if not self.cached_subtitle_checked:
1918 subtitle = self.getCurrentServiceSubtitle()
1919 self.cached_subtitle_checked = True
1920 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1921 if self.__selected_subtitle:
1922 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1923 self.subtitle_window.show()
1924 self.__subtitles_enabled = True
1926 def getCurrentServiceSubtitle(self):
1927 service = self.session.nav.getCurrentService()
1928 return service and service.subtitle()
1930 def setSubtitlesEnable(self, enable=True):
1931 subtitle = self.getCurrentServiceSubtitle()
1932 if enable and self.__selected_subtitle is not None:
1933 if subtitle and not self.__subtitles_enabled:
1934 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1935 self.subtitle_window.show()
1936 self.__subtitles_enabled = True
1939 subtitle.disableSubtitles(self.subtitle_window.instance)
1940 self.__subtitles_enabled = False
1941 self.subtitle_window.hide()
1943 def setSelectedSubtitle(self, subtitle):
1944 self.__selected_subtitle = subtitle
1946 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1947 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1949 class InfoBarServiceErrorPopupSupport:
1951 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1953 iPlayableService.evTuneFailed: self.__tuneFailed,
1954 iPlayableService.evStart: self.__serviceStarted
1956 self.__serviceStarted()
1958 def __serviceStarted(self):
1959 self.last_error = None
1960 Notifications.RemovePopup(id = "ZapError")
1962 def __tuneFailed(self):
1963 service = self.session.nav.getCurrentService()
1964 info = service and service.info()
1965 error = info and info.getInfo(iServiceInformation.sDVBState)
1967 if error == self.last_error:
1970 self.last_error = error
1973 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1974 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1975 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1976 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1977 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1978 eDVBServicePMTHandler.eventNewProgramInfo: None,
1979 eDVBServicePMTHandler.eventTuned: None,
1980 eDVBServicePMTHandler.eventSOF: None,
1981 eDVBServicePMTHandler.eventEOF: None
1984 error = errors.get(error) #this returns None when the key not exist in the dict
1986 if error is not None:
1987 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1989 Notifications.RemovePopup(id = "ZapError")