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,
657 "pauseService": (self.pauseService, _("pause")),
658 "unPauseService": (self.unPauseService, _("continue")),
660 "seekFwd": (self.seekFwd, _("skip forward")),
661 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
662 "seekBack": (self.seekBack, _("skip backward")),
663 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
665 "seekFwdDef": (self.seekFwdDef, _("skip forward (self defined)")),
666 "seekBackDef": (self.seekBackDef, _("skip backward (self defined)"))
668 # give them a little more priority to win over color buttons
670 self["SeekActions"].setEnabled(False)
672 self.seekstate = self.SEEK_STATE_PLAY
674 self.onPlayStateChanged = [ ]
676 self.lockedBecauseOfSkipping = False
678 self.__seekableStatusChanged()
680 def showAfterSeek(self):
681 if isinstance(self, InfoBarShowHide):
691 service = self.session.nav.getCurrentService()
695 seek = service.seek()
697 if seek is None or not seek.isCurrentlySeekable():
702 def isSeekable(self):
703 if self.getSeek() is None:
707 def __seekableStatusChanged(self):
708 print "seekable status changed!"
709 if not self.isSeekable():
710 self["SeekActions"].setEnabled(False)
711 print "not seekable, return to play"
712 self.setSeekState(self.SEEK_STATE_PLAY)
714 self["SeekActions"].setEnabled(True)
717 def __serviceStarted(self):
718 self.seekstate = self.SEEK_STATE_PLAY
719 self.__seekableStatusChanged()
721 def setSeekState(self, state):
722 service = self.session.nav.getCurrentService()
727 if not self.isSeekable():
728 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
729 state = self.SEEK_STATE_PLAY
731 pauseable = service.pause()
733 if pauseable is None:
734 print "not pauseable."
735 state = self.SEEK_STATE_PLAY
737 oldstate = self.seekstate
738 self.seekstate = state
741 if oldstate[i] != self.seekstate[i]:
742 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
744 for c in self.onPlayStateChanged:
747 self.checkSkipShowHideLock()
751 def playpauseService(self):
752 if self.seekstate != self.SEEK_STATE_PLAY:
753 self.unPauseService()
757 def pauseService(self):
758 if self.seekstate == self.SEEK_STATE_PAUSE:
759 print "pause, but in fact unpause"
760 self.unPauseService()
762 if self.seekstate == self.SEEK_STATE_PLAY:
763 print "yes, playing."
765 print "no", self.seekstate
767 self.setSeekState(self.SEEK_STATE_PAUSE);
769 def unPauseService(self):
771 if self.seekstate == self.SEEK_STATE_PLAY:
773 self.setSeekState(self.SEEK_STATE_PLAY)
775 def doSeek(self, seektime):
776 print "doseek", seektime
777 service = self.session.nav.getCurrentService()
781 seekable = self.getSeek()
785 seekable.seekTo(90 * seektime)
789 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
790 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
791 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
792 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
793 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
794 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
795 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
796 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
797 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
798 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
799 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
800 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
801 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
802 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
803 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
804 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
806 self.setSeekState(lookup[self.seekstate])
810 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
811 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
812 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
813 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
814 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
815 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
816 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
817 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
818 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
819 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
820 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
821 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
822 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
823 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
824 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
825 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
827 self.setSeekState(lookup[self.seekstate])
829 if self.seekstate == self.SEEK_STATE_PAUSE:
830 seekable = self.getSeek()
831 if seekable is not None:
832 seekable.seekRelative(-1, 3)
834 def seekFwdDef(self):
835 seconds = config.usage.self_defined_seek.value
836 print "Seek", seconds, "seconds self defined forward"
837 seekable = self.getSeek()
838 if seekable is not None:
839 seekable.seekRelative(1, seconds * 90000)
841 def seekBackDef(self):
842 seconds = config.usage.self_defined_seek.value
843 print "Seek", seconds, "seconds self defined backward"
844 seekable = self.getSeek()
845 if seekable is not None:
846 seekable.seekRelative(1, 0 - seconds * 90000)
848 def seekFwdManual(self):
849 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
851 def fwdSeekTo(self, minutes):
852 print "Seek", minutes, "minutes forward"
854 seekable = self.getSeek()
855 if seekable is not None:
856 seekable.seekRelative(1, minutes * 60 * 90000)
858 def seekBackManual(self):
859 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
861 def rwdSeekTo(self, minutes):
863 self.fwdSeekTo(0 - minutes)
865 def checkSkipShowHideLock(self):
866 wantlock = self.seekstate != self.SEEK_STATE_PLAY
868 if config.usage.show_infobar_on_zap.value:
869 if self.lockedBecauseOfSkipping and not wantlock:
871 self.lockedBecauseOfSkipping = False
873 if wantlock and not self.lockedBecauseOfSkipping:
875 self.lockedBecauseOfSkipping = True
878 if self.seekstate == self.SEEK_STATE_EOF:
880 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
881 print "end of stream while seeking back, ignoring."
884 # if we are seeking, we try to end up ~1s before the end, and pause there.
885 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
886 self.setSeekState(self.SEEK_STATE_EOF)
887 self.seekRelativeToEnd(-90000)
889 self.setSeekState(self.SEEK_STATE_EOF)
892 self.setSeekState(self.SEEK_STATE_PLAY)
895 def seekRelative(self, diff):
896 seekable = self.getSeek()
897 if seekable is not None:
898 print "seekRelative: res:", seekable.seekRelative(1, diff)
902 def seekRelativeToEnd(self, diff):
903 assert diff <= 0, "diff is expected to be negative!"
905 # might sound like an evil hack, but:
906 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
907 # and we don't get that by passing 0 here (it would seek to begin).
911 # relative-to-end seeking is implemented as absolutes seeks with negative time
912 self.seekAbsolute(diff)
914 def seekAbsolute(self, abs):
915 seekable = self.getSeek()
916 if seekable is not None:
919 from Screens.PVRState import PVRState, TimeshiftState
921 class InfoBarPVRState:
922 def __init__(self, screen=PVRState):
923 self.onPlayStateChanged.append(self.__playStateChanged)
924 self.pvrStateDialog = self.session.instantiateDialog(screen)
925 self.onShow.append(self._mayShow)
926 self.onHide.append(self.pvrStateDialog.hide)
929 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
930 self.pvrStateDialog.show()
932 def __playStateChanged(self, state):
933 playstateString = state[3]
934 self.pvrStateDialog["state"].setText(playstateString)
937 class InfoBarTimeshiftState(InfoBarPVRState):
939 InfoBarPVRState.__init__(self, screen=TimeshiftState)
942 if self.execing and self.timeshift_enabled:
943 self.pvrStateDialog.show()
945 class InfoBarShowMovies:
947 # i don't really like this class.
948 # it calls a not further specified "movie list" on up/down/movieList,
949 # so this is not more than an action map
951 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
953 "movieList": (self.showMovies, _("movie list")),
954 "up": (self.showMovies, _("movie list")),
955 "down": (self.showMovies, _("movie list"))
958 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
962 # Timeshift works the following way:
963 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
964 # - normal playback TUNER unused PLAY enable disable disable
965 # - user presses "yellow" button. FILE record PAUSE enable disable enable
966 # - user presess pause again FILE record PLAY enable disable enable
967 # - user fast forwards FILE record FF enable disable enable
968 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
969 # - user backwards FILE record BACK # !! enable disable enable
973 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
974 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
975 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
976 # - the user can now PVR around
977 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
978 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
980 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
981 # - if the user rewinds, or press pause, timeshift will be activated again
983 # note that a timeshift can be enabled ("recording") and
984 # activated (currently time-shifting).
986 class InfoBarTimeshift:
988 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
990 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
991 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
993 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
995 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
996 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
997 }, prio=-1) # priority over record
999 self.timeshift_enabled = 0
1000 self.timeshift_state = 0
1001 self.ts_rewind_timer = eTimer()
1002 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1004 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1006 iPlayableService.evStart: self.__serviceStarted,
1007 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1010 def getTimeshift(self):
1011 service = self.session.nav.getCurrentService()
1012 return service and service.timeshift()
1014 def startTimeshift(self):
1015 print "enable timeshift"
1016 ts = self.getTimeshift()
1018 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1019 print "no ts interface"
1022 if self.timeshift_enabled:
1023 print "hu, timeshift already enabled?"
1025 if not ts.startTimeshift():
1026 self.timeshift_enabled = 1
1028 # we remove the "relative time" for now.
1029 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1032 #self.setSeekState(self.SEEK_STATE_PAUSE)
1033 self.activateTimeshiftEnd(False)
1035 # enable the "TimeshiftEnableActions", which will override
1036 # the startTimeshift actions
1037 self.__seekableStatusChanged()
1039 print "timeshift failed"
1041 def stopTimeshift(self):
1042 if not self.timeshift_enabled:
1044 print "disable timeshift"
1045 ts = self.getTimeshift()
1048 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1050 def stopTimeshiftConfirmed(self, confirmed):
1054 ts = self.getTimeshift()
1059 self.timeshift_enabled = 0
1062 self.__seekableStatusChanged()
1064 # activates timeshift, and seeks to (almost) the end
1065 def activateTimeshiftEnd(self, back = True):
1066 ts = self.getTimeshift()
1067 print "activateTimeshiftEnd"
1072 if ts.isTimeshiftActive():
1073 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1077 ts.activateTimeshift() # activate timeshift will automatically pause
1078 self.setSeekState(self.SEEK_STATE_PAUSE)
1079 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1082 self.ts_rewind_timer.start(200, 1)
1084 def rewindService(self):
1085 self.setSeekState(self.SEEK_STATE_BACK_16X)
1087 # same as activateTimeshiftEnd, but pauses afterwards.
1088 def activateTimeshiftEndAndPause(self):
1089 print "activateTimeshiftEndAndPause"
1090 #state = self.seekstate
1091 self.activateTimeshiftEnd(False)
1093 def __seekableStatusChanged(self):
1096 print "self.isSeekable", self.isSeekable()
1097 print "self.timeshift_enabled", self.timeshift_enabled
1099 # when this service is not seekable, but timeshift
1100 # is enabled, this means we can activate
1102 if not self.isSeekable() and self.timeshift_enabled:
1105 print "timeshift activate:", enabled
1106 self["TimeshiftActivateActions"].setEnabled(enabled)
1108 def __serviceStarted(self):
1109 self.timeshift_enabled = False
1110 self.__seekableStatusChanged()
1112 from Screens.PiPSetup import PiPSetup
1114 class InfoBarExtensions:
1115 EXTENSION_SINGLE = 0
1121 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1123 "extensions": (self.showExtensionSelection, _("view extensions...")),
1126 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1127 self.list.append((type, extension, key))
1129 def updateExtension(self, extension, key = None):
1130 self.extensionsList.append(extension)
1132 if self.extensionKeys.has_key(key):
1136 for x in self.availableKeys:
1137 if not self.extensionKeys.has_key(x):
1142 self.extensionKeys[key] = len(self.extensionsList) - 1
1144 def updateExtensions(self):
1145 self.extensionsList = []
1146 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1147 self.extensionKeys = {}
1149 if x[0] == self.EXTENSION_SINGLE:
1150 self.updateExtension(x[1], x[2])
1153 self.updateExtension(y[0], y[1])
1156 def showExtensionSelection(self):
1157 self.updateExtensions()
1158 extensionsList = self.extensionsList[:]
1161 for x in self.availableKeys:
1162 if self.extensionKeys.has_key(x):
1163 entry = self.extensionKeys[x]
1164 extension = self.extensionsList[entry]
1166 name = str(extension[0]())
1167 list.append((extension[0](), extension))
1169 extensionsList.remove(extension)
1171 extensionsList.remove(extension)
1172 for x in extensionsList:
1173 list.append((x[0](), x))
1174 keys += [""] * len(extensionsList)
1175 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1177 def extensionCallback(self, answer):
1178 if answer is not None:
1181 from Tools.BoundFunction import boundFunction
1183 # depends on InfoBarExtensions
1184 from Components.PluginComponent import plugins
1186 class InfoBarPlugins:
1188 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1190 def getPluginName(self, name):
1193 def getPluginList(self):
1195 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1196 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1199 def runPlugin(self, plugin):
1200 plugin(session = self.session)
1202 # depends on InfoBarExtensions
1203 class InfoBarSleepTimer:
1205 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1207 def available(self):
1210 def getSleepTimerName(self):
1211 return _("Sleep Timer")
1213 def showSleepTimerSetup(self):
1214 self.session.open(SleepTimerEdit)
1216 # depends on InfoBarExtensions
1219 self.session.pipshown = False
1221 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1222 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1223 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1225 def available(self):
1229 return self.session.pipshown
1231 def getShowHideName(self):
1232 if self.session.pipshown:
1233 return _("Disable Picture in Picture")
1235 return _("Activate Picture in Picture")
1237 def getSwapName(self):
1238 return _("Swap Services")
1240 def getMoveName(self):
1241 return _("Move Picture in Picture")
1244 if self.session.pipshown:
1245 del self.session.pip
1246 self.session.pipshown = False
1248 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1249 self.session.pip.show()
1250 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1251 if self.session.pip.playService(newservice):
1252 self.session.pipshown = True
1253 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1255 self.session.pipshown = False
1256 del self.session.pip
1257 self.session.nav.playService(newservice)
1260 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1261 if self.session.pip.servicePath:
1262 servicepath = self.servicelist.getCurrentServicePath()
1263 ref=servicepath[len(servicepath)-1]
1264 pipref=self.session.pip.getCurrentService()
1265 self.session.pip.playService(swapservice)
1266 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1267 if pipref.toString() != ref.toString(): # is a subservice ?
1268 self.session.nav.stopService() # stop portal
1269 self.session.nav.playService(pipref) # start subservice
1270 self.session.pip.servicePath=servicepath
1273 self.session.open(PiPSetup, pip = self.session.pip)
1275 from RecordTimer import parseEvent
1277 class InfoBarInstantRecord:
1278 """Instant Record - handles the instantRecord action in order to
1279 start/stop instant records"""
1281 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1283 "instantRecord": (self.instantRecord, _("Instant Record...")),
1286 self["BlinkingPoint"] = BlinkingPixmapConditional()
1287 self["BlinkingPoint"].hide()
1288 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1290 def stopCurrentRecording(self, entry = -1):
1291 if entry is not None and entry != -1:
1292 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1293 self.recording.remove(self.recording[entry])
1295 def startInstantRecording(self, limitEvent = False):
1296 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1298 # try to get event info
1301 service = self.session.nav.getCurrentService()
1302 epg = eEPGCache.getInstance()
1303 event = epg.lookupEventTime(serviceref, -1, 0)
1305 info = service.info()
1306 ev = info.getEvent(0)
1312 end = time() + 3600 * 10
1313 name = "instant record"
1317 if event is not None:
1318 curEvent = parseEvent(event)
1320 description = curEvent[3]
1321 eventid = curEvent[4]
1326 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1328 data = (begin, end, name, description, eventid)
1330 recording = self.session.nav.recordWithTimer(serviceref, *data)
1331 recording.dontSave = True
1332 self.recording.append(recording)
1334 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1336 def isInstantRecordRunning(self):
1337 print "self.recording:", self.recording
1338 if len(self.recording) > 0:
1339 for x in self.recording:
1344 def recordQuestionCallback(self, answer):
1345 print "pre:\n", self.recording
1347 if answer is None or answer[1] == "no":
1350 recording = self.recording[:]
1352 if not x in self.session.nav.RecordTimer.timer_list:
1353 self.recording.remove(x)
1354 elif x.dontSave and x.isRunning():
1355 list.append(TimerEntryComponent(x, False))
1357 if answer[1] == "changeduration":
1358 if len(self.recording) == 1:
1359 self.changeDuration(0)
1361 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1362 elif answer[1] == "changeendtime":
1363 if len(self.recording) == 1:
1366 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1367 elif answer[1] == "stop":
1368 if len(self.recording) == 1:
1369 self.stopCurrentRecording(0)
1371 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1372 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1373 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1374 if answer[1] == "manualduration":
1375 self.changeDuration(len(self.recording)-1)
1376 elif answer[1] == "manualendtime":
1377 self.setEndtime(len(self.recording)-1)
1378 print "after:\n", self.recording
1380 def setEndtime(self, entry):
1381 if entry is not None:
1382 self.selectedEntry = entry
1383 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1384 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1385 dlg.setTitle(_("Please change recording endtime"))
1387 def TimeDateInputClosed(self, ret):
1390 localendtime = localtime(ret[1])
1391 print "stopping recording at", strftime("%c", localendtime)
1392 self.recording[self.selectedEntry].end = ret[1]
1393 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1395 def changeDuration(self, entry):
1396 if entry is not None:
1397 self.selectedEntry = entry
1398 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1400 def inputCallback(self, value):
1401 if value is not None:
1402 print "stopping recording after", int(value), "minutes."
1403 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1404 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1406 def instantRecord(self):
1408 stat = os_stat(resolveFilename(SCOPE_HDD))
1410 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1413 if self.isInstantRecordRunning():
1414 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1415 title=_("A recording is currently running.\nWhat do you want to do?"), \
1416 list=[(_("stop recording"), "stop"), \
1417 (_("change recording (duration)"), "changeduration"), \
1418 (_("change recording (endtime)"), "changeendtime"), \
1419 (_("add recording (indefinitely)"), "indefinitely"), \
1420 (_("add recording (stop after current event)"), "event"), \
1421 (_("add recording (enter recording duration)"), "manualduration"), \
1422 (_("add recording (enter recording endtime)"), "manualendtime"), \
1423 (_("do nothing"), "no")])
1425 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1426 title=_("Start recording?"), \
1427 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1428 (_("add recording (stop after current event)"), "event"), \
1429 (_("add recording (enter recording duration)"), "manualduration"), \
1430 (_("add recording (enter recording endtime)"), "manualendtime"), \
1431 (_("don't record"), "no")])
1433 from Tools.ISO639 import LanguageCodes
1435 class InfoBarAudioSelection:
1437 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1439 "audioSelection": (self.audioSelection, _("Audio Options...")),
1442 def audioSelection(self):
1443 service = self.session.nav.getCurrentService()
1444 audio = service and service.audioTracks()
1445 self.audioTracks = audio
1446 n = audio and audio.getNumberOfTracks() or 0
1447 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1449 print "tlist:", tlist
1451 self.audioChannel = service.audioChannel()
1454 i = audio.getTrackInfo(x)
1455 language = i.getLanguage()
1456 description = i.getDescription()
1458 if LanguageCodes.has_key(language):
1459 language = LanguageCodes[language][0]
1461 if len(description):
1462 description += " (" + language + ")"
1464 description = language
1466 tlist.append((description, x))
1468 selectedAudio = tlist[0][1]
1469 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1473 if x[1] != selectedAudio:
1478 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1479 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1481 del self.audioTracks
1483 def audioSelected(self, audio):
1484 if audio is not None:
1485 if isinstance(audio[1], str):
1486 if audio[1] == "mode":
1487 keys = ["red", "green", "yellow"]
1488 selection = self.audioChannel.getCurrentChannel()
1489 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1490 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1492 del self.audioChannel
1493 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1494 self.audioTracks.selectTrack(audio[1])
1496 del self.audioChannel
1497 del self.audioTracks
1499 def modeSelected(self, mode):
1500 if mode is not None:
1501 self.audioChannel.selectChannel(mode[1])
1502 del self.audioChannel
1504 class InfoBarSubserviceSelection:
1506 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1508 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1511 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1513 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1514 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1516 self["SubserviceQuickzapAction"].setEnabled(False)
1518 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1522 def checkSubservicesAvail(self, ev):
1523 if ev == iPlayableService.evUpdatedEventInfo:
1524 service = self.session.nav.getCurrentService()
1525 subservices = service and service.subServices()
1526 if not subservices or subservices.getNumberOfSubservices() == 0:
1527 self["SubserviceQuickzapAction"].setEnabled(False)
1529 def nextSubservice(self):
1530 self.changeSubservice(+1)
1532 def prevSubservice(self):
1533 self.changeSubservice(-1)
1535 def changeSubservice(self, direction):
1536 service = self.session.nav.getCurrentService()
1537 subservices = service and service.subServices()
1538 n = subservices and subservices.getNumberOfSubservices()
1541 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1543 if subservices.getSubservice(x).toString() == ref.toString():
1546 selection += direction
1551 newservice = subservices.getSubservice(selection)
1552 if newservice.valid():
1555 self.session.nav.playService(newservice)
1557 def subserviceSelection(self):
1558 service = self.session.nav.getCurrentService()
1559 subservices = service and service.subServices()
1560 self.bouquets = self.servicelist.getBouquetList()
1561 n = subservices and subservices.getNumberOfSubservices()
1564 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1567 i = subservices.getSubservice(x)
1568 if i.toString() == ref.toString():
1570 tlist.append((i.getName(), i))
1572 if self.bouquets and len(self.bouquets):
1573 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1574 if config.usage.multibouquet.value:
1575 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1577 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1580 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1581 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1584 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1586 def subserviceSelected(self, service):
1588 if not service is None:
1589 if isinstance(service[1], str):
1590 if service[1] == "quickzap":
1591 from Screens.SubservicesQuickzap import SubservicesQuickzap
1592 self.session.open(SubservicesQuickzap, service[2])
1594 self["SubserviceQuickzapAction"].setEnabled(True)
1595 self.session.nav.playService(service[1])
1597 def addSubserviceToBouquetCallback(self, service):
1598 if len(service) > 1 and isinstance(service[1], eServiceReference):
1599 self.selectedSubservice = service
1600 if self.bouquets is None:
1603 cnt = len(self.bouquets)
1604 if cnt > 1: # show bouquet list
1605 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1606 elif cnt == 1: # add to only one existing bouquet
1607 self.addSubserviceToBouquet(self.bouquets[0][1])
1608 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1610 def bouquetSelClosed(self, confirmed):
1612 del self.selectedSubservice
1614 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1616 def addSubserviceToBouquet(self, dest):
1617 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1619 self.bsel.close(True)
1621 del self.selectedSubservice
1623 class InfoBarAdditionalInfo:
1625 self["NimA"] = Pixmap()
1626 self["NimB"] = Pixmap()
1627 self["NimA_Active"] = Pixmap()
1628 self["NimB_Active"] = Pixmap()
1630 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1631 self["TimeshiftPossible"] = self["RecordingPossible"]
1632 self["ExtensionsAvailable"] = Boolean(fixed=1)
1634 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1635 res_mgr = eDVBResourceManager.getInstance()
1637 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1639 def tunerUseMaskChanged(self, mask):
1641 self["NimA_Active"].show()
1643 self["NimA_Active"].hide()
1645 self["NimB_Active"].show()
1647 self["NimB_Active"].hide()
1649 def checkTunerState(self, service):
1650 info = service and service.frontendInfo()
1651 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1652 if feNumber is None:
1662 def gotServiceEvent(self, ev):
1663 service = self.session.nav.getCurrentService()
1664 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1665 self.checkTunerState(service)
1667 class InfoBarNotifications:
1669 self.onExecBegin.append(self.checkNotifications)
1670 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1671 self.onClose.append(self.__removeNotification)
1673 def __removeNotification(self):
1674 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1676 def checkNotificationsIfExecing(self):
1678 self.checkNotifications()
1680 def checkNotifications(self):
1681 if len(Notifications.notifications):
1682 n = Notifications.notifications[0]
1684 Notifications.notifications = Notifications.notifications[1:]
1687 if n[3].has_key("onSessionOpenCallback"):
1688 n[3]["onSessionOpenCallback"]()
1689 del n[3]["onSessionOpenCallback"]
1692 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1694 dlg = self.session.open(n[1], *n[2], **n[3])
1696 # remember that this notification is currently active
1698 Notifications.current_notifications.append(d)
1699 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1701 def __notificationClosed(self, d):
1702 Notifications.current_notifications.remove(d)
1704 class InfoBarServiceNotifications:
1706 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1708 iPlayableService.evEnd: self.serviceHasEnded
1711 def serviceHasEnded(self):
1712 print "service end!"
1715 self.setSeekState(self.SEEK_STATE_PLAY)
1719 class InfoBarCueSheetSupport:
1725 ENABLE_RESUME_SUPPORT = False
1727 def __init__(self, actionmap = "InfobarCueSheetActions"):
1728 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1730 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1731 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1732 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1736 self.is_closing = False
1737 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1739 iPlayableService.evStart: self.__serviceStarted,
1742 def __serviceStarted(self):
1745 print "new service started! trying to download cuts!"
1746 self.downloadCuesheet()
1748 if self.ENABLE_RESUME_SUPPORT:
1751 for (pts, what) in self.cut_list:
1752 if what == self.CUT_TYPE_LAST:
1755 if last is not None:
1756 self.resume_point = last
1757 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1759 def playLastCB(self, answer):
1761 seekable = self.__getSeekable()
1762 if seekable is not None:
1763 seekable.seekTo(self.resume_point)
1764 self.hideAfterResume()
1766 def hideAfterResume(self):
1767 if isinstance(self, InfoBarShowHide):
1770 def __getSeekable(self):
1771 service = self.session.nav.getCurrentService()
1774 return service.seek()
1776 def cueGetCurrentPosition(self):
1777 seek = self.__getSeekable()
1780 r = seek.getPlayPosition()
1785 def jumpPreviousNextMark(self, cmp, alternative=None):
1786 current_pos = self.cueGetCurrentPosition()
1787 if current_pos is None:
1789 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1790 if mark is not None:
1792 elif alternative is not None:
1797 seekable = self.__getSeekable()
1798 if seekable is not None:
1799 seekable.seekTo(pts)
1801 def jumpPreviousMark(self):
1802 # we add 2 seconds, so if the play position is <2s after
1803 # the mark, the mark before will be used
1804 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1806 def jumpNextMark(self):
1807 self.jumpPreviousNextMark(lambda x: x)
1809 def getNearestCutPoint(self, pts, cmp=abs):
1812 for cp in self.cut_list:
1813 diff = cmp(cp[0] - pts)
1814 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1818 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1819 current_pos = self.cueGetCurrentPosition()
1820 if current_pos is None:
1821 print "not seekable"
1824 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1826 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1828 return nearest_cutpoint
1830 self.removeMark(nearest_cutpoint)
1831 elif not onlyremove and not onlyreturn:
1832 self.addMark((current_pos, self.CUT_TYPE_MARK))
1837 def addMark(self, point):
1838 insort(self.cut_list, point)
1839 self.uploadCuesheet()
1840 self.showAfterCuesheetOperation()
1842 def removeMark(self, point):
1843 self.cut_list.remove(point)
1844 self.uploadCuesheet()
1845 self.showAfterCuesheetOperation()
1847 def showAfterCuesheetOperation(self):
1848 if isinstance(self, InfoBarShowHide):
1851 def __getCuesheet(self):
1852 service = self.session.nav.getCurrentService()
1855 return service.cueSheet()
1857 def uploadCuesheet(self):
1858 cue = self.__getCuesheet()
1861 print "upload failed, no cuesheet interface"
1863 cue.setCutList(self.cut_list)
1865 def downloadCuesheet(self):
1866 cue = self.__getCuesheet()
1869 print "download failed, no cuesheet interface"
1872 self.cut_list = cue.getCutList()
1874 class InfoBarSummary(Screen):
1876 <screen position="0,0" size="132,64">
1877 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1878 <convert type="ClockToText">WithSeconds</convert>
1880 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1881 <convert type="ServiceName">Name</convert>
1885 def __init__(self, session, parent):
1886 Screen.__init__(self, session)
1887 self["CurrentService"] = CurrentService(self.session.nav)
1888 self["CurrentTime"] = Clock()
1890 class InfoBarSummarySupport:
1894 def createSummary(self):
1895 return InfoBarSummary
1897 class InfoBarTeletextPlugin:
1899 self.teletext_plugin = None
1901 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1902 self.teletext_plugin = p
1904 if self.teletext_plugin is not None:
1905 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1907 "startTeletext": (self.startTeletext, _("View teletext..."))
1910 print "no teletext plugin found!"
1912 def startTeletext(self):
1913 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1915 class InfoBarSubtitleSupport(object):
1917 object.__init__(self)
1918 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1919 self.__subtitles_enabled = False
1921 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1923 iPlayableService.evEnd: self.__serviceStopped,
1924 iPlayableService.evUpdatedInfo: self.__updatedInfo
1926 self.cached_subtitle_checked = False
1927 self.__selected_subtitle = None
1929 def __serviceStopped(self):
1930 self.subtitle_window.hide()
1931 self.__subtitles_enabled = False
1932 self.cached_subtitle_checked = False
1934 def __updatedInfo(self):
1935 if not self.cached_subtitle_checked:
1936 subtitle = self.getCurrentServiceSubtitle()
1937 self.cached_subtitle_checked = True
1938 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1939 if self.__selected_subtitle:
1940 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1941 self.subtitle_window.show()
1942 self.__subtitles_enabled = True
1944 def getCurrentServiceSubtitle(self):
1945 service = self.session.nav.getCurrentService()
1946 return service and service.subtitle()
1948 def setSubtitlesEnable(self, enable=True):
1949 subtitle = self.getCurrentServiceSubtitle()
1950 if enable and self.__selected_subtitle is not None:
1951 if subtitle and not self.__subtitles_enabled:
1952 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1953 self.subtitle_window.show()
1954 self.__subtitles_enabled = True
1957 subtitle.disableSubtitles(self.subtitle_window.instance)
1958 self.__subtitles_enabled = False
1959 self.subtitle_window.hide()
1961 def setSelectedSubtitle(self, subtitle):
1962 self.__selected_subtitle = subtitle
1964 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1965 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1967 class InfoBarServiceErrorPopupSupport:
1969 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1971 iPlayableService.evTuneFailed: self.__tuneFailed,
1972 iPlayableService.evStart: self.__serviceStarted
1974 self.__serviceStarted()
1976 def __serviceStarted(self):
1977 self.last_error = None
1978 Notifications.RemovePopup(id = "ZapError")
1980 def __tuneFailed(self):
1981 service = self.session.nav.getCurrentService()
1982 info = service and service.info()
1983 error = info and info.getInfo(iServiceInformation.sDVBState)
1985 if error == self.last_error:
1988 self.last_error = error
1991 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1992 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1993 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1994 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1995 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1996 eDVBServicePMTHandler.eventNewProgramInfo: None,
1997 eDVBServicePMTHandler.eventTuned: None,
1998 eDVBServicePMTHandler.eventSOF: None,
1999 eDVBServicePMTHandler.eventEOF: None
2002 error = errors.get(error) #this returns None when the key not exist in the dict
2004 if error is not None:
2005 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2007 Notifications.RemovePopup(id = "ZapError")