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")
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)
657 return HelpableActionMap.action(self, contexts, action)
659 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
661 "playpauseService": (self.playpauseService, _("pause")),
662 "pauseService": (self.pauseService, _("pause")),
663 "unPauseService": (self.unPauseService, _("continue")),
665 "seekFwd": (self.seekFwd, _("skip forward")),
666 "seekFwdDown": self.seekFwdDown,
667 "seekFwdUp": self.seekFwdUp,
668 "seekBack": (self.seekBack, _("skip backward")),
669 "seekBackDown": self.seekBackDown,
670 "seekBackUp": self.seekBackUp,
672 # give them a little more priority to win over color buttons
674 self["SeekActions"].setEnabled(False)
676 self.seekstate = self.SEEK_STATE_PLAY
677 self.onClose.append(self.delTimer)
679 self.fwdtimer = False
680 self.fwdKeyTimer = eTimer()
681 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
683 self.rwdtimer = False
684 self.rwdKeyTimer = eTimer()
685 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
687 self.onPlayStateChanged = [ ]
689 self.lockedBecauseOfSkipping = False
702 service = self.session.nav.getCurrentService()
706 seek = service.seek()
708 if seek is None or not seek.isCurrentlySeekable():
713 def isSeekable(self):
714 if self.getSeek() is None:
718 def __seekableStatusChanged(self):
719 print "seekable status changed!"
720 if not self.isSeekable():
721 self["SeekActions"].setEnabled(False)
722 print "not seekable, return to play"
723 self.setSeekState(self.SEEK_STATE_PLAY)
725 self["SeekActions"].setEnabled(True)
728 def __serviceStarted(self):
729 self.seekstate = self.SEEK_STATE_PLAY
730 self.__seekableStatusChanged()
732 def setSeekState(self, state):
733 service = self.session.nav.getCurrentService()
738 if not self.isSeekable():
739 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
740 state = self.SEEK_STATE_PLAY
742 pauseable = service.pause()
744 if pauseable is None:
745 print "not pauseable."
746 state = self.SEEK_STATE_PLAY
748 oldstate = self.seekstate
749 self.seekstate = state
752 if oldstate[i] != self.seekstate[i]:
753 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
755 for c in self.onPlayStateChanged:
758 self.checkSkipShowHideLock()
762 def playpauseService(self):
763 if self.seekstate != self.SEEK_STATE_PLAY:
764 self.unPauseService()
768 def pauseService(self):
769 if self.seekstate == self.SEEK_STATE_PAUSE:
770 print "pause, but in fact unpause"
771 self.unPauseService()
773 if self.seekstate == self.SEEK_STATE_PLAY:
774 print "yes, playing."
776 print "no", self.seekstate
778 self.setSeekState(self.SEEK_STATE_PAUSE);
780 def unPauseService(self):
782 if self.seekstate == self.SEEK_STATE_PLAY:
784 self.setSeekState(self.SEEK_STATE_PLAY)
786 def doSeek(self, seektime):
787 print "doseek", seektime
788 service = self.session.nav.getCurrentService()
792 seekable = self.getSeek()
796 seekable.seekTo(90 * seektime)
798 def seekFwdDown(self):
799 print "start fwd timer"
801 self.fwdKeyTimer.start(1000)
803 def seekBackDown(self):
804 print "start rewind timer"
806 self.rwdKeyTimer.start(1000)
811 self.fwdKeyTimer.stop()
812 self.fwdtimer = False
817 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
818 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
819 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
820 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
821 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
822 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
823 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
824 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
825 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
826 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
827 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
828 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
829 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
830 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
831 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
832 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
834 self.setSeekState(lookup[self.seekstate])
836 def seekBackUp(self):
839 self.rwdKeyTimer.stop()
840 self.rwdtimer = False
845 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
846 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
847 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
848 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
849 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
850 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
851 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
852 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
853 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
854 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
855 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
856 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
857 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
858 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
859 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
860 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
862 self.setSeekState(lookup[self.seekstate])
864 if self.seekstate == self.SEEK_STATE_PAUSE:
865 seekable = self.getSeek()
866 if seekable is not None:
867 seekable.seekRelative(-1, 3)
869 def fwdTimerFire(self):
870 print "Display seek fwd"
871 self.fwdKeyTimer.stop()
872 self.fwdtimer = False
873 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
875 def fwdSeekTo(self, minutes):
876 print "Seek", minutes, "minutes forward"
878 seekable = self.getSeek()
879 if seekable is not None:
880 seekable.seekRelative(1, minutes * 60 * 90000)
882 def rwdTimerFire(self):
884 self.rwdKeyTimer.stop()
885 self.rwdtimer = False
886 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
888 def rwdSeekTo(self, minutes):
890 self.fwdSeekTo(0 - minutes)
892 def checkSkipShowHideLock(self):
893 wantlock = self.seekstate != self.SEEK_STATE_PLAY
895 if config.usage.show_infobar_on_zap.value:
896 if self.lockedBecauseOfSkipping and not wantlock:
898 self.lockedBecauseOfSkipping = False
900 if wantlock and not self.lockedBecauseOfSkipping:
902 self.lockedBecauseOfSkipping = True
905 if self.seekstate == self.SEEK_STATE_EOF:
907 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
908 print "end of stream while seeking back, ignoring."
911 # if we are seeking, we try to end up ~1s before the end, and pause there.
912 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
913 self.setSeekState(self.SEEK_STATE_EOF)
914 self.seekRelativeToEnd(-90000)
916 self.setSeekState(self.SEEK_STATE_EOF)
919 self.setSeekState(self.SEEK_STATE_PLAY)
922 def seekRelative(self, diff):
923 seekable = self.getSeek()
924 if seekable is not None:
925 print "seekRelative: res:", seekable.seekRelative(1, diff)
929 def seekRelativeToEnd(self, diff):
930 assert diff <= 0, "diff is expected to be negative!"
932 # might sound like an evil hack, but:
933 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
934 # and we don't get that by passing 0 here (it would seek to begin).
938 # relative-to-end seeking is implemented as absolutes seeks with negative time
939 self.seekAbsolute(diff)
941 def seekAbsolute(self, abs):
942 seekable = self.getSeek()
943 if seekable is not None:
946 from Screens.PVRState import PVRState, TimeshiftState
948 class InfoBarPVRState:
949 def __init__(self, screen=PVRState):
950 self.onPlayStateChanged.append(self.__playStateChanged)
951 self.pvrStateDialog = self.session.instantiateDialog(screen)
952 self.onShow.append(self._mayShow)
953 self.onHide.append(self.pvrStateDialog.hide)
956 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
957 self.pvrStateDialog.show()
959 def __playStateChanged(self, state):
960 playstateString = state[3]
961 self.pvrStateDialog["state"].setText(playstateString)
964 class InfoBarTimeshiftState(InfoBarPVRState):
966 InfoBarPVRState.__init__(self, screen=TimeshiftState)
969 if self.execing and self.timeshift_enabled:
970 self.pvrStateDialog.show()
972 class InfoBarShowMovies:
974 # i don't really like this class.
975 # it calls a not further specified "movie list" on up/down/movieList,
976 # so this is not more than an action map
978 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
980 "movieList": (self.showMovies, "movie list"),
981 "up": (self.showMovies, "movie list"),
982 "down": (self.showMovies, "movie list")
985 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
989 # Timeshift works the following way:
990 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
991 # - normal playback TUNER unused PLAY enable disable disable
992 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
993 # - user presess pause again FILE record PLAY enable disable enable
994 # - user fast forwards FILE record FF enable disable enable
995 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
996 # - user backwards FILE record BACK # !! enable disable enable
1000 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1001 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1002 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1003 # - the user can now PVR around
1004 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1005 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1007 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1008 # - if the user rewinds, or press pause, timeshift will be activated again
1010 # note that a timeshift can be enabled ("recording") and
1011 # activated (currently time-shifting).
1013 class InfoBarTimeshift:
1015 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1017 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1018 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1020 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1022 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1023 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1024 }, prio=-1) # priority over record
1026 self.timeshift_enabled = 0
1027 self.timeshift_state = 0
1028 self.ts_rewind_timer = eTimer()
1029 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1031 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1033 iPlayableService.evStart: self.__serviceStarted,
1034 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1037 def getTimeshift(self):
1038 service = self.session.nav.getCurrentService()
1039 return service and service.timeshift()
1041 def startTimeshift(self):
1042 print "enable timeshift"
1043 ts = self.getTimeshift()
1045 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1046 print "no ts interface"
1049 if self.timeshift_enabled:
1050 print "hu, timeshift already enabled?"
1052 if not ts.startTimeshift():
1053 self.timeshift_enabled = 1
1055 # we remove the "relative time" for now.
1056 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1059 self.setSeekState(self.SEEK_STATE_PAUSE)
1061 # enable the "TimeshiftEnableActions", which will override
1062 # the startTimeshift actions
1063 self.__seekableStatusChanged()
1065 print "timeshift failed"
1067 def stopTimeshift(self):
1068 if not self.timeshift_enabled:
1070 print "disable timeshift"
1071 ts = self.getTimeshift()
1074 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1076 def stopTimeshiftConfirmed(self, confirmed):
1080 ts = self.getTimeshift()
1085 self.timeshift_enabled = 0
1088 self.__seekableStatusChanged()
1090 # activates timeshift, and seeks to (almost) the end
1091 def activateTimeshiftEnd(self, back = True):
1092 ts = self.getTimeshift()
1093 print "activateTimeshiftEnd"
1098 if ts.isTimeshiftActive():
1099 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1103 ts.activateTimeshift() # activate timeshift will automatically pause
1104 self.setSeekState(self.SEEK_STATE_PAUSE)
1105 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1108 self.ts_rewind_timer.start(200, 1)
1110 def rewindService(self):
1111 self.setSeekState(self.SEEK_STATE_BACK_16X)
1113 # same as activateTimeshiftEnd, but pauses afterwards.
1114 def activateTimeshiftEndAndPause(self):
1115 print "activateTimeshiftEndAndPause"
1116 #state = self.seekstate
1117 self.activateTimeshiftEnd(False)
1119 def __seekableStatusChanged(self):
1122 print "self.isSeekable", self.isSeekable()
1123 print "self.timeshift_enabled", self.timeshift_enabled
1125 # when this service is not seekable, but timeshift
1126 # is enabled, this means we can activate
1128 if not self.isSeekable() and self.timeshift_enabled:
1131 print "timeshift activate:", enabled
1132 self["TimeshiftActivateActions"].setEnabled(enabled)
1134 def __serviceStarted(self):
1135 self.timeshift_enabled = False
1136 self.__seekableStatusChanged()
1138 from Screens.PiPSetup import PiPSetup
1140 class InfoBarExtensions:
1141 EXTENSION_SINGLE = 0
1147 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1149 "extensions": (self.showExtensionSelection, _("view extensions...")),
1152 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1153 self.list.append((type, extension, key))
1155 def updateExtension(self, extension, key = None):
1156 self.extensionsList.append(extension)
1158 if self.extensionKeys.has_key(key):
1162 for x in self.availableKeys:
1163 if not self.extensionKeys.has_key(x):
1168 self.extensionKeys[key] = len(self.extensionsList) - 1
1170 def updateExtensions(self):
1171 self.extensionsList = []
1172 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1173 self.extensionKeys = {}
1175 if x[0] == self.EXTENSION_SINGLE:
1176 self.updateExtension(x[1], x[2])
1179 self.updateExtension(y[0], y[1])
1182 def showExtensionSelection(self):
1183 self.updateExtensions()
1184 extensionsList = self.extensionsList[:]
1187 for x in self.availableKeys:
1188 if self.extensionKeys.has_key(x):
1189 entry = self.extensionKeys[x]
1190 extension = self.extensionsList[entry]
1192 name = str(extension[0]())
1193 list.append((extension[0](), extension))
1195 extensionsList.remove(extension)
1197 extensionsList.remove(extension)
1198 for x in extensionsList:
1199 list.append((x[0](), x))
1200 keys += [""] * len(extensionsList)
1201 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1203 def extensionCallback(self, answer):
1204 if answer is not None:
1207 from Tools.BoundFunction import boundFunction
1209 # depends on InfoBarExtensions
1210 from Components.PluginComponent import plugins
1212 class InfoBarPlugins:
1214 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1216 def getPluginName(self, name):
1219 def getPluginList(self):
1221 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1222 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1225 def runPlugin(self, plugin):
1226 plugin(session = self.session)
1228 # depends on InfoBarExtensions
1229 class InfoBarSleepTimer:
1231 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1233 def available(self):
1236 def getSleepTimerName(self):
1237 return _("Sleep Timer")
1239 def showSleepTimerSetup(self):
1240 self.session.open(SleepTimerEdit)
1242 # depends on InfoBarExtensions
1245 self.session.pipshown = False
1247 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1248 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1249 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1251 def available(self):
1255 return self.session.pipshown
1257 def getShowHideName(self):
1258 if self.session.pipshown:
1259 return _("Disable Picture in Picture")
1261 return _("Activate Picture in Picture")
1263 def getSwapName(self):
1264 return _("Swap Services")
1266 def getMoveName(self):
1267 return _("Move Picture in Picture")
1270 if self.session.pipshown:
1271 del self.session.pip
1272 self.session.pipshown = False
1274 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1275 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1276 if self.session.pip.playService(newservice):
1277 self.session.pipshown = True
1278 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1280 self.session.pipshown = False
1281 del self.session.pip
1282 self.session.nav.playService(newservice)
1285 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1286 if self.session.pip.servicePath:
1287 servicepath = self.servicelist.getCurrentServicePath()
1288 ref=servicepath[len(servicepath)-1]
1289 pipref=self.session.pip.getCurrentService()
1290 self.session.pip.playService(swapservice)
1291 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1292 if pipref.toString() != ref.toString(): # is a subservice ?
1293 self.session.nav.stopService() # stop portal
1294 self.session.nav.playService(pipref) # start subservice
1295 self.session.pip.servicePath=servicepath
1298 self.session.open(PiPSetup, pip = self.session.pip)
1300 from RecordTimer import parseEvent
1302 class InfoBarInstantRecord:
1303 """Instant Record - handles the instantRecord action in order to
1304 start/stop instant records"""
1306 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1308 "instantRecord": (self.instantRecord, _("Instant Record...")),
1311 self["BlinkingPoint"] = BlinkingPixmapConditional()
1312 self["BlinkingPoint"].hide()
1313 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1315 def stopCurrentRecording(self, entry = -1):
1316 if entry is not None and entry != -1:
1317 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1318 self.recording.remove(self.recording[entry])
1320 def startInstantRecording(self, limitEvent = False):
1321 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1323 # try to get event info
1326 service = self.session.nav.getCurrentService()
1327 epg = eEPGCache.getInstance()
1328 event = epg.lookupEventTime(serviceref, -1, 0)
1330 info = service.info()
1331 ev = info.getEvent(0)
1337 end = time() + 3600 * 10
1338 name = "instant record"
1342 if event is not None:
1343 curEvent = parseEvent(event)
1345 description = curEvent[3]
1346 eventid = curEvent[4]
1351 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1353 data = (begin, end, name, description, eventid)
1355 recording = self.session.nav.recordWithTimer(serviceref, *data)
1356 recording.dontSave = True
1357 self.recording.append(recording)
1359 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1361 def isInstantRecordRunning(self):
1362 print "self.recording:", self.recording
1363 if len(self.recording) > 0:
1364 for x in self.recording:
1369 def recordQuestionCallback(self, answer):
1370 print "pre:\n", self.recording
1372 if answer is None or answer[1] == "no":
1375 recording = self.recording[:]
1377 if not x in self.session.nav.RecordTimer.timer_list:
1378 self.recording.remove(x)
1379 elif x.dontSave and x.isRunning():
1380 list.append(TimerEntryComponent(x, False))
1382 if answer[1] == "changeduration":
1383 if len(self.recording) == 1:
1384 self.changeDuration(0)
1386 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1387 elif answer[1] == "stop":
1388 if len(self.recording) == 1:
1389 self.stopCurrentRecording(0)
1391 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1392 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1394 if answer[1] == "event":
1396 if answer[1] == "manualduration":
1397 self.selectedEntry = len(self.recording)
1398 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1399 self.startInstantRecording(limitEvent = limitEvent)
1401 print "after:\n", self.recording
1403 def changeDuration(self, entry):
1404 if entry is not None:
1405 self.selectedEntry = entry
1406 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1408 def inputCallback(self, value):
1409 if value is not None:
1410 print "stopping recording after", int(value), "minutes."
1411 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1412 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1414 def instantRecord(self):
1416 stat = os_stat(resolveFilename(SCOPE_HDD))
1418 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1421 if self.isInstantRecordRunning():
1422 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1423 title=_("A recording is currently running.\nWhat do you want to do?"), \
1424 list=[(_("stop recording"), "stop"), \
1425 (_("change recording (duration)"), "changeduration"), \
1426 (_("add recording (indefinitely)"), "indefinitely"), \
1427 (_("add recording (stop after current event)"), "event"), \
1428 (_("add recording (enter recording duration)"), "manualduration"), \
1429 (_("do nothing"), "no")])
1431 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1432 title=_("Start recording?"), \
1433 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1434 (_("add recording (stop after current event)"), "event"), \
1435 (_("add recording (enter recording duration)"), "manualduration"), \
1436 (_("don't record"), "no")])
1438 from Tools.ISO639 import LanguageCodes
1440 class InfoBarAudioSelection:
1442 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1444 "audioSelection": (self.audioSelection, _("Audio Options...")),
1447 def audioSelection(self):
1448 service = self.session.nav.getCurrentService()
1449 audio = service and service.audioTracks()
1450 self.audioTracks = audio
1451 n = audio and audio.getNumberOfTracks() or 0
1452 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1454 print "tlist:", tlist
1456 self.audioChannel = service.audioChannel()
1459 i = audio.getTrackInfo(x)
1460 language = i.getLanguage()
1461 description = i.getDescription()
1463 if LanguageCodes.has_key(language):
1464 language = LanguageCodes[language][0]
1466 if len(description):
1467 description += " (" + language + ")"
1469 description = language
1471 tlist.append((description, x))
1473 selectedAudio = tlist[0][1]
1474 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1478 if x[1] != selectedAudio:
1483 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1484 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1486 del self.audioTracks
1488 def audioSelected(self, audio):
1489 if audio is not None:
1490 if isinstance(audio[1], str):
1491 if audio[1] == "mode":
1492 keys = ["red", "green", "yellow"]
1493 selection = self.audioChannel.getCurrentChannel()
1494 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1495 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1497 del self.audioChannel
1498 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1499 self.audioTracks.selectTrack(audio[1])
1501 del self.audioChannel
1502 del self.audioTracks
1504 def modeSelected(self, mode):
1505 if mode is not None:
1506 self.audioChannel.selectChannel(mode[1])
1507 del self.audioChannel
1509 class InfoBarSubserviceSelection:
1511 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1513 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1516 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1518 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1519 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1521 self["SubserviceQuickzapAction"].setEnabled(False)
1523 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1527 def checkSubservicesAvail(self, ev):
1528 if ev == iPlayableService.evUpdatedEventInfo:
1529 service = self.session.nav.getCurrentService()
1530 subservices = service and service.subServices()
1531 if not subservices or subservices.getNumberOfSubservices() == 0:
1532 self["SubserviceQuickzapAction"].setEnabled(False)
1534 def nextSubservice(self):
1535 self.changeSubservice(+1)
1537 def prevSubservice(self):
1538 self.changeSubservice(-1)
1540 def changeSubservice(self, direction):
1541 service = self.session.nav.getCurrentService()
1542 subservices = service and service.subServices()
1543 n = subservices and subservices.getNumberOfSubservices()
1546 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1548 if subservices.getSubservice(x).toString() == ref.toString():
1551 selection += direction
1556 newservice = subservices.getSubservice(selection)
1557 if newservice.valid():
1560 self.session.nav.playService(newservice)
1562 def subserviceSelection(self):
1563 service = self.session.nav.getCurrentService()
1564 subservices = service and service.subServices()
1565 self.bouquets = self.servicelist.getBouquetList()
1566 n = subservices and subservices.getNumberOfSubservices()
1569 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1572 i = subservices.getSubservice(x)
1573 if i.toString() == ref.toString():
1575 tlist.append((i.getName(), i))
1577 if self.bouquets and len(self.bouquets):
1578 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1579 if config.usage.multibouquet.value:
1580 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1582 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1585 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1586 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1589 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1591 def subserviceSelected(self, service):
1593 if not service is None:
1594 if isinstance(service[1], str):
1595 if service[1] == "quickzap":
1596 from Screens.SubservicesQuickzap import SubservicesQuickzap
1597 self.session.open(SubservicesQuickzap, service[2])
1599 self["SubserviceQuickzapAction"].setEnabled(True)
1600 self.session.nav.playService(service[1])
1602 def addSubserviceToBouquetCallback(self, service):
1603 if len(service) > 1 and isinstance(service[1], eServiceReference):
1604 self.selectedSubservice = service
1605 if self.bouquets is None:
1608 cnt = len(self.bouquets)
1609 if cnt > 1: # show bouquet list
1610 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1611 elif cnt == 1: # add to only one existing bouquet
1612 self.addSubserviceToBouquet(self.bouquets[0][1])
1613 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1615 def bouquetSelClosed(self, confirmed):
1617 del self.selectedSubservice
1619 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1621 def addSubserviceToBouquet(self, dest):
1622 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1624 self.bsel.close(True)
1626 del self.selectedSubservice
1628 class InfoBarAdditionalInfo:
1630 self["NimA"] = Pixmap()
1631 self["NimB"] = Pixmap()
1632 self["NimA_Active"] = Pixmap()
1633 self["NimB_Active"] = Pixmap()
1635 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1636 self["TimeshiftPossible"] = self["RecordingPossible"]
1637 self["ExtensionsAvailable"] = Boolean(fixed=1)
1639 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1640 res_mgr = eDVBResourceManager.getInstance()
1642 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1644 def tunerUseMaskChanged(self, mask):
1646 self["NimA_Active"].show()
1648 self["NimA_Active"].hide()
1650 self["NimB_Active"].show()
1652 self["NimB_Active"].hide()
1654 def checkTunerState(self, service):
1655 info = service and service.frontendInfo()
1656 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1657 if feNumber is None:
1667 def gotServiceEvent(self, ev):
1668 service = self.session.nav.getCurrentService()
1669 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1670 self.checkTunerState(service)
1672 class InfoBarNotifications:
1674 self.onExecBegin.append(self.checkNotifications)
1675 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1676 self.onClose.append(self.__removeNotification)
1678 def __removeNotification(self):
1679 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1681 def checkNotificationsIfExecing(self):
1683 self.checkNotifications()
1685 def checkNotifications(self):
1686 if len(Notifications.notifications):
1687 n = Notifications.notifications[0]
1689 Notifications.notifications = Notifications.notifications[1:]
1692 if n[3].has_key("onSessionOpenCallback"):
1693 n[3]["onSessionOpenCallback"]()
1694 del n[3]["onSessionOpenCallback"]
1697 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1699 dlg = self.session.open(n[1], *n[2], **n[3])
1701 # remember that this notification is currently active
1703 Notifications.current_notifications.append(d)
1704 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1706 def __notificationClosed(self, d):
1707 Notifications.current_notifications.remove(d)
1709 class InfoBarServiceNotifications:
1711 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1713 iPlayableService.evEnd: self.serviceHasEnded
1716 def serviceHasEnded(self):
1717 print "service end!"
1720 self.setSeekState(self.SEEK_STATE_PLAY)
1724 class InfoBarCueSheetSupport:
1730 ENABLE_RESUME_SUPPORT = False
1733 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1735 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1736 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1737 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1741 self.is_closing = False
1742 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1744 iPlayableService.evStart: self.__serviceStarted,
1747 def __serviceStarted(self):
1750 print "new service started! trying to download cuts!"
1751 self.downloadCuesheet()
1753 if self.ENABLE_RESUME_SUPPORT:
1756 for (pts, what) in self.cut_list:
1757 if what == self.CUT_TYPE_LAST:
1760 if last is not None:
1761 self.resume_point = last
1762 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1764 def playLastCB(self, answer):
1766 seekable = self.__getSeekable()
1767 if seekable is not None:
1768 seekable.seekTo(self.resume_point)
1770 def __getSeekable(self):
1771 service = self.session.nav.getCurrentService()
1774 return service.seek()
1776 def cueGetCurrentPosition(self):
1777 seek = self.__getSeekable()
1780 r = seek.getPlayPosition()
1785 def jumpPreviousNextMark(self, cmp, alternative=None):
1786 current_pos = self.cueGetCurrentPosition()
1787 if current_pos is None:
1789 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1790 if mark is not None:
1792 elif alternative is not None:
1797 seekable = self.__getSeekable()
1798 if seekable is not None:
1799 seekable.seekTo(pts)
1801 def jumpPreviousMark(self):
1802 # we add 2 seconds, so if the play position is <2s after
1803 # the mark, the mark before will be used
1804 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1806 def jumpNextMark(self):
1807 self.jumpPreviousNextMark(lambda x: x)
1809 def getNearestCutPoint(self, pts, cmp=abs):
1812 for cp in self.cut_list:
1813 diff = cmp(cp[0] - pts)
1814 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1818 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1819 current_pos = self.cueGetCurrentPosition()
1820 if current_pos is None:
1821 print "not seekable"
1824 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1826 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1828 return nearest_cutpoint
1830 self.removeMark(nearest_cutpoint)
1831 elif not onlyremove and not onlyreturn:
1832 self.addMark((current_pos, self.CUT_TYPE_MARK))
1837 def addMark(self, point):
1838 insort(self.cut_list, point)
1839 self.uploadCuesheet()
1841 def removeMark(self, point):
1842 self.cut_list.remove(point)
1843 self.uploadCuesheet()
1845 def __getCuesheet(self):
1846 service = self.session.nav.getCurrentService()
1849 return service.cueSheet()
1851 def uploadCuesheet(self):
1852 cue = self.__getCuesheet()
1855 print "upload failed, no cuesheet interface"
1857 cue.setCutList(self.cut_list)
1859 def downloadCuesheet(self):
1860 cue = self.__getCuesheet()
1863 print "upload failed, no cuesheet interface"
1865 self.cut_list = cue.getCutList()
1867 class InfoBarSummary(Screen):
1869 <screen position="0,0" size="132,64">
1870 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1871 <convert type="ClockToText">WithSeconds</convert>
1873 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1874 <convert type="ServiceName">Name</convert>
1878 def __init__(self, session, parent):
1879 Screen.__init__(self, session)
1880 self["CurrentService"] = CurrentService(self.session.nav)
1881 self["CurrentTime"] = Clock()
1883 class InfoBarSummarySupport:
1887 def createSummary(self):
1888 return InfoBarSummary
1890 class InfoBarTeletextPlugin:
1892 self.teletext_plugin = None
1894 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1895 self.teletext_plugin = p
1897 if self.teletext_plugin is not None:
1898 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1900 "startTeletext": (self.startTeletext, _("View teletext..."))
1903 print "no teletext plugin found!"
1905 def startTeletext(self):
1906 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1908 class InfoBarSubtitleSupport(object):
1910 object.__init__(self)
1911 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1912 self.__subtitles_enabled = False
1914 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1916 iPlayableService.evEnd: self.__serviceStopped,
1917 iPlayableService.evUpdatedInfo: self.__updatedInfo
1919 self.cached_subtitle_checked = False
1921 def __serviceStopped(self):
1922 self.subtitle_window.hide()
1923 self.__subtitles_enabled = False
1924 self.cached_subtitle_checked = False
1926 def __updatedInfo(self):
1927 if not self.cached_subtitle_checked:
1928 subtitle = self.getCurrentServiceSubtitle()
1929 self.cached_subtitle_checked = True
1931 self.__selected_subtitle = subtitle.getCachedSubtitle()
1932 if self.__selected_subtitle:
1933 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1934 self.subtitle_window.show()
1935 self.__subtitles_enabled = True
1937 def getCurrentServiceSubtitle(self):
1938 service = self.session.nav.getCurrentService()
1939 return service and service.subtitle()
1941 def setSubtitlesEnable(self, enable=True):
1942 subtitle = self.getCurrentServiceSubtitle()
1943 if enable and self.__selected_subtitle is not None:
1944 if subtitle and not self.__subtitles_enabled:
1945 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1946 self.subtitle_window.show()
1947 self.__subtitles_enabled = True
1950 subtitle.disableSubtitles(self.subtitle_window.instance)
1951 self.__subtitles_enabled = False
1952 self.subtitle_window.hide()
1954 def setSelectedSubtitle(self, subtitle):
1955 self.__selected_subtitle = subtitle
1957 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1958 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1960 class InfoBarServiceErrorPopupSupport:
1962 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1964 iPlayableService.evTuneFailed: self.__tuneFailed,
1965 iPlayableService.evStart: self.__serviceStarted
1967 self.__serviceStarted()
1969 def __serviceStarted(self):
1970 self.last_error = None
1971 Notifications.RemovePopup(id = "ZapError")
1973 def __tuneFailed(self):
1974 service = self.session.nav.getCurrentService()
1975 info = service and service.info()
1976 error = info and info.getInfo(iServiceInformation.sDVBState)
1978 if error == self.last_error:
1981 self.last_error = error
1984 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1985 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1986 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1987 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1988 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1989 eDVBServicePMTHandler.eventNewProgramInfo: None,
1990 eDVBServicePMTHandler.eventTuned: None,
1991 eDVBServicePMTHandler.eventSOF: None,
1992 eDVBServicePMTHandler.eventEOF: None
1995 error = errors.get(error) #this returns None when the key not exist in the dict
1997 if error is not None:
1998 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2000 Notifications.RemovePopup(id = "ZapError")