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.__state = self.STATE_SHOWN
74 self.hideTimer = eTimer()
75 self.hideTimer.timeout.get().append(self.doTimerHide)
76 self.hideTimer.start(5000, True)
78 self.onShow.append(self.__onShow)
79 self.onHide.append(self.__onHide)
82 self.__state = self.STATE_SHOWN
85 def startHideTimer(self):
86 if self.__state == self.STATE_SHOWN and not self.__locked:
87 idx = config.usage.infobar_timeout.index
89 self.hideTimer.start(idx*1000, True)
92 self.__state = self.STATE_HIDDEN
98 def doTimerHide(self):
100 if self.__state == self.STATE_SHOWN:
103 def toggleShow(self):
104 if self.__state == self.STATE_SHOWN:
106 self.hideTimer.stop()
107 elif self.__state == self.STATE_HIDDEN:
111 self.__locked = self.__locked + 1
114 self.hideTimer.stop()
116 def unlockShow(self):
117 self.__locked = self.__locked - 1
119 self.startHideTimer()
121 # def startShow(self):
122 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
123 # self.__state = self.STATE_SHOWN
125 # def startHide(self):
126 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
127 # self.__state = self.STATE_HIDDEN
129 class NumberZap(Screen):
136 self.close(int(self["number"].getText()))
138 def keyNumberGlobal(self, number):
139 self.Timer.start(3000, True) #reset timer
140 self.field = self.field + str(number)
141 self["number"].setText(self.field)
142 if len(self.field) >= 4:
145 def __init__(self, session, number):
146 Screen.__init__(self, session)
147 self.field = str(number)
149 self["channel"] = Label(_("Channel:"))
151 self["number"] = Label(self.field)
153 self["actions"] = NumberActionMap( [ "SetupActions" ],
157 "1": self.keyNumberGlobal,
158 "2": self.keyNumberGlobal,
159 "3": self.keyNumberGlobal,
160 "4": self.keyNumberGlobal,
161 "5": self.keyNumberGlobal,
162 "6": self.keyNumberGlobal,
163 "7": self.keyNumberGlobal,
164 "8": self.keyNumberGlobal,
165 "9": self.keyNumberGlobal,
166 "0": self.keyNumberGlobal
169 self.Timer = eTimer()
170 self.Timer.timeout.get().append(self.keyOK)
171 self.Timer.start(3000, True)
173 class InfoBarNumberZap:
174 """ Handles an initial number for NumberZapping """
176 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
178 "1": self.keyNumberGlobal,
179 "2": self.keyNumberGlobal,
180 "3": self.keyNumberGlobal,
181 "4": self.keyNumberGlobal,
182 "5": self.keyNumberGlobal,
183 "6": self.keyNumberGlobal,
184 "7": self.keyNumberGlobal,
185 "8": self.keyNumberGlobal,
186 "9": self.keyNumberGlobal,
187 "0": self.keyNumberGlobal,
190 def keyNumberGlobal(self, number):
191 # print "You pressed number " + str(number)
193 self.servicelist.recallPrevService()
194 if config.usage.show_infobar_on_zap.value:
197 self.session.openWithCallback(self.numberEntered, NumberZap, number)
199 def numberEntered(self, retval):
200 # print self.servicelist
202 self.zapToNumber(retval)
204 def searchNumberHelper(self, serviceHandler, num, bouquet):
205 servicelist = serviceHandler.list(bouquet)
206 if not servicelist is None:
208 serviceIterator = servicelist.getNext()
209 if not serviceIterator.valid(): #check end of list
211 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
214 if not num: #found service with searched number ?
215 return serviceIterator, 0
218 def zapToNumber(self, number):
219 bouquet = self.servicelist.bouquet_root
221 serviceHandler = eServiceCenter.getInstance()
222 if not config.usage.multibouquet.value:
223 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
225 bouquetlist = serviceHandler.list(bouquet)
226 if not bouquetlist is None:
228 bouquet = bouquetlist.getNext()
229 if not bouquet.valid(): #check end of list
231 if bouquet.flags & eServiceReference.isDirectory:
232 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
233 if not service is None:
234 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
235 self.servicelist.clearPath()
236 if self.servicelist.bouquet_root != bouquet:
237 self.servicelist.enterPath(self.servicelist.bouquet_root)
238 self.servicelist.enterPath(bouquet)
239 self.servicelist.setCurrentSelection(service) #select the service in servicelist
240 self.servicelist.zap()
242 config.misc.initialchannelselection = ConfigBoolean(default = True)
244 class InfoBarChannelSelection:
245 """ ChannelSelection - handles the channelSelection dialog and the initial
246 channelChange actions which open the channelSelection dialog """
249 self.servicelist = self.session.instantiateDialog(ChannelSelection)
251 if config.misc.initialchannelselection.value:
252 self.onShown.append(self.firstRun)
254 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
256 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
257 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
258 "zapUp": (self.zapUp, _("previous channel")),
259 "zapDown": (self.zapDown, _("next channel")),
260 "historyBack": (self.historyBack, _("previous channel in history")),
261 "historyNext": (self.historyNext, _("next channel in history")),
262 "openServiceList": (self.openServiceList, _("open servicelist")),
265 def showTvChannelList(self, zap=False):
266 self.servicelist.setModeTv()
268 self.servicelist.zap()
269 self.session.execDialog(self.servicelist)
271 def showRadioChannelList(self, zap=False):
272 self.servicelist.setModeRadio()
274 self.servicelist.zap()
275 self.session.execDialog(self.servicelist)
278 self.onShown.remove(self.firstRun)
279 config.misc.initialchannelselection.value = False
280 config.misc.initialchannelselection.save()
281 self.switchChannelDown()
283 def historyBack(self):
284 self.servicelist.historyBack()
286 def historyNext(self):
287 self.servicelist.historyNext()
289 def switchChannelUp(self):
290 self.servicelist.moveUp()
291 self.session.execDialog(self.servicelist)
293 def switchChannelDown(self):
294 self.servicelist.moveDown()
295 self.session.execDialog(self.servicelist)
297 def openServiceList(self):
298 self.session.execDialog(self.servicelist)
301 if self.servicelist.inBouquet():
302 prev = self.servicelist.getCurrentSelection()
304 prev = prev.toString()
306 if config.usage.quickzap_bouquet_change.value:
307 if self.servicelist.atBegin():
308 self.servicelist.prevBouquet()
309 self.servicelist.moveUp()
310 cur = self.servicelist.getCurrentSelection()
311 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
314 self.servicelist.moveUp()
315 self.servicelist.zap()
316 if config.usage.show_infobar_on_zap.value:
320 if self.servicelist.inBouquet():
321 prev = self.servicelist.getCurrentSelection()
323 prev = prev.toString()
325 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
326 self.servicelist.nextBouquet()
328 self.servicelist.moveDown()
329 cur = self.servicelist.getCurrentSelection()
330 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
333 self.servicelist.moveDown()
334 self.servicelist.zap()
335 if config.usage.show_infobar_on_zap.value:
339 """ Handles a menu action, to open the (main) menu """
341 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
343 "mainMenu": (self.mainMenu, _("Enter main menu...")),
345 self.session.infobar = None
348 print "loading mainmenu XML..."
349 menu = mdom.childNodes[0]
350 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
352 self.session.infobar = self
353 # so we can access the currently active infobar from screens opened from within the mainmenu
354 # at the moment used from the SubserviceSelection
356 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
358 def mainMenuClosed(self, *val):
359 self.session.infobar = None
361 class InfoBarSimpleEventView:
362 """ Opens the Eventview for now/next """
364 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
366 "showEventInfo": (self.openEventView, _("show event details")),
369 def openEventView(self):
371 service = self.session.nav.getCurrentService()
372 ref = self.session.nav.getCurrentlyPlayingServiceReference()
373 info = service.info()
376 self.epglist.append(ptr)
379 self.epglist.append(ptr)
380 if len(self.epglist) > 0:
381 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
383 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
384 if len(self.epglist) > 1:
385 tmp = self.epglist[0]
386 self.epglist[0]=self.epglist[1]
388 setEvent(self.epglist[0])
391 """ EPG - Opens an EPG list when the showEPGList action fires """
393 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
395 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
398 self.is_now_next = False
400 self.bouquetSel = None
401 self.eventView = None
402 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
404 "showEventInfo": (self.openEventView, _("show EPG...")),
407 def zapToService(self, service):
408 if not service is None:
409 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
410 self.servicelist.clearPath()
411 if self.servicelist.bouquet_root != self.epg_bouquet:
412 self.servicelist.enterPath(self.servicelist.bouquet_root)
413 self.servicelist.enterPath(self.epg_bouquet)
414 self.servicelist.setCurrentSelection(service) #select the service in servicelist
415 self.servicelist.zap()
417 def getBouquetServices(self, bouquet):
419 servicelist = eServiceCenter.getInstance().list(bouquet)
420 if not servicelist is None:
422 service = servicelist.getNext()
423 if not service.valid(): #check if end of list
425 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
427 services.append(ServiceReference(service))
430 def openBouquetEPG(self, bouquet, withCallback=True):
431 services = self.getBouquetServices(bouquet)
433 self.epg_bouquet = bouquet
435 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
437 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
439 def changeBouquetCB(self, direction, epg):
442 self.bouquetSel.down()
445 bouquet = self.bouquetSel.getCurrent()
446 services = self.getBouquetServices(bouquet)
448 self.epg_bouquet = bouquet
449 epg.setServices(services)
451 def closed(self, ret=False):
452 closedScreen = self.dlg_stack.pop()
453 if self.bouquetSel and closedScreen == self.bouquetSel:
454 self.bouquetSel = None
455 elif self.eventView and closedScreen == self.eventView:
456 self.eventView = None
458 dlgs=len(self.dlg_stack)
460 self.dlg_stack[dlgs-1].close(dlgs > 1)
462 def openMultiServiceEPG(self, withCallback=True):
463 bouquets = self.servicelist.getBouquetList()
468 if cnt > 1: # show bouquet list
470 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
471 self.dlg_stack.append(self.bouquetSel)
473 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
475 self.openBouquetEPG(bouquets[0][1], withCallback)
477 def openSingleServiceEPG(self):
478 ref=self.session.nav.getCurrentlyPlayingServiceReference()
479 self.session.open(EPGSelection, ref)
481 def openSimilarList(self, eventid, refstr):
482 self.session.open(EPGSelection, refstr, None, eventid)
484 def getNowNext(self):
486 service = self.session.nav.getCurrentService()
487 info = service and service.info()
488 ptr = info and info.getEvent(0)
490 self.epglist.append(ptr)
491 ptr = info and info.getEvent(1)
493 self.epglist.append(ptr)
495 def __evEventInfoChanged(self):
496 if self.is_now_next and len(self.dlg_stack) == 1:
498 assert self.eventView
499 if len(self.epglist):
500 self.eventView.setEvent(self.epglist[0])
502 def openEventView(self):
503 ref = self.session.nav.getCurrentlyPlayingServiceReference()
505 if len(self.epglist) == 0:
506 self.is_now_next = False
507 epg = eEPGCache.getInstance()
508 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
510 self.epglist.append(ptr)
511 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
513 self.epglist.append(ptr)
515 self.is_now_next = True
516 if len(self.epglist) > 0:
517 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
518 self.dlg_stack.append(self.eventView)
520 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
521 self.openMultiServiceEPG(False)
523 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
524 if len(self.epglist) > 1:
525 tmp = self.epglist[0]
526 self.epglist[0]=self.epglist[1]
528 setEvent(self.epglist[0])
531 """provides a snr/agc/ber display"""
533 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
536 """provides a current/next event info display"""
538 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
539 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
541 class InfoBarRdsDecoder:
542 """provides RDS and Rass support/display"""
544 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
545 self.rass_interactive = None
547 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
549 iPlayableService.evEnd: self.__serviceStopped,
550 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
553 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
555 "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
558 self["RdsActions"].setEnabled(False)
560 self.onLayoutFinish.append(self.rds_display.show)
561 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
563 def RassInteractivePossibilityChanged(self, state):
564 self["RdsActions"].setEnabled(state)
566 def RassSlidePicChanged(self):
567 if not self.rass_interactive:
568 service = self.session.nav.getCurrentService()
569 decoder = service and service.rdsDecoder()
571 decoder.showRassSlidePicture()
573 def __serviceStopped(self):
574 if self.rass_interactive is not None:
575 rass_interactive = self.rass_interactive
576 self.rass_interactive = None
577 rass_interactive.close()
579 def startRassInteractive(self):
580 self.rds_display.hide()
581 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
583 def RassInteractiveClosed(self, *val):
584 if self.rass_interactive is not None:
585 self.rass_interactive = None
586 self.RassSlidePicChanged()
587 self.rds_display.show()
589 class InfoBarServiceName:
591 self["CurrentService"] = CurrentService(self.session.nav)
594 """handles actions like seeking, pause"""
596 # ispause, isff, issm
597 SEEK_STATE_PLAY = (0, 0, 0, ">")
598 SEEK_STATE_PAUSE = (1, 0, 0, "||")
599 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
600 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
601 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
602 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
603 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
604 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
606 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
607 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
608 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
609 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
611 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
612 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
613 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
616 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
618 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
619 iPlayableService.evStart: self.__serviceStarted,
621 iPlayableService.evEOF: self.__evEOF,
622 iPlayableService.evSOF: self.__evSOF,
625 class InfoBarSeekActionMap(HelpableActionMap):
626 def __init__(self, screen, *args, **kwargs):
627 HelpableActionMap.__init__(self, screen, *args, **kwargs)
630 def action(self, contexts, action):
631 if action[:5] == "seek:":
632 time = int(action[5:])
633 self.screen.seekRelative(time * 90000)
636 return HelpableActionMap.action(self, contexts, action)
638 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
640 "playpauseService": (self.playpauseService, _("pause")),
641 "pauseService": (self.pauseService, _("pause")),
642 "unPauseService": (self.unPauseService, _("continue")),
644 "seekFwd": (self.seekFwd, _("skip forward")),
645 "seekFwdDown": self.seekFwdDown,
646 "seekFwdUp": self.seekFwdUp,
647 "seekBack": (self.seekBack, _("skip backward")),
648 "seekBackDown": self.seekBackDown,
649 "seekBackUp": self.seekBackUp,
651 # give them a little more priority to win over color buttons
653 self["SeekActions"].setEnabled(False)
655 self.seekstate = self.SEEK_STATE_PLAY
656 self.onClose.append(self.delTimer)
658 self.fwdtimer = False
659 self.fwdKeyTimer = eTimer()
660 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
662 self.rwdtimer = False
663 self.rwdKeyTimer = eTimer()
664 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
666 self.onPlayStateChanged = [ ]
668 self.lockedBecauseOfSkipping = False
681 service = self.session.nav.getCurrentService()
685 seek = service.seek()
687 if seek is None or not seek.isCurrentlySeekable():
692 def isSeekable(self):
693 if self.getSeek() is None:
697 def __seekableStatusChanged(self):
698 print "seekable status changed!"
699 if not self.isSeekable():
700 self["SeekActions"].setEnabled(False)
701 print "not seekable, return to play"
702 self.setSeekState(self.SEEK_STATE_PLAY)
704 self["SeekActions"].setEnabled(True)
707 def __serviceStarted(self):
708 self.seekstate = self.SEEK_STATE_PLAY
710 def setSeekState(self, state):
711 service = self.session.nav.getCurrentService()
716 if not self.isSeekable():
717 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
718 state = self.SEEK_STATE_PLAY
720 pauseable = service.pause()
722 if pauseable is None:
723 print "not pauseable."
724 state = self.SEEK_STATE_PLAY
726 oldstate = self.seekstate
727 self.seekstate = state
730 if oldstate[i] != self.seekstate[i]:
731 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
733 for c in self.onPlayStateChanged:
736 self.checkSkipShowHideLock()
740 def playpauseService(self):
741 if self.seekstate != self.SEEK_STATE_PLAY:
742 self.unPauseService()
746 def pauseService(self):
747 if self.seekstate == self.SEEK_STATE_PAUSE:
748 print "pause, but in fact unpause"
749 self.unPauseService()
751 if self.seekstate == self.SEEK_STATE_PLAY:
752 print "yes, playing."
754 print "no", self.seekstate
756 self.setSeekState(self.SEEK_STATE_PAUSE);
758 def unPauseService(self):
760 if self.seekstate == self.SEEK_STATE_PLAY:
762 self.setSeekState(self.SEEK_STATE_PLAY)
764 def doSeek(self, seektime):
765 print "doseek", seektime
766 service = self.session.nav.getCurrentService()
770 seekable = self.getSeek()
774 seekable.seekTo(90 * seektime)
776 def seekFwdDown(self):
777 print "start fwd timer"
779 self.fwdKeyTimer.start(1000)
781 def seekBackDown(self):
782 print "start rewind timer"
784 self.rwdKeyTimer.start(1000)
789 self.fwdKeyTimer.stop()
790 self.fwdtimer = False
795 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
796 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
797 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
798 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
799 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
800 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
801 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
802 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
803 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
804 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
805 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
806 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
807 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
808 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
809 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
811 self.setSeekState(lookup[self.seekstate])
813 def seekBackUp(self):
816 self.rwdKeyTimer.stop()
817 self.rwdtimer = False
822 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
823 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
824 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
825 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
826 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
827 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
828 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
829 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
830 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
831 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
832 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
833 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
834 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
835 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
836 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
838 self.setSeekState(lookup[self.seekstate])
840 if self.seekstate == self.SEEK_STATE_PAUSE:
841 seekable = self.getSeek()
842 if seekable is not None:
843 seekable.seekRelative(-1, 3)
845 def fwdTimerFire(self):
846 print "Display seek fwd"
847 self.fwdKeyTimer.stop()
848 self.fwdtimer = False
849 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
851 def fwdSeekTo(self, minutes):
852 print "Seek", minutes, "minutes forward"
854 seekable = self.getSeek()
855 if seekable is not None:
856 seekable.seekRelative(1, minutes * 60 * 90000)
858 def rwdTimerFire(self):
860 self.rwdKeyTimer.stop()
861 self.rwdtimer = False
862 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
864 def rwdSeekTo(self, minutes):
866 self.fwdSeekTo(0 - minutes)
868 def checkSkipShowHideLock(self):
869 wantlock = self.seekstate != self.SEEK_STATE_PLAY
871 if config.usage.show_infobar_on_zap.value:
872 if self.lockedBecauseOfSkipping and not wantlock:
874 self.lockedBecauseOfSkipping = False
876 if wantlock and not self.lockedBecauseOfSkipping:
878 self.lockedBecauseOfSkipping = True
881 if self.seekstate != self.SEEK_STATE_PLAY:
882 self.setSeekState(self.SEEK_STATE_PAUSE)
884 #self.getSeek().seekRelative(1, -90000)
885 self.setSeekState(self.SEEK_STATE_PLAY)
887 self.setSeekState(self.SEEK_STATE_PAUSE)
890 self.setSeekState(self.SEEK_STATE_PLAY)
893 def seekRelative(self, diff):
894 seekable = self.getSeek()
895 if seekable is not None:
896 seekable.seekRelative(1, diff)
898 def seekAbsolute(self, abs):
899 seekable = self.getSeek()
900 if seekable is not None:
903 from Screens.PVRState import PVRState, TimeshiftState
905 class InfoBarPVRState:
906 def __init__(self, screen=PVRState):
907 self.onPlayStateChanged.append(self.__playStateChanged)
908 self.pvrStateDialog = self.session.instantiateDialog(screen)
909 self.onShow.append(self._mayShow)
910 self.onHide.append(self.pvrStateDialog.hide)
913 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
914 self.pvrStateDialog.show()
916 def __playStateChanged(self, state):
917 playstateString = state[3]
918 self.pvrStateDialog["state"].setText(playstateString)
921 class InfoBarTimeshiftState(InfoBarPVRState):
923 InfoBarPVRState.__init__(self, screen=TimeshiftState)
926 if self.execing and self.timeshift_enabled:
927 self.pvrStateDialog.show()
929 class InfoBarShowMovies:
931 # i don't really like this class.
932 # it calls a not further specified "movie list" on up/down/movieList,
933 # so this is not more than an action map
935 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
937 "movieList": (self.showMovies, "movie list"),
938 "up": (self.showMovies, "movie list"),
939 "down": (self.showMovies, "movie list")
942 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
946 # Timeshift works the following way:
947 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
948 # - normal playback TUNER unused PLAY enable disable disable
949 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
950 # - user presess pause again FILE record PLAY enable disable enable
951 # - user fast forwards FILE record FF enable disable enable
952 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
953 # - user backwards FILE record BACK # !! enable disable enable
957 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
958 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
959 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
960 # - the user can now PVR around
961 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
962 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
964 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
965 # - if the user rewinds, or press pause, timeshift will be activated again
967 # note that a timeshift can be enabled ("recording") and
968 # activated (currently time-shifting).
970 class InfoBarTimeshift:
972 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
974 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
975 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
977 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
979 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
980 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
981 }, prio=-1) # priority over record
983 self.timeshift_enabled = 0
984 self.timeshift_state = 0
985 self.ts_pause_timer = eTimer()
986 self.ts_pause_timer.timeout.get().append(self.pauseService)
988 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
990 iPlayableService.evStart: self.__serviceStarted,
991 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
994 def getTimeshift(self):
995 service = self.session.nav.getCurrentService()
996 return service and service.timeshift()
998 def startTimeshift(self):
999 print "enable timeshift"
1000 ts = self.getTimeshift()
1002 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1003 print "no ts interface"
1006 if self.timeshift_enabled:
1007 print "hu, timeshift already enabled?"
1009 if not ts.startTimeshift():
1010 self.timeshift_enabled = 1
1012 # we remove the "relative time" for now.
1013 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1016 self.setSeekState(self.SEEK_STATE_PAUSE)
1018 # enable the "TimeshiftEnableActions", which will override
1019 # the startTimeshift actions
1020 self.__seekableStatusChanged()
1022 print "timeshift failed"
1024 def stopTimeshift(self):
1025 if not self.timeshift_enabled:
1027 print "disable timeshift"
1028 ts = self.getTimeshift()
1031 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1033 def stopTimeshiftConfirmed(self, confirmed):
1037 ts = self.getTimeshift()
1042 self.timeshift_enabled = 0
1045 self.__seekableStatusChanged()
1047 # activates timeshift, and seeks to (almost) the end
1048 def activateTimeshiftEnd(self):
1049 ts = self.getTimeshift()
1054 if ts.isTimeshiftActive():
1055 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1058 self.setSeekState(self.SEEK_STATE_PLAY)
1059 ts.activateTimeshift()
1060 self.seekRelative(0)
1062 # same as activateTimeshiftEnd, but pauses afterwards.
1063 def activateTimeshiftEndAndPause(self):
1064 state = self.seekstate
1065 self.activateTimeshiftEnd()
1067 # well, this is "andPause", but it could be pressed from pause,
1068 # when pausing on the (fake-)"live" picture, so an un-pause
1071 print "now, pauseService"
1072 if state == self.SEEK_STATE_PLAY:
1073 print "is PLAYING, start pause timer"
1074 self.ts_pause_timer.start(200, 1)
1077 self.unPauseService()
1079 def __seekableStatusChanged(self):
1082 print "self.isSeekable", self.isSeekable()
1083 print "self.timeshift_enabled", self.timeshift_enabled
1085 # when this service is not seekable, but timeshift
1086 # is enabled, this means we can activate
1088 if not self.isSeekable() and self.timeshift_enabled:
1091 print "timeshift activate:", enabled
1092 self["TimeshiftActivateActions"].setEnabled(enabled)
1094 def __serviceStarted(self):
1095 self.timeshift_enabled = False
1096 self.__seekableStatusChanged()
1098 from Screens.PiPSetup import PiPSetup
1100 class InfoBarExtensions:
1101 EXTENSION_SINGLE = 0
1107 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1109 "extensions": (self.showExtensionSelection, _("view extensions...")),
1112 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1113 self.list.append((type, extension, key))
1115 def updateExtension(self, extension, key = None):
1116 self.extensionsList.append(extension)
1118 if self.extensionKeys.has_key(key):
1122 for x in self.availableKeys:
1123 if not self.extensionKeys.has_key(x):
1128 self.extensionKeys[key] = len(self.extensionsList) - 1
1130 def updateExtensions(self):
1131 self.extensionsList = []
1132 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1133 self.extensionKeys = {}
1135 if x[0] == self.EXTENSION_SINGLE:
1136 self.updateExtension(x[1], x[2])
1139 self.updateExtension(y[0], y[1])
1142 def showExtensionSelection(self):
1143 self.updateExtensions()
1144 extensionsList = self.extensionsList[:]
1147 for x in self.availableKeys:
1148 if self.extensionKeys.has_key(x):
1149 entry = self.extensionKeys[x]
1150 extension = self.extensionsList[entry]
1152 name = str(extension[0]())
1153 list.append((extension[0](), extension))
1155 extensionsList.remove(extension)
1157 extensionsList.remove(extension)
1158 for x in extensionsList:
1159 list.append((x[0](), x))
1160 keys += [""] * len(extensionsList)
1161 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1163 def extensionCallback(self, answer):
1164 if answer is not None:
1167 from Tools.BoundFunction import boundFunction
1169 # depends on InfoBarExtensions
1170 from Components.PluginComponent import plugins
1172 class InfoBarPlugins:
1174 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1176 def getPluginName(self, name):
1179 def getPluginList(self):
1181 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1182 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1185 def runPlugin(self, plugin):
1186 plugin(session = self.session)
1188 # depends on InfoBarExtensions
1189 class InfoBarSleepTimer:
1191 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1193 def available(self):
1196 def getSleepTimerName(self):
1197 return _("Sleep Timer")
1199 def showSleepTimerSetup(self):
1200 self.session.open(SleepTimerEdit)
1202 # depends on InfoBarExtensions
1205 self.session.pipshown = False
1207 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1208 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1209 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1211 def available(self):
1215 return self.session.pipshown
1217 def getShowHideName(self):
1218 if self.session.pipshown:
1219 return _("Disable Picture in Picture")
1221 return _("Activate Picture in Picture")
1223 def getSwapName(self):
1224 return _("Swap Services")
1226 def getMoveName(self):
1227 return _("Move Picture in Picture")
1230 if self.session.pipshown:
1231 del self.session.pip
1232 self.session.pipshown = False
1234 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1235 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1236 if self.session.pip.playService(newservice):
1237 self.session.pipshown = True
1238 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1240 self.session.pipshown = False
1241 del self.session.pip
1242 self.session.nav.playService(newservice)
1245 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1246 if self.session.pip.servicePath:
1247 servicepath = self.servicelist.getCurrentServicePath()
1248 ref=servicepath[len(servicepath)-1]
1249 pipref=self.session.pip.getCurrentService()
1250 self.session.pip.playService(swapservice)
1251 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1252 if pipref.toString() != ref.toString(): # is a subservice ?
1253 self.session.nav.stopService() # stop portal
1254 self.session.nav.playService(pipref) # start subservice
1255 self.session.pip.servicePath=servicepath
1258 self.session.open(PiPSetup, pip = self.session.pip)
1260 from RecordTimer import parseEvent
1262 class InfoBarInstantRecord:
1263 """Instant Record - handles the instantRecord action in order to
1264 start/stop instant records"""
1266 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1268 "instantRecord": (self.instantRecord, _("Instant Record...")),
1271 self["BlinkingPoint"] = BlinkingPixmapConditional()
1272 self["BlinkingPoint"].hide()
1273 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1275 def stopCurrentRecording(self, entry = -1):
1276 if entry is not None and entry != -1:
1277 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1278 self.recording.remove(self.recording[entry])
1280 def startInstantRecording(self, limitEvent = False):
1281 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1283 # try to get event info
1286 service = self.session.nav.getCurrentService()
1287 epg = eEPGCache.getInstance()
1288 event = epg.lookupEventTime(serviceref, -1, 0)
1290 info = service.info()
1291 ev = info.getEvent(0)
1297 end = time() + 3600 * 10
1298 name = "instant record"
1302 if event is not None:
1303 curEvent = parseEvent(event)
1305 description = curEvent[3]
1306 eventid = curEvent[4]
1311 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1313 data = (begin, end, name, description, eventid)
1315 recording = self.session.nav.recordWithTimer(serviceref, *data)
1316 recording.dontSave = True
1317 self.recording.append(recording)
1319 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1321 def isInstantRecordRunning(self):
1322 print "self.recording:", self.recording
1323 if len(self.recording) > 0:
1324 for x in self.recording:
1329 def recordQuestionCallback(self, answer):
1330 print "pre:\n", self.recording
1332 if answer is None or answer[1] == "no":
1335 recording = self.recording[:]
1337 if not x in self.session.nav.RecordTimer.timer_list:
1338 self.recording.remove(x)
1339 elif x.dontSave and x.isRunning():
1340 list.append(TimerEntryComponent(x, False))
1342 if answer[1] == "changeduration":
1343 if len(self.recording) == 1:
1344 self.changeDuration(0)
1346 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1347 elif answer[1] == "stop":
1348 if len(self.recording) == 1:
1349 self.stopCurrentRecording(0)
1351 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1352 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1354 if answer[1] == "event":
1356 if answer[1] == "manualduration":
1357 self.selectedEntry = len(self.recording)
1358 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1359 self.startInstantRecording(limitEvent = limitEvent)
1361 print "after:\n", self.recording
1363 def changeDuration(self, entry):
1364 if entry is not None:
1365 self.selectedEntry = entry
1366 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1368 def inputCallback(self, value):
1369 if value is not None:
1370 print "stopping recording after", int(value), "minutes."
1371 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1372 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1374 def instantRecord(self):
1376 stat = os_stat(resolveFilename(SCOPE_HDD))
1378 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1381 if self.isInstantRecordRunning():
1382 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1383 title=_("A recording is currently running.\nWhat do you want to do?"), \
1384 list=[(_("stop recording"), "stop"), \
1385 (_("change recording (duration)"), "changeduration"), \
1386 (_("add recording (indefinitely)"), "indefinitely"), \
1387 (_("add recording (stop after current event)"), "event"), \
1388 (_("add recording (enter recording duration)"), "manualduration"), \
1389 (_("do nothing"), "no")])
1391 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1392 title=_("Start recording?"), \
1393 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1394 (_("add recording (stop after current event)"), "event"), \
1395 (_("add recording (enter recording duration)"), "manualduration"), \
1396 (_("don't record"), "no")])
1398 from Tools.ISO639 import LanguageCodes
1400 class InfoBarAudioSelection:
1402 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1404 "audioSelection": (self.audioSelection, _("Audio Options...")),
1407 def audioSelection(self):
1408 service = self.session.nav.getCurrentService()
1409 audio = service and service.audioTracks()
1410 self.audioTracks = audio
1411 n = audio and audio.getNumberOfTracks() or 0
1412 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1414 print "tlist:", tlist
1416 self.audioChannel = service.audioChannel()
1419 i = audio.getTrackInfo(x)
1420 language = i.getLanguage()
1421 description = i.getDescription()
1423 if LanguageCodes.has_key(language):
1424 language = LanguageCodes[language][0]
1426 if len(description):
1427 description += " (" + language + ")"
1429 description = language
1431 tlist.append((description, x))
1433 selectedAudio = tlist[0][1]
1434 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1438 if x[1] != selectedAudio:
1443 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1444 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1446 del self.audioTracks
1448 def audioSelected(self, audio):
1449 if audio is not None:
1450 if isinstance(audio[1], str):
1451 if audio[1] == "mode":
1452 keys = ["red", "green", "yellow"]
1453 selection = self.audioChannel.getCurrentChannel()
1454 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1455 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1457 del self.audioChannel
1458 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1459 self.audioTracks.selectTrack(audio[1])
1461 del self.audioChannel
1462 del self.audioTracks
1464 def modeSelected(self, mode):
1465 if mode is not None:
1466 self.audioChannel.selectChannel(mode[1])
1467 del self.audioChannel
1469 class InfoBarSubserviceSelection:
1471 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1473 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1476 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1478 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1479 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1481 self["SubserviceQuickzapAction"].setEnabled(False)
1483 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1487 def checkSubservicesAvail(self, ev):
1488 if ev == iPlayableService.evUpdatedEventInfo:
1489 service = self.session.nav.getCurrentService()
1490 subservices = service and service.subServices()
1491 if not subservices or subservices.getNumberOfSubservices() == 0:
1492 self["SubserviceQuickzapAction"].setEnabled(False)
1494 def nextSubservice(self):
1495 self.changeSubservice(+1)
1497 def prevSubservice(self):
1498 self.changeSubservice(-1)
1500 def changeSubservice(self, direction):
1501 service = self.session.nav.getCurrentService()
1502 subservices = service and service.subServices()
1503 n = subservices and subservices.getNumberOfSubservices()
1506 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1508 if subservices.getSubservice(x).toString() == ref.toString():
1511 selection += direction
1516 newservice = subservices.getSubservice(selection)
1517 if newservice.valid():
1520 if config.usage.show_infobar_on_zap.value:
1522 self.session.nav.playService(newservice)
1524 def subserviceSelection(self):
1525 service = self.session.nav.getCurrentService()
1526 subservices = service and service.subServices()
1527 self.bouquets = self.servicelist.getBouquetList()
1528 n = subservices and subservices.getNumberOfSubservices()
1531 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1534 i = subservices.getSubservice(x)
1535 if i.toString() == ref.toString():
1537 tlist.append((i.getName(), i))
1539 if self.bouquets and len(self.bouquets):
1540 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1541 if config.usage.multibouquet.value:
1542 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1544 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1547 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1548 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1551 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1553 def subserviceSelected(self, service):
1555 if not service is None:
1556 if isinstance(service[1], str):
1557 if service[1] == "quickzap":
1558 from Screens.SubservicesQuickzap import SubservicesQuickzap
1559 self.session.open(SubservicesQuickzap, service[2])
1561 self["SubserviceQuickzapAction"].setEnabled(True)
1562 if config.usage.show_infobar_on_zap.value:
1564 self.session.nav.playService(service[1])
1566 def addSubserviceToBouquetCallback(self, service):
1567 if len(service) > 1 and isinstance(service[1], eServiceReference):
1568 self.selectedSubservice = service
1569 if self.bouquets is None:
1572 cnt = len(self.bouquets)
1573 if cnt > 1: # show bouquet list
1574 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1575 elif cnt == 1: # add to only one existing bouquet
1576 self.addSubserviceToBouquet(self.bouquets[0][1])
1577 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1579 def bouquetSelClosed(self, confirmed):
1581 del self.selectedSubservice
1583 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1585 def addSubserviceToBouquet(self, dest):
1586 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1588 self.bsel.close(True)
1590 del self.selectedSubservice
1592 class InfoBarAdditionalInfo:
1594 self["NimA"] = Pixmap()
1595 self["NimB"] = Pixmap()
1596 self["NimA_Active"] = Pixmap()
1597 self["NimB_Active"] = Pixmap()
1599 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1600 self["TimeshiftPossible"] = self["RecordingPossible"]
1601 self["ExtensionsAvailable"] = Boolean(fixed=1)
1603 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1604 res_mgr = eDVBResourceManager.getInstance()
1606 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1608 def tunerUseMaskChanged(self, mask):
1610 self["NimA_Active"].show()
1612 self["NimA_Active"].hide()
1614 self["NimB_Active"].show()
1616 self["NimB_Active"].hide()
1618 def checkTunerState(self, service):
1619 info = service and service.frontendInfo()
1620 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1621 if feNumber is None:
1631 def gotServiceEvent(self, ev):
1632 service = self.session.nav.getCurrentService()
1633 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1634 self.checkTunerState(service)
1636 class InfoBarNotifications:
1638 self.onExecBegin.append(self.checkNotifications)
1639 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1640 self.onClose.append(self.__removeNotification)
1642 def __removeNotification(self):
1643 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1645 def checkNotificationsIfExecing(self):
1647 self.checkNotifications()
1649 def checkNotifications(self):
1650 if len(Notifications.notifications):
1651 n = Notifications.notifications[0]
1653 Notifications.notifications = Notifications.notifications[1:]
1656 if n[3].has_key("onSessionOpenCallback"):
1657 n[3]["onSessionOpenCallback"]()
1658 del n[3]["onSessionOpenCallback"]
1661 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1663 dlg = self.session.open(n[1], *n[2], **n[3])
1665 # remember that this notification is currently active
1667 Notifications.current_notifications.append(d)
1668 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1670 def __notificationClosed(self, d):
1671 Notifications.current_notifications.remove(d)
1673 class InfoBarServiceNotifications:
1675 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1677 iPlayableService.evEnd: self.serviceHasEnded
1680 def serviceHasEnded(self):
1681 print "service end!"
1684 self.setSeekState(self.SEEK_STATE_PLAY)
1688 class InfoBarCueSheetSupport:
1694 ENABLE_RESUME_SUPPORT = False
1697 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1699 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1700 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1701 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1705 self.is_closing = False
1706 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1708 iPlayableService.evStart: self.__serviceStarted,
1711 def __serviceStarted(self):
1714 print "new service started! trying to download cuts!"
1715 self.downloadCuesheet()
1717 if self.ENABLE_RESUME_SUPPORT:
1720 for (pts, what) in self.cut_list:
1721 if what == self.CUT_TYPE_LAST:
1724 if last is not None:
1725 self.resume_point = last
1726 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1728 def playLastCB(self, answer):
1730 seekable = self.__getSeekable()
1731 if seekable is not None:
1732 seekable.seekTo(self.resume_point)
1734 def __getSeekable(self):
1735 service = self.session.nav.getCurrentService()
1738 return service.seek()
1740 def cueGetCurrentPosition(self):
1741 seek = self.__getSeekable()
1744 r = seek.getPlayPosition()
1749 def jumpPreviousNextMark(self, cmp, alternative=None):
1750 current_pos = self.cueGetCurrentPosition()
1751 if current_pos is None:
1753 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1754 if mark is not None:
1756 elif alternative is not None:
1761 seekable = self.__getSeekable()
1762 if seekable is not None:
1763 seekable.seekTo(pts)
1765 def jumpPreviousMark(self):
1766 # we add 2 seconds, so if the play position is <2s after
1767 # the mark, the mark before will be used
1768 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1770 def jumpNextMark(self):
1771 self.jumpPreviousNextMark(lambda x: x)
1773 def getNearestCutPoint(self, pts, cmp=abs):
1776 for cp in self.cut_list:
1777 diff = cmp(cp[0] - pts)
1778 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1782 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1783 current_pos = self.cueGetCurrentPosition()
1784 if current_pos is None:
1785 print "not seekable"
1788 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1790 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1792 return nearest_cutpoint
1794 self.removeMark(nearest_cutpoint)
1795 elif not onlyremove and not onlyreturn:
1796 self.addMark((current_pos, self.CUT_TYPE_MARK))
1801 def addMark(self, point):
1802 insort(self.cut_list, point)
1803 self.uploadCuesheet()
1805 def removeMark(self, point):
1806 self.cut_list.remove(point)
1807 self.uploadCuesheet()
1809 def __getCuesheet(self):
1810 service = self.session.nav.getCurrentService()
1813 return service.cueSheet()
1815 def uploadCuesheet(self):
1816 cue = self.__getCuesheet()
1819 print "upload failed, no cuesheet interface"
1821 cue.setCutList(self.cut_list)
1823 def downloadCuesheet(self):
1824 cue = self.__getCuesheet()
1827 print "upload failed, no cuesheet interface"
1829 self.cut_list = cue.getCutList()
1831 class InfoBarSummary(Screen):
1833 <screen position="0,0" size="132,64">
1834 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1835 <convert type="ClockToText">WithSeconds</convert>
1837 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1838 <convert type="ServiceName">Name</convert>
1842 def __init__(self, session, parent):
1843 Screen.__init__(self, session)
1844 self["CurrentService"] = CurrentService(self.session.nav)
1845 self["CurrentTime"] = Clock()
1847 class InfoBarSummarySupport:
1851 def createSummary(self):
1852 return InfoBarSummary
1854 class InfoBarTeletextPlugin:
1856 self.teletext_plugin = None
1858 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1859 self.teletext_plugin = p
1861 if self.teletext_plugin is not None:
1862 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1864 "startTeletext": (self.startTeletext, _("View teletext..."))
1867 print "no teletext plugin found!"
1869 def startTeletext(self):
1870 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1872 class InfoBarSubtitleSupport(object):
1874 object.__init__(self)
1875 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1876 self.__subtitles_enabled = False
1878 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1880 iPlayableService.evEnd: self.__serviceStopped,
1881 iPlayableService.evUpdatedInfo: self.__updatedInfo
1883 self.cached_subtitle_checked = False
1885 def __serviceStopped(self):
1886 self.subtitle_window.hide()
1887 self.__subtitles_enabled = False
1888 self.cached_subtitle_checked = False
1890 def __updatedInfo(self):
1891 if not self.cached_subtitle_checked:
1892 subtitle = self.getCurrentServiceSubtitle()
1893 self.cached_subtitle_checked = True
1895 self.__selected_subtitle = subtitle.getCachedSubtitle()
1896 if self.__selected_subtitle:
1897 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1898 self.subtitle_window.show()
1899 self.__subtitles_enabled = True
1901 def getCurrentServiceSubtitle(self):
1902 service = self.session.nav.getCurrentService()
1903 return service and service.subtitle()
1905 def setSubtitlesEnable(self, enable=True):
1906 subtitle = self.getCurrentServiceSubtitle()
1907 if enable and self.__selected_subtitle is not None:
1908 if subtitle and not self.__subtitles_enabled:
1909 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1910 self.subtitle_window.show()
1911 self.__subtitles_enabled = True
1914 subtitle.disableSubtitles(self.subtitle_window.instance)
1915 self.__subtitles_enabled = False
1916 self.subtitle_window.hide()
1918 def setSelectedSubtitle(self, subtitle):
1919 self.__selected_subtitle = subtitle
1921 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1922 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1924 class InfoBarServiceErrorPopupSupport:
1926 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1928 iPlayableService.evTuneFailed: self.__tuneFailed,
1929 iPlayableService.evStart: self.__serviceStarted
1931 self.__serviceStarted()
1933 def __serviceStarted(self):
1934 self.last_error = None
1935 Notifications.RemovePopup(id = "ZapError")
1937 def __tuneFailed(self):
1938 service = self.session.nav.getCurrentService()
1939 info = service and service.info()
1940 error = info and info.getInfo(iServiceInformation.sDVBState)
1942 if error == self.last_error:
1945 self.last_error = error
1948 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1949 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1950 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1951 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1952 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1953 eDVBServicePMTHandler.eventNewProgramInfo: None,
1954 eDVBServicePMTHandler.eventTuned: None,
1955 eDVBServicePMTHandler.eventSOF: None,
1956 eDVBServicePMTHandler.eventEOF: None
1959 error = errors.get(error) #this returns None when the key not exist in the dict
1961 if error is not None:
1962 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1964 Notifications.RemovePopup(id = "ZapError")