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)
86 self.current_begin_time=0
88 def __eventInfoChanged(self):
90 service = self.session.nav.getCurrentService()
91 old_begin_time = self.current_begin_time
92 info = service and service.info()
93 ptr = info and info.getEvent(0)
94 self.current_begin_time = ptr and ptr.getBeginTime() or 0
95 if config.usage.show_infobar_on_event_change.value:
96 if old_begin_time and old_begin_time != self.current_begin_time:
99 def __serviceStarted(self):
101 self.current_begin_time=0
102 if config.usage.show_infobar_on_zap.value:
106 self.__state = self.STATE_SHOWN
107 self.startHideTimer()
109 def startHideTimer(self):
110 if self.__state == self.STATE_SHOWN and not self.__locked:
111 idx = config.usage.infobar_timeout.index
113 self.hideTimer.start(idx*1000, True)
116 self.__state = self.STATE_HIDDEN
120 self.startHideTimer()
122 def doTimerHide(self):
123 self.hideTimer.stop()
124 if self.__state == self.STATE_SHOWN:
127 def toggleShow(self):
128 if self.__state == self.STATE_SHOWN:
130 self.hideTimer.stop()
131 elif self.__state == self.STATE_HIDDEN:
135 self.__locked = self.__locked + 1
138 self.hideTimer.stop()
140 def unlockShow(self):
141 self.__locked = self.__locked - 1
143 self.startHideTimer()
145 # def startShow(self):
146 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
147 # self.__state = self.STATE_SHOWN
149 # def startHide(self):
150 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
151 # self.__state = self.STATE_HIDDEN
153 class NumberZap(Screen):
160 self.close(int(self["number"].getText()))
162 def keyNumberGlobal(self, number):
163 self.Timer.start(3000, True) #reset timer
164 self.field = self.field + str(number)
165 self["number"].setText(self.field)
166 if len(self.field) >= 4:
169 def __init__(self, session, number):
170 Screen.__init__(self, session)
171 self.field = str(number)
173 self["channel"] = Label(_("Channel:"))
175 self["number"] = Label(self.field)
177 self["actions"] = NumberActionMap( [ "SetupActions" ],
181 "1": self.keyNumberGlobal,
182 "2": self.keyNumberGlobal,
183 "3": self.keyNumberGlobal,
184 "4": self.keyNumberGlobal,
185 "5": self.keyNumberGlobal,
186 "6": self.keyNumberGlobal,
187 "7": self.keyNumberGlobal,
188 "8": self.keyNumberGlobal,
189 "9": self.keyNumberGlobal,
190 "0": self.keyNumberGlobal
193 self.Timer = eTimer()
194 self.Timer.timeout.get().append(self.keyOK)
195 self.Timer.start(3000, True)
197 class InfoBarNumberZap:
198 """ Handles an initial number for NumberZapping """
200 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
202 "1": self.keyNumberGlobal,
203 "2": self.keyNumberGlobal,
204 "3": self.keyNumberGlobal,
205 "4": self.keyNumberGlobal,
206 "5": self.keyNumberGlobal,
207 "6": self.keyNumberGlobal,
208 "7": self.keyNumberGlobal,
209 "8": self.keyNumberGlobal,
210 "9": self.keyNumberGlobal,
211 "0": self.keyNumberGlobal,
214 def keyNumberGlobal(self, number):
215 # print "You pressed number " + str(number)
217 self.servicelist.recallPrevService()
219 self.session.openWithCallback(self.numberEntered, NumberZap, number)
221 def numberEntered(self, retval):
222 # print self.servicelist
224 self.zapToNumber(retval)
226 def searchNumberHelper(self, serviceHandler, num, bouquet):
227 servicelist = serviceHandler.list(bouquet)
228 if not servicelist is None:
230 serviceIterator = servicelist.getNext()
231 if not serviceIterator.valid(): #check end of list
233 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
236 if not num: #found service with searched number ?
237 return serviceIterator, 0
240 def zapToNumber(self, number):
241 bouquet = self.servicelist.bouquet_root
243 serviceHandler = eServiceCenter.getInstance()
244 if not config.usage.multibouquet.value:
245 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
247 bouquetlist = serviceHandler.list(bouquet)
248 if not bouquetlist is None:
250 bouquet = bouquetlist.getNext()
251 if not bouquet.valid(): #check end of list
253 if bouquet.flags & eServiceReference.isDirectory:
254 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
255 if not service is None:
256 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
257 self.servicelist.clearPath()
258 if self.servicelist.bouquet_root != bouquet:
259 self.servicelist.enterPath(self.servicelist.bouquet_root)
260 self.servicelist.enterPath(bouquet)
261 self.servicelist.setCurrentSelection(service) #select the service in servicelist
262 self.servicelist.zap()
264 config.misc.initialchannelselection = ConfigBoolean(default = True)
266 class InfoBarChannelSelection:
267 """ ChannelSelection - handles the channelSelection dialog and the initial
268 channelChange actions which open the channelSelection dialog """
271 self.servicelist = self.session.instantiateDialog(ChannelSelection)
273 if config.misc.initialchannelselection.value:
274 self.onShown.append(self.firstRun)
276 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
278 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
279 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
280 "zapUp": (self.zapUp, _("previous channel")),
281 "zapDown": (self.zapDown, _("next channel")),
282 "historyBack": (self.historyBack, _("previous channel in history")),
283 "historyNext": (self.historyNext, _("next channel in history")),
284 "openServiceList": (self.openServiceList, _("open servicelist")),
287 def showTvChannelList(self, zap=False):
288 self.servicelist.setModeTv()
290 self.servicelist.zap()
291 self.session.execDialog(self.servicelist)
293 def showRadioChannelList(self, zap=False):
294 self.servicelist.setModeRadio()
296 self.servicelist.zap()
297 self.session.execDialog(self.servicelist)
300 self.onShown.remove(self.firstRun)
301 config.misc.initialchannelselection.value = False
302 config.misc.initialchannelselection.save()
303 self.switchChannelDown()
305 def historyBack(self):
306 self.servicelist.historyBack()
308 def historyNext(self):
309 self.servicelist.historyNext()
311 def switchChannelUp(self):
312 self.servicelist.moveUp()
313 self.session.execDialog(self.servicelist)
315 def switchChannelDown(self):
316 self.servicelist.moveDown()
317 self.session.execDialog(self.servicelist)
319 def openServiceList(self):
320 self.session.execDialog(self.servicelist)
323 if self.servicelist.inBouquet():
324 prev = self.servicelist.getCurrentSelection()
326 prev = prev.toString()
328 if config.usage.quickzap_bouquet_change.value:
329 if self.servicelist.atBegin():
330 self.servicelist.prevBouquet()
331 self.servicelist.moveUp()
332 cur = self.servicelist.getCurrentSelection()
333 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
336 self.servicelist.moveUp()
337 self.servicelist.zap()
340 if self.servicelist.inBouquet():
341 prev = self.servicelist.getCurrentSelection()
343 prev = prev.toString()
345 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
346 self.servicelist.nextBouquet()
348 self.servicelist.moveDown()
349 cur = self.servicelist.getCurrentSelection()
350 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
353 self.servicelist.moveDown()
354 self.servicelist.zap()
357 """ Handles a menu action, to open the (main) menu """
359 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
361 "mainMenu": (self.mainMenu, _("Enter main menu...")),
363 self.session.infobar = None
366 print "loading mainmenu XML..."
367 menu = mdom.childNodes[0]
368 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
370 self.session.infobar = self
371 # so we can access the currently active infobar from screens opened from within the mainmenu
372 # at the moment used from the SubserviceSelection
374 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
376 def mainMenuClosed(self, *val):
377 self.session.infobar = None
379 class InfoBarSimpleEventView:
380 """ Opens the Eventview for now/next """
382 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
384 "showEventInfo": (self.openEventView, _("show event details")),
387 def openEventView(self):
389 service = self.session.nav.getCurrentService()
390 ref = self.session.nav.getCurrentlyPlayingServiceReference()
391 info = service.info()
394 self.epglist.append(ptr)
397 self.epglist.append(ptr)
398 if len(self.epglist) > 0:
399 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
401 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
402 if len(self.epglist) > 1:
403 tmp = self.epglist[0]
404 self.epglist[0]=self.epglist[1]
406 setEvent(self.epglist[0])
409 """ EPG - Opens an EPG list when the showEPGList action fires """
411 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
413 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
416 self.is_now_next = False
418 self.bouquetSel = None
419 self.eventView = None
420 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
422 "showEventInfo": (self.openEventView, _("show EPG...")),
425 def zapToService(self, service):
426 if not service is None:
427 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
428 self.servicelist.clearPath()
429 if self.servicelist.bouquet_root != self.epg_bouquet:
430 self.servicelist.enterPath(self.servicelist.bouquet_root)
431 self.servicelist.enterPath(self.epg_bouquet)
432 self.servicelist.setCurrentSelection(service) #select the service in servicelist
433 self.servicelist.zap()
435 def getBouquetServices(self, bouquet):
437 servicelist = eServiceCenter.getInstance().list(bouquet)
438 if not servicelist is None:
440 service = servicelist.getNext()
441 if not service.valid(): #check if end of list
443 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
445 services.append(ServiceReference(service))
448 def openBouquetEPG(self, bouquet, withCallback=True):
449 services = self.getBouquetServices(bouquet)
451 self.epg_bouquet = bouquet
453 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
455 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
457 def changeBouquetCB(self, direction, epg):
460 self.bouquetSel.down()
463 bouquet = self.bouquetSel.getCurrent()
464 services = self.getBouquetServices(bouquet)
466 self.epg_bouquet = bouquet
467 epg.setServices(services)
469 def closed(self, ret=False):
470 closedScreen = self.dlg_stack.pop()
471 if self.bouquetSel and closedScreen == self.bouquetSel:
472 self.bouquetSel = None
473 elif self.eventView and closedScreen == self.eventView:
474 self.eventView = None
476 dlgs=len(self.dlg_stack)
478 self.dlg_stack[dlgs-1].close(dlgs > 1)
480 def openMultiServiceEPG(self, withCallback=True):
481 bouquets = self.servicelist.getBouquetList()
486 if cnt > 1: # show bouquet list
488 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
489 self.dlg_stack.append(self.bouquetSel)
491 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
493 self.openBouquetEPG(bouquets[0][1], withCallback)
495 def openSingleServiceEPG(self):
496 ref=self.session.nav.getCurrentlyPlayingServiceReference()
497 self.session.open(EPGSelection, ref)
499 def openSimilarList(self, eventid, refstr):
500 self.session.open(EPGSelection, refstr, None, eventid)
502 def getNowNext(self):
504 service = self.session.nav.getCurrentService()
505 info = service and service.info()
506 ptr = info and info.getEvent(0)
508 self.epglist.append(ptr)
509 ptr = info and info.getEvent(1)
511 self.epglist.append(ptr)
513 def __evEventInfoChanged(self):
514 if self.is_now_next and len(self.dlg_stack) == 1:
516 assert self.eventView
517 if len(self.epglist):
518 self.eventView.setEvent(self.epglist[0])
520 def openEventView(self):
521 ref = self.session.nav.getCurrentlyPlayingServiceReference()
523 if len(self.epglist) == 0:
524 self.is_now_next = False
525 epg = eEPGCache.getInstance()
526 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
528 self.epglist.append(ptr)
529 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
531 self.epglist.append(ptr)
533 self.is_now_next = True
534 if len(self.epglist) > 0:
535 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
536 self.dlg_stack.append(self.eventView)
538 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
539 self.openMultiServiceEPG(False)
541 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
542 if len(self.epglist) > 1:
543 tmp = self.epglist[0]
544 self.epglist[0]=self.epglist[1]
546 setEvent(self.epglist[0])
549 """provides a snr/agc/ber display"""
551 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
554 """provides a current/next event info display"""
556 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
557 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
559 class InfoBarRdsDecoder:
560 """provides RDS and Rass support/display"""
562 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
563 self.rass_interactive = None
565 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
567 iPlayableService.evEnd: self.__serviceStopped,
568 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
571 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
573 "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
576 self["RdsActions"].setEnabled(False)
578 self.onLayoutFinish.append(self.rds_display.show)
579 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
581 def RassInteractivePossibilityChanged(self, state):
582 self["RdsActions"].setEnabled(state)
584 def RassSlidePicChanged(self):
585 if not self.rass_interactive:
586 service = self.session.nav.getCurrentService()
587 decoder = service and service.rdsDecoder()
589 decoder.showRassSlidePicture()
591 def __serviceStopped(self):
592 if self.rass_interactive is not None:
593 rass_interactive = self.rass_interactive
594 self.rass_interactive = None
595 rass_interactive.close()
597 def startRassInteractive(self):
598 self.rds_display.hide()
599 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
601 def RassInteractiveClosed(self, *val):
602 if self.rass_interactive is not None:
603 self.rass_interactive = None
604 self.RassSlidePicChanged()
605 self.rds_display.show()
607 class InfoBarServiceName:
609 self["CurrentService"] = CurrentService(self.session.nav)
612 """handles actions like seeking, pause"""
614 # ispause, isff, issm
615 SEEK_STATE_PLAY = (0, 0, 0, ">")
616 SEEK_STATE_PAUSE = (1, 0, 0, "||")
617 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
618 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
619 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
620 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
621 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
622 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
624 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
625 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
626 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
627 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
629 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
630 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
631 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
634 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
636 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
637 iPlayableService.evStart: self.__serviceStarted,
639 iPlayableService.evEOF: self.__evEOF,
640 iPlayableService.evSOF: self.__evSOF,
643 class InfoBarSeekActionMap(HelpableActionMap):
644 def __init__(self, screen, *args, **kwargs):
645 HelpableActionMap.__init__(self, screen, *args, **kwargs)
648 def action(self, contexts, action):
649 if action[:5] == "seek:":
650 time = int(action[5:])
651 self.screen.seekRelative(time * 90000)
654 return HelpableActionMap.action(self, contexts, action)
656 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
658 "playpauseService": (self.playpauseService, _("pause")),
659 "pauseService": (self.pauseService, _("pause")),
660 "unPauseService": (self.unPauseService, _("continue")),
662 "seekFwd": (self.seekFwd, _("skip forward")),
663 "seekFwdDown": self.seekFwdDown,
664 "seekFwdUp": self.seekFwdUp,
665 "seekBack": (self.seekBack, _("skip backward")),
666 "seekBackDown": self.seekBackDown,
667 "seekBackUp": self.seekBackUp,
669 # give them a little more priority to win over color buttons
671 self["SeekActions"].setEnabled(False)
673 self.seekstate = self.SEEK_STATE_PLAY
674 self.onClose.append(self.delTimer)
676 self.fwdtimer = False
677 self.fwdKeyTimer = eTimer()
678 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
680 self.rwdtimer = False
681 self.rwdKeyTimer = eTimer()
682 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
684 self.onPlayStateChanged = [ ]
686 self.lockedBecauseOfSkipping = False
699 service = self.session.nav.getCurrentService()
703 seek = service.seek()
705 if seek is None or not seek.isCurrentlySeekable():
710 def isSeekable(self):
711 if self.getSeek() is None:
715 def __seekableStatusChanged(self):
716 print "seekable status changed!"
717 if not self.isSeekable():
718 self["SeekActions"].setEnabled(False)
719 print "not seekable, return to play"
720 self.setSeekState(self.SEEK_STATE_PLAY)
722 self["SeekActions"].setEnabled(True)
725 def __serviceStarted(self):
726 self.seekstate = self.SEEK_STATE_PLAY
728 def setSeekState(self, state):
729 service = self.session.nav.getCurrentService()
734 if not self.isSeekable():
735 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
736 state = self.SEEK_STATE_PLAY
738 pauseable = service.pause()
740 if pauseable is None:
741 print "not pauseable."
742 state = self.SEEK_STATE_PLAY
744 oldstate = self.seekstate
745 self.seekstate = state
748 if oldstate[i] != self.seekstate[i]:
749 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
751 for c in self.onPlayStateChanged:
754 self.checkSkipShowHideLock()
758 def playpauseService(self):
759 if self.seekstate != self.SEEK_STATE_PLAY:
760 self.unPauseService()
764 def pauseService(self):
765 if self.seekstate == self.SEEK_STATE_PAUSE:
766 print "pause, but in fact unpause"
767 self.unPauseService()
769 if self.seekstate == self.SEEK_STATE_PLAY:
770 print "yes, playing."
772 print "no", self.seekstate
774 self.setSeekState(self.SEEK_STATE_PAUSE);
776 def unPauseService(self):
778 if self.seekstate == self.SEEK_STATE_PLAY:
780 self.setSeekState(self.SEEK_STATE_PLAY)
782 def doSeek(self, seektime):
783 print "doseek", seektime
784 service = self.session.nav.getCurrentService()
788 seekable = self.getSeek()
792 seekable.seekTo(90 * seektime)
794 def seekFwdDown(self):
795 print "start fwd timer"
797 self.fwdKeyTimer.start(1000)
799 def seekBackDown(self):
800 print "start rewind timer"
802 self.rwdKeyTimer.start(1000)
807 self.fwdKeyTimer.stop()
808 self.fwdtimer = False
813 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
814 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
815 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
816 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
817 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
818 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
819 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
820 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
821 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
822 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
823 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
824 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
825 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
826 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
827 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
829 self.setSeekState(lookup[self.seekstate])
831 def seekBackUp(self):
834 self.rwdKeyTimer.stop()
835 self.rwdtimer = False
840 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
841 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
842 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
843 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
844 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
845 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
846 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
847 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
848 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
849 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
850 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
851 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
852 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
853 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
854 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
856 self.setSeekState(lookup[self.seekstate])
858 if self.seekstate == self.SEEK_STATE_PAUSE:
859 seekable = self.getSeek()
860 if seekable is not None:
861 seekable.seekRelative(-1, 3)
863 def fwdTimerFire(self):
864 print "Display seek fwd"
865 self.fwdKeyTimer.stop()
866 self.fwdtimer = False
867 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
869 def fwdSeekTo(self, minutes):
870 print "Seek", minutes, "minutes forward"
872 seekable = self.getSeek()
873 if seekable is not None:
874 seekable.seekRelative(1, minutes * 60 * 90000)
876 def rwdTimerFire(self):
878 self.rwdKeyTimer.stop()
879 self.rwdtimer = False
880 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
882 def rwdSeekTo(self, minutes):
884 self.fwdSeekTo(0 - minutes)
886 def checkSkipShowHideLock(self):
887 wantlock = self.seekstate != self.SEEK_STATE_PLAY
889 if config.usage.show_infobar_on_zap.value:
890 if self.lockedBecauseOfSkipping and not wantlock:
892 self.lockedBecauseOfSkipping = False
894 if wantlock and not self.lockedBecauseOfSkipping:
896 self.lockedBecauseOfSkipping = True
899 if self.seekstate != self.SEEK_STATE_PLAY:
900 self.setSeekState(self.SEEK_STATE_PAUSE)
902 #self.getSeek().seekRelative(1, -90000)
903 self.setSeekState(self.SEEK_STATE_PLAY)
905 self.setSeekState(self.SEEK_STATE_PAUSE)
908 self.setSeekState(self.SEEK_STATE_PLAY)
911 def seekRelative(self, diff):
912 seekable = self.getSeek()
913 if seekable is not None:
914 seekable.seekRelative(1, diff)
916 def seekAbsolute(self, abs):
917 seekable = self.getSeek()
918 if seekable is not None:
921 from Screens.PVRState import PVRState, TimeshiftState
923 class InfoBarPVRState:
924 def __init__(self, screen=PVRState):
925 self.onPlayStateChanged.append(self.__playStateChanged)
926 self.pvrStateDialog = self.session.instantiateDialog(screen)
927 self.onShow.append(self._mayShow)
928 self.onHide.append(self.pvrStateDialog.hide)
931 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
932 self.pvrStateDialog.show()
934 def __playStateChanged(self, state):
935 playstateString = state[3]
936 self.pvrStateDialog["state"].setText(playstateString)
939 class InfoBarTimeshiftState(InfoBarPVRState):
941 InfoBarPVRState.__init__(self, screen=TimeshiftState)
944 if self.execing and self.timeshift_enabled:
945 self.pvrStateDialog.show()
947 class InfoBarShowMovies:
949 # i don't really like this class.
950 # it calls a not further specified "movie list" on up/down/movieList,
951 # so this is not more than an action map
953 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
955 "movieList": (self.showMovies, "movie list"),
956 "up": (self.showMovies, "movie list"),
957 "down": (self.showMovies, "movie list")
960 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
964 # Timeshift works the following way:
965 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
966 # - normal playback TUNER unused PLAY enable disable disable
967 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
968 # - user presess pause again FILE record PLAY enable disable enable
969 # - user fast forwards FILE record FF enable disable enable
970 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
971 # - user backwards FILE record BACK # !! enable disable enable
975 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
976 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
977 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
978 # - the user can now PVR around
979 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
980 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
982 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
983 # - if the user rewinds, or press pause, timeshift will be activated again
985 # note that a timeshift can be enabled ("recording") and
986 # activated (currently time-shifting).
988 class InfoBarTimeshift:
990 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
992 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
993 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
995 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
997 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
998 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
999 }, prio=-1) # priority over record
1001 self.timeshift_enabled = 0
1002 self.timeshift_state = 0
1003 self.ts_pause_timer = eTimer()
1004 self.ts_pause_timer.timeout.get().append(self.pauseService)
1006 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1008 iPlayableService.evStart: self.__serviceStarted,
1009 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1012 def getTimeshift(self):
1013 service = self.session.nav.getCurrentService()
1014 return service and service.timeshift()
1016 def startTimeshift(self):
1017 print "enable timeshift"
1018 ts = self.getTimeshift()
1020 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1021 print "no ts interface"
1024 if self.timeshift_enabled:
1025 print "hu, timeshift already enabled?"
1027 if not ts.startTimeshift():
1028 self.timeshift_enabled = 1
1030 # we remove the "relative time" for now.
1031 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1034 self.setSeekState(self.SEEK_STATE_PAUSE)
1036 # enable the "TimeshiftEnableActions", which will override
1037 # the startTimeshift actions
1038 self.__seekableStatusChanged()
1040 print "timeshift failed"
1042 def stopTimeshift(self):
1043 if not self.timeshift_enabled:
1045 print "disable timeshift"
1046 ts = self.getTimeshift()
1049 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1051 def stopTimeshiftConfirmed(self, confirmed):
1055 ts = self.getTimeshift()
1060 self.timeshift_enabled = 0
1063 self.__seekableStatusChanged()
1065 # activates timeshift, and seeks to (almost) the end
1066 def activateTimeshiftEnd(self):
1067 ts = self.getTimeshift()
1072 if ts.isTimeshiftActive():
1073 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1076 self.setSeekState(self.SEEK_STATE_PLAY)
1077 ts.activateTimeshift()
1078 self.seekRelative(0)
1080 # same as activateTimeshiftEnd, but pauses afterwards.
1081 def activateTimeshiftEndAndPause(self):
1082 state = self.seekstate
1083 self.activateTimeshiftEnd()
1085 # well, this is "andPause", but it could be pressed from pause,
1086 # when pausing on the (fake-)"live" picture, so an un-pause
1089 print "now, pauseService"
1090 if state == self.SEEK_STATE_PLAY:
1091 print "is PLAYING, start pause timer"
1092 self.ts_pause_timer.start(200, 1)
1095 self.unPauseService()
1097 def __seekableStatusChanged(self):
1100 print "self.isSeekable", self.isSeekable()
1101 print "self.timeshift_enabled", self.timeshift_enabled
1103 # when this service is not seekable, but timeshift
1104 # is enabled, this means we can activate
1106 if not self.isSeekable() and self.timeshift_enabled:
1109 print "timeshift activate:", enabled
1110 self["TimeshiftActivateActions"].setEnabled(enabled)
1112 def __serviceStarted(self):
1113 self.timeshift_enabled = False
1114 self.__seekableStatusChanged()
1116 from Screens.PiPSetup import PiPSetup
1118 class InfoBarExtensions:
1119 EXTENSION_SINGLE = 0
1125 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1127 "extensions": (self.showExtensionSelection, _("view extensions...")),
1130 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1131 self.list.append((type, extension, key))
1133 def updateExtension(self, extension, key = None):
1134 self.extensionsList.append(extension)
1136 if self.extensionKeys.has_key(key):
1140 for x in self.availableKeys:
1141 if not self.extensionKeys.has_key(x):
1146 self.extensionKeys[key] = len(self.extensionsList) - 1
1148 def updateExtensions(self):
1149 self.extensionsList = []
1150 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1151 self.extensionKeys = {}
1153 if x[0] == self.EXTENSION_SINGLE:
1154 self.updateExtension(x[1], x[2])
1157 self.updateExtension(y[0], y[1])
1160 def showExtensionSelection(self):
1161 self.updateExtensions()
1162 extensionsList = self.extensionsList[:]
1165 for x in self.availableKeys:
1166 if self.extensionKeys.has_key(x):
1167 entry = self.extensionKeys[x]
1168 extension = self.extensionsList[entry]
1170 name = str(extension[0]())
1171 list.append((extension[0](), extension))
1173 extensionsList.remove(extension)
1175 extensionsList.remove(extension)
1176 for x in extensionsList:
1177 list.append((x[0](), x))
1178 keys += [""] * len(extensionsList)
1179 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1181 def extensionCallback(self, answer):
1182 if answer is not None:
1185 from Tools.BoundFunction import boundFunction
1187 # depends on InfoBarExtensions
1188 from Components.PluginComponent import plugins
1190 class InfoBarPlugins:
1192 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1194 def getPluginName(self, name):
1197 def getPluginList(self):
1199 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1200 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1203 def runPlugin(self, plugin):
1204 plugin(session = self.session)
1206 # depends on InfoBarExtensions
1207 class InfoBarSleepTimer:
1209 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1211 def available(self):
1214 def getSleepTimerName(self):
1215 return _("Sleep Timer")
1217 def showSleepTimerSetup(self):
1218 self.session.open(SleepTimerEdit)
1220 # depends on InfoBarExtensions
1223 self.session.pipshown = False
1225 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1226 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1227 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1229 def available(self):
1233 return self.session.pipshown
1235 def getShowHideName(self):
1236 if self.session.pipshown:
1237 return _("Disable Picture in Picture")
1239 return _("Activate Picture in Picture")
1241 def getSwapName(self):
1242 return _("Swap Services")
1244 def getMoveName(self):
1245 return _("Move Picture in Picture")
1248 if self.session.pipshown:
1249 del self.session.pip
1250 self.session.pipshown = False
1252 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1253 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1254 if self.session.pip.playService(newservice):
1255 self.session.pipshown = True
1256 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1258 self.session.pipshown = False
1259 del self.session.pip
1260 self.session.nav.playService(newservice)
1263 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1264 if self.session.pip.servicePath:
1265 servicepath = self.servicelist.getCurrentServicePath()
1266 ref=servicepath[len(servicepath)-1]
1267 pipref=self.session.pip.getCurrentService()
1268 self.session.pip.playService(swapservice)
1269 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1270 if pipref.toString() != ref.toString(): # is a subservice ?
1271 self.session.nav.stopService() # stop portal
1272 self.session.nav.playService(pipref) # start subservice
1273 self.session.pip.servicePath=servicepath
1276 self.session.open(PiPSetup, pip = self.session.pip)
1278 from RecordTimer import parseEvent
1280 class InfoBarInstantRecord:
1281 """Instant Record - handles the instantRecord action in order to
1282 start/stop instant records"""
1284 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1286 "instantRecord": (self.instantRecord, _("Instant Record...")),
1289 self["BlinkingPoint"] = BlinkingPixmapConditional()
1290 self["BlinkingPoint"].hide()
1291 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1293 def stopCurrentRecording(self, entry = -1):
1294 if entry is not None and entry != -1:
1295 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1296 self.recording.remove(self.recording[entry])
1298 def startInstantRecording(self, limitEvent = False):
1299 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1301 # try to get event info
1304 service = self.session.nav.getCurrentService()
1305 epg = eEPGCache.getInstance()
1306 event = epg.lookupEventTime(serviceref, -1, 0)
1308 info = service.info()
1309 ev = info.getEvent(0)
1315 end = time() + 3600 * 10
1316 name = "instant record"
1320 if event is not None:
1321 curEvent = parseEvent(event)
1323 description = curEvent[3]
1324 eventid = curEvent[4]
1329 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1331 data = (begin, end, name, description, eventid)
1333 recording = self.session.nav.recordWithTimer(serviceref, *data)
1334 recording.dontSave = True
1335 self.recording.append(recording)
1337 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1339 def isInstantRecordRunning(self):
1340 print "self.recording:", self.recording
1341 if len(self.recording) > 0:
1342 for x in self.recording:
1347 def recordQuestionCallback(self, answer):
1348 print "pre:\n", self.recording
1350 if answer is None or answer[1] == "no":
1353 recording = self.recording[:]
1355 if not x in self.session.nav.RecordTimer.timer_list:
1356 self.recording.remove(x)
1357 elif x.dontSave and x.isRunning():
1358 list.append(TimerEntryComponent(x, False))
1360 if answer[1] == "changeduration":
1361 if len(self.recording) == 1:
1362 self.changeDuration(0)
1364 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1365 elif answer[1] == "stop":
1366 if len(self.recording) == 1:
1367 self.stopCurrentRecording(0)
1369 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1370 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1372 if answer[1] == "event":
1374 if answer[1] == "manualduration":
1375 self.selectedEntry = len(self.recording)
1376 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1377 self.startInstantRecording(limitEvent = limitEvent)
1379 print "after:\n", self.recording
1381 def changeDuration(self, entry):
1382 if entry is not None:
1383 self.selectedEntry = entry
1384 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1386 def inputCallback(self, value):
1387 if value is not None:
1388 print "stopping recording after", int(value), "minutes."
1389 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1390 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1392 def instantRecord(self):
1394 stat = os_stat(resolveFilename(SCOPE_HDD))
1396 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1399 if self.isInstantRecordRunning():
1400 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1401 title=_("A recording is currently running.\nWhat do you want to do?"), \
1402 list=[(_("stop recording"), "stop"), \
1403 (_("change recording (duration)"), "changeduration"), \
1404 (_("add recording (indefinitely)"), "indefinitely"), \
1405 (_("add recording (stop after current event)"), "event"), \
1406 (_("add recording (enter recording duration)"), "manualduration"), \
1407 (_("do nothing"), "no")])
1409 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1410 title=_("Start recording?"), \
1411 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1412 (_("add recording (stop after current event)"), "event"), \
1413 (_("add recording (enter recording duration)"), "manualduration"), \
1414 (_("don't record"), "no")])
1416 from Tools.ISO639 import LanguageCodes
1418 class InfoBarAudioSelection:
1420 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1422 "audioSelection": (self.audioSelection, _("Audio Options...")),
1425 def audioSelection(self):
1426 service = self.session.nav.getCurrentService()
1427 audio = service and service.audioTracks()
1428 self.audioTracks = audio
1429 n = audio and audio.getNumberOfTracks() or 0
1430 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1432 print "tlist:", tlist
1434 self.audioChannel = service.audioChannel()
1437 i = audio.getTrackInfo(x)
1438 language = i.getLanguage()
1439 description = i.getDescription()
1441 if LanguageCodes.has_key(language):
1442 language = LanguageCodes[language][0]
1444 if len(description):
1445 description += " (" + language + ")"
1447 description = language
1449 tlist.append((description, x))
1451 selectedAudio = tlist[0][1]
1452 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1456 if x[1] != selectedAudio:
1461 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1462 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1464 del self.audioTracks
1466 def audioSelected(self, audio):
1467 if audio is not None:
1468 if isinstance(audio[1], str):
1469 if audio[1] == "mode":
1470 keys = ["red", "green", "yellow"]
1471 selection = self.audioChannel.getCurrentChannel()
1472 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1473 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1475 del self.audioChannel
1476 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1477 self.audioTracks.selectTrack(audio[1])
1479 del self.audioChannel
1480 del self.audioTracks
1482 def modeSelected(self, mode):
1483 if mode is not None:
1484 self.audioChannel.selectChannel(mode[1])
1485 del self.audioChannel
1487 class InfoBarSubserviceSelection:
1489 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1491 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1494 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1496 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1497 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1499 self["SubserviceQuickzapAction"].setEnabled(False)
1501 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1505 def checkSubservicesAvail(self, ev):
1506 if ev == iPlayableService.evUpdatedEventInfo:
1507 service = self.session.nav.getCurrentService()
1508 subservices = service and service.subServices()
1509 if not subservices or subservices.getNumberOfSubservices() == 0:
1510 self["SubserviceQuickzapAction"].setEnabled(False)
1512 def nextSubservice(self):
1513 self.changeSubservice(+1)
1515 def prevSubservice(self):
1516 self.changeSubservice(-1)
1518 def changeSubservice(self, direction):
1519 service = self.session.nav.getCurrentService()
1520 subservices = service and service.subServices()
1521 n = subservices and subservices.getNumberOfSubservices()
1524 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1526 if subservices.getSubservice(x).toString() == ref.toString():
1529 selection += direction
1534 newservice = subservices.getSubservice(selection)
1535 if newservice.valid():
1538 self.session.nav.playService(newservice)
1540 def subserviceSelection(self):
1541 service = self.session.nav.getCurrentService()
1542 subservices = service and service.subServices()
1543 self.bouquets = self.servicelist.getBouquetList()
1544 n = subservices and subservices.getNumberOfSubservices()
1547 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1550 i = subservices.getSubservice(x)
1551 if i.toString() == ref.toString():
1553 tlist.append((i.getName(), i))
1555 if self.bouquets and len(self.bouquets):
1556 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1557 if config.usage.multibouquet.value:
1558 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1560 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1563 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1564 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1567 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1569 def subserviceSelected(self, service):
1571 if not service is None:
1572 if isinstance(service[1], str):
1573 if service[1] == "quickzap":
1574 from Screens.SubservicesQuickzap import SubservicesQuickzap
1575 self.session.open(SubservicesQuickzap, service[2])
1577 self["SubserviceQuickzapAction"].setEnabled(True)
1578 self.session.nav.playService(service[1])
1580 def addSubserviceToBouquetCallback(self, service):
1581 if len(service) > 1 and isinstance(service[1], eServiceReference):
1582 self.selectedSubservice = service
1583 if self.bouquets is None:
1586 cnt = len(self.bouquets)
1587 if cnt > 1: # show bouquet list
1588 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1589 elif cnt == 1: # add to only one existing bouquet
1590 self.addSubserviceToBouquet(self.bouquets[0][1])
1591 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1593 def bouquetSelClosed(self, confirmed):
1595 del self.selectedSubservice
1597 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1599 def addSubserviceToBouquet(self, dest):
1600 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1602 self.bsel.close(True)
1604 del self.selectedSubservice
1606 class InfoBarAdditionalInfo:
1608 self["NimA"] = Pixmap()
1609 self["NimB"] = Pixmap()
1610 self["NimA_Active"] = Pixmap()
1611 self["NimB_Active"] = Pixmap()
1613 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1614 self["TimeshiftPossible"] = self["RecordingPossible"]
1615 self["ExtensionsAvailable"] = Boolean(fixed=1)
1617 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1618 res_mgr = eDVBResourceManager.getInstance()
1620 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1622 def tunerUseMaskChanged(self, mask):
1624 self["NimA_Active"].show()
1626 self["NimA_Active"].hide()
1628 self["NimB_Active"].show()
1630 self["NimB_Active"].hide()
1632 def checkTunerState(self, service):
1633 info = service and service.frontendInfo()
1634 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1635 if feNumber is None:
1645 def gotServiceEvent(self, ev):
1646 service = self.session.nav.getCurrentService()
1647 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1648 self.checkTunerState(service)
1650 class InfoBarNotifications:
1652 self.onExecBegin.append(self.checkNotifications)
1653 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1654 self.onClose.append(self.__removeNotification)
1656 def __removeNotification(self):
1657 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1659 def checkNotificationsIfExecing(self):
1661 self.checkNotifications()
1663 def checkNotifications(self):
1664 if len(Notifications.notifications):
1665 n = Notifications.notifications[0]
1667 Notifications.notifications = Notifications.notifications[1:]
1670 if n[3].has_key("onSessionOpenCallback"):
1671 n[3]["onSessionOpenCallback"]()
1672 del n[3]["onSessionOpenCallback"]
1675 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1677 dlg = self.session.open(n[1], *n[2], **n[3])
1679 # remember that this notification is currently active
1681 Notifications.current_notifications.append(d)
1682 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1684 def __notificationClosed(self, d):
1685 Notifications.current_notifications.remove(d)
1687 class InfoBarServiceNotifications:
1689 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1691 iPlayableService.evEnd: self.serviceHasEnded
1694 def serviceHasEnded(self):
1695 print "service end!"
1698 self.setSeekState(self.SEEK_STATE_PLAY)
1702 class InfoBarCueSheetSupport:
1708 ENABLE_RESUME_SUPPORT = False
1711 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1713 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1714 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1715 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1719 self.is_closing = False
1720 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1722 iPlayableService.evStart: self.__serviceStarted,
1725 def __serviceStarted(self):
1728 print "new service started! trying to download cuts!"
1729 self.downloadCuesheet()
1731 if self.ENABLE_RESUME_SUPPORT:
1734 for (pts, what) in self.cut_list:
1735 if what == self.CUT_TYPE_LAST:
1738 if last is not None:
1739 self.resume_point = last
1740 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1742 def playLastCB(self, answer):
1744 seekable = self.__getSeekable()
1745 if seekable is not None:
1746 seekable.seekTo(self.resume_point)
1748 def __getSeekable(self):
1749 service = self.session.nav.getCurrentService()
1752 return service.seek()
1754 def cueGetCurrentPosition(self):
1755 seek = self.__getSeekable()
1758 r = seek.getPlayPosition()
1763 def jumpPreviousNextMark(self, cmp, alternative=None):
1764 current_pos = self.cueGetCurrentPosition()
1765 if current_pos is None:
1767 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1768 if mark is not None:
1770 elif alternative is not None:
1775 seekable = self.__getSeekable()
1776 if seekable is not None:
1777 seekable.seekTo(pts)
1779 def jumpPreviousMark(self):
1780 # we add 2 seconds, so if the play position is <2s after
1781 # the mark, the mark before will be used
1782 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1784 def jumpNextMark(self):
1785 self.jumpPreviousNextMark(lambda x: x)
1787 def getNearestCutPoint(self, pts, cmp=abs):
1790 for cp in self.cut_list:
1791 diff = cmp(cp[0] - pts)
1792 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1796 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1797 current_pos = self.cueGetCurrentPosition()
1798 if current_pos is None:
1799 print "not seekable"
1802 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1804 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1806 return nearest_cutpoint
1808 self.removeMark(nearest_cutpoint)
1809 elif not onlyremove and not onlyreturn:
1810 self.addMark((current_pos, self.CUT_TYPE_MARK))
1815 def addMark(self, point):
1816 insort(self.cut_list, point)
1817 self.uploadCuesheet()
1819 def removeMark(self, point):
1820 self.cut_list.remove(point)
1821 self.uploadCuesheet()
1823 def __getCuesheet(self):
1824 service = self.session.nav.getCurrentService()
1827 return service.cueSheet()
1829 def uploadCuesheet(self):
1830 cue = self.__getCuesheet()
1833 print "upload failed, no cuesheet interface"
1835 cue.setCutList(self.cut_list)
1837 def downloadCuesheet(self):
1838 cue = self.__getCuesheet()
1841 print "upload failed, no cuesheet interface"
1843 self.cut_list = cue.getCutList()
1845 class InfoBarSummary(Screen):
1847 <screen position="0,0" size="132,64">
1848 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1849 <convert type="ClockToText">WithSeconds</convert>
1851 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1852 <convert type="ServiceName">Name</convert>
1856 def __init__(self, session, parent):
1857 Screen.__init__(self, session)
1858 self["CurrentService"] = CurrentService(self.session.nav)
1859 self["CurrentTime"] = Clock()
1861 class InfoBarSummarySupport:
1865 def createSummary(self):
1866 return InfoBarSummary
1868 class InfoBarTeletextPlugin:
1870 self.teletext_plugin = None
1872 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1873 self.teletext_plugin = p
1875 if self.teletext_plugin is not None:
1876 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1878 "startTeletext": (self.startTeletext, _("View teletext..."))
1881 print "no teletext plugin found!"
1883 def startTeletext(self):
1884 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1886 class InfoBarSubtitleSupport(object):
1888 object.__init__(self)
1889 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1890 self.__subtitles_enabled = False
1892 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1894 iPlayableService.evEnd: self.__serviceStopped,
1895 iPlayableService.evUpdatedInfo: self.__updatedInfo
1897 self.cached_subtitle_checked = False
1899 def __serviceStopped(self):
1900 self.subtitle_window.hide()
1901 self.__subtitles_enabled = False
1902 self.cached_subtitle_checked = False
1904 def __updatedInfo(self):
1905 if not self.cached_subtitle_checked:
1906 subtitle = self.getCurrentServiceSubtitle()
1907 self.cached_subtitle_checked = True
1909 self.__selected_subtitle = subtitle.getCachedSubtitle()
1910 if self.__selected_subtitle:
1911 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1912 self.subtitle_window.show()
1913 self.__subtitles_enabled = True
1915 def getCurrentServiceSubtitle(self):
1916 service = self.session.nav.getCurrentService()
1917 return service and service.subtitle()
1919 def setSubtitlesEnable(self, enable=True):
1920 subtitle = self.getCurrentServiceSubtitle()
1921 if enable and self.__selected_subtitle is not None:
1922 if subtitle and not self.__subtitles_enabled:
1923 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1924 self.subtitle_window.show()
1925 self.__subtitles_enabled = True
1928 subtitle.disableSubtitles(self.subtitle_window.instance)
1929 self.__subtitles_enabled = False
1930 self.subtitle_window.hide()
1932 def setSelectedSubtitle(self, subtitle):
1933 self.__selected_subtitle = subtitle
1935 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1936 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1938 class InfoBarServiceErrorPopupSupport:
1940 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1942 iPlayableService.evTuneFailed: self.__tuneFailed,
1943 iPlayableService.evStart: self.__serviceStarted
1945 self.__serviceStarted()
1947 def __serviceStarted(self):
1948 self.last_error = None
1949 Notifications.RemovePopup(id = "ZapError")
1951 def __tuneFailed(self):
1952 service = self.session.nav.getCurrentService()
1953 info = service and service.info()
1954 error = info and info.getInfo(iServiceInformation.sDVBState)
1956 if error == self.last_error:
1959 self.last_error = error
1962 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1963 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1964 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1965 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1966 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1967 eDVBServicePMTHandler.eventNewProgramInfo: None,
1968 eDVBServicePMTHandler.eventTuned: None,
1969 eDVBServicePMTHandler.eventSOF: None,
1970 eDVBServicePMTHandler.eventEOF: None
1973 error = errors.get(error) #this returns None when the key not exist in the dict
1975 if error is not None:
1976 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1978 Notifications.RemovePopup(id = "ZapError")