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.RadioText import RadioText
16 from Components.Sources.FrontendStatus import FrontendStatus
17 from Components.Sources.Boolean import Boolean
18 from Components.Sources.Clock import Clock
19 from Components.TimerList import TimerEntryComponent
20 from Components.config import config, ConfigBoolean
22 from EpgSelection import EPGSelection
23 from Plugins.Plugin import PluginDescriptor
25 from Screen import Screen
26 from Screens.ChoiceBox import ChoiceBox
27 from Screens.Dish import Dish
28 from Screens.EventView import EventViewEPGSelect, EventViewSimple
29 from Screens.InputBox import InputBox
30 from Screens.MessageBox import MessageBox
31 from Screens.MinuteInput import MinuteInput
32 from Screens.TimerSelection import TimerSelection
33 from Screens.PictureInPicture import PictureInPicture
34 from Screens.SubtitleDisplay import SubtitleDisplay
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.onExecBegin.append(self.show)
76 self.hideTimer = eTimer()
77 self.hideTimer.timeout.get().append(self.doTimerHide)
78 self.hideTimer.start(5000, True)
80 self.onShow.append(self.__onShow)
81 self.onHide.append(self.__onHide)
84 self.__state = self.STATE_SHOWN
87 def startHideTimer(self):
88 if self.__state == self.STATE_SHOWN and not self.__locked:
89 idx = config.usage.infobar_timeout.index
91 self.hideTimer.start(idx*1000, True)
94 self.__state = self.STATE_HIDDEN
100 def doTimerHide(self):
101 self.hideTimer.stop()
102 if self.__state == self.STATE_SHOWN:
105 def toggleShow(self):
106 if self.__state == self.STATE_SHOWN:
108 self.hideTimer.stop()
109 elif self.__state == self.STATE_HIDDEN:
113 self.__locked = self.__locked + 1
116 self.hideTimer.stop()
118 def unlockShow(self):
119 self.__locked = self.__locked - 1
121 self.startHideTimer()
123 # def startShow(self):
124 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
125 # self.__state = self.STATE_SHOWN
127 # def startHide(self):
128 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
129 # self.__state = self.STATE_HIDDEN
131 class NumberZap(Screen):
138 self.close(int(self["number"].getText()))
140 def keyNumberGlobal(self, number):
141 self.Timer.start(3000, True) #reset timer
142 self.field = self.field + str(number)
143 self["number"].setText(self.field)
144 if len(self.field) >= 4:
147 def __init__(self, session, number):
148 Screen.__init__(self, session)
149 self.field = str(number)
151 self["channel"] = Label(_("Channel:"))
153 self["number"] = Label(self.field)
155 self["actions"] = NumberActionMap( [ "SetupActions" ],
159 "1": self.keyNumberGlobal,
160 "2": self.keyNumberGlobal,
161 "3": self.keyNumberGlobal,
162 "4": self.keyNumberGlobal,
163 "5": self.keyNumberGlobal,
164 "6": self.keyNumberGlobal,
165 "7": self.keyNumberGlobal,
166 "8": self.keyNumberGlobal,
167 "9": self.keyNumberGlobal,
168 "0": self.keyNumberGlobal
171 self.Timer = eTimer()
172 self.Timer.timeout.get().append(self.keyOK)
173 self.Timer.start(3000, True)
175 class InfoBarNumberZap:
176 """ Handles an initial number for NumberZapping """
178 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
180 "1": self.keyNumberGlobal,
181 "2": self.keyNumberGlobal,
182 "3": self.keyNumberGlobal,
183 "4": self.keyNumberGlobal,
184 "5": self.keyNumberGlobal,
185 "6": self.keyNumberGlobal,
186 "7": self.keyNumberGlobal,
187 "8": self.keyNumberGlobal,
188 "9": self.keyNumberGlobal,
189 "0": self.keyNumberGlobal,
192 def keyNumberGlobal(self, number):
193 # print "You pressed number " + str(number)
195 self.servicelist.recallPrevService()
196 if config.usage.show_infobar_on_zap.value:
199 self.session.openWithCallback(self.numberEntered, NumberZap, number)
201 def numberEntered(self, retval):
202 # print self.servicelist
204 self.zapToNumber(retval)
206 def searchNumberHelper(self, serviceHandler, num, bouquet):
207 servicelist = serviceHandler.list(bouquet)
208 if not servicelist is None:
210 serviceIterator = servicelist.getNext()
211 if not serviceIterator.valid(): #check end of list
213 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
216 if not num: #found service with searched number ?
217 return serviceIterator, 0
220 def zapToNumber(self, number):
221 bouquet = self.servicelist.bouquet_root
223 serviceHandler = eServiceCenter.getInstance()
224 if not config.usage.multibouquet.value:
225 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
227 bouquetlist = serviceHandler.list(bouquet)
228 if not bouquetlist is None:
230 bouquet = bouquetlist.getNext()
231 if not bouquet.valid(): #check end of list
233 if bouquet.flags & eServiceReference.isDirectory:
234 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
235 if not service is None:
236 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
237 self.servicelist.clearPath()
238 if self.servicelist.bouquet_root != bouquet:
239 self.servicelist.enterPath(self.servicelist.bouquet_root)
240 self.servicelist.enterPath(bouquet)
241 self.servicelist.setCurrentSelection(service) #select the service in servicelist
242 self.servicelist.zap()
244 config.misc.initialchannelselection = ConfigBoolean(default = True)
246 class InfoBarChannelSelection:
247 """ ChannelSelection - handles the channelSelection dialog and the initial
248 channelChange actions which open the channelSelection dialog """
251 self.servicelist = self.session.instantiateDialog(ChannelSelection)
253 if config.misc.initialchannelselection.value:
254 self.onShown.append(self.firstRun)
256 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
258 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
259 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
260 "zapUp": (self.zapUp, _("previous channel")),
261 "zapDown": (self.zapDown, _("next channel")),
262 "historyBack": (self.historyBack, _("previous channel in history")),
263 "historyNext": (self.historyNext, _("next channel in history")),
264 "openServiceList": (self.openServiceList, _("open servicelist")),
267 def showTvChannelList(self, zap=False):
268 self.servicelist.setModeTv()
270 self.servicelist.zap()
271 self.session.execDialog(self.servicelist)
273 def showRadioChannelList(self, zap=False):
274 self.servicelist.setModeRadio()
276 self.servicelist.zap()
277 self.session.execDialog(self.servicelist)
280 self.onShown.remove(self.firstRun)
281 config.misc.initialchannelselection.value = False
282 config.misc.initialchannelselection.save()
283 self.switchChannelDown()
285 def historyBack(self):
286 self.servicelist.historyBack()
288 def historyNext(self):
289 self.servicelist.historyNext()
291 def switchChannelUp(self):
292 self.servicelist.moveUp()
293 self.session.execDialog(self.servicelist)
295 def switchChannelDown(self):
296 self.servicelist.moveDown()
297 self.session.execDialog(self.servicelist)
299 def openServiceList(self):
300 self.session.execDialog(self.servicelist)
303 if self.servicelist.inBouquet():
304 prev = self.servicelist.getCurrentSelection()
306 prev = prev.toString()
308 if config.usage.quickzap_bouquet_change.value:
309 if self.servicelist.atBegin():
310 self.servicelist.prevBouquet()
311 self.servicelist.moveUp()
312 cur = self.servicelist.getCurrentSelection()
313 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
316 self.servicelist.moveUp()
317 self.servicelist.zap()
318 if config.usage.show_infobar_on_zap.value:
322 if self.servicelist.inBouquet():
323 prev = self.servicelist.getCurrentSelection()
325 prev = prev.toString()
327 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
328 self.servicelist.nextBouquet()
330 self.servicelist.moveDown()
331 cur = self.servicelist.getCurrentSelection()
332 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
335 self.servicelist.moveDown()
336 self.servicelist.zap()
337 if config.usage.show_infobar_on_zap.value:
341 """ Handles a menu action, to open the (main) menu """
343 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
345 "mainMenu": (self.mainMenu, _("Enter main menu...")),
347 self.session.infobar = None
350 print "loading mainmenu XML..."
351 menu = mdom.childNodes[0]
352 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
354 self.session.infobar = self
355 # so we can access the currently active infobar from screens opened from within the mainmenu
356 # at the moment used from the SubserviceSelection
358 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
360 def mainMenuClosed(self, *val):
361 self.session.infobar = None
363 class InfoBarSimpleEventView:
364 """ Opens the Eventview for now/next """
366 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
368 "showEventInfo": (self.openEventView, _("show event details")),
371 def openEventView(self):
373 service = self.session.nav.getCurrentService()
374 ref = self.session.nav.getCurrentlyPlayingServiceReference()
375 info = service.info()
378 self.epglist.append(ptr)
381 self.epglist.append(ptr)
382 if len(self.epglist) > 0:
383 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
385 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
386 if len(self.epglist) > 1:
387 tmp = self.epglist[0]
388 self.epglist[0]=self.epglist[1]
390 setEvent(self.epglist[0])
393 """ EPG - Opens an EPG list when the showEPGList action fires """
395 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
397 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
400 self.is_now_next = False
402 self.bouquetSel = None
403 self.eventView = None
404 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
406 "showEventInfo": (self.openEventView, _("show EPG...")),
409 def zapToService(self, service):
410 if not service is None:
411 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
412 self.servicelist.clearPath()
413 if self.servicelist.bouquet_root != self.epg_bouquet:
414 self.servicelist.enterPath(self.servicelist.bouquet_root)
415 self.servicelist.enterPath(self.epg_bouquet)
416 self.servicelist.setCurrentSelection(service) #select the service in servicelist
417 self.servicelist.zap()
419 def getBouquetServices(self, bouquet):
421 servicelist = eServiceCenter.getInstance().list(bouquet)
422 if not servicelist is None:
424 service = servicelist.getNext()
425 if not service.valid(): #check if end of list
427 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
429 services.append(ServiceReference(service))
432 def openBouquetEPG(self, bouquet, withCallback=True):
433 services = self.getBouquetServices(bouquet)
435 self.epg_bouquet = bouquet
437 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
439 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
441 def changeBouquetCB(self, direction, epg):
444 self.bouquetSel.down()
447 bouquet = self.bouquetSel.getCurrent()
448 services = self.getBouquetServices(bouquet)
450 self.epg_bouquet = bouquet
451 epg.setServices(services)
453 def closed(self, ret=False):
454 closedScreen = self.dlg_stack.pop()
455 if self.bouquetSel and closedScreen == self.bouquetSel:
456 self.bouquetSel = None
457 elif self.eventView and closedScreen == self.eventView:
458 self.eventView = None
460 dlgs=len(self.dlg_stack)
462 self.dlg_stack[dlgs-1].close(dlgs > 1)
464 def openMultiServiceEPG(self, withCallback=True):
465 bouquets = self.servicelist.getBouquetList()
470 if cnt > 1: # show bouquet list
472 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
473 self.dlg_stack.append(self.bouquetSel)
475 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
477 self.openBouquetEPG(bouquets[0][1], withCallback)
479 def openSingleServiceEPG(self):
480 ref=self.session.nav.getCurrentlyPlayingServiceReference()
481 self.session.open(EPGSelection, ref)
483 def openSimilarList(self, eventid, refstr):
484 self.session.open(EPGSelection, refstr, None, eventid)
486 def getNowNext(self):
488 service = self.session.nav.getCurrentService()
489 info = service and service.info()
490 ptr = info and info.getEvent(0)
492 self.epglist.append(ptr)
493 ptr = info and info.getEvent(1)
495 self.epglist.append(ptr)
497 def __evEventInfoChanged(self):
498 if self.is_now_next and len(self.dlg_stack) == 1:
500 assert self.eventView
501 if len(self.epglist):
502 self.eventView.setEvent(self.epglist[0])
504 def openEventView(self):
505 ref = self.session.nav.getCurrentlyPlayingServiceReference()
507 if len(self.epglist) == 0:
508 self.is_now_next = False
509 epg = eEPGCache.getInstance()
510 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
512 self.epglist.append(ptr)
513 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
515 self.epglist.append(ptr)
517 self.is_now_next = True
518 if len(self.epglist) > 0:
519 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
520 self.dlg_stack.append(self.eventView)
522 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
523 self.openMultiServiceEPG(False)
525 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
526 if len(self.epglist) > 1:
527 tmp = self.epglist[0]
528 self.epglist[0]=self.epglist[1]
530 setEvent(self.epglist[0])
533 """provides a snr/agc/ber display"""
535 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
538 """provides a current/next event info display"""
540 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
541 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
543 class InfoBarRadioText:
544 """provides radio (RDS) text info display"""
546 self["RadioText"] = RadioText(self.session.nav)
548 class InfoBarServiceName:
550 self["CurrentService"] = CurrentService(self.session.nav)
553 """handles actions like seeking, pause"""
555 # ispause, isff, issm
556 SEEK_STATE_PLAY = (0, 0, 0, ">")
557 SEEK_STATE_PAUSE = (1, 0, 0, "||")
558 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
559 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
560 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
561 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
562 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
563 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
565 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
566 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
567 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
568 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
570 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
571 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
572 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
575 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
577 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
578 iPlayableService.evStart: self.__serviceStarted,
580 iPlayableService.evEOF: self.__evEOF,
581 iPlayableService.evSOF: self.__evSOF,
584 class InfoBarSeekActionMap(HelpableActionMap):
585 def __init__(self, screen, *args, **kwargs):
586 HelpableActionMap.__init__(self, screen, *args, **kwargs)
589 def action(self, contexts, action):
590 if action[:5] == "seek:":
591 time = int(action[5:])
592 self.screen.seekRelative(time * 90000)
595 return HelpableActionMap.action(self, contexts, action)
597 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
599 "playpauseService": (self.playpauseService, _("pause")),
600 "pauseService": (self.pauseService, _("pause")),
601 "unPauseService": (self.unPauseService, _("continue")),
603 "seekFwd": (self.seekFwd, _("skip forward")),
604 "seekFwdDown": self.seekFwdDown,
605 "seekFwdUp": self.seekFwdUp,
606 "seekBack": (self.seekBack, _("skip backward")),
607 "seekBackDown": self.seekBackDown,
608 "seekBackUp": self.seekBackUp,
610 # give them a little more priority to win over color buttons
612 self["SeekActions"].setEnabled(False)
614 self.seekstate = self.SEEK_STATE_PLAY
615 self.onClose.append(self.delTimer)
617 self.fwdtimer = False
618 self.fwdKeyTimer = eTimer()
619 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
621 self.rwdtimer = False
622 self.rwdKeyTimer = eTimer()
623 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
625 self.onPlayStateChanged = [ ]
627 self.lockedBecauseOfSkipping = False
640 service = self.session.nav.getCurrentService()
644 seek = service.seek()
646 if seek is None or not seek.isCurrentlySeekable():
651 def isSeekable(self):
652 if self.getSeek() is None:
656 def __seekableStatusChanged(self):
657 print "seekable status changed!"
658 if not self.isSeekable():
659 self["SeekActions"].setEnabled(False)
660 print "not seekable, return to play"
661 self.setSeekState(self.SEEK_STATE_PLAY)
663 self["SeekActions"].setEnabled(True)
666 def __serviceStarted(self):
667 self.seekstate = self.SEEK_STATE_PLAY
669 def setSeekState(self, state):
670 service = self.session.nav.getCurrentService()
675 if not self.isSeekable():
676 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
677 state = self.SEEK_STATE_PLAY
679 pauseable = service.pause()
681 if pauseable is None:
682 print "not pauseable."
683 state = self.SEEK_STATE_PLAY
685 oldstate = self.seekstate
686 self.seekstate = state
689 if oldstate[i] != self.seekstate[i]:
690 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
692 for c in self.onPlayStateChanged:
695 self.checkSkipShowHideLock()
699 def playpauseService(self):
700 if self.seekstate != self.SEEK_STATE_PLAY:
701 self.unPauseService()
705 def pauseService(self):
706 if self.seekstate == self.SEEK_STATE_PAUSE:
707 print "pause, but in fact unpause"
708 self.unPauseService()
710 if self.seekstate == self.SEEK_STATE_PLAY:
711 print "yes, playing."
713 print "no", self.seekstate
715 self.setSeekState(self.SEEK_STATE_PAUSE);
717 def unPauseService(self):
719 if self.seekstate == self.SEEK_STATE_PLAY:
721 self.setSeekState(self.SEEK_STATE_PLAY)
723 def doSeek(self, seektime):
724 print "doseek", seektime
725 service = self.session.nav.getCurrentService()
729 seekable = self.getSeek()
733 seekable.seekTo(90 * seektime)
735 def seekFwdDown(self):
736 print "start fwd timer"
738 self.fwdKeyTimer.start(1000)
740 def seekBackDown(self):
741 print "start rewind timer"
743 self.rwdKeyTimer.start(1000)
748 self.fwdKeyTimer.stop()
749 self.fwdtimer = False
754 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
755 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
756 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
757 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
758 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
759 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
760 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
761 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
762 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
763 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
764 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
765 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
766 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
767 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
768 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
770 self.setSeekState(lookup[self.seekstate])
772 def seekBackUp(self):
775 self.rwdKeyTimer.stop()
776 self.rwdtimer = False
781 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
782 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
783 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
784 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
785 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
786 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
787 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
788 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
789 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
790 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
791 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
792 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
793 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
794 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
795 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
797 self.setSeekState(lookup[self.seekstate])
799 if self.seekstate == self.SEEK_STATE_PAUSE:
800 seekable = self.getSeek()
801 if seekable is not None:
802 seekable.seekRelative(-1, 3)
804 def fwdTimerFire(self):
805 print "Display seek fwd"
806 self.fwdKeyTimer.stop()
807 self.fwdtimer = False
808 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
810 def fwdSeekTo(self, minutes):
811 print "Seek", minutes, "minutes forward"
813 seekable = self.getSeek()
814 if seekable is not None:
815 seekable.seekRelative(1, minutes * 60 * 90000)
817 def rwdTimerFire(self):
819 self.rwdKeyTimer.stop()
820 self.rwdtimer = False
821 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
823 def rwdSeekTo(self, minutes):
825 self.fwdSeekTo(0 - minutes)
827 def checkSkipShowHideLock(self):
828 wantlock = self.seekstate != self.SEEK_STATE_PLAY
830 if config.usage.show_infobar_on_zap.value:
831 if self.lockedBecauseOfSkipping and not wantlock:
833 self.lockedBecauseOfSkipping = False
835 if wantlock and not self.lockedBecauseOfSkipping:
837 self.lockedBecauseOfSkipping = True
840 if self.seekstate != self.SEEK_STATE_PLAY:
841 self.setSeekState(self.SEEK_STATE_PAUSE)
843 #self.getSeek().seekRelative(1, -90000)
844 self.setSeekState(self.SEEK_STATE_PLAY)
846 self.setSeekState(self.SEEK_STATE_PAUSE)
849 self.setSeekState(self.SEEK_STATE_PLAY)
852 def seekRelative(self, diff):
853 seekable = self.getSeek()
854 if seekable is not None:
855 seekable.seekRelative(1, diff)
857 def seekAbsolute(self, abs):
858 seekable = self.getSeek()
859 if seekable is not None:
862 from Screens.PVRState import PVRState, TimeshiftState
864 class InfoBarPVRState:
865 def __init__(self, screen=PVRState):
866 self.onPlayStateChanged.append(self.__playStateChanged)
867 self.pvrStateDialog = self.session.instantiateDialog(screen)
868 self.onShow.append(self._mayShow)
869 self.onHide.append(self.pvrStateDialog.hide)
872 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
873 self.pvrStateDialog.show()
875 def __playStateChanged(self, state):
876 playstateString = state[3]
877 self.pvrStateDialog["state"].setText(playstateString)
880 class InfoBarTimeshiftState(InfoBarPVRState):
882 InfoBarPVRState.__init__(self, screen=TimeshiftState)
885 if self.execing and self.timeshift_enabled:
886 self.pvrStateDialog.show()
888 class InfoBarShowMovies:
890 # i don't really like this class.
891 # it calls a not further specified "movie list" on up/down/movieList,
892 # so this is not more than an action map
894 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
896 "movieList": (self.showMovies, "movie list"),
897 "up": (self.showMovies, "movie list"),
898 "down": (self.showMovies, "movie list")
901 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
905 # Timeshift works the following way:
906 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
907 # - normal playback TUNER unused PLAY enable disable disable
908 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
909 # - user presess pause again FILE record PLAY enable disable enable
910 # - user fast forwards FILE record FF enable disable enable
911 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
912 # - user backwards FILE record BACK # !! enable disable enable
916 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
917 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
918 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
919 # - the user can now PVR around
920 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
921 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
923 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
924 # - if the user rewinds, or press pause, timeshift will be activated again
926 # note that a timeshift can be enabled ("recording") and
927 # activated (currently time-shifting).
929 class InfoBarTimeshift:
931 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
933 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
934 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
936 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
938 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
939 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
940 }, prio=-1) # priority over record
942 self.timeshift_enabled = 0
943 self.timeshift_state = 0
944 self.ts_pause_timer = eTimer()
945 self.ts_pause_timer.timeout.get().append(self.pauseService)
947 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
949 iPlayableService.evStart: self.__serviceStarted,
950 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
953 def getTimeshift(self):
954 service = self.session.nav.getCurrentService()
955 return service and service.timeshift()
957 def startTimeshift(self):
958 print "enable timeshift"
959 ts = self.getTimeshift()
961 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
962 print "no ts interface"
965 if self.timeshift_enabled:
966 print "hu, timeshift already enabled?"
968 if not ts.startTimeshift():
969 self.timeshift_enabled = 1
971 # we remove the "relative time" for now.
972 #self.pvrStateDialog["timeshift"].setRelative(time.time())
975 self.setSeekState(self.SEEK_STATE_PAUSE)
977 # enable the "TimeshiftEnableActions", which will override
978 # the startTimeshift actions
979 self.__seekableStatusChanged()
981 print "timeshift failed"
983 def stopTimeshift(self):
984 if not self.timeshift_enabled:
986 print "disable timeshift"
987 ts = self.getTimeshift()
990 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
992 def stopTimeshiftConfirmed(self, confirmed):
996 ts = self.getTimeshift()
1001 self.timeshift_enabled = 0
1004 self.__seekableStatusChanged()
1006 # activates timeshift, and seeks to (almost) the end
1007 def activateTimeshiftEnd(self):
1008 ts = self.getTimeshift()
1013 if ts.isTimeshiftActive():
1014 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1017 self.setSeekState(self.SEEK_STATE_PLAY)
1018 ts.activateTimeshift()
1019 self.seekRelative(0)
1021 # same as activateTimeshiftEnd, but pauses afterwards.
1022 def activateTimeshiftEndAndPause(self):
1023 state = self.seekstate
1024 self.activateTimeshiftEnd()
1026 # well, this is "andPause", but it could be pressed from pause,
1027 # when pausing on the (fake-)"live" picture, so an un-pause
1030 print "now, pauseService"
1031 if state == self.SEEK_STATE_PLAY:
1032 print "is PLAYING, start pause timer"
1033 self.ts_pause_timer.start(200, 1)
1036 self.unPauseService()
1038 def __seekableStatusChanged(self):
1041 print "self.isSeekable", self.isSeekable()
1042 print "self.timeshift_enabled", self.timeshift_enabled
1044 # when this service is not seekable, but timeshift
1045 # is enabled, this means we can activate
1047 if not self.isSeekable() and self.timeshift_enabled:
1050 print "timeshift activate:", enabled
1051 self["TimeshiftActivateActions"].setEnabled(enabled)
1053 def __serviceStarted(self):
1054 self.timeshift_enabled = False
1055 self.__seekableStatusChanged()
1057 from Screens.PiPSetup import PiPSetup
1059 class InfoBarExtensions:
1060 EXTENSION_SINGLE = 0
1066 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1068 "extensions": (self.showExtensionSelection, _("view extensions...")),
1071 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1072 self.list.append((type, extension, key))
1074 def updateExtension(self, extension, key = None):
1075 self.extensionsList.append(extension)
1077 if self.extensionKeys.has_key(key):
1081 for x in self.availableKeys:
1082 if not self.extensionKeys.has_key(x):
1087 self.extensionKeys[key] = len(self.extensionsList) - 1
1089 def updateExtensions(self):
1090 self.extensionsList = []
1091 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1092 self.extensionKeys = {}
1094 if x[0] == self.EXTENSION_SINGLE:
1095 self.updateExtension(x[1], x[2])
1098 self.updateExtension(y[0], y[1])
1101 def showExtensionSelection(self):
1102 self.updateExtensions()
1103 extensionsList = self.extensionsList[:]
1106 for x in self.availableKeys:
1107 if self.extensionKeys.has_key(x):
1108 entry = self.extensionKeys[x]
1109 extension = self.extensionsList[entry]
1111 name = str(extension[0]())
1112 list.append((extension[0](), extension))
1114 extensionsList.remove(extension)
1116 extensionsList.remove(extension)
1117 for x in extensionsList:
1118 list.append((x[0](), x))
1119 keys += [""] * len(extensionsList)
1120 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1122 def extensionCallback(self, answer):
1123 if answer is not None:
1126 from Tools.BoundFunction import boundFunction
1128 # depends on InfoBarExtensions
1129 from Components.PluginComponent import plugins
1131 class InfoBarPlugins:
1133 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1135 def getPluginName(self, name):
1138 def getPluginList(self):
1140 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1141 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1144 def runPlugin(self, plugin):
1145 plugin(session = self.session)
1147 # depends on InfoBarExtensions
1148 class InfoBarSleepTimer:
1150 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1152 def available(self):
1155 def getSleepTimerName(self):
1156 return _("Sleep Timer")
1158 def showSleepTimerSetup(self):
1159 self.session.open(SleepTimerEdit)
1161 # depends on InfoBarExtensions
1164 self.session.pipshown = False
1166 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1167 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1168 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1170 def available(self):
1174 return self.session.pipshown
1176 def getShowHideName(self):
1177 if self.session.pipshown:
1178 return _("Disable Picture in Picture")
1180 return _("Activate Picture in Picture")
1182 def getSwapName(self):
1183 return _("Swap Services")
1185 def getMoveName(self):
1186 return _("Move Picture in Picture")
1189 if self.session.pipshown:
1190 del self.session.pip
1191 self.session.pipshown = False
1193 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1194 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1195 if self.session.pip.playService(newservice):
1196 self.session.pipshown = True
1197 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1199 self.session.pipshown = False
1200 del self.session.pip
1201 self.session.nav.playService(newservice)
1204 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1205 if self.session.pip.servicePath:
1206 servicepath = self.servicelist.getCurrentServicePath()
1207 ref=servicepath[len(servicepath)-1]
1208 pipref=self.session.pip.getCurrentService()
1209 self.session.pip.playService(swapservice)
1210 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1211 if pipref.toString() != ref.toString(): # is a subservice ?
1212 self.session.nav.stopService() # stop portal
1213 self.session.nav.playService(pipref) # start subservice
1214 self.session.pip.servicePath=servicepath
1217 self.session.open(PiPSetup, pip = self.session.pip)
1219 from RecordTimer import parseEvent
1221 class InfoBarInstantRecord:
1222 """Instant Record - handles the instantRecord action in order to
1223 start/stop instant records"""
1225 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1227 "instantRecord": (self.instantRecord, _("Instant Record...")),
1230 self["BlinkingPoint"] = BlinkingPixmapConditional()
1231 self["BlinkingPoint"].hide()
1232 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1234 def stopCurrentRecording(self, entry = -1):
1235 if entry is not None and entry != -1:
1236 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1237 self.recording.remove(self.recording[entry])
1239 def startInstantRecording(self, limitEvent = False):
1240 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1242 # try to get event info
1245 service = self.session.nav.getCurrentService()
1246 epg = eEPGCache.getInstance()
1247 event = epg.lookupEventTime(serviceref, -1, 0)
1249 info = service.info()
1250 ev = info.getEvent(0)
1256 end = time() + 3600 * 10
1257 name = "instant record"
1261 if event is not None:
1262 curEvent = parseEvent(event)
1264 description = curEvent[3]
1265 eventid = curEvent[4]
1270 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1272 data = (begin, end, name, description, eventid)
1274 recording = self.session.nav.recordWithTimer(serviceref, *data)
1275 recording.dontSave = True
1276 self.recording.append(recording)
1278 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1280 def isInstantRecordRunning(self):
1281 print "self.recording:", self.recording
1282 if len(self.recording) > 0:
1283 for x in self.recording:
1288 def recordQuestionCallback(self, answer):
1289 print "pre:\n", self.recording
1291 if answer is None or answer[1] == "no":
1294 recording = self.recording[:]
1296 if not x in self.session.nav.RecordTimer.timer_list:
1297 self.recording.remove(x)
1298 elif x.dontSave and x.isRunning():
1299 list.append(TimerEntryComponent(x, False))
1301 if answer[1] == "changeduration":
1302 if len(self.recording) == 1:
1303 self.changeDuration(0)
1305 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1306 elif answer[1] == "stop":
1307 if len(self.recording) == 1:
1308 self.stopCurrentRecording(0)
1310 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1311 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1313 if answer[1] == "event":
1315 if answer[1] == "manualduration":
1316 self.selectedEntry = len(self.recording)
1317 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1318 self.startInstantRecording(limitEvent = limitEvent)
1320 print "after:\n", self.recording
1322 def changeDuration(self, entry):
1323 if entry is not None:
1324 self.selectedEntry = entry
1325 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1327 def inputCallback(self, value):
1328 if value is not None:
1329 print "stopping recording after", int(value), "minutes."
1330 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1331 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1333 def instantRecord(self):
1335 stat = os_stat(resolveFilename(SCOPE_HDD))
1337 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1340 if self.isInstantRecordRunning():
1341 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1342 title=_("A recording is currently running.\nWhat do you want to do?"), \
1343 list=[(_("stop recording"), "stop"), \
1344 (_("change recording (duration)"), "changeduration"), \
1345 (_("add recording (indefinitely)"), "indefinitely"), \
1346 (_("add recording (stop after current event)"), "event"), \
1347 (_("add recording (enter recording duration)"), "manualduration"), \
1348 (_("do nothing"), "no")])
1350 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1351 title=_("Start recording?"), \
1352 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1353 (_("add recording (stop after current event)"), "event"), \
1354 (_("add recording (enter recording duration)"), "manualduration"), \
1355 (_("don't record"), "no")])
1357 from Tools.ISO639 import LanguageCodes
1359 class InfoBarAudioSelection:
1361 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1363 "audioSelection": (self.audioSelection, _("Audio Options...")),
1366 def audioSelection(self):
1367 service = self.session.nav.getCurrentService()
1368 audio = service and service.audioTracks()
1369 self.audioTracks = audio
1370 n = audio and audio.getNumberOfTracks() or 0
1371 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1373 print "tlist:", tlist
1375 self.audioChannel = service.audioChannel()
1378 i = audio.getTrackInfo(x)
1379 language = i.getLanguage()
1380 description = i.getDescription()
1382 if LanguageCodes.has_key(language):
1383 language = LanguageCodes[language][0]
1385 if len(description):
1386 description += " (" + language + ")"
1388 description = language
1390 tlist.append((description, x))
1392 selectedAudio = tlist[0][1]
1393 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1397 if x[1] != selectedAudio:
1402 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1403 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1405 del self.audioTracks
1407 def audioSelected(self, audio):
1408 if audio is not None:
1409 if isinstance(audio[1], str):
1410 if audio[1] == "mode":
1411 keys = ["red", "green", "yellow"]
1412 selection = self.audioChannel.getCurrentChannel()
1413 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1414 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1416 del self.audioChannel
1417 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1418 self.audioTracks.selectTrack(audio[1])
1420 del self.audioChannel
1421 del self.audioTracks
1423 def modeSelected(self, mode):
1424 if mode is not None:
1425 self.audioChannel.selectChannel(mode[1])
1426 del self.audioChannel
1428 class InfoBarSubserviceSelection:
1430 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1432 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1435 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1437 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1438 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1440 self["SubserviceQuickzapAction"].setEnabled(False)
1442 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1446 def checkSubservicesAvail(self, ev):
1447 if ev == iPlayableService.evUpdatedEventInfo:
1448 service = self.session.nav.getCurrentService()
1449 subservices = service and service.subServices()
1450 if not subservices or subservices.getNumberOfSubservices() == 0:
1451 self["SubserviceQuickzapAction"].setEnabled(False)
1453 def nextSubservice(self):
1454 self.changeSubservice(+1)
1456 def prevSubservice(self):
1457 self.changeSubservice(-1)
1459 def changeSubservice(self, direction):
1460 service = self.session.nav.getCurrentService()
1461 subservices = service and service.subServices()
1462 n = subservices and subservices.getNumberOfSubservices()
1465 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1467 if subservices.getSubservice(x).toString() == ref.toString():
1470 selection += direction
1475 newservice = subservices.getSubservice(selection)
1476 if newservice.valid():
1479 if config.usage.show_infobar_on_zap.value:
1481 self.session.nav.playService(newservice)
1483 def subserviceSelection(self):
1484 service = self.session.nav.getCurrentService()
1485 subservices = service and service.subServices()
1486 self.bouquets = self.servicelist.getBouquetList()
1487 n = subservices and subservices.getNumberOfSubservices()
1490 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1493 i = subservices.getSubservice(x)
1494 if i.toString() == ref.toString():
1496 tlist.append((i.getName(), i))
1498 if self.bouquets and len(self.bouquets):
1499 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1500 if config.usage.multibouquet.value:
1501 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1503 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1506 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1507 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1510 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1512 def subserviceSelected(self, service):
1514 if not service is None:
1515 if isinstance(service[1], str):
1516 if service[1] == "quickzap":
1517 from Screens.SubservicesQuickzap import SubservicesQuickzap
1518 self.session.open(SubservicesQuickzap, service[2])
1520 self["SubserviceQuickzapAction"].setEnabled(True)
1521 if config.usage.show_infobar_on_zap.value:
1523 self.session.nav.playService(service[1])
1525 def addSubserviceToBouquetCallback(self, service):
1526 if len(service) > 1 and isinstance(service[1], eServiceReference):
1527 self.selectedSubservice = service
1528 if self.bouquets is None:
1531 cnt = len(self.bouquets)
1532 if cnt > 1: # show bouquet list
1533 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1534 elif cnt == 1: # add to only one existing bouquet
1535 self.addSubserviceToBouquet(self.bouquets[0][1])
1536 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1538 def bouquetSelClosed(self, confirmed):
1540 del self.selectedSubservice
1542 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1544 def addSubserviceToBouquet(self, dest):
1545 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1547 self.bsel.close(True)
1549 del self.selectedSubservice
1551 class InfoBarAdditionalInfo:
1553 self["NimA"] = Pixmap()
1554 self["NimB"] = Pixmap()
1555 self["NimA_Active"] = Pixmap()
1556 self["NimB_Active"] = Pixmap()
1558 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1559 self["TimeshiftPossible"] = self["RecordingPossible"]
1560 self["ExtensionsAvailable"] = Boolean(fixed=1)
1562 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1563 res_mgr = eDVBResourceManager.getInstance()
1565 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1567 def tunerUseMaskChanged(self, mask):
1569 self["NimA_Active"].show()
1571 self["NimA_Active"].hide()
1573 self["NimB_Active"].show()
1575 self["NimB_Active"].hide()
1577 def checkTunerState(self, service):
1578 info = service and service.frontendInfo()
1579 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1580 if feNumber is None:
1590 def gotServiceEvent(self, ev):
1591 service = self.session.nav.getCurrentService()
1592 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1593 self.checkTunerState(service)
1595 class InfoBarNotifications:
1597 self.onExecBegin.append(self.checkNotifications)
1598 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1599 self.onClose.append(self.__removeNotification)
1601 def __removeNotification(self):
1602 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1604 def checkNotificationsIfExecing(self):
1606 self.checkNotifications()
1608 def checkNotifications(self):
1609 if len(Notifications.notifications):
1610 n = Notifications.notifications[0]
1612 Notifications.notifications = Notifications.notifications[1:]
1615 if n[3].has_key("onSessionOpenCallback"):
1616 n[3]["onSessionOpenCallback"]()
1617 del n[3]["onSessionOpenCallback"]
1620 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1622 dlg = self.session.open(n[1], *n[2], **n[3])
1624 # remember that this notification is currently active
1626 Notifications.current_notifications.append(d)
1627 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1629 def __notificationClosed(self, d):
1630 Notifications.current_notifications.remove(d)
1632 class InfoBarServiceNotifications:
1634 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1636 iPlayableService.evEnd: self.serviceHasEnded
1639 def serviceHasEnded(self):
1640 print "service end!"
1643 self.setSeekState(self.SEEK_STATE_PLAY)
1647 class InfoBarCueSheetSupport:
1653 ENABLE_RESUME_SUPPORT = False
1656 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1658 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1659 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1660 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1664 self.is_closing = False
1665 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1667 iPlayableService.evStart: self.__serviceStarted,
1670 def __serviceStarted(self):
1673 print "new service started! trying to download cuts!"
1674 self.downloadCuesheet()
1676 if self.ENABLE_RESUME_SUPPORT:
1679 for (pts, what) in self.cut_list:
1680 if what == self.CUT_TYPE_LAST:
1683 if last is not None:
1684 self.resume_point = last
1685 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1687 def playLastCB(self, answer):
1689 seekable = self.__getSeekable()
1690 if seekable is not None:
1691 seekable.seekTo(self.resume_point)
1693 def __getSeekable(self):
1694 service = self.session.nav.getCurrentService()
1697 return service.seek()
1699 def cueGetCurrentPosition(self):
1700 seek = self.__getSeekable()
1703 r = seek.getPlayPosition()
1708 def jumpPreviousNextMark(self, cmp, alternative=None):
1709 current_pos = self.cueGetCurrentPosition()
1710 if current_pos is None:
1712 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1713 if mark is not None:
1715 elif alternative is not None:
1720 seekable = self.__getSeekable()
1721 if seekable is not None:
1722 seekable.seekTo(pts)
1724 def jumpPreviousMark(self):
1725 # we add 2 seconds, so if the play position is <2s after
1726 # the mark, the mark before will be used
1727 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1729 def jumpNextMark(self):
1730 self.jumpPreviousNextMark(lambda x: x)
1732 def getNearestCutPoint(self, pts, cmp=abs):
1735 for cp in self.cut_list:
1736 diff = cmp(cp[0] - pts)
1737 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1741 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1742 current_pos = self.cueGetCurrentPosition()
1743 if current_pos is None:
1744 print "not seekable"
1747 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1749 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1751 return nearest_cutpoint
1753 self.removeMark(nearest_cutpoint)
1754 elif not onlyremove and not onlyreturn:
1755 self.addMark((current_pos, self.CUT_TYPE_MARK))
1760 def addMark(self, point):
1761 insort(self.cut_list, point)
1762 self.uploadCuesheet()
1764 def removeMark(self, point):
1765 self.cut_list.remove(point)
1766 self.uploadCuesheet()
1768 def __getCuesheet(self):
1769 service = self.session.nav.getCurrentService()
1772 return service.cueSheet()
1774 def uploadCuesheet(self):
1775 cue = self.__getCuesheet()
1778 print "upload failed, no cuesheet interface"
1780 cue.setCutList(self.cut_list)
1782 def downloadCuesheet(self):
1783 cue = self.__getCuesheet()
1786 print "upload failed, no cuesheet interface"
1788 self.cut_list = cue.getCutList()
1790 class InfoBarSummary(Screen):
1792 <screen position="0,0" size="132,64">
1793 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1794 <convert type="ClockToText">WithSeconds</convert>
1796 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1797 <convert type="ServiceName">Name</convert>
1801 def __init__(self, session, parent):
1802 Screen.__init__(self, session)
1803 self["CurrentService"] = CurrentService(self.session.nav)
1804 self["CurrentTime"] = Clock()
1806 class InfoBarSummarySupport:
1810 def createSummary(self):
1811 return InfoBarSummary
1813 class InfoBarTeletextPlugin:
1815 self.teletext_plugin = None
1817 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1818 self.teletext_plugin = p
1820 if self.teletext_plugin is not None:
1821 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1823 "startTeletext": (self.startTeletext, _("View teletext..."))
1826 print "no teletext plugin found!"
1828 def startTeletext(self):
1829 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1831 class InfoBarSubtitleSupport(object):
1833 object.__init__(self)
1834 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1835 self.__subtitles_enabled = False
1837 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1839 iPlayableService.evEnd: self.__serviceStopped,
1840 iPlayableService.evUpdatedInfo: self.__updatedInfo
1842 self.cached_subtitle_checked = False
1844 def __serviceStopped(self):
1845 self.subtitle_window.hide()
1846 self.__subtitles_enabled = False
1847 self.cached_subtitle_checked = False
1849 def __updatedInfo(self):
1850 if not self.cached_subtitle_checked:
1851 subtitle = self.getCurrentServiceSubtitle()
1852 self.cached_subtitle_checked = True
1854 self.__selected_subtitle = subtitle.getCachedSubtitle()
1855 if self.__selected_subtitle:
1856 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1857 self.subtitle_window.show()
1858 self.__subtitles_enabled = True
1860 def getCurrentServiceSubtitle(self):
1861 service = self.session.nav.getCurrentService()
1862 return service and service.subtitle()
1864 def setSubtitlesEnable(self, enable=True):
1865 subtitle = self.getCurrentServiceSubtitle()
1866 if enable and self.__selected_subtitle is not None:
1867 if subtitle and not self.__subtitles_enabled:
1868 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1869 self.subtitle_window.show()
1870 self.__subtitles_enabled = True
1873 subtitle.disableSubtitles(self.subtitle_window.instance)
1874 self.__subtitles_enabled = False
1875 self.subtitle_window.hide()
1877 def setSelectedSubtitle(self, subtitle):
1878 self.__selected_subtitle = subtitle
1880 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1881 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1883 class InfoBarServiceErrorPopupSupport:
1885 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1887 iPlayableService.evTuneFailed: self.__tuneFailed,
1888 iPlayableService.evStart: self.__serviceStarted
1890 self.__serviceStarted()
1892 def __serviceStarted(self):
1893 self.last_error = None
1894 Notifications.RemovePopup(id = "ZapError")
1896 def __tuneFailed(self):
1897 service = self.session.nav.getCurrentService()
1898 info = service and service.info()
1899 error = info and info.getInfo(iServiceInformation.sDVBState)
1901 if error == self.last_error:
1904 self.last_error = error
1907 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1908 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1909 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1910 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1911 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1912 eDVBServicePMTHandler.eventNewProgramInfo: None,
1913 eDVBServicePMTHandler.eventTuned: None,
1914 eDVBServicePMTHandler.eventSOF: None,
1915 eDVBServicePMTHandler.eventEOF: None
1918 error = errors.get(error) #this returns None when the key not exist in the dict
1920 if error is not None:
1921 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1923 Notifications.RemovePopup(id = "ZapError")