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, ConfigClock
20 from EpgSelection import EPGSelection
21 from Plugins.Plugin import PluginDescriptor
23 from Screen import Screen
24 from Screens.ChoiceBox import ChoiceBox
25 from Screens.Dish import Dish
26 from Screens.EventView import EventViewEPGSelect, EventViewSimple
27 from Screens.InputBox import InputBox
28 from Screens.MessageBox import MessageBox
29 from Screens.MinuteInput import MinuteInput
30 from Screens.TimerSelection import TimerSelection
31 from Screens.PictureInPicture import PictureInPicture
32 from Screens.SubtitleDisplay import SubtitleDisplay
33 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
34 from Screens.SleepTimerEdit import SleepTimerEdit
35 from Screens.TimeDateInput import TimeDateInput
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
44 from time import time, localtime, strftime
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,
76 self.__state = self.STATE_SHOWN
79 self.hideTimer = eTimer()
80 self.hideTimer.timeout.get().append(self.doTimerHide)
81 self.hideTimer.start(5000, True)
83 self.onShow.append(self.__onShow)
84 self.onHide.append(self.__onHide)
86 def serviceStarted(self):
88 if config.usage.show_infobar_on_zap.value:
92 self.__state = self.STATE_SHOWN
95 def startHideTimer(self):
96 if self.__state == self.STATE_SHOWN and not self.__locked:
97 idx = config.usage.infobar_timeout.index
99 self.hideTimer.start(idx*1000, True)
102 self.__state = self.STATE_HIDDEN
106 self.startHideTimer()
108 def doTimerHide(self):
109 self.hideTimer.stop()
110 if self.__state == self.STATE_SHOWN:
113 def toggleShow(self):
114 if self.__state == self.STATE_SHOWN:
116 self.hideTimer.stop()
117 elif self.__state == self.STATE_HIDDEN:
121 self.__locked = self.__locked + 1
124 self.hideTimer.stop()
126 def unlockShow(self):
127 self.__locked = self.__locked - 1
129 self.startHideTimer()
131 # def startShow(self):
132 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
133 # self.__state = self.STATE_SHOWN
135 # def startHide(self):
136 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
137 # self.__state = self.STATE_HIDDEN
139 class NumberZap(Screen):
146 self.close(int(self["number"].getText()))
148 def keyNumberGlobal(self, number):
149 self.Timer.start(3000, True) #reset timer
150 self.field = self.field + str(number)
151 self["number"].setText(self.field)
152 if len(self.field) >= 4:
155 def __init__(self, session, number):
156 Screen.__init__(self, session)
157 self.field = str(number)
159 self["channel"] = Label(_("Channel:"))
161 self["number"] = Label(self.field)
163 self["actions"] = NumberActionMap( [ "SetupActions" ],
167 "1": self.keyNumberGlobal,
168 "2": self.keyNumberGlobal,
169 "3": self.keyNumberGlobal,
170 "4": self.keyNumberGlobal,
171 "5": self.keyNumberGlobal,
172 "6": self.keyNumberGlobal,
173 "7": self.keyNumberGlobal,
174 "8": self.keyNumberGlobal,
175 "9": self.keyNumberGlobal,
176 "0": self.keyNumberGlobal
179 self.Timer = eTimer()
180 self.Timer.timeout.get().append(self.keyOK)
181 self.Timer.start(3000, True)
183 class InfoBarNumberZap:
184 """ Handles an initial number for NumberZapping """
186 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
188 "1": self.keyNumberGlobal,
189 "2": self.keyNumberGlobal,
190 "3": self.keyNumberGlobal,
191 "4": self.keyNumberGlobal,
192 "5": self.keyNumberGlobal,
193 "6": self.keyNumberGlobal,
194 "7": self.keyNumberGlobal,
195 "8": self.keyNumberGlobal,
196 "9": self.keyNumberGlobal,
197 "0": self.keyNumberGlobal,
200 def keyNumberGlobal(self, number):
201 # print "You pressed number " + str(number)
203 self.servicelist.recallPrevService()
205 self.session.openWithCallback(self.numberEntered, NumberZap, number)
207 def numberEntered(self, retval):
208 # print self.servicelist
210 self.zapToNumber(retval)
212 def searchNumberHelper(self, serviceHandler, num, bouquet):
213 servicelist = serviceHandler.list(bouquet)
214 if not servicelist is None:
216 serviceIterator = servicelist.getNext()
217 if not serviceIterator.valid(): #check end of list
219 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
222 if not num: #found service with searched number ?
223 return serviceIterator, 0
226 def zapToNumber(self, number):
227 bouquet = self.servicelist.bouquet_root
229 serviceHandler = eServiceCenter.getInstance()
230 if not config.usage.multibouquet.value:
231 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
233 bouquetlist = serviceHandler.list(bouquet)
234 if not bouquetlist is None:
236 bouquet = bouquetlist.getNext()
237 if not bouquet.valid(): #check end of list
239 if bouquet.flags & eServiceReference.isDirectory:
240 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
241 if not service is None:
242 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
243 self.servicelist.clearPath()
244 if self.servicelist.bouquet_root != bouquet:
245 self.servicelist.enterPath(self.servicelist.bouquet_root)
246 self.servicelist.enterPath(bouquet)
247 self.servicelist.setCurrentSelection(service) #select the service in servicelist
248 self.servicelist.zap()
250 config.misc.initialchannelselection = ConfigBoolean(default = True)
252 class InfoBarChannelSelection:
253 """ ChannelSelection - handles the channelSelection dialog and the initial
254 channelChange actions which open the channelSelection dialog """
257 self.servicelist = self.session.instantiateDialog(ChannelSelection)
259 if config.misc.initialchannelselection.value:
260 self.onShown.append(self.firstRun)
262 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
264 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
265 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
266 "zapUp": (self.zapUp, _("previous channel")),
267 "zapDown": (self.zapDown, _("next channel")),
268 "historyBack": (self.historyBack, _("previous channel in history")),
269 "historyNext": (self.historyNext, _("next channel in history")),
270 "openServiceList": (self.openServiceList, _("open servicelist")),
273 def showTvChannelList(self, zap=False):
274 self.servicelist.setModeTv()
276 self.servicelist.zap()
277 self.session.execDialog(self.servicelist)
279 def showRadioChannelList(self, zap=False):
280 self.servicelist.setModeRadio()
282 self.servicelist.zap()
283 self.session.execDialog(self.servicelist)
286 self.onShown.remove(self.firstRun)
287 config.misc.initialchannelselection.value = False
288 config.misc.initialchannelselection.save()
289 self.switchChannelDown()
291 def historyBack(self):
292 self.servicelist.historyBack()
294 def historyNext(self):
295 self.servicelist.historyNext()
297 def switchChannelUp(self):
298 self.servicelist.moveUp()
299 self.session.execDialog(self.servicelist)
301 def switchChannelDown(self):
302 self.servicelist.moveDown()
303 self.session.execDialog(self.servicelist)
305 def openServiceList(self):
306 self.session.execDialog(self.servicelist)
309 if self.servicelist.inBouquet():
310 prev = self.servicelist.getCurrentSelection()
312 prev = prev.toString()
314 if config.usage.quickzap_bouquet_change.value:
315 if self.servicelist.atBegin():
316 self.servicelist.prevBouquet()
317 self.servicelist.moveUp()
318 cur = self.servicelist.getCurrentSelection()
319 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
322 self.servicelist.moveUp()
323 self.servicelist.zap()
326 if self.servicelist.inBouquet():
327 prev = self.servicelist.getCurrentSelection()
329 prev = prev.toString()
331 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
332 self.servicelist.nextBouquet()
334 self.servicelist.moveDown()
335 cur = self.servicelist.getCurrentSelection()
336 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
339 self.servicelist.moveDown()
340 self.servicelist.zap()
343 """ Handles a menu action, to open the (main) menu """
345 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
347 "mainMenu": (self.mainMenu, _("Enter main menu...")),
349 self.session.infobar = None
352 print "loading mainmenu XML..."
353 menu = mdom.childNodes[0]
354 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
356 self.session.infobar = self
357 # so we can access the currently active infobar from screens opened from within the mainmenu
358 # at the moment used from the SubserviceSelection
360 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
362 def mainMenuClosed(self, *val):
363 self.session.infobar = None
365 class InfoBarSimpleEventView:
366 """ Opens the Eventview for now/next """
368 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
370 "showEventInfo": (self.openEventView, _("show event details")),
373 def openEventView(self):
375 service = self.session.nav.getCurrentService()
376 ref = self.session.nav.getCurrentlyPlayingServiceReference()
377 info = service.info()
380 self.epglist.append(ptr)
383 self.epglist.append(ptr)
384 if len(self.epglist) > 0:
385 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
387 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
388 if len(self.epglist) > 1:
389 tmp = self.epglist[0]
390 self.epglist[0]=self.epglist[1]
392 setEvent(self.epglist[0])
395 """ EPG - Opens an EPG list when the showEPGList action fires """
397 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
399 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
402 self.is_now_next = False
404 self.bouquetSel = None
405 self.eventView = None
406 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
408 "showEventInfo": (self.openEventView, _("show EPG...")),
411 def zapToService(self, service):
412 if not service is None:
413 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
414 self.servicelist.clearPath()
415 if self.servicelist.bouquet_root != self.epg_bouquet:
416 self.servicelist.enterPath(self.servicelist.bouquet_root)
417 self.servicelist.enterPath(self.epg_bouquet)
418 self.servicelist.setCurrentSelection(service) #select the service in servicelist
419 self.servicelist.zap()
421 def getBouquetServices(self, bouquet):
423 servicelist = eServiceCenter.getInstance().list(bouquet)
424 if not servicelist is None:
426 service = servicelist.getNext()
427 if not service.valid(): #check if end of list
429 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
431 services.append(ServiceReference(service))
434 def openBouquetEPG(self, bouquet, withCallback=True):
435 services = self.getBouquetServices(bouquet)
437 self.epg_bouquet = bouquet
439 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
441 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
443 def changeBouquetCB(self, direction, epg):
446 self.bouquetSel.down()
449 bouquet = self.bouquetSel.getCurrent()
450 services = self.getBouquetServices(bouquet)
452 self.epg_bouquet = bouquet
453 epg.setServices(services)
455 def closed(self, ret=False):
456 closedScreen = self.dlg_stack.pop()
457 if self.bouquetSel and closedScreen == self.bouquetSel:
458 self.bouquetSel = None
459 elif self.eventView and closedScreen == self.eventView:
460 self.eventView = None
462 dlgs=len(self.dlg_stack)
464 self.dlg_stack[dlgs-1].close(dlgs > 1)
466 def openMultiServiceEPG(self, withCallback=True):
467 bouquets = self.servicelist.getBouquetList()
472 if cnt > 1: # show bouquet list
474 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
475 self.dlg_stack.append(self.bouquetSel)
477 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
479 self.openBouquetEPG(bouquets[0][1], withCallback)
481 def openSingleServiceEPG(self):
482 ref=self.session.nav.getCurrentlyPlayingServiceReference()
483 self.session.open(EPGSelection, ref)
485 def openSimilarList(self, eventid, refstr):
486 self.session.open(EPGSelection, refstr, None, eventid)
488 def getNowNext(self):
490 service = self.session.nav.getCurrentService()
491 info = service and service.info()
492 ptr = info and info.getEvent(0)
494 self.epglist.append(ptr)
495 ptr = info and info.getEvent(1)
497 self.epglist.append(ptr)
499 def __evEventInfoChanged(self):
500 if self.is_now_next and len(self.dlg_stack) == 1:
502 assert self.eventView
503 if len(self.epglist):
504 self.eventView.setEvent(self.epglist[0])
506 def openEventView(self):
507 ref = self.session.nav.getCurrentlyPlayingServiceReference()
509 if len(self.epglist) == 0:
510 self.is_now_next = False
511 epg = eEPGCache.getInstance()
512 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
514 self.epglist.append(ptr)
515 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
517 self.epglist.append(ptr)
519 self.is_now_next = True
520 if len(self.epglist) > 0:
521 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
522 self.dlg_stack.append(self.eventView)
524 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
525 self.openMultiServiceEPG(False)
527 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
528 if len(self.epglist) > 1:
529 tmp = self.epglist[0]
530 self.epglist[0]=self.epglist[1]
532 setEvent(self.epglist[0])
535 """provides a snr/agc/ber display"""
537 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
540 """provides a current/next event info display"""
542 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
543 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
545 class InfoBarRdsDecoder:
546 """provides RDS and Rass support/display"""
548 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
549 self.rass_interactive = None
551 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
553 iPlayableService.evEnd: self.__serviceStopped,
554 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
557 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
559 "startRassInteractive": self.startRassInteractive
562 self["RdsActions"].setEnabled(False)
564 self.onLayoutFinish.append(self.rds_display.show)
565 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
567 def RassInteractivePossibilityChanged(self, state):
568 self["RdsActions"].setEnabled(state)
570 def RassSlidePicChanged(self):
571 if not self.rass_interactive:
572 service = self.session.nav.getCurrentService()
573 decoder = service and service.rdsDecoder()
575 decoder.showRassSlidePicture()
577 def __serviceStopped(self):
578 if self.rass_interactive is not None:
579 rass_interactive = self.rass_interactive
580 self.rass_interactive = None
581 rass_interactive.close()
583 def startRassInteractive(self):
584 self.rds_display.hide()
585 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
587 def RassInteractiveClosed(self, *val):
588 if self.rass_interactive is not None:
589 self.rass_interactive = None
590 self.RassSlidePicChanged()
591 self.rds_display.show()
593 class InfoBarServiceName:
595 self["CurrentService"] = CurrentService(self.session.nav)
598 """handles actions like seeking, pause"""
600 # ispause, isff, issm
601 SEEK_STATE_PLAY = (0, 0, 0, ">")
602 SEEK_STATE_PAUSE = (1, 0, 0, "||")
603 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
604 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
605 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
606 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
607 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
608 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
610 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
611 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
612 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
613 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
615 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
616 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
617 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
619 SEEK_STATE_EOF = (1, 0, 0, "END")
622 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
624 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
625 iPlayableService.evStart: self.__serviceStarted,
627 iPlayableService.evEOF: self.__evEOF,
628 iPlayableService.evSOF: self.__evSOF,
631 class InfoBarSeekActionMap(HelpableActionMap):
632 def __init__(self, screen, *args, **kwargs):
633 HelpableActionMap.__init__(self, screen, *args, **kwargs)
636 def action(self, contexts, action):
637 print "action:", action
638 if action[:5] == "seek:":
639 time = int(action[5:])
640 self.screen.seekRelative(time * 90000)
641 if isinstance(self.screen, InfoBarShowHide):
645 return HelpableActionMap.action(self, contexts, action)
647 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
649 "playpauseService": (self.playpauseService, _("pause")),
650 "pauseService": (self.pauseService, _("pause")),
651 "unPauseService": (self.unPauseService, _("continue")),
653 "seekFwd": (self.seekFwd, _("skip forward")),
654 "seekFwdDown": self.seekFwdDown,
655 "seekFwdUp": self.seekFwdUp,
656 "seekBack": (self.seekBack, _("skip backward")),
657 "seekBackDown": self.seekBackDown,
658 "seekBackUp": self.seekBackUp,
660 # give them a little more priority to win over color buttons
662 self["SeekActions"].setEnabled(False)
664 self.seekstate = self.SEEK_STATE_PLAY
665 self.onClose.append(self.delTimer)
667 self.fwdtimer = False
668 self.fwdKeyTimer = eTimer()
669 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
671 self.rwdtimer = False
672 self.rwdKeyTimer = eTimer()
673 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
675 self.onPlayStateChanged = [ ]
677 self.lockedBecauseOfSkipping = False
679 self.__seekableStatusChanged()
692 service = self.session.nav.getCurrentService()
696 seek = service.seek()
698 if seek is None or not seek.isCurrentlySeekable():
703 def isSeekable(self):
704 if self.getSeek() is None:
708 def __seekableStatusChanged(self):
709 print "seekable status changed!"
710 if not self.isSeekable():
711 self["SeekActions"].setEnabled(False)
712 print "not seekable, return to play"
713 self.setSeekState(self.SEEK_STATE_PLAY)
715 self["SeekActions"].setEnabled(True)
718 def __serviceStarted(self):
719 self.seekstate = self.SEEK_STATE_PLAY
720 self.__seekableStatusChanged()
722 def setSeekState(self, state):
723 service = self.session.nav.getCurrentService()
728 if not self.isSeekable():
729 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
730 state = self.SEEK_STATE_PLAY
732 pauseable = service.pause()
734 if pauseable is None:
735 print "not pauseable."
736 state = self.SEEK_STATE_PLAY
738 oldstate = self.seekstate
739 self.seekstate = state
742 if oldstate[i] != self.seekstate[i]:
743 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
745 for c in self.onPlayStateChanged:
748 self.checkSkipShowHideLock()
752 def playpauseService(self):
753 if self.seekstate != self.SEEK_STATE_PLAY:
754 self.unPauseService()
758 def pauseService(self):
759 if self.seekstate == self.SEEK_STATE_PAUSE:
760 print "pause, but in fact unpause"
761 self.unPauseService()
763 if self.seekstate == self.SEEK_STATE_PLAY:
764 print "yes, playing."
766 print "no", self.seekstate
768 self.setSeekState(self.SEEK_STATE_PAUSE);
770 def unPauseService(self):
772 if self.seekstate == self.SEEK_STATE_PLAY:
774 self.setSeekState(self.SEEK_STATE_PLAY)
776 def doSeek(self, seektime):
777 print "doseek", seektime
778 service = self.session.nav.getCurrentService()
782 seekable = self.getSeek()
786 seekable.seekTo(90 * seektime)
788 def seekFwdDown(self):
789 print "start fwd timer"
791 self.fwdKeyTimer.start(1000)
793 def seekBackDown(self):
794 print "start rewind timer"
796 self.rwdKeyTimer.start(1000)
801 self.fwdKeyTimer.stop()
802 self.fwdtimer = False
807 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
808 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
809 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
810 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
811 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
812 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
813 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
814 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
815 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
816 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
817 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
818 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
819 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
820 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
821 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
822 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
824 self.setSeekState(lookup[self.seekstate])
826 def seekBackUp(self):
829 self.rwdKeyTimer.stop()
830 self.rwdtimer = False
835 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
836 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
837 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
838 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
839 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
840 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
841 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
842 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
843 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
844 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
845 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
846 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
847 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
848 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
849 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
850 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
852 self.setSeekState(lookup[self.seekstate])
854 if self.seekstate == self.SEEK_STATE_PAUSE:
855 seekable = self.getSeek()
856 if seekable is not None:
857 seekable.seekRelative(-1, 3)
859 def fwdTimerFire(self):
860 print "Display seek fwd"
861 self.fwdKeyTimer.stop()
862 self.fwdtimer = False
863 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
865 def fwdSeekTo(self, minutes):
866 print "Seek", minutes, "minutes forward"
868 seekable = self.getSeek()
869 if seekable is not None:
870 seekable.seekRelative(1, minutes * 60 * 90000)
872 def rwdTimerFire(self):
874 self.rwdKeyTimer.stop()
875 self.rwdtimer = False
876 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
878 def rwdSeekTo(self, minutes):
880 self.fwdSeekTo(0 - minutes)
882 def checkSkipShowHideLock(self):
883 wantlock = self.seekstate != self.SEEK_STATE_PLAY
885 if config.usage.show_infobar_on_zap.value:
886 if self.lockedBecauseOfSkipping and not wantlock:
888 self.lockedBecauseOfSkipping = False
890 if wantlock and not self.lockedBecauseOfSkipping:
892 self.lockedBecauseOfSkipping = True
895 if self.seekstate == self.SEEK_STATE_EOF:
897 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
898 print "end of stream while seeking back, ignoring."
901 # if we are seeking, we try to end up ~1s before the end, and pause there.
902 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
903 self.setSeekState(self.SEEK_STATE_EOF)
904 self.seekRelativeToEnd(-90000)
906 self.setSeekState(self.SEEK_STATE_EOF)
909 self.setSeekState(self.SEEK_STATE_PLAY)
912 def seekRelative(self, diff):
913 seekable = self.getSeek()
914 if seekable is not None:
915 print "seekRelative: res:", seekable.seekRelative(1, diff)
919 def seekRelativeToEnd(self, diff):
920 assert diff <= 0, "diff is expected to be negative!"
922 # might sound like an evil hack, but:
923 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
924 # and we don't get that by passing 0 here (it would seek to begin).
928 # relative-to-end seeking is implemented as absolutes seeks with negative time
929 self.seekAbsolute(diff)
931 def seekAbsolute(self, abs):
932 seekable = self.getSeek()
933 if seekable is not None:
936 from Screens.PVRState import PVRState, TimeshiftState
938 class InfoBarPVRState:
939 def __init__(self, screen=PVRState):
940 self.onPlayStateChanged.append(self.__playStateChanged)
941 self.pvrStateDialog = self.session.instantiateDialog(screen)
942 self.onShow.append(self._mayShow)
943 self.onHide.append(self.pvrStateDialog.hide)
946 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
947 self.pvrStateDialog.show()
949 def __playStateChanged(self, state):
950 playstateString = state[3]
951 self.pvrStateDialog["state"].setText(playstateString)
954 class InfoBarTimeshiftState(InfoBarPVRState):
956 InfoBarPVRState.__init__(self, screen=TimeshiftState)
959 if self.execing and self.timeshift_enabled:
960 self.pvrStateDialog.show()
962 class InfoBarShowMovies:
964 # i don't really like this class.
965 # it calls a not further specified "movie list" on up/down/movieList,
966 # so this is not more than an action map
968 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
970 "movieList": (self.showMovies, "movie list"),
971 "up": (self.showMovies, "movie list"),
972 "down": (self.showMovies, "movie list")
975 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
979 # Timeshift works the following way:
980 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
981 # - normal playback TUNER unused PLAY enable disable disable
982 # - user presses "yellow" button. FILE record PAUSE enable disable enable
983 # - user presess pause again FILE record PLAY enable disable enable
984 # - user fast forwards FILE record FF enable disable enable
985 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
986 # - user backwards FILE record BACK # !! enable disable enable
990 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
991 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
992 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
993 # - the user can now PVR around
994 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
995 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
997 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
998 # - if the user rewinds, or press pause, timeshift will be activated again
1000 # note that a timeshift can be enabled ("recording") and
1001 # activated (currently time-shifting).
1003 class InfoBarTimeshift:
1005 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1007 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1008 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1010 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1012 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1013 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1014 }, prio=-1) # priority over record
1016 self.timeshift_enabled = 0
1017 self.timeshift_state = 0
1018 self.ts_rewind_timer = eTimer()
1019 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1021 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1023 iPlayableService.evStart: self.__serviceStarted,
1024 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1027 def getTimeshift(self):
1028 service = self.session.nav.getCurrentService()
1029 return service and service.timeshift()
1031 def startTimeshift(self):
1032 print "enable timeshift"
1033 ts = self.getTimeshift()
1035 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1036 print "no ts interface"
1039 if self.timeshift_enabled:
1040 print "hu, timeshift already enabled?"
1042 if not ts.startTimeshift():
1043 self.timeshift_enabled = 1
1045 # we remove the "relative time" for now.
1046 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1049 #self.setSeekState(self.SEEK_STATE_PAUSE)
1050 self.activateTimeshiftEnd(False)
1052 # enable the "TimeshiftEnableActions", which will override
1053 # the startTimeshift actions
1054 self.__seekableStatusChanged()
1056 print "timeshift failed"
1058 def stopTimeshift(self):
1059 if not self.timeshift_enabled:
1061 print "disable timeshift"
1062 ts = self.getTimeshift()
1065 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1067 def stopTimeshiftConfirmed(self, confirmed):
1071 ts = self.getTimeshift()
1076 self.timeshift_enabled = 0
1079 self.__seekableStatusChanged()
1081 # activates timeshift, and seeks to (almost) the end
1082 def activateTimeshiftEnd(self, back = True):
1083 ts = self.getTimeshift()
1084 print "activateTimeshiftEnd"
1089 if ts.isTimeshiftActive():
1090 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1094 ts.activateTimeshift() # activate timeshift will automatically pause
1095 self.setSeekState(self.SEEK_STATE_PAUSE)
1096 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1099 self.ts_rewind_timer.start(200, 1)
1101 def rewindService(self):
1102 self.setSeekState(self.SEEK_STATE_BACK_16X)
1104 # same as activateTimeshiftEnd, but pauses afterwards.
1105 def activateTimeshiftEndAndPause(self):
1106 print "activateTimeshiftEndAndPause"
1107 #state = self.seekstate
1108 self.activateTimeshiftEnd(False)
1110 def __seekableStatusChanged(self):
1113 print "self.isSeekable", self.isSeekable()
1114 print "self.timeshift_enabled", self.timeshift_enabled
1116 # when this service is not seekable, but timeshift
1117 # is enabled, this means we can activate
1119 if not self.isSeekable() and self.timeshift_enabled:
1122 print "timeshift activate:", enabled
1123 self["TimeshiftActivateActions"].setEnabled(enabled)
1125 def __serviceStarted(self):
1126 self.timeshift_enabled = False
1127 self.__seekableStatusChanged()
1129 from Screens.PiPSetup import PiPSetup
1131 class InfoBarExtensions:
1132 EXTENSION_SINGLE = 0
1138 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1140 "extensions": (self.showExtensionSelection, _("view extensions...")),
1143 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1144 self.list.append((type, extension, key))
1146 def updateExtension(self, extension, key = None):
1147 self.extensionsList.append(extension)
1149 if self.extensionKeys.has_key(key):
1153 for x in self.availableKeys:
1154 if not self.extensionKeys.has_key(x):
1159 self.extensionKeys[key] = len(self.extensionsList) - 1
1161 def updateExtensions(self):
1162 self.extensionsList = []
1163 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1164 self.extensionKeys = {}
1166 if x[0] == self.EXTENSION_SINGLE:
1167 self.updateExtension(x[1], x[2])
1170 self.updateExtension(y[0], y[1])
1173 def showExtensionSelection(self):
1174 self.updateExtensions()
1175 extensionsList = self.extensionsList[:]
1178 for x in self.availableKeys:
1179 if self.extensionKeys.has_key(x):
1180 entry = self.extensionKeys[x]
1181 extension = self.extensionsList[entry]
1183 name = str(extension[0]())
1184 list.append((extension[0](), extension))
1186 extensionsList.remove(extension)
1188 extensionsList.remove(extension)
1189 for x in extensionsList:
1190 list.append((x[0](), x))
1191 keys += [""] * len(extensionsList)
1192 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1194 def extensionCallback(self, answer):
1195 if answer is not None:
1198 from Tools.BoundFunction import boundFunction
1200 # depends on InfoBarExtensions
1201 from Components.PluginComponent import plugins
1203 class InfoBarPlugins:
1205 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1207 def getPluginName(self, name):
1210 def getPluginList(self):
1212 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1213 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1216 def runPlugin(self, plugin):
1217 plugin(session = self.session)
1219 # depends on InfoBarExtensions
1220 class InfoBarSleepTimer:
1222 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1224 def available(self):
1227 def getSleepTimerName(self):
1228 return _("Sleep Timer")
1230 def showSleepTimerSetup(self):
1231 self.session.open(SleepTimerEdit)
1233 # depends on InfoBarExtensions
1236 self.session.pipshown = False
1238 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1239 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1240 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1242 def available(self):
1246 return self.session.pipshown
1248 def getShowHideName(self):
1249 if self.session.pipshown:
1250 return _("Disable Picture in Picture")
1252 return _("Activate Picture in Picture")
1254 def getSwapName(self):
1255 return _("Swap Services")
1257 def getMoveName(self):
1258 return _("Move Picture in Picture")
1261 if self.session.pipshown:
1262 del self.session.pip
1263 self.session.pipshown = False
1265 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1266 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1267 if self.session.pip.playService(newservice):
1268 self.session.pipshown = True
1269 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1271 self.session.pipshown = False
1272 del self.session.pip
1273 self.session.nav.playService(newservice)
1276 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1277 if self.session.pip.servicePath:
1278 servicepath = self.servicelist.getCurrentServicePath()
1279 ref=servicepath[len(servicepath)-1]
1280 pipref=self.session.pip.getCurrentService()
1281 self.session.pip.playService(swapservice)
1282 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1283 if pipref.toString() != ref.toString(): # is a subservice ?
1284 self.session.nav.stopService() # stop portal
1285 self.session.nav.playService(pipref) # start subservice
1286 self.session.pip.servicePath=servicepath
1289 self.session.open(PiPSetup, pip = self.session.pip)
1291 from RecordTimer import parseEvent
1293 class InfoBarInstantRecord:
1294 """Instant Record - handles the instantRecord action in order to
1295 start/stop instant records"""
1297 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1299 "instantRecord": (self.instantRecord, _("Instant Record...")),
1302 self["BlinkingPoint"] = BlinkingPixmapConditional()
1303 self["BlinkingPoint"].hide()
1304 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1306 def stopCurrentRecording(self, entry = -1):
1307 if entry is not None and entry != -1:
1308 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1309 self.recording.remove(self.recording[entry])
1311 def startInstantRecording(self, limitEvent = False):
1312 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1314 # try to get event info
1317 service = self.session.nav.getCurrentService()
1318 epg = eEPGCache.getInstance()
1319 event = epg.lookupEventTime(serviceref, -1, 0)
1321 info = service.info()
1322 ev = info.getEvent(0)
1328 end = time() + 3600 * 10
1329 name = "instant record"
1333 if event is not None:
1334 curEvent = parseEvent(event)
1336 description = curEvent[3]
1337 eventid = curEvent[4]
1342 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1344 data = (begin, end, name, description, eventid)
1346 recording = self.session.nav.recordWithTimer(serviceref, *data)
1347 recording.dontSave = True
1348 self.recording.append(recording)
1350 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1352 def isInstantRecordRunning(self):
1353 print "self.recording:", self.recording
1354 if len(self.recording) > 0:
1355 for x in self.recording:
1360 def recordQuestionCallback(self, answer):
1361 print "pre:\n", self.recording
1363 if answer is None or answer[1] == "no":
1366 recording = self.recording[:]
1368 if not x in self.session.nav.RecordTimer.timer_list:
1369 self.recording.remove(x)
1370 elif x.dontSave and x.isRunning():
1371 list.append(TimerEntryComponent(x, False))
1373 if answer[1] == "changeduration":
1374 if len(self.recording) == 1:
1375 self.changeDuration(0)
1377 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1378 elif answer[1] == "changeendtime":
1379 if len(self.recording) == 1:
1382 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1383 elif answer[1] == "stop":
1384 if len(self.recording) == 1:
1385 self.stopCurrentRecording(0)
1387 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1388 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1389 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1390 if answer[1] == "manualduration":
1391 self.changeDuration(len(self.recording)-1)
1392 elif answer[1] == "manualendtime":
1393 self.setEndtime(len(self.recording)-1)
1394 print "after:\n", self.recording
1396 def setEndtime(self, entry):
1397 if entry is not None:
1398 self.selectedEntry = entry
1399 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1400 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1401 dlg.setTitle(_("Please change recording endtime"))
1403 def TimeDateInputClosed(self, ret):
1406 localendtime = localtime(ret[1])
1407 print "stopping recording at", strftime("%c", localendtime)
1408 self.recording[self.selectedEntry].end = ret[1]
1409 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1411 def changeDuration(self, entry):
1412 if entry is not None:
1413 self.selectedEntry = entry
1414 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1416 def inputCallback(self, value):
1417 if value is not None:
1418 print "stopping recording after", int(value), "minutes."
1419 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1420 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1422 def instantRecord(self):
1424 stat = os_stat(resolveFilename(SCOPE_HDD))
1426 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1429 if self.isInstantRecordRunning():
1430 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1431 title=_("A recording is currently running.\nWhat do you want to do?"), \
1432 list=[(_("stop recording"), "stop"), \
1433 (_("change recording (duration)"), "changeduration"), \
1434 (_("change recording (endtime)"), "changeendtime"), \
1435 (_("add recording (indefinitely)"), "indefinitely"), \
1436 (_("add recording (stop after current event)"), "event"), \
1437 (_("add recording (enter recording duration)"), "manualduration"), \
1438 (_("add recording (enter recording endtime)"), "manualendtime"), \
1439 (_("do nothing"), "no")])
1441 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1442 title=_("Start recording?"), \
1443 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1444 (_("add recording (stop after current event)"), "event"), \
1445 (_("add recording (enter recording duration)"), "manualduration"), \
1446 (_("add recording (enter recording endtime)"), "manualendtime"), \
1447 (_("don't record"), "no")])
1449 from Tools.ISO639 import LanguageCodes
1451 class InfoBarAudioSelection:
1453 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1455 "audioSelection": (self.audioSelection, _("Audio Options...")),
1458 def audioSelection(self):
1459 service = self.session.nav.getCurrentService()
1460 audio = service and service.audioTracks()
1461 self.audioTracks = audio
1462 n = audio and audio.getNumberOfTracks() or 0
1463 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1465 print "tlist:", tlist
1467 self.audioChannel = service.audioChannel()
1470 i = audio.getTrackInfo(x)
1471 language = i.getLanguage()
1472 description = i.getDescription()
1474 if LanguageCodes.has_key(language):
1475 language = LanguageCodes[language][0]
1477 if len(description):
1478 description += " (" + language + ")"
1480 description = language
1482 tlist.append((description, x))
1484 selectedAudio = tlist[0][1]
1485 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1489 if x[1] != selectedAudio:
1494 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1495 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1497 del self.audioTracks
1499 def audioSelected(self, audio):
1500 if audio is not None:
1501 if isinstance(audio[1], str):
1502 if audio[1] == "mode":
1503 keys = ["red", "green", "yellow"]
1504 selection = self.audioChannel.getCurrentChannel()
1505 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1506 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1508 del self.audioChannel
1509 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1510 self.audioTracks.selectTrack(audio[1])
1512 del self.audioChannel
1513 del self.audioTracks
1515 def modeSelected(self, mode):
1516 if mode is not None:
1517 self.audioChannel.selectChannel(mode[1])
1518 del self.audioChannel
1520 class InfoBarSubserviceSelection:
1522 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1524 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1527 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1529 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1530 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1532 self["SubserviceQuickzapAction"].setEnabled(False)
1534 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1538 def checkSubservicesAvail(self, ev):
1539 if ev == iPlayableService.evUpdatedEventInfo:
1540 service = self.session.nav.getCurrentService()
1541 subservices = service and service.subServices()
1542 if not subservices or subservices.getNumberOfSubservices() == 0:
1543 self["SubserviceQuickzapAction"].setEnabled(False)
1545 def nextSubservice(self):
1546 self.changeSubservice(+1)
1548 def prevSubservice(self):
1549 self.changeSubservice(-1)
1551 def changeSubservice(self, direction):
1552 service = self.session.nav.getCurrentService()
1553 subservices = service and service.subServices()
1554 n = subservices and subservices.getNumberOfSubservices()
1557 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1559 if subservices.getSubservice(x).toString() == ref.toString():
1562 selection += direction
1567 newservice = subservices.getSubservice(selection)
1568 if newservice.valid():
1571 self.session.nav.playService(newservice)
1573 def subserviceSelection(self):
1574 service = self.session.nav.getCurrentService()
1575 subservices = service and service.subServices()
1576 self.bouquets = self.servicelist.getBouquetList()
1577 n = subservices and subservices.getNumberOfSubservices()
1580 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1583 i = subservices.getSubservice(x)
1584 if i.toString() == ref.toString():
1586 tlist.append((i.getName(), i))
1588 if self.bouquets and len(self.bouquets):
1589 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1590 if config.usage.multibouquet.value:
1591 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1593 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1596 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1597 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1600 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1602 def subserviceSelected(self, service):
1604 if not service is None:
1605 if isinstance(service[1], str):
1606 if service[1] == "quickzap":
1607 from Screens.SubservicesQuickzap import SubservicesQuickzap
1608 self.session.open(SubservicesQuickzap, service[2])
1610 self["SubserviceQuickzapAction"].setEnabled(True)
1611 self.session.nav.playService(service[1])
1613 def addSubserviceToBouquetCallback(self, service):
1614 if len(service) > 1 and isinstance(service[1], eServiceReference):
1615 self.selectedSubservice = service
1616 if self.bouquets is None:
1619 cnt = len(self.bouquets)
1620 if cnt > 1: # show bouquet list
1621 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1622 elif cnt == 1: # add to only one existing bouquet
1623 self.addSubserviceToBouquet(self.bouquets[0][1])
1624 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1626 def bouquetSelClosed(self, confirmed):
1628 del self.selectedSubservice
1630 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1632 def addSubserviceToBouquet(self, dest):
1633 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1635 self.bsel.close(True)
1637 del self.selectedSubservice
1639 class InfoBarAdditionalInfo:
1641 self["NimA"] = Pixmap()
1642 self["NimB"] = Pixmap()
1643 self["NimA_Active"] = Pixmap()
1644 self["NimB_Active"] = Pixmap()
1646 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1647 self["TimeshiftPossible"] = self["RecordingPossible"]
1648 self["ExtensionsAvailable"] = Boolean(fixed=1)
1650 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1651 res_mgr = eDVBResourceManager.getInstance()
1653 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1655 def tunerUseMaskChanged(self, mask):
1657 self["NimA_Active"].show()
1659 self["NimA_Active"].hide()
1661 self["NimB_Active"].show()
1663 self["NimB_Active"].hide()
1665 def checkTunerState(self, service):
1666 info = service and service.frontendInfo()
1667 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1668 if feNumber is None:
1678 def gotServiceEvent(self, ev):
1679 service = self.session.nav.getCurrentService()
1680 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1681 self.checkTunerState(service)
1683 class InfoBarNotifications:
1685 self.onExecBegin.append(self.checkNotifications)
1686 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1687 self.onClose.append(self.__removeNotification)
1689 def __removeNotification(self):
1690 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1692 def checkNotificationsIfExecing(self):
1694 self.checkNotifications()
1696 def checkNotifications(self):
1697 if len(Notifications.notifications):
1698 n = Notifications.notifications[0]
1700 Notifications.notifications = Notifications.notifications[1:]
1703 if n[3].has_key("onSessionOpenCallback"):
1704 n[3]["onSessionOpenCallback"]()
1705 del n[3]["onSessionOpenCallback"]
1708 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1710 dlg = self.session.open(n[1], *n[2], **n[3])
1712 # remember that this notification is currently active
1714 Notifications.current_notifications.append(d)
1715 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1717 def __notificationClosed(self, d):
1718 Notifications.current_notifications.remove(d)
1720 class InfoBarServiceNotifications:
1722 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1724 iPlayableService.evEnd: self.serviceHasEnded
1727 def serviceHasEnded(self):
1728 print "service end!"
1731 self.setSeekState(self.SEEK_STATE_PLAY)
1735 class InfoBarCueSheetSupport:
1741 ENABLE_RESUME_SUPPORT = False
1744 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1746 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1747 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1748 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1752 self.is_closing = False
1753 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1755 iPlayableService.evStart: self.__serviceStarted,
1758 def __serviceStarted(self):
1761 print "new service started! trying to download cuts!"
1762 self.downloadCuesheet()
1764 if self.ENABLE_RESUME_SUPPORT:
1767 for (pts, what) in self.cut_list:
1768 if what == self.CUT_TYPE_LAST:
1771 if last is not None:
1772 self.resume_point = last
1773 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1775 def playLastCB(self, answer):
1777 seekable = self.__getSeekable()
1778 if seekable is not None:
1779 seekable.seekTo(self.resume_point)
1781 def __getSeekable(self):
1782 service = self.session.nav.getCurrentService()
1785 return service.seek()
1787 def cueGetCurrentPosition(self):
1788 seek = self.__getSeekable()
1791 r = seek.getPlayPosition()
1796 def jumpPreviousNextMark(self, cmp, alternative=None):
1797 current_pos = self.cueGetCurrentPosition()
1798 if current_pos is None:
1800 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1801 if mark is not None:
1803 elif alternative is not None:
1808 seekable = self.__getSeekable()
1809 if seekable is not None:
1810 seekable.seekTo(pts)
1812 def jumpPreviousMark(self):
1813 # we add 2 seconds, so if the play position is <2s after
1814 # the mark, the mark before will be used
1815 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1817 def jumpNextMark(self):
1818 self.jumpPreviousNextMark(lambda x: x)
1820 def getNearestCutPoint(self, pts, cmp=abs):
1823 for cp in self.cut_list:
1824 diff = cmp(cp[0] - pts)
1825 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1829 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1830 current_pos = self.cueGetCurrentPosition()
1831 if current_pos is None:
1832 print "not seekable"
1835 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1837 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1839 return nearest_cutpoint
1841 self.removeMark(nearest_cutpoint)
1842 elif not onlyremove and not onlyreturn:
1843 self.addMark((current_pos, self.CUT_TYPE_MARK))
1848 def addMark(self, point):
1849 insort(self.cut_list, point)
1850 self.uploadCuesheet()
1852 def removeMark(self, point):
1853 self.cut_list.remove(point)
1854 self.uploadCuesheet()
1856 def __getCuesheet(self):
1857 service = self.session.nav.getCurrentService()
1860 return service.cueSheet()
1862 def uploadCuesheet(self):
1863 cue = self.__getCuesheet()
1866 print "upload failed, no cuesheet interface"
1868 cue.setCutList(self.cut_list)
1870 def downloadCuesheet(self):
1871 cue = self.__getCuesheet()
1874 print "upload failed, no cuesheet interface"
1876 self.cut_list = cue.getCutList()
1878 class InfoBarSummary(Screen):
1880 <screen position="0,0" size="132,64">
1881 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1882 <convert type="ClockToText">WithSeconds</convert>
1884 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1885 <convert type="ServiceName">Name</convert>
1889 def __init__(self, session, parent):
1890 Screen.__init__(self, session)
1891 self["CurrentService"] = CurrentService(self.session.nav)
1892 self["CurrentTime"] = Clock()
1894 class InfoBarSummarySupport:
1898 def createSummary(self):
1899 return InfoBarSummary
1901 class InfoBarTeletextPlugin:
1903 self.teletext_plugin = None
1905 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1906 self.teletext_plugin = p
1908 if self.teletext_plugin is not None:
1909 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1911 "startTeletext": (self.startTeletext, _("View teletext..."))
1914 print "no teletext plugin found!"
1916 def startTeletext(self):
1917 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1919 class InfoBarSubtitleSupport(object):
1921 object.__init__(self)
1922 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1923 self.__subtitles_enabled = False
1925 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1927 iPlayableService.evEnd: self.__serviceStopped,
1928 iPlayableService.evUpdatedInfo: self.__updatedInfo
1930 self.cached_subtitle_checked = False
1931 self.__selected_subtitle = None
1933 def __serviceStopped(self):
1934 self.subtitle_window.hide()
1935 self.__subtitles_enabled = False
1936 self.cached_subtitle_checked = False
1938 def __updatedInfo(self):
1939 if not self.cached_subtitle_checked:
1940 subtitle = self.getCurrentServiceSubtitle()
1941 self.cached_subtitle_checked = True
1942 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1943 if self.__selected_subtitle:
1944 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1945 self.subtitle_window.show()
1946 self.__subtitles_enabled = True
1948 def getCurrentServiceSubtitle(self):
1949 service = self.session.nav.getCurrentService()
1950 return service and service.subtitle()
1952 def setSubtitlesEnable(self, enable=True):
1953 subtitle = self.getCurrentServiceSubtitle()
1954 if enable and self.__selected_subtitle is not None:
1955 if subtitle and not self.__subtitles_enabled:
1956 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1957 self.subtitle_window.show()
1958 self.__subtitles_enabled = True
1961 subtitle.disableSubtitles(self.subtitle_window.instance)
1962 self.__subtitles_enabled = False
1963 self.subtitle_window.hide()
1965 def setSelectedSubtitle(self, subtitle):
1966 self.__selected_subtitle = subtitle
1968 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1969 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1971 class InfoBarServiceErrorPopupSupport:
1973 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1975 iPlayableService.evTuneFailed: self.__tuneFailed,
1976 iPlayableService.evStart: self.__serviceStarted
1978 self.__serviceStarted()
1980 def __serviceStarted(self):
1981 self.last_error = None
1982 Notifications.RemovePopup(id = "ZapError")
1984 def __tuneFailed(self):
1985 service = self.session.nav.getCurrentService()
1986 info = service and service.info()
1987 error = info and info.getInfo(iServiceInformation.sDVBState)
1989 if error == self.last_error:
1992 self.last_error = error
1995 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1996 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1997 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1998 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1999 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2000 eDVBServicePMTHandler.eventNewProgramInfo: None,
2001 eDVBServicePMTHandler.eventTuned: None,
2002 eDVBServicePMTHandler.eventSOF: None,
2003 eDVBServicePMTHandler.eventEOF: None
2006 error = errors.get(error) #this returns None when the key not exist in the dict
2008 if error is not None:
2009 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2011 Notifications.RemovePopup(id = "ZapError")