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"] = ActionMap(["InfobarRdsActions"],
573 "startRassInteractive": self.startRassInteractive
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")
633 SEEK_STATE_EOF = (1, 0, 0, "END")
636 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
638 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
639 iPlayableService.evStart: self.__serviceStarted,
641 iPlayableService.evEOF: self.__evEOF,
642 iPlayableService.evSOF: self.__evSOF,
645 class InfoBarSeekActionMap(HelpableActionMap):
646 def __init__(self, screen, *args, **kwargs):
647 HelpableActionMap.__init__(self, screen, *args, **kwargs)
650 def action(self, contexts, action):
651 print "action:", action
652 if action[:5] == "seek:":
653 time = int(action[5:])
654 self.screen.seekRelative(time * 90000)
658 return HelpableActionMap.action(self, contexts, action)
660 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
662 "playpauseService": (self.playpauseService, _("pause")),
663 "pauseService": (self.pauseService, _("pause")),
664 "unPauseService": (self.unPauseService, _("continue")),
666 "seekFwd": (self.seekFwd, _("skip forward")),
667 "seekFwdDown": self.seekFwdDown,
668 "seekFwdUp": self.seekFwdUp,
669 "seekBack": (self.seekBack, _("skip backward")),
670 "seekBackDown": self.seekBackDown,
671 "seekBackUp": self.seekBackUp,
673 # give them a little more priority to win over color buttons
675 self["SeekActions"].setEnabled(False)
677 self.seekstate = self.SEEK_STATE_PLAY
678 self.onClose.append(self.delTimer)
680 self.fwdtimer = False
681 self.fwdKeyTimer = eTimer()
682 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
684 self.rwdtimer = False
685 self.rwdKeyTimer = eTimer()
686 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
688 self.onPlayStateChanged = [ ]
690 self.lockedBecauseOfSkipping = False
703 service = self.session.nav.getCurrentService()
707 seek = service.seek()
709 if seek is None or not seek.isCurrentlySeekable():
714 def isSeekable(self):
715 if self.getSeek() is None:
719 def __seekableStatusChanged(self):
720 print "seekable status changed!"
721 if not self.isSeekable():
722 self["SeekActions"].setEnabled(False)
723 print "not seekable, return to play"
724 self.setSeekState(self.SEEK_STATE_PLAY)
726 self["SeekActions"].setEnabled(True)
729 def __serviceStarted(self):
730 self.seekstate = self.SEEK_STATE_PLAY
731 self.__seekableStatusChanged()
733 def setSeekState(self, state):
734 service = self.session.nav.getCurrentService()
739 if not self.isSeekable():
740 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
741 state = self.SEEK_STATE_PLAY
743 pauseable = service.pause()
745 if pauseable is None:
746 print "not pauseable."
747 state = self.SEEK_STATE_PLAY
749 oldstate = self.seekstate
750 self.seekstate = state
753 if oldstate[i] != self.seekstate[i]:
754 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
756 for c in self.onPlayStateChanged:
759 self.checkSkipShowHideLock()
763 def playpauseService(self):
764 if self.seekstate != self.SEEK_STATE_PLAY:
765 self.unPauseService()
769 def pauseService(self):
770 if self.seekstate == self.SEEK_STATE_PAUSE:
771 print "pause, but in fact unpause"
772 self.unPauseService()
774 if self.seekstate == self.SEEK_STATE_PLAY:
775 print "yes, playing."
777 print "no", self.seekstate
779 self.setSeekState(self.SEEK_STATE_PAUSE);
781 def unPauseService(self):
783 if self.seekstate == self.SEEK_STATE_PLAY:
785 self.setSeekState(self.SEEK_STATE_PLAY)
787 def doSeek(self, seektime):
788 print "doseek", seektime
789 service = self.session.nav.getCurrentService()
793 seekable = self.getSeek()
797 seekable.seekTo(90 * seektime)
799 def seekFwdDown(self):
800 print "start fwd timer"
802 self.fwdKeyTimer.start(1000)
804 def seekBackDown(self):
805 print "start rewind timer"
807 self.rwdKeyTimer.start(1000)
812 self.fwdKeyTimer.stop()
813 self.fwdtimer = False
818 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
819 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
820 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
821 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
822 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
823 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
824 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
825 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
826 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
827 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
828 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
829 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
830 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
831 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
832 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
833 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
835 self.setSeekState(lookup[self.seekstate])
837 def seekBackUp(self):
840 self.rwdKeyTimer.stop()
841 self.rwdtimer = False
846 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
847 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
848 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
849 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
850 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
851 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
852 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
853 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
854 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
855 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
856 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
857 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
858 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
859 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
860 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
861 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
863 self.setSeekState(lookup[self.seekstate])
865 if self.seekstate == self.SEEK_STATE_PAUSE:
866 seekable = self.getSeek()
867 if seekable is not None:
868 seekable.seekRelative(-1, 3)
870 def fwdTimerFire(self):
871 print "Display seek fwd"
872 self.fwdKeyTimer.stop()
873 self.fwdtimer = False
874 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
876 def fwdSeekTo(self, minutes):
877 print "Seek", minutes, "minutes forward"
879 seekable = self.getSeek()
880 if seekable is not None:
881 seekable.seekRelative(1, minutes * 60 * 90000)
883 def rwdTimerFire(self):
885 self.rwdKeyTimer.stop()
886 self.rwdtimer = False
887 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
889 def rwdSeekTo(self, minutes):
891 self.fwdSeekTo(0 - minutes)
893 def checkSkipShowHideLock(self):
894 wantlock = self.seekstate != self.SEEK_STATE_PLAY
896 if config.usage.show_infobar_on_zap.value:
897 if self.lockedBecauseOfSkipping and not wantlock:
899 self.lockedBecauseOfSkipping = False
901 if wantlock and not self.lockedBecauseOfSkipping:
903 self.lockedBecauseOfSkipping = True
906 if self.seekstate == self.SEEK_STATE_EOF:
908 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
909 print "end of stream while seeking back, ignoring."
912 # if we are seeking, we try to end up ~1s before the end, and pause there.
913 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
914 self.setSeekState(self.SEEK_STATE_EOF)
915 self.seekRelativeToEnd(-90000)
917 self.setSeekState(self.SEEK_STATE_EOF)
920 self.setSeekState(self.SEEK_STATE_PLAY)
923 def seekRelative(self, diff):
924 seekable = self.getSeek()
925 if seekable is not None:
926 print "seekRelative: res:", seekable.seekRelative(1, diff)
930 def seekRelativeToEnd(self, diff):
931 assert diff <= 0, "diff is expected to be negative!"
933 # might sound like an evil hack, but:
934 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
935 # and we don't get that by passing 0 here (it would seek to begin).
939 # relative-to-end seeking is implemented as absolutes seeks with negative time
940 self.seekAbsolute(diff)
942 def seekAbsolute(self, abs):
943 seekable = self.getSeek()
944 if seekable is not None:
947 from Screens.PVRState import PVRState, TimeshiftState
949 class InfoBarPVRState:
950 def __init__(self, screen=PVRState):
951 self.onPlayStateChanged.append(self.__playStateChanged)
952 self.pvrStateDialog = self.session.instantiateDialog(screen)
953 self.onShow.append(self._mayShow)
954 self.onHide.append(self.pvrStateDialog.hide)
957 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
958 self.pvrStateDialog.show()
960 def __playStateChanged(self, state):
961 playstateString = state[3]
962 self.pvrStateDialog["state"].setText(playstateString)
965 class InfoBarTimeshiftState(InfoBarPVRState):
967 InfoBarPVRState.__init__(self, screen=TimeshiftState)
970 if self.execing and self.timeshift_enabled:
971 self.pvrStateDialog.show()
973 class InfoBarShowMovies:
975 # i don't really like this class.
976 # it calls a not further specified "movie list" on up/down/movieList,
977 # so this is not more than an action map
979 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
981 "movieList": (self.showMovies, "movie list"),
982 "up": (self.showMovies, "movie list"),
983 "down": (self.showMovies, "movie list")
986 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
990 # Timeshift works the following way:
991 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
992 # - normal playback TUNER unused PLAY enable disable disable
993 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
994 # - user presess pause again FILE record PLAY enable disable enable
995 # - user fast forwards FILE record FF enable disable enable
996 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
997 # - user backwards FILE record BACK # !! enable disable enable
1001 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1002 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1003 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1004 # - the user can now PVR around
1005 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1006 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1008 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1009 # - if the user rewinds, or press pause, timeshift will be activated again
1011 # note that a timeshift can be enabled ("recording") and
1012 # activated (currently time-shifting).
1014 class InfoBarTimeshift:
1016 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1018 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1019 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1021 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1023 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1024 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1025 }, prio=-1) # priority over record
1027 self.timeshift_enabled = 0
1028 self.timeshift_state = 0
1029 self.ts_rewind_timer = eTimer()
1030 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1032 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1034 iPlayableService.evStart: self.__serviceStarted,
1035 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1038 def getTimeshift(self):
1039 service = self.session.nav.getCurrentService()
1040 return service and service.timeshift()
1042 def startTimeshift(self):
1043 print "enable timeshift"
1044 ts = self.getTimeshift()
1046 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1047 print "no ts interface"
1050 if self.timeshift_enabled:
1051 print "hu, timeshift already enabled?"
1053 if not ts.startTimeshift():
1054 self.timeshift_enabled = 1
1056 # we remove the "relative time" for now.
1057 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1060 self.setSeekState(self.SEEK_STATE_PAUSE)
1062 # enable the "TimeshiftEnableActions", which will override
1063 # the startTimeshift actions
1064 self.__seekableStatusChanged()
1066 print "timeshift failed"
1068 def stopTimeshift(self):
1069 if not self.timeshift_enabled:
1071 print "disable timeshift"
1072 ts = self.getTimeshift()
1075 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1077 def stopTimeshiftConfirmed(self, confirmed):
1081 ts = self.getTimeshift()
1086 self.timeshift_enabled = 0
1089 self.__seekableStatusChanged()
1091 # activates timeshift, and seeks to (almost) the end
1092 def activateTimeshiftEnd(self, back = True):
1093 ts = self.getTimeshift()
1094 print "activateTimeshiftEnd"
1099 if ts.isTimeshiftActive():
1100 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1104 ts.activateTimeshift() # activate timeshift will automatically pause
1105 self.setSeekState(self.SEEK_STATE_PAUSE)
1106 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1109 self.ts_rewind_timer.start(200, 1)
1111 def rewindService(self):
1112 self.setSeekState(self.SEEK_STATE_BACK_16X)
1114 # same as activateTimeshiftEnd, but pauses afterwards.
1115 def activateTimeshiftEndAndPause(self):
1116 print "activateTimeshiftEndAndPause"
1117 #state = self.seekstate
1118 self.activateTimeshiftEnd(False)
1120 def __seekableStatusChanged(self):
1123 print "self.isSeekable", self.isSeekable()
1124 print "self.timeshift_enabled", self.timeshift_enabled
1126 # when this service is not seekable, but timeshift
1127 # is enabled, this means we can activate
1129 if not self.isSeekable() and self.timeshift_enabled:
1132 print "timeshift activate:", enabled
1133 self["TimeshiftActivateActions"].setEnabled(enabled)
1135 def __serviceStarted(self):
1136 self.timeshift_enabled = False
1137 self.__seekableStatusChanged()
1139 from Screens.PiPSetup import PiPSetup
1141 class InfoBarExtensions:
1142 EXTENSION_SINGLE = 0
1148 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1150 "extensions": (self.showExtensionSelection, _("view extensions...")),
1153 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1154 self.list.append((type, extension, key))
1156 def updateExtension(self, extension, key = None):
1157 self.extensionsList.append(extension)
1159 if self.extensionKeys.has_key(key):
1163 for x in self.availableKeys:
1164 if not self.extensionKeys.has_key(x):
1169 self.extensionKeys[key] = len(self.extensionsList) - 1
1171 def updateExtensions(self):
1172 self.extensionsList = []
1173 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1174 self.extensionKeys = {}
1176 if x[0] == self.EXTENSION_SINGLE:
1177 self.updateExtension(x[1], x[2])
1180 self.updateExtension(y[0], y[1])
1183 def showExtensionSelection(self):
1184 self.updateExtensions()
1185 extensionsList = self.extensionsList[:]
1188 for x in self.availableKeys:
1189 if self.extensionKeys.has_key(x):
1190 entry = self.extensionKeys[x]
1191 extension = self.extensionsList[entry]
1193 name = str(extension[0]())
1194 list.append((extension[0](), extension))
1196 extensionsList.remove(extension)
1198 extensionsList.remove(extension)
1199 for x in extensionsList:
1200 list.append((x[0](), x))
1201 keys += [""] * len(extensionsList)
1202 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1204 def extensionCallback(self, answer):
1205 if answer is not None:
1208 from Tools.BoundFunction import boundFunction
1210 # depends on InfoBarExtensions
1211 from Components.PluginComponent import plugins
1213 class InfoBarPlugins:
1215 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1217 def getPluginName(self, name):
1220 def getPluginList(self):
1222 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1223 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1226 def runPlugin(self, plugin):
1227 plugin(session = self.session)
1229 # depends on InfoBarExtensions
1230 class InfoBarSleepTimer:
1232 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1234 def available(self):
1237 def getSleepTimerName(self):
1238 return _("Sleep Timer")
1240 def showSleepTimerSetup(self):
1241 self.session.open(SleepTimerEdit)
1243 # depends on InfoBarExtensions
1246 self.session.pipshown = False
1248 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1249 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1250 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1252 def available(self):
1256 return self.session.pipshown
1258 def getShowHideName(self):
1259 if self.session.pipshown:
1260 return _("Disable Picture in Picture")
1262 return _("Activate Picture in Picture")
1264 def getSwapName(self):
1265 return _("Swap Services")
1267 def getMoveName(self):
1268 return _("Move Picture in Picture")
1271 if self.session.pipshown:
1272 del self.session.pip
1273 self.session.pipshown = False
1275 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1276 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1277 if self.session.pip.playService(newservice):
1278 self.session.pipshown = True
1279 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1281 self.session.pipshown = False
1282 del self.session.pip
1283 self.session.nav.playService(newservice)
1286 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1287 if self.session.pip.servicePath:
1288 servicepath = self.servicelist.getCurrentServicePath()
1289 ref=servicepath[len(servicepath)-1]
1290 pipref=self.session.pip.getCurrentService()
1291 self.session.pip.playService(swapservice)
1292 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1293 if pipref.toString() != ref.toString(): # is a subservice ?
1294 self.session.nav.stopService() # stop portal
1295 self.session.nav.playService(pipref) # start subservice
1296 self.session.pip.servicePath=servicepath
1299 self.session.open(PiPSetup, pip = self.session.pip)
1301 from RecordTimer import parseEvent
1303 class InfoBarInstantRecord:
1304 """Instant Record - handles the instantRecord action in order to
1305 start/stop instant records"""
1307 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1309 "instantRecord": (self.instantRecord, _("Instant Record...")),
1312 self["BlinkingPoint"] = BlinkingPixmapConditional()
1313 self["BlinkingPoint"].hide()
1314 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1316 def stopCurrentRecording(self, entry = -1):
1317 if entry is not None and entry != -1:
1318 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1319 self.recording.remove(self.recording[entry])
1321 def startInstantRecording(self, limitEvent = False):
1322 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1324 # try to get event info
1327 service = self.session.nav.getCurrentService()
1328 epg = eEPGCache.getInstance()
1329 event = epg.lookupEventTime(serviceref, -1, 0)
1331 info = service.info()
1332 ev = info.getEvent(0)
1338 end = time() + 3600 * 10
1339 name = "instant record"
1343 if event is not None:
1344 curEvent = parseEvent(event)
1346 description = curEvent[3]
1347 eventid = curEvent[4]
1352 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1354 data = (begin, end, name, description, eventid)
1356 recording = self.session.nav.recordWithTimer(serviceref, *data)
1357 recording.dontSave = True
1358 self.recording.append(recording)
1360 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1362 def isInstantRecordRunning(self):
1363 print "self.recording:", self.recording
1364 if len(self.recording) > 0:
1365 for x in self.recording:
1370 def recordQuestionCallback(self, answer):
1371 print "pre:\n", self.recording
1373 if answer is None or answer[1] == "no":
1376 recording = self.recording[:]
1378 if not x in self.session.nav.RecordTimer.timer_list:
1379 self.recording.remove(x)
1380 elif x.dontSave and x.isRunning():
1381 list.append(TimerEntryComponent(x, False))
1383 if answer[1] == "changeduration":
1384 if len(self.recording) == 1:
1385 self.changeDuration(0)
1387 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1388 elif answer[1] == "stop":
1389 if len(self.recording) == 1:
1390 self.stopCurrentRecording(0)
1392 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1393 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1395 if answer[1] == "event":
1397 if answer[1] == "manualduration":
1398 self.selectedEntry = len(self.recording)
1399 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1400 self.startInstantRecording(limitEvent = limitEvent)
1402 print "after:\n", self.recording
1404 def changeDuration(self, entry):
1405 if entry is not None:
1406 self.selectedEntry = entry
1407 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1409 def inputCallback(self, value):
1410 if value is not None:
1411 print "stopping recording after", int(value), "minutes."
1412 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1413 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1415 def instantRecord(self):
1417 stat = os_stat(resolveFilename(SCOPE_HDD))
1419 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1422 if self.isInstantRecordRunning():
1423 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1424 title=_("A recording is currently running.\nWhat do you want to do?"), \
1425 list=[(_("stop recording"), "stop"), \
1426 (_("change recording (duration)"), "changeduration"), \
1427 (_("add recording (indefinitely)"), "indefinitely"), \
1428 (_("add recording (stop after current event)"), "event"), \
1429 (_("add recording (enter recording duration)"), "manualduration"), \
1430 (_("do nothing"), "no")])
1432 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1433 title=_("Start recording?"), \
1434 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1435 (_("add recording (stop after current event)"), "event"), \
1436 (_("add recording (enter recording duration)"), "manualduration"), \
1437 (_("don't record"), "no")])
1439 from Tools.ISO639 import LanguageCodes
1441 class InfoBarAudioSelection:
1443 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1445 "audioSelection": (self.audioSelection, _("Audio Options...")),
1448 def audioSelection(self):
1449 service = self.session.nav.getCurrentService()
1450 audio = service and service.audioTracks()
1451 self.audioTracks = audio
1452 n = audio and audio.getNumberOfTracks() or 0
1453 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1455 print "tlist:", tlist
1457 self.audioChannel = service.audioChannel()
1460 i = audio.getTrackInfo(x)
1461 language = i.getLanguage()
1462 description = i.getDescription()
1464 if LanguageCodes.has_key(language):
1465 language = LanguageCodes[language][0]
1467 if len(description):
1468 description += " (" + language + ")"
1470 description = language
1472 tlist.append((description, x))
1474 selectedAudio = tlist[0][1]
1475 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1479 if x[1] != selectedAudio:
1484 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1485 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1487 del self.audioTracks
1489 def audioSelected(self, audio):
1490 if audio is not None:
1491 if isinstance(audio[1], str):
1492 if audio[1] == "mode":
1493 keys = ["red", "green", "yellow"]
1494 selection = self.audioChannel.getCurrentChannel()
1495 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1496 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1498 del self.audioChannel
1499 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1500 self.audioTracks.selectTrack(audio[1])
1502 del self.audioChannel
1503 del self.audioTracks
1505 def modeSelected(self, mode):
1506 if mode is not None:
1507 self.audioChannel.selectChannel(mode[1])
1508 del self.audioChannel
1510 class InfoBarSubserviceSelection:
1512 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1514 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1517 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1519 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1520 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1522 self["SubserviceQuickzapAction"].setEnabled(False)
1524 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1528 def checkSubservicesAvail(self, ev):
1529 if ev == iPlayableService.evUpdatedEventInfo:
1530 service = self.session.nav.getCurrentService()
1531 subservices = service and service.subServices()
1532 if not subservices or subservices.getNumberOfSubservices() == 0:
1533 self["SubserviceQuickzapAction"].setEnabled(False)
1535 def nextSubservice(self):
1536 self.changeSubservice(+1)
1538 def prevSubservice(self):
1539 self.changeSubservice(-1)
1541 def changeSubservice(self, direction):
1542 service = self.session.nav.getCurrentService()
1543 subservices = service and service.subServices()
1544 n = subservices and subservices.getNumberOfSubservices()
1547 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1549 if subservices.getSubservice(x).toString() == ref.toString():
1552 selection += direction
1557 newservice = subservices.getSubservice(selection)
1558 if newservice.valid():
1561 self.session.nav.playService(newservice)
1563 def subserviceSelection(self):
1564 service = self.session.nav.getCurrentService()
1565 subservices = service and service.subServices()
1566 self.bouquets = self.servicelist.getBouquetList()
1567 n = subservices and subservices.getNumberOfSubservices()
1570 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1573 i = subservices.getSubservice(x)
1574 if i.toString() == ref.toString():
1576 tlist.append((i.getName(), i))
1578 if self.bouquets and len(self.bouquets):
1579 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1580 if config.usage.multibouquet.value:
1581 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1583 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1586 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1587 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1590 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1592 def subserviceSelected(self, service):
1594 if not service is None:
1595 if isinstance(service[1], str):
1596 if service[1] == "quickzap":
1597 from Screens.SubservicesQuickzap import SubservicesQuickzap
1598 self.session.open(SubservicesQuickzap, service[2])
1600 self["SubserviceQuickzapAction"].setEnabled(True)
1601 self.session.nav.playService(service[1])
1603 def addSubserviceToBouquetCallback(self, service):
1604 if len(service) > 1 and isinstance(service[1], eServiceReference):
1605 self.selectedSubservice = service
1606 if self.bouquets is None:
1609 cnt = len(self.bouquets)
1610 if cnt > 1: # show bouquet list
1611 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1612 elif cnt == 1: # add to only one existing bouquet
1613 self.addSubserviceToBouquet(self.bouquets[0][1])
1614 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1616 def bouquetSelClosed(self, confirmed):
1618 del self.selectedSubservice
1620 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1622 def addSubserviceToBouquet(self, dest):
1623 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1625 self.bsel.close(True)
1627 del self.selectedSubservice
1629 class InfoBarAdditionalInfo:
1631 self["NimA"] = Pixmap()
1632 self["NimB"] = Pixmap()
1633 self["NimA_Active"] = Pixmap()
1634 self["NimB_Active"] = Pixmap()
1636 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1637 self["TimeshiftPossible"] = self["RecordingPossible"]
1638 self["ExtensionsAvailable"] = Boolean(fixed=1)
1640 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1641 res_mgr = eDVBResourceManager.getInstance()
1643 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1645 def tunerUseMaskChanged(self, mask):
1647 self["NimA_Active"].show()
1649 self["NimA_Active"].hide()
1651 self["NimB_Active"].show()
1653 self["NimB_Active"].hide()
1655 def checkTunerState(self, service):
1656 info = service and service.frontendInfo()
1657 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1658 if feNumber is None:
1668 def gotServiceEvent(self, ev):
1669 service = self.session.nav.getCurrentService()
1670 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1671 self.checkTunerState(service)
1673 class InfoBarNotifications:
1675 self.onExecBegin.append(self.checkNotifications)
1676 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1677 self.onClose.append(self.__removeNotification)
1679 def __removeNotification(self):
1680 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1682 def checkNotificationsIfExecing(self):
1684 self.checkNotifications()
1686 def checkNotifications(self):
1687 if len(Notifications.notifications):
1688 n = Notifications.notifications[0]
1690 Notifications.notifications = Notifications.notifications[1:]
1693 if n[3].has_key("onSessionOpenCallback"):
1694 n[3]["onSessionOpenCallback"]()
1695 del n[3]["onSessionOpenCallback"]
1698 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1700 dlg = self.session.open(n[1], *n[2], **n[3])
1702 # remember that this notification is currently active
1704 Notifications.current_notifications.append(d)
1705 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1707 def __notificationClosed(self, d):
1708 Notifications.current_notifications.remove(d)
1710 class InfoBarServiceNotifications:
1712 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1714 iPlayableService.evEnd: self.serviceHasEnded
1717 def serviceHasEnded(self):
1718 print "service end!"
1721 self.setSeekState(self.SEEK_STATE_PLAY)
1725 class InfoBarCueSheetSupport:
1731 ENABLE_RESUME_SUPPORT = False
1734 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1736 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1737 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1738 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1742 self.is_closing = False
1743 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1745 iPlayableService.evStart: self.__serviceStarted,
1748 def __serviceStarted(self):
1751 print "new service started! trying to download cuts!"
1752 self.downloadCuesheet()
1754 if self.ENABLE_RESUME_SUPPORT:
1757 for (pts, what) in self.cut_list:
1758 if what == self.CUT_TYPE_LAST:
1761 if last is not None:
1762 self.resume_point = last
1763 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1765 def playLastCB(self, answer):
1767 seekable = self.__getSeekable()
1768 if seekable is not None:
1769 seekable.seekTo(self.resume_point)
1771 def __getSeekable(self):
1772 service = self.session.nav.getCurrentService()
1775 return service.seek()
1777 def cueGetCurrentPosition(self):
1778 seek = self.__getSeekable()
1781 r = seek.getPlayPosition()
1786 def jumpPreviousNextMark(self, cmp, alternative=None):
1787 current_pos = self.cueGetCurrentPosition()
1788 if current_pos is None:
1790 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1791 if mark is not None:
1793 elif alternative is not None:
1798 seekable = self.__getSeekable()
1799 if seekable is not None:
1800 seekable.seekTo(pts)
1802 def jumpPreviousMark(self):
1803 # we add 2 seconds, so if the play position is <2s after
1804 # the mark, the mark before will be used
1805 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1807 def jumpNextMark(self):
1808 self.jumpPreviousNextMark(lambda x: x)
1810 def getNearestCutPoint(self, pts, cmp=abs):
1813 for cp in self.cut_list:
1814 diff = cmp(cp[0] - pts)
1815 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1819 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1820 current_pos = self.cueGetCurrentPosition()
1821 if current_pos is None:
1822 print "not seekable"
1825 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1827 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1829 return nearest_cutpoint
1831 self.removeMark(nearest_cutpoint)
1832 elif not onlyremove and not onlyreturn:
1833 self.addMark((current_pos, self.CUT_TYPE_MARK))
1838 def addMark(self, point):
1839 insort(self.cut_list, point)
1840 self.uploadCuesheet()
1842 def removeMark(self, point):
1843 self.cut_list.remove(point)
1844 self.uploadCuesheet()
1846 def __getCuesheet(self):
1847 service = self.session.nav.getCurrentService()
1850 return service.cueSheet()
1852 def uploadCuesheet(self):
1853 cue = self.__getCuesheet()
1856 print "upload failed, no cuesheet interface"
1858 cue.setCutList(self.cut_list)
1860 def downloadCuesheet(self):
1861 cue = self.__getCuesheet()
1864 print "upload failed, no cuesheet interface"
1866 self.cut_list = cue.getCutList()
1868 class InfoBarSummary(Screen):
1870 <screen position="0,0" size="132,64">
1871 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1872 <convert type="ClockToText">WithSeconds</convert>
1874 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1875 <convert type="ServiceName">Name</convert>
1879 def __init__(self, session, parent):
1880 Screen.__init__(self, session)
1881 self["CurrentService"] = CurrentService(self.session.nav)
1882 self["CurrentTime"] = Clock()
1884 class InfoBarSummarySupport:
1888 def createSummary(self):
1889 return InfoBarSummary
1891 class InfoBarTeletextPlugin:
1893 self.teletext_plugin = None
1895 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1896 self.teletext_plugin = p
1898 if self.teletext_plugin is not None:
1899 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1901 "startTeletext": (self.startTeletext, _("View teletext..."))
1904 print "no teletext plugin found!"
1906 def startTeletext(self):
1907 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1909 class InfoBarSubtitleSupport(object):
1911 object.__init__(self)
1912 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1913 self.__subtitles_enabled = False
1915 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1917 iPlayableService.evEnd: self.__serviceStopped,
1918 iPlayableService.evUpdatedInfo: self.__updatedInfo
1920 self.cached_subtitle_checked = False
1922 def __serviceStopped(self):
1923 self.subtitle_window.hide()
1924 self.__subtitles_enabled = False
1925 self.cached_subtitle_checked = False
1927 def __updatedInfo(self):
1928 if not self.cached_subtitle_checked:
1929 subtitle = self.getCurrentServiceSubtitle()
1930 self.cached_subtitle_checked = True
1932 self.__selected_subtitle = subtitle.getCachedSubtitle()
1933 if self.__selected_subtitle:
1934 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1935 self.subtitle_window.show()
1936 self.__subtitles_enabled = True
1938 def getCurrentServiceSubtitle(self):
1939 service = self.session.nav.getCurrentService()
1940 return service and service.subtitle()
1942 def setSubtitlesEnable(self, enable=True):
1943 subtitle = self.getCurrentServiceSubtitle()
1944 if enable and self.__selected_subtitle is not None:
1945 if subtitle and not self.__subtitles_enabled:
1946 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1947 self.subtitle_window.show()
1948 self.__subtitles_enabled = True
1951 subtitle.disableSubtitles(self.subtitle_window.instance)
1952 self.__subtitles_enabled = False
1953 self.subtitle_window.hide()
1955 def setSelectedSubtitle(self, subtitle):
1956 self.__selected_subtitle = subtitle
1958 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1959 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1961 class InfoBarServiceErrorPopupSupport:
1963 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1965 iPlayableService.evTuneFailed: self.__tuneFailed,
1966 iPlayableService.evStart: self.__serviceStarted
1968 self.__serviceStarted()
1970 def __serviceStarted(self):
1971 self.last_error = None
1972 Notifications.RemovePopup(id = "ZapError")
1974 def __tuneFailed(self):
1975 service = self.session.nav.getCurrentService()
1976 info = service and service.info()
1977 error = info and info.getInfo(iServiceInformation.sDVBState)
1979 if error == self.last_error:
1982 self.last_error = error
1985 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1986 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1987 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1988 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1989 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1990 eDVBServicePMTHandler.eventNewProgramInfo: None,
1991 eDVBServicePMTHandler.eventTuned: None,
1992 eDVBServicePMTHandler.eventSOF: None,
1993 eDVBServicePMTHandler.eventEOF: None
1996 error = errors.get(error) #this returns None when the key not exist in the dict
1998 if error is not None:
1999 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2001 Notifications.RemovePopup(id = "ZapError")