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
21 from EpgSelection import EPGSelection
22 from Plugins.Plugin import PluginDescriptor
24 from Screen import Screen
25 from Screens.ChoiceBox import ChoiceBox
26 from Screens.Dish import Dish
27 from Screens.EventView import EventViewEPGSelect, EventViewSimple
28 from Screens.InputBox import InputBox
29 from Screens.MessageBox import MessageBox
30 from Screens.MinuteInput import MinuteInput
31 from Screens.TimerSelection import TimerSelection
32 from Screens.PictureInPicture import PictureInPicture
33 from Screens.SubtitleDisplay import SubtitleDisplay
34 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
35 from Screens.SleepTimerEdit import SleepTimerEdit
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
45 from os import stat as os_stat
46 from bisect import insort
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
69 }, 1) # lower prio to make it possible to override ok and cancel..
71 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
73 iPlayableService.evStart: self.__serviceStarted,
74 iPlayableService.evUpdatedEventInfo: self.__eventInfoChanged
77 self.__state = self.STATE_SHOWN
80 self.hideTimer = eTimer()
81 self.hideTimer.timeout.get().append(self.doTimerHide)
82 self.hideTimer.start(5000, True)
84 self.onShow.append(self.__onShow)
85 self.onHide.append(self.__onHide)
87 def __eventInfoChanged(self):
88 old_begin_time = self.current_begin_time
89 service = self.session.nav.getCurrentService()
90 info = service and service.info()
91 ptr = info and info.getEvent(0)
93 self.current_begin_time = ptr.getBeginTime()
94 if config.usage.show_infobar_on_event_change.value:
95 if old_begin_time and old_begin_time != self.current_begin_time:
98 def __serviceStarted(self):
99 self.current_begin_time=0
100 if config.usage.show_infobar_on_zap.value:
104 self.__state = self.STATE_SHOWN
105 self.startHideTimer()
107 def startHideTimer(self):
108 if self.__state == self.STATE_SHOWN and not self.__locked:
109 idx = config.usage.infobar_timeout.index
111 self.hideTimer.start(idx*1000, True)
114 self.__state = self.STATE_HIDDEN
118 self.startHideTimer()
120 def doTimerHide(self):
121 self.hideTimer.stop()
122 if self.__state == self.STATE_SHOWN:
125 def toggleShow(self):
126 if self.__state == self.STATE_SHOWN:
128 self.hideTimer.stop()
129 elif self.__state == self.STATE_HIDDEN:
133 self.__locked = self.__locked + 1
136 self.hideTimer.stop()
138 def unlockShow(self):
139 self.__locked = self.__locked - 1
141 self.startHideTimer()
143 # def startShow(self):
144 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
145 # self.__state = self.STATE_SHOWN
147 # def startHide(self):
148 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
149 # self.__state = self.STATE_HIDDEN
151 class NumberZap(Screen):
158 self.close(int(self["number"].getText()))
160 def keyNumberGlobal(self, number):
161 self.Timer.start(3000, True) #reset timer
162 self.field = self.field + str(number)
163 self["number"].setText(self.field)
164 if len(self.field) >= 4:
167 def __init__(self, session, number):
168 Screen.__init__(self, session)
169 self.field = str(number)
171 self["channel"] = Label(_("Channel:"))
173 self["number"] = Label(self.field)
175 self["actions"] = NumberActionMap( [ "SetupActions" ],
179 "1": self.keyNumberGlobal,
180 "2": self.keyNumberGlobal,
181 "3": self.keyNumberGlobal,
182 "4": self.keyNumberGlobal,
183 "5": self.keyNumberGlobal,
184 "6": self.keyNumberGlobal,
185 "7": self.keyNumberGlobal,
186 "8": self.keyNumberGlobal,
187 "9": self.keyNumberGlobal,
188 "0": self.keyNumberGlobal
191 self.Timer = eTimer()
192 self.Timer.timeout.get().append(self.keyOK)
193 self.Timer.start(3000, True)
195 class InfoBarNumberZap:
196 """ Handles an initial number for NumberZapping """
198 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
200 "1": self.keyNumberGlobal,
201 "2": self.keyNumberGlobal,
202 "3": self.keyNumberGlobal,
203 "4": self.keyNumberGlobal,
204 "5": self.keyNumberGlobal,
205 "6": self.keyNumberGlobal,
206 "7": self.keyNumberGlobal,
207 "8": self.keyNumberGlobal,
208 "9": self.keyNumberGlobal,
209 "0": self.keyNumberGlobal,
212 def keyNumberGlobal(self, number):
213 # print "You pressed number " + str(number)
215 self.servicelist.recallPrevService()
217 self.session.openWithCallback(self.numberEntered, NumberZap, number)
219 def numberEntered(self, retval):
220 # print self.servicelist
222 self.zapToNumber(retval)
224 def searchNumberHelper(self, serviceHandler, num, bouquet):
225 servicelist = serviceHandler.list(bouquet)
226 if not servicelist is None:
228 serviceIterator = servicelist.getNext()
229 if not serviceIterator.valid(): #check end of list
231 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
234 if not num: #found service with searched number ?
235 return serviceIterator, 0
238 def zapToNumber(self, number):
239 bouquet = self.servicelist.bouquet_root
241 serviceHandler = eServiceCenter.getInstance()
242 if not config.usage.multibouquet.value:
243 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
245 bouquetlist = serviceHandler.list(bouquet)
246 if not bouquetlist is None:
248 bouquet = bouquetlist.getNext()
249 if not bouquet.valid(): #check end of list
251 if bouquet.flags & eServiceReference.isDirectory:
252 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
253 if not service is None:
254 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
255 self.servicelist.clearPath()
256 if self.servicelist.bouquet_root != bouquet:
257 self.servicelist.enterPath(self.servicelist.bouquet_root)
258 self.servicelist.enterPath(bouquet)
259 self.servicelist.setCurrentSelection(service) #select the service in servicelist
260 self.servicelist.zap()
262 config.misc.initialchannelselection = ConfigBoolean(default = True)
264 class InfoBarChannelSelection:
265 """ ChannelSelection - handles the channelSelection dialog and the initial
266 channelChange actions which open the channelSelection dialog """
269 self.servicelist = self.session.instantiateDialog(ChannelSelection)
271 if config.misc.initialchannelselection.value:
272 self.onShown.append(self.firstRun)
274 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
276 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
277 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
278 "zapUp": (self.zapUp, _("previous channel")),
279 "zapDown": (self.zapDown, _("next channel")),
280 "historyBack": (self.historyBack, _("previous channel in history")),
281 "historyNext": (self.historyNext, _("next channel in history")),
282 "openServiceList": (self.openServiceList, _("open servicelist")),
285 def showTvChannelList(self, zap=False):
286 self.servicelist.setModeTv()
288 self.servicelist.zap()
289 self.session.execDialog(self.servicelist)
291 def showRadioChannelList(self, zap=False):
292 self.servicelist.setModeRadio()
294 self.servicelist.zap()
295 self.session.execDialog(self.servicelist)
298 self.onShown.remove(self.firstRun)
299 config.misc.initialchannelselection.value = False
300 config.misc.initialchannelselection.save()
301 self.switchChannelDown()
303 def historyBack(self):
304 self.servicelist.historyBack()
306 def historyNext(self):
307 self.servicelist.historyNext()
309 def switchChannelUp(self):
310 self.servicelist.moveUp()
311 self.session.execDialog(self.servicelist)
313 def switchChannelDown(self):
314 self.servicelist.moveDown()
315 self.session.execDialog(self.servicelist)
317 def openServiceList(self):
318 self.session.execDialog(self.servicelist)
321 if self.servicelist.inBouquet():
322 prev = self.servicelist.getCurrentSelection()
324 prev = prev.toString()
326 if config.usage.quickzap_bouquet_change.value:
327 if self.servicelist.atBegin():
328 self.servicelist.prevBouquet()
329 self.servicelist.moveUp()
330 cur = self.servicelist.getCurrentSelection()
331 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
334 self.servicelist.moveUp()
335 self.servicelist.zap()
338 if self.servicelist.inBouquet():
339 prev = self.servicelist.getCurrentSelection()
341 prev = prev.toString()
343 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
344 self.servicelist.nextBouquet()
346 self.servicelist.moveDown()
347 cur = self.servicelist.getCurrentSelection()
348 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
351 self.servicelist.moveDown()
352 self.servicelist.zap()
355 """ Handles a menu action, to open the (main) menu """
357 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
359 "mainMenu": (self.mainMenu, _("Enter main menu...")),
361 self.session.infobar = None
364 print "loading mainmenu XML..."
365 menu = mdom.childNodes[0]
366 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
368 self.session.infobar = self
369 # so we can access the currently active infobar from screens opened from within the mainmenu
370 # at the moment used from the SubserviceSelection
372 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
374 def mainMenuClosed(self, *val):
375 self.session.infobar = None
377 class InfoBarSimpleEventView:
378 """ Opens the Eventview for now/next """
380 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
382 "showEventInfo": (self.openEventView, _("show event details")),
385 def openEventView(self):
387 service = self.session.nav.getCurrentService()
388 ref = self.session.nav.getCurrentlyPlayingServiceReference()
389 info = service.info()
392 self.epglist.append(ptr)
395 self.epglist.append(ptr)
396 if len(self.epglist) > 0:
397 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
399 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
400 if len(self.epglist) > 1:
401 tmp = self.epglist[0]
402 self.epglist[0]=self.epglist[1]
404 setEvent(self.epglist[0])
407 """ EPG - Opens an EPG list when the showEPGList action fires """
409 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
411 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
414 self.is_now_next = False
416 self.bouquetSel = None
417 self.eventView = None
418 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
420 "showEventInfo": (self.openEventView, _("show EPG...")),
423 def zapToService(self, service):
424 if not service is None:
425 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
426 self.servicelist.clearPath()
427 if self.servicelist.bouquet_root != self.epg_bouquet:
428 self.servicelist.enterPath(self.servicelist.bouquet_root)
429 self.servicelist.enterPath(self.epg_bouquet)
430 self.servicelist.setCurrentSelection(service) #select the service in servicelist
431 self.servicelist.zap()
433 def getBouquetServices(self, bouquet):
435 servicelist = eServiceCenter.getInstance().list(bouquet)
436 if not servicelist is None:
438 service = servicelist.getNext()
439 if not service.valid(): #check if end of list
441 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
443 services.append(ServiceReference(service))
446 def openBouquetEPG(self, bouquet, withCallback=True):
447 services = self.getBouquetServices(bouquet)
449 self.epg_bouquet = bouquet
451 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
453 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
455 def changeBouquetCB(self, direction, epg):
458 self.bouquetSel.down()
461 bouquet = self.bouquetSel.getCurrent()
462 services = self.getBouquetServices(bouquet)
464 self.epg_bouquet = bouquet
465 epg.setServices(services)
467 def closed(self, ret=False):
468 closedScreen = self.dlg_stack.pop()
469 if self.bouquetSel and closedScreen == self.bouquetSel:
470 self.bouquetSel = None
471 elif self.eventView and closedScreen == self.eventView:
472 self.eventView = None
474 dlgs=len(self.dlg_stack)
476 self.dlg_stack[dlgs-1].close(dlgs > 1)
478 def openMultiServiceEPG(self, withCallback=True):
479 bouquets = self.servicelist.getBouquetList()
484 if cnt > 1: # show bouquet list
486 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
487 self.dlg_stack.append(self.bouquetSel)
489 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
491 self.openBouquetEPG(bouquets[0][1], withCallback)
493 def openSingleServiceEPG(self):
494 ref=self.session.nav.getCurrentlyPlayingServiceReference()
495 self.session.open(EPGSelection, ref)
497 def openSimilarList(self, eventid, refstr):
498 self.session.open(EPGSelection, refstr, None, eventid)
500 def getNowNext(self):
502 service = self.session.nav.getCurrentService()
503 info = service and service.info()
504 ptr = info and info.getEvent(0)
506 self.epglist.append(ptr)
507 ptr = info and info.getEvent(1)
509 self.epglist.append(ptr)
511 def __evEventInfoChanged(self):
512 if self.is_now_next and len(self.dlg_stack) == 1:
514 assert self.eventView
515 if len(self.epglist):
516 self.eventView.setEvent(self.epglist[0])
518 def openEventView(self):
519 ref = self.session.nav.getCurrentlyPlayingServiceReference()
521 if len(self.epglist) == 0:
522 self.is_now_next = False
523 epg = eEPGCache.getInstance()
524 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
526 self.epglist.append(ptr)
527 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
529 self.epglist.append(ptr)
531 self.is_now_next = True
532 if len(self.epglist) > 0:
533 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
534 self.dlg_stack.append(self.eventView)
536 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
537 self.openMultiServiceEPG(False)
539 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
540 if len(self.epglist) > 1:
541 tmp = self.epglist[0]
542 self.epglist[0]=self.epglist[1]
544 setEvent(self.epglist[0])
547 """provides a snr/agc/ber display"""
549 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
552 """provides a current/next event info display"""
554 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
555 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
557 class InfoBarRdsDecoder:
558 """provides RDS and Rass support/display"""
560 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
561 self.rass_interactive = None
563 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
565 iPlayableService.evEnd: self.__serviceStopped,
566 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
569 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
571 "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
574 self["RdsActions"].setEnabled(False)
576 self.onLayoutFinish.append(self.rds_display.show)
577 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
579 def RassInteractivePossibilityChanged(self, state):
580 self["RdsActions"].setEnabled(state)
582 def RassSlidePicChanged(self):
583 if not self.rass_interactive:
584 service = self.session.nav.getCurrentService()
585 decoder = service and service.rdsDecoder()
587 decoder.showRassSlidePicture()
589 def __serviceStopped(self):
590 if self.rass_interactive is not None:
591 rass_interactive = self.rass_interactive
592 self.rass_interactive = None
593 rass_interactive.close()
595 def startRassInteractive(self):
596 self.rds_display.hide()
597 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
599 def RassInteractiveClosed(self, *val):
600 if self.rass_interactive is not None:
601 self.rass_interactive = None
602 self.RassSlidePicChanged()
603 self.rds_display.show()
605 class InfoBarServiceName:
607 self["CurrentService"] = CurrentService(self.session.nav)
610 """handles actions like seeking, pause"""
612 # ispause, isff, issm
613 SEEK_STATE_PLAY = (0, 0, 0, ">")
614 SEEK_STATE_PAUSE = (1, 0, 0, "||")
615 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
616 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
617 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
618 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
619 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
620 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
622 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
623 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
624 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
625 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
627 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
628 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
629 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
632 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
634 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
635 iPlayableService.evStart: self.__serviceStarted,
637 iPlayableService.evEOF: self.__evEOF,
638 iPlayableService.evSOF: self.__evSOF,
641 class InfoBarSeekActionMap(HelpableActionMap):
642 def __init__(self, screen, *args, **kwargs):
643 HelpableActionMap.__init__(self, screen, *args, **kwargs)
646 def action(self, contexts, action):
647 if action[:5] == "seek:":
648 time = int(action[5:])
649 self.screen.seekRelative(time * 90000)
652 return HelpableActionMap.action(self, contexts, action)
654 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
656 "playpauseService": (self.playpauseService, _("pause")),
657 "pauseService": (self.pauseService, _("pause")),
658 "unPauseService": (self.unPauseService, _("continue")),
660 "seekFwd": (self.seekFwd, _("skip forward")),
661 "seekFwdDown": self.seekFwdDown,
662 "seekFwdUp": self.seekFwdUp,
663 "seekBack": (self.seekBack, _("skip backward")),
664 "seekBackDown": self.seekBackDown,
665 "seekBackUp": self.seekBackUp,
667 # give them a little more priority to win over color buttons
669 self["SeekActions"].setEnabled(False)
671 self.seekstate = self.SEEK_STATE_PLAY
672 self.onClose.append(self.delTimer)
674 self.fwdtimer = False
675 self.fwdKeyTimer = eTimer()
676 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
678 self.rwdtimer = False
679 self.rwdKeyTimer = eTimer()
680 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
682 self.onPlayStateChanged = [ ]
684 self.lockedBecauseOfSkipping = False
697 service = self.session.nav.getCurrentService()
701 seek = service.seek()
703 if seek is None or not seek.isCurrentlySeekable():
708 def isSeekable(self):
709 if self.getSeek() is None:
713 def __seekableStatusChanged(self):
714 print "seekable status changed!"
715 if not self.isSeekable():
716 self["SeekActions"].setEnabled(False)
717 print "not seekable, return to play"
718 self.setSeekState(self.SEEK_STATE_PLAY)
720 self["SeekActions"].setEnabled(True)
723 def __serviceStarted(self):
724 self.seekstate = self.SEEK_STATE_PLAY
726 def setSeekState(self, state):
727 service = self.session.nav.getCurrentService()
732 if not self.isSeekable():
733 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
734 state = self.SEEK_STATE_PLAY
736 pauseable = service.pause()
738 if pauseable is None:
739 print "not pauseable."
740 state = self.SEEK_STATE_PLAY
742 oldstate = self.seekstate
743 self.seekstate = state
746 if oldstate[i] != self.seekstate[i]:
747 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
749 for c in self.onPlayStateChanged:
752 self.checkSkipShowHideLock()
756 def playpauseService(self):
757 if self.seekstate != self.SEEK_STATE_PLAY:
758 self.unPauseService()
762 def pauseService(self):
763 if self.seekstate == self.SEEK_STATE_PAUSE:
764 print "pause, but in fact unpause"
765 self.unPauseService()
767 if self.seekstate == self.SEEK_STATE_PLAY:
768 print "yes, playing."
770 print "no", self.seekstate
772 self.setSeekState(self.SEEK_STATE_PAUSE);
774 def unPauseService(self):
776 if self.seekstate == self.SEEK_STATE_PLAY:
778 self.setSeekState(self.SEEK_STATE_PLAY)
780 def doSeek(self, seektime):
781 print "doseek", seektime
782 service = self.session.nav.getCurrentService()
786 seekable = self.getSeek()
790 seekable.seekTo(90 * seektime)
792 def seekFwdDown(self):
793 print "start fwd timer"
795 self.fwdKeyTimer.start(1000)
797 def seekBackDown(self):
798 print "start rewind timer"
800 self.rwdKeyTimer.start(1000)
805 self.fwdKeyTimer.stop()
806 self.fwdtimer = False
811 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
812 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
813 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
814 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
815 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
816 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
817 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
818 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
819 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
820 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
821 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
822 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
823 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
824 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
825 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
827 self.setSeekState(lookup[self.seekstate])
829 def seekBackUp(self):
832 self.rwdKeyTimer.stop()
833 self.rwdtimer = False
838 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
839 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
840 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
841 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
842 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
843 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
844 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
845 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
846 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
847 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
848 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
849 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
850 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
851 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
852 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
854 self.setSeekState(lookup[self.seekstate])
856 if self.seekstate == self.SEEK_STATE_PAUSE:
857 seekable = self.getSeek()
858 if seekable is not None:
859 seekable.seekRelative(-1, 3)
861 def fwdTimerFire(self):
862 print "Display seek fwd"
863 self.fwdKeyTimer.stop()
864 self.fwdtimer = False
865 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
867 def fwdSeekTo(self, minutes):
868 print "Seek", minutes, "minutes forward"
870 seekable = self.getSeek()
871 if seekable is not None:
872 seekable.seekRelative(1, minutes * 60 * 90000)
874 def rwdTimerFire(self):
876 self.rwdKeyTimer.stop()
877 self.rwdtimer = False
878 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
880 def rwdSeekTo(self, minutes):
882 self.fwdSeekTo(0 - minutes)
884 def checkSkipShowHideLock(self):
885 wantlock = self.seekstate != self.SEEK_STATE_PLAY
887 if config.usage.show_infobar_on_zap.value:
888 if self.lockedBecauseOfSkipping and not wantlock:
890 self.lockedBecauseOfSkipping = False
892 if wantlock and not self.lockedBecauseOfSkipping:
894 self.lockedBecauseOfSkipping = True
897 if self.seekstate != self.SEEK_STATE_PLAY:
898 self.setSeekState(self.SEEK_STATE_PAUSE)
900 #self.getSeek().seekRelative(1, -90000)
901 self.setSeekState(self.SEEK_STATE_PLAY)
903 self.setSeekState(self.SEEK_STATE_PAUSE)
906 self.setSeekState(self.SEEK_STATE_PLAY)
909 def seekRelative(self, diff):
910 seekable = self.getSeek()
911 if seekable is not None:
912 seekable.seekRelative(1, 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. TUNER 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 "pause key"
996 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
997 }, prio=-1) # priority over record
999 self.timeshift_enabled = 0
1000 self.timeshift_state = 0
1001 self.ts_pause_timer = eTimer()
1002 self.ts_pause_timer.timeout.get().append(self.pauseService)
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)
1034 # enable the "TimeshiftEnableActions", which will override
1035 # the startTimeshift actions
1036 self.__seekableStatusChanged()
1038 print "timeshift failed"
1040 def stopTimeshift(self):
1041 if not self.timeshift_enabled:
1043 print "disable timeshift"
1044 ts = self.getTimeshift()
1047 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1049 def stopTimeshiftConfirmed(self, confirmed):
1053 ts = self.getTimeshift()
1058 self.timeshift_enabled = 0
1061 self.__seekableStatusChanged()
1063 # activates timeshift, and seeks to (almost) the end
1064 def activateTimeshiftEnd(self):
1065 ts = self.getTimeshift()
1070 if ts.isTimeshiftActive():
1071 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1074 self.setSeekState(self.SEEK_STATE_PLAY)
1075 ts.activateTimeshift()
1076 self.seekRelative(0)
1078 # same as activateTimeshiftEnd, but pauses afterwards.
1079 def activateTimeshiftEndAndPause(self):
1080 state = self.seekstate
1081 self.activateTimeshiftEnd()
1083 # well, this is "andPause", but it could be pressed from pause,
1084 # when pausing on the (fake-)"live" picture, so an un-pause
1087 print "now, pauseService"
1088 if state == self.SEEK_STATE_PLAY:
1089 print "is PLAYING, start pause timer"
1090 self.ts_pause_timer.start(200, 1)
1093 self.unPauseService()
1095 def __seekableStatusChanged(self):
1098 print "self.isSeekable", self.isSeekable()
1099 print "self.timeshift_enabled", self.timeshift_enabled
1101 # when this service is not seekable, but timeshift
1102 # is enabled, this means we can activate
1104 if not self.isSeekable() and self.timeshift_enabled:
1107 print "timeshift activate:", enabled
1108 self["TimeshiftActivateActions"].setEnabled(enabled)
1110 def __serviceStarted(self):
1111 self.timeshift_enabled = False
1112 self.__seekableStatusChanged()
1114 from Screens.PiPSetup import PiPSetup
1116 class InfoBarExtensions:
1117 EXTENSION_SINGLE = 0
1123 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1125 "extensions": (self.showExtensionSelection, _("view extensions...")),
1128 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1129 self.list.append((type, extension, key))
1131 def updateExtension(self, extension, key = None):
1132 self.extensionsList.append(extension)
1134 if self.extensionKeys.has_key(key):
1138 for x in self.availableKeys:
1139 if not self.extensionKeys.has_key(x):
1144 self.extensionKeys[key] = len(self.extensionsList) - 1
1146 def updateExtensions(self):
1147 self.extensionsList = []
1148 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1149 self.extensionKeys = {}
1151 if x[0] == self.EXTENSION_SINGLE:
1152 self.updateExtension(x[1], x[2])
1155 self.updateExtension(y[0], y[1])
1158 def showExtensionSelection(self):
1159 self.updateExtensions()
1160 extensionsList = self.extensionsList[:]
1163 for x in self.availableKeys:
1164 if self.extensionKeys.has_key(x):
1165 entry = self.extensionKeys[x]
1166 extension = self.extensionsList[entry]
1168 name = str(extension[0]())
1169 list.append((extension[0](), extension))
1171 extensionsList.remove(extension)
1173 extensionsList.remove(extension)
1174 for x in extensionsList:
1175 list.append((x[0](), x))
1176 keys += [""] * len(extensionsList)
1177 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1179 def extensionCallback(self, answer):
1180 if answer is not None:
1183 from Tools.BoundFunction import boundFunction
1185 # depends on InfoBarExtensions
1186 from Components.PluginComponent import plugins
1188 class InfoBarPlugins:
1190 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1192 def getPluginName(self, name):
1195 def getPluginList(self):
1197 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1198 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1201 def runPlugin(self, plugin):
1202 plugin(session = self.session)
1204 # depends on InfoBarExtensions
1205 class InfoBarSleepTimer:
1207 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1209 def available(self):
1212 def getSleepTimerName(self):
1213 return _("Sleep Timer")
1215 def showSleepTimerSetup(self):
1216 self.session.open(SleepTimerEdit)
1218 # depends on InfoBarExtensions
1221 self.session.pipshown = False
1223 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1224 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1225 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1227 def available(self):
1231 return self.session.pipshown
1233 def getShowHideName(self):
1234 if self.session.pipshown:
1235 return _("Disable Picture in Picture")
1237 return _("Activate Picture in Picture")
1239 def getSwapName(self):
1240 return _("Swap Services")
1242 def getMoveName(self):
1243 return _("Move Picture in Picture")
1246 if self.session.pipshown:
1247 del self.session.pip
1248 self.session.pipshown = False
1250 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1251 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1252 if self.session.pip.playService(newservice):
1253 self.session.pipshown = True
1254 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1256 self.session.pipshown = False
1257 del self.session.pip
1258 self.session.nav.playService(newservice)
1261 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1262 if self.session.pip.servicePath:
1263 servicepath = self.servicelist.getCurrentServicePath()
1264 ref=servicepath[len(servicepath)-1]
1265 pipref=self.session.pip.getCurrentService()
1266 self.session.pip.playService(swapservice)
1267 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1268 if pipref.toString() != ref.toString(): # is a subservice ?
1269 self.session.nav.stopService() # stop portal
1270 self.session.nav.playService(pipref) # start subservice
1271 self.session.pip.servicePath=servicepath
1274 self.session.open(PiPSetup, pip = self.session.pip)
1276 from RecordTimer import parseEvent
1278 class InfoBarInstantRecord:
1279 """Instant Record - handles the instantRecord action in order to
1280 start/stop instant records"""
1282 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1284 "instantRecord": (self.instantRecord, _("Instant Record...")),
1287 self["BlinkingPoint"] = BlinkingPixmapConditional()
1288 self["BlinkingPoint"].hide()
1289 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1291 def stopCurrentRecording(self, entry = -1):
1292 if entry is not None and entry != -1:
1293 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1294 self.recording.remove(self.recording[entry])
1296 def startInstantRecording(self, limitEvent = False):
1297 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1299 # try to get event info
1302 service = self.session.nav.getCurrentService()
1303 epg = eEPGCache.getInstance()
1304 event = epg.lookupEventTime(serviceref, -1, 0)
1306 info = service.info()
1307 ev = info.getEvent(0)
1313 end = time() + 3600 * 10
1314 name = "instant record"
1318 if event is not None:
1319 curEvent = parseEvent(event)
1321 description = curEvent[3]
1322 eventid = curEvent[4]
1327 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1329 data = (begin, end, name, description, eventid)
1331 recording = self.session.nav.recordWithTimer(serviceref, *data)
1332 recording.dontSave = True
1333 self.recording.append(recording)
1335 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1337 def isInstantRecordRunning(self):
1338 print "self.recording:", self.recording
1339 if len(self.recording) > 0:
1340 for x in self.recording:
1345 def recordQuestionCallback(self, answer):
1346 print "pre:\n", self.recording
1348 if answer is None or answer[1] == "no":
1351 recording = self.recording[:]
1353 if not x in self.session.nav.RecordTimer.timer_list:
1354 self.recording.remove(x)
1355 elif x.dontSave and x.isRunning():
1356 list.append(TimerEntryComponent(x, False))
1358 if answer[1] == "changeduration":
1359 if len(self.recording) == 1:
1360 self.changeDuration(0)
1362 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1363 elif answer[1] == "stop":
1364 if len(self.recording) == 1:
1365 self.stopCurrentRecording(0)
1367 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1368 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1370 if answer[1] == "event":
1372 if answer[1] == "manualduration":
1373 self.selectedEntry = len(self.recording)
1374 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1375 self.startInstantRecording(limitEvent = limitEvent)
1377 print "after:\n", self.recording
1379 def changeDuration(self, entry):
1380 if entry is not None:
1381 self.selectedEntry = entry
1382 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1384 def inputCallback(self, value):
1385 if value is not None:
1386 print "stopping recording after", int(value), "minutes."
1387 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1388 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1390 def instantRecord(self):
1392 stat = os_stat(resolveFilename(SCOPE_HDD))
1394 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1397 if self.isInstantRecordRunning():
1398 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1399 title=_("A recording is currently running.\nWhat do you want to do?"), \
1400 list=[(_("stop recording"), "stop"), \
1401 (_("change recording (duration)"), "changeduration"), \
1402 (_("add recording (indefinitely)"), "indefinitely"), \
1403 (_("add recording (stop after current event)"), "event"), \
1404 (_("add recording (enter recording duration)"), "manualduration"), \
1405 (_("do nothing"), "no")])
1407 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1408 title=_("Start recording?"), \
1409 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1410 (_("add recording (stop after current event)"), "event"), \
1411 (_("add recording (enter recording duration)"), "manualduration"), \
1412 (_("don't record"), "no")])
1414 from Tools.ISO639 import LanguageCodes
1416 class InfoBarAudioSelection:
1418 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1420 "audioSelection": (self.audioSelection, _("Audio Options...")),
1423 def audioSelection(self):
1424 service = self.session.nav.getCurrentService()
1425 audio = service and service.audioTracks()
1426 self.audioTracks = audio
1427 n = audio and audio.getNumberOfTracks() or 0
1428 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1430 print "tlist:", tlist
1432 self.audioChannel = service.audioChannel()
1435 i = audio.getTrackInfo(x)
1436 language = i.getLanguage()
1437 description = i.getDescription()
1439 if LanguageCodes.has_key(language):
1440 language = LanguageCodes[language][0]
1442 if len(description):
1443 description += " (" + language + ")"
1445 description = language
1447 tlist.append((description, x))
1449 selectedAudio = tlist[0][1]
1450 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1454 if x[1] != selectedAudio:
1459 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1460 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1462 del self.audioTracks
1464 def audioSelected(self, audio):
1465 if audio is not None:
1466 if isinstance(audio[1], str):
1467 if audio[1] == "mode":
1468 keys = ["red", "green", "yellow"]
1469 selection = self.audioChannel.getCurrentChannel()
1470 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1471 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1473 del self.audioChannel
1474 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1475 self.audioTracks.selectTrack(audio[1])
1477 del self.audioChannel
1478 del self.audioTracks
1480 def modeSelected(self, mode):
1481 if mode is not None:
1482 self.audioChannel.selectChannel(mode[1])
1483 del self.audioChannel
1485 class InfoBarSubserviceSelection:
1487 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1489 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1492 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1494 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1495 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1497 self["SubserviceQuickzapAction"].setEnabled(False)
1499 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1503 def checkSubservicesAvail(self, ev):
1504 if ev == iPlayableService.evUpdatedEventInfo:
1505 service = self.session.nav.getCurrentService()
1506 subservices = service and service.subServices()
1507 if not subservices or subservices.getNumberOfSubservices() == 0:
1508 self["SubserviceQuickzapAction"].setEnabled(False)
1510 def nextSubservice(self):
1511 self.changeSubservice(+1)
1513 def prevSubservice(self):
1514 self.changeSubservice(-1)
1516 def changeSubservice(self, direction):
1517 service = self.session.nav.getCurrentService()
1518 subservices = service and service.subServices()
1519 n = subservices and subservices.getNumberOfSubservices()
1522 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1524 if subservices.getSubservice(x).toString() == ref.toString():
1527 selection += direction
1532 newservice = subservices.getSubservice(selection)
1533 if newservice.valid():
1536 self.session.nav.playService(newservice)
1538 def subserviceSelection(self):
1539 service = self.session.nav.getCurrentService()
1540 subservices = service and service.subServices()
1541 self.bouquets = self.servicelist.getBouquetList()
1542 n = subservices and subservices.getNumberOfSubservices()
1545 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1548 i = subservices.getSubservice(x)
1549 if i.toString() == ref.toString():
1551 tlist.append((i.getName(), i))
1553 if self.bouquets and len(self.bouquets):
1554 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1555 if config.usage.multibouquet.value:
1556 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1558 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1561 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1562 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1565 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1567 def subserviceSelected(self, service):
1569 if not service is None:
1570 if isinstance(service[1], str):
1571 if service[1] == "quickzap":
1572 from Screens.SubservicesQuickzap import SubservicesQuickzap
1573 self.session.open(SubservicesQuickzap, service[2])
1575 self["SubserviceQuickzapAction"].setEnabled(True)
1576 self.session.nav.playService(service[1])
1578 def addSubserviceToBouquetCallback(self, service):
1579 if len(service) > 1 and isinstance(service[1], eServiceReference):
1580 self.selectedSubservice = service
1581 if self.bouquets is None:
1584 cnt = len(self.bouquets)
1585 if cnt > 1: # show bouquet list
1586 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1587 elif cnt == 1: # add to only one existing bouquet
1588 self.addSubserviceToBouquet(self.bouquets[0][1])
1589 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1591 def bouquetSelClosed(self, confirmed):
1593 del self.selectedSubservice
1595 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1597 def addSubserviceToBouquet(self, dest):
1598 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1600 self.bsel.close(True)
1602 del self.selectedSubservice
1604 class InfoBarAdditionalInfo:
1606 self["NimA"] = Pixmap()
1607 self["NimB"] = Pixmap()
1608 self["NimA_Active"] = Pixmap()
1609 self["NimB_Active"] = Pixmap()
1611 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1612 self["TimeshiftPossible"] = self["RecordingPossible"]
1613 self["ExtensionsAvailable"] = Boolean(fixed=1)
1615 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1616 res_mgr = eDVBResourceManager.getInstance()
1618 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1620 def tunerUseMaskChanged(self, mask):
1622 self["NimA_Active"].show()
1624 self["NimA_Active"].hide()
1626 self["NimB_Active"].show()
1628 self["NimB_Active"].hide()
1630 def checkTunerState(self, service):
1631 info = service and service.frontendInfo()
1632 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1633 if feNumber is None:
1643 def gotServiceEvent(self, ev):
1644 service = self.session.nav.getCurrentService()
1645 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1646 self.checkTunerState(service)
1648 class InfoBarNotifications:
1650 self.onExecBegin.append(self.checkNotifications)
1651 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1652 self.onClose.append(self.__removeNotification)
1654 def __removeNotification(self):
1655 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1657 def checkNotificationsIfExecing(self):
1659 self.checkNotifications()
1661 def checkNotifications(self):
1662 if len(Notifications.notifications):
1663 n = Notifications.notifications[0]
1665 Notifications.notifications = Notifications.notifications[1:]
1668 if n[3].has_key("onSessionOpenCallback"):
1669 n[3]["onSessionOpenCallback"]()
1670 del n[3]["onSessionOpenCallback"]
1673 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1675 dlg = self.session.open(n[1], *n[2], **n[3])
1677 # remember that this notification is currently active
1679 Notifications.current_notifications.append(d)
1680 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1682 def __notificationClosed(self, d):
1683 Notifications.current_notifications.remove(d)
1685 class InfoBarServiceNotifications:
1687 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1689 iPlayableService.evEnd: self.serviceHasEnded
1692 def serviceHasEnded(self):
1693 print "service end!"
1696 self.setSeekState(self.SEEK_STATE_PLAY)
1700 class InfoBarCueSheetSupport:
1706 ENABLE_RESUME_SUPPORT = False
1709 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1711 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1712 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1713 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1717 self.is_closing = False
1718 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1720 iPlayableService.evStart: self.__serviceStarted,
1723 def __serviceStarted(self):
1726 print "new service started! trying to download cuts!"
1727 self.downloadCuesheet()
1729 if self.ENABLE_RESUME_SUPPORT:
1732 for (pts, what) in self.cut_list:
1733 if what == self.CUT_TYPE_LAST:
1736 if last is not None:
1737 self.resume_point = last
1738 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1740 def playLastCB(self, answer):
1742 seekable = self.__getSeekable()
1743 if seekable is not None:
1744 seekable.seekTo(self.resume_point)
1746 def __getSeekable(self):
1747 service = self.session.nav.getCurrentService()
1750 return service.seek()
1752 def cueGetCurrentPosition(self):
1753 seek = self.__getSeekable()
1756 r = seek.getPlayPosition()
1761 def jumpPreviousNextMark(self, cmp, alternative=None):
1762 current_pos = self.cueGetCurrentPosition()
1763 if current_pos is None:
1765 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1766 if mark is not None:
1768 elif alternative is not None:
1773 seekable = self.__getSeekable()
1774 if seekable is not None:
1775 seekable.seekTo(pts)
1777 def jumpPreviousMark(self):
1778 # we add 2 seconds, so if the play position is <2s after
1779 # the mark, the mark before will be used
1780 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1782 def jumpNextMark(self):
1783 self.jumpPreviousNextMark(lambda x: x)
1785 def getNearestCutPoint(self, pts, cmp=abs):
1788 for cp in self.cut_list:
1789 diff = cmp(cp[0] - pts)
1790 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1794 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1795 current_pos = self.cueGetCurrentPosition()
1796 if current_pos is None:
1797 print "not seekable"
1800 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1802 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1804 return nearest_cutpoint
1806 self.removeMark(nearest_cutpoint)
1807 elif not onlyremove and not onlyreturn:
1808 self.addMark((current_pos, self.CUT_TYPE_MARK))
1813 def addMark(self, point):
1814 insort(self.cut_list, point)
1815 self.uploadCuesheet()
1817 def removeMark(self, point):
1818 self.cut_list.remove(point)
1819 self.uploadCuesheet()
1821 def __getCuesheet(self):
1822 service = self.session.nav.getCurrentService()
1825 return service.cueSheet()
1827 def uploadCuesheet(self):
1828 cue = self.__getCuesheet()
1831 print "upload failed, no cuesheet interface"
1833 cue.setCutList(self.cut_list)
1835 def downloadCuesheet(self):
1836 cue = self.__getCuesheet()
1839 print "upload failed, no cuesheet interface"
1841 self.cut_list = cue.getCutList()
1843 class InfoBarSummary(Screen):
1845 <screen position="0,0" size="132,64">
1846 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1847 <convert type="ClockToText">WithSeconds</convert>
1849 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1850 <convert type="ServiceName">Name</convert>
1854 def __init__(self, session, parent):
1855 Screen.__init__(self, session)
1856 self["CurrentService"] = CurrentService(self.session.nav)
1857 self["CurrentTime"] = Clock()
1859 class InfoBarSummarySupport:
1863 def createSummary(self):
1864 return InfoBarSummary
1866 class InfoBarTeletextPlugin:
1868 self.teletext_plugin = None
1870 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1871 self.teletext_plugin = p
1873 if self.teletext_plugin is not None:
1874 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1876 "startTeletext": (self.startTeletext, _("View teletext..."))
1879 print "no teletext plugin found!"
1881 def startTeletext(self):
1882 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1884 class InfoBarSubtitleSupport(object):
1886 object.__init__(self)
1887 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1888 self.__subtitles_enabled = False
1890 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1892 iPlayableService.evEnd: self.__serviceStopped,
1893 iPlayableService.evUpdatedInfo: self.__updatedInfo
1895 self.cached_subtitle_checked = False
1897 def __serviceStopped(self):
1898 self.subtitle_window.hide()
1899 self.__subtitles_enabled = False
1900 self.cached_subtitle_checked = False
1902 def __updatedInfo(self):
1903 if not self.cached_subtitle_checked:
1904 subtitle = self.getCurrentServiceSubtitle()
1905 self.cached_subtitle_checked = True
1907 self.__selected_subtitle = subtitle.getCachedSubtitle()
1908 if self.__selected_subtitle:
1909 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1910 self.subtitle_window.show()
1911 self.__subtitles_enabled = True
1913 def getCurrentServiceSubtitle(self):
1914 service = self.session.nav.getCurrentService()
1915 return service and service.subtitle()
1917 def setSubtitlesEnable(self, enable=True):
1918 subtitle = self.getCurrentServiceSubtitle()
1919 if enable and self.__selected_subtitle is not None:
1920 if subtitle and not self.__subtitles_enabled:
1921 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1922 self.subtitle_window.show()
1923 self.__subtitles_enabled = True
1926 subtitle.disableSubtitles(self.subtitle_window.instance)
1927 self.__subtitles_enabled = False
1928 self.subtitle_window.hide()
1930 def setSelectedSubtitle(self, subtitle):
1931 self.__selected_subtitle = subtitle
1933 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1934 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1936 class InfoBarServiceErrorPopupSupport:
1938 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1940 iPlayableService.evTuneFailed: self.__tuneFailed,
1941 iPlayableService.evStart: self.__serviceStarted
1943 self.__serviceStarted()
1945 def __serviceStarted(self):
1946 self.last_error = None
1947 Notifications.RemovePopup(id = "ZapError")
1949 def __tuneFailed(self):
1950 service = self.session.nav.getCurrentService()
1951 info = service and service.info()
1952 error = info and info.getInfo(iServiceInformation.sDVBState)
1954 if error == self.last_error:
1957 self.last_error = error
1960 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1961 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1962 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1963 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1964 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1965 eDVBServicePMTHandler.eventNewProgramInfo: None,
1966 eDVBServicePMTHandler.eventTuned: None,
1967 eDVBServicePMTHandler.eventSOF: None,
1968 eDVBServicePMTHandler.eventEOF: None
1971 error = errors.get(error) #this returns None when the key not exist in the dict
1973 if error is not None:
1974 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1976 Notifications.RemovePopup(id = "ZapError")