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...")),
409 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
412 def showEventInfoWhenNotVisible(self):
419 def zapToService(self, service):
420 if not service is None:
421 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
422 self.servicelist.clearPath()
423 if self.servicelist.bouquet_root != self.epg_bouquet:
424 self.servicelist.enterPath(self.servicelist.bouquet_root)
425 self.servicelist.enterPath(self.epg_bouquet)
426 self.servicelist.setCurrentSelection(service) #select the service in servicelist
427 self.servicelist.zap()
429 def getBouquetServices(self, bouquet):
431 servicelist = eServiceCenter.getInstance().list(bouquet)
432 if not servicelist is None:
434 service = servicelist.getNext()
435 if not service.valid(): #check if end of list
437 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
439 services.append(ServiceReference(service))
442 def openBouquetEPG(self, bouquet, withCallback=True):
443 services = self.getBouquetServices(bouquet)
445 self.epg_bouquet = bouquet
447 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
449 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
451 def changeBouquetCB(self, direction, epg):
454 self.bouquetSel.down()
457 bouquet = self.bouquetSel.getCurrent()
458 services = self.getBouquetServices(bouquet)
460 self.epg_bouquet = bouquet
461 epg.setServices(services)
463 def closed(self, ret=False):
464 closedScreen = self.dlg_stack.pop()
465 if self.bouquetSel and closedScreen == self.bouquetSel:
466 self.bouquetSel = None
467 elif self.eventView and closedScreen == self.eventView:
468 self.eventView = None
470 dlgs=len(self.dlg_stack)
472 self.dlg_stack[dlgs-1].close(dlgs > 1)
474 def openMultiServiceEPG(self, withCallback=True):
475 bouquets = self.servicelist.getBouquetList()
480 if cnt > 1: # show bouquet list
482 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
483 self.dlg_stack.append(self.bouquetSel)
485 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
487 self.openBouquetEPG(bouquets[0][1], withCallback)
489 def openSingleServiceEPG(self):
490 ref=self.session.nav.getCurrentlyPlayingServiceReference()
491 self.session.open(EPGSelection, ref)
493 def openSimilarList(self, eventid, refstr):
494 self.session.open(EPGSelection, refstr, None, eventid)
496 def getNowNext(self):
498 service = self.session.nav.getCurrentService()
499 info = service and service.info()
500 ptr = info and info.getEvent(0)
502 self.epglist.append(ptr)
503 ptr = info and info.getEvent(1)
505 self.epglist.append(ptr)
507 def __evEventInfoChanged(self):
508 if self.is_now_next and len(self.dlg_stack) == 1:
510 assert self.eventView
511 if len(self.epglist):
512 self.eventView.setEvent(self.epglist[0])
514 def openEventView(self):
515 ref = self.session.nav.getCurrentlyPlayingServiceReference()
517 if len(self.epglist) == 0:
518 self.is_now_next = False
519 epg = eEPGCache.getInstance()
520 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
522 self.epglist.append(ptr)
523 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
525 self.epglist.append(ptr)
527 self.is_now_next = True
528 if len(self.epglist) > 0:
529 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
530 self.dlg_stack.append(self.eventView)
532 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
533 self.openMultiServiceEPG(False)
535 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
536 if len(self.epglist) > 1:
537 tmp = self.epglist[0]
538 self.epglist[0]=self.epglist[1]
540 setEvent(self.epglist[0])
543 """provides a snr/agc/ber display"""
545 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
548 """provides a current/next event info display"""
550 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
551 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
553 class InfoBarRdsDecoder:
554 """provides RDS and Rass support/display"""
556 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
557 self.rass_interactive = None
559 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
561 iPlayableService.evEnd: self.__serviceStopped,
562 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
565 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
567 "startRassInteractive": self.startRassInteractive
570 self["RdsActions"].setEnabled(False)
572 self.onLayoutFinish.append(self.rds_display.show)
573 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
575 def RassInteractivePossibilityChanged(self, state):
576 self["RdsActions"].setEnabled(state)
578 def RassSlidePicChanged(self):
579 if not self.rass_interactive:
580 service = self.session.nav.getCurrentService()
581 decoder = service and service.rdsDecoder()
583 decoder.showRassSlidePicture()
585 def __serviceStopped(self):
586 if self.rass_interactive is not None:
587 rass_interactive = self.rass_interactive
588 self.rass_interactive = None
589 rass_interactive.close()
591 def startRassInteractive(self):
592 self.rds_display.hide()
593 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
595 def RassInteractiveClosed(self, *val):
596 if self.rass_interactive is not None:
597 self.rass_interactive = None
598 self.RassSlidePicChanged()
599 self.rds_display.show()
601 class InfoBarServiceName:
603 self["CurrentService"] = CurrentService(self.session.nav)
606 """handles actions like seeking, pause"""
608 # ispause, isff, issm
609 SEEK_STATE_PLAY = (0, 0, 0, ">")
610 SEEK_STATE_PAUSE = (1, 0, 0, "||")
611 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
612 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
613 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
614 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
615 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
616 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
618 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
619 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
620 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
621 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
623 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
624 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
625 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
627 SEEK_STATE_EOF = (1, 0, 0, "END")
629 def __init__(self, actionmap = "InfobarSeekActions"):
630 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
632 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
633 iPlayableService.evStart: self.__serviceStarted,
635 iPlayableService.evEOF: self.__evEOF,
636 iPlayableService.evSOF: self.__evSOF,
639 class InfoBarSeekActionMap(HelpableActionMap):
640 def __init__(self, screen, *args, **kwargs):
641 HelpableActionMap.__init__(self, screen, *args, **kwargs)
644 def action(self, contexts, action):
645 print "action:", action
646 if action[:5] == "seek:":
647 time = int(action[5:])
648 self.screen.seekRelative(time * 90000)
649 self.screen.showAfterSeek()
652 return HelpableActionMap.action(self, contexts, action)
654 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
656 "playpauseService": (self.playpauseService, _("pause")),
657 "pauseService": (self.pauseService, _("pause")),
658 "unPauseService": (self.unPauseService, _("continue")),
660 "seekFwd": (self.seekFwd, _("skip forward")),
661 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
662 "seekBack": (self.seekBack, _("skip backward")),
663 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
665 # give them a little more priority to win over color buttons
667 self["SeekActions"].setEnabled(False)
669 self.seekstate = self.SEEK_STATE_PLAY
671 self.onPlayStateChanged = [ ]
673 self.lockedBecauseOfSkipping = False
675 self.__seekableStatusChanged()
677 def showAfterSeek(self):
678 if isinstance(self, InfoBarShowHide):
688 service = self.session.nav.getCurrentService()
692 seek = service.seek()
694 if seek is None or not seek.isCurrentlySeekable():
699 def isSeekable(self):
700 if self.getSeek() is None:
704 def __seekableStatusChanged(self):
705 print "seekable status changed!"
706 if not self.isSeekable():
707 self["SeekActions"].setEnabled(False)
708 print "not seekable, return to play"
709 self.setSeekState(self.SEEK_STATE_PLAY)
711 self["SeekActions"].setEnabled(True)
714 def __serviceStarted(self):
715 self.seekstate = self.SEEK_STATE_PLAY
716 self.__seekableStatusChanged()
718 def setSeekState(self, state):
719 service = self.session.nav.getCurrentService()
724 if not self.isSeekable():
725 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
726 state = self.SEEK_STATE_PLAY
728 pauseable = service.pause()
730 if pauseable is None:
731 print "not pauseable."
732 state = self.SEEK_STATE_PLAY
734 oldstate = self.seekstate
735 self.seekstate = state
738 if oldstate[i] != self.seekstate[i]:
739 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
741 for c in self.onPlayStateChanged:
744 self.checkSkipShowHideLock()
748 def playpauseService(self):
749 if self.seekstate != self.SEEK_STATE_PLAY:
750 self.unPauseService()
754 def pauseService(self):
755 if self.seekstate == self.SEEK_STATE_PAUSE:
756 print "pause, but in fact unpause"
757 self.unPauseService()
759 if self.seekstate == self.SEEK_STATE_PLAY:
760 print "yes, playing."
762 print "no", self.seekstate
764 self.setSeekState(self.SEEK_STATE_PAUSE);
766 def unPauseService(self):
768 if self.seekstate == self.SEEK_STATE_PLAY:
770 self.setSeekState(self.SEEK_STATE_PLAY)
772 def doSeek(self, seektime):
773 print "doseek", seektime
774 service = self.session.nav.getCurrentService()
778 seekable = self.getSeek()
782 seekable.seekTo(90 * seektime)
786 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
787 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
788 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
789 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
790 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
791 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
792 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
793 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
794 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
795 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
796 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
797 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
798 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
799 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
800 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
801 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
803 self.setSeekState(lookup[self.seekstate])
807 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
808 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
809 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
810 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
811 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
812 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
813 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
814 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
815 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
816 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
817 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
818 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
819 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
820 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
821 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
822 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
824 self.setSeekState(lookup[self.seekstate])
826 if self.seekstate == self.SEEK_STATE_PAUSE:
827 seekable = self.getSeek()
828 if seekable is not None:
829 seekable.seekRelative(-1, 3)
831 def seekFwdManual(self):
832 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
834 def fwdSeekTo(self, minutes):
835 print "Seek", minutes, "minutes forward"
837 seekable = self.getSeek()
838 if seekable is not None:
839 seekable.seekRelative(1, minutes * 60 * 90000)
841 def seekBackManual(self):
842 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
844 def rwdSeekTo(self, minutes):
846 self.fwdSeekTo(0 - minutes)
848 def checkSkipShowHideLock(self):
849 wantlock = self.seekstate != self.SEEK_STATE_PLAY
851 if config.usage.show_infobar_on_zap.value:
852 if self.lockedBecauseOfSkipping and not wantlock:
854 self.lockedBecauseOfSkipping = False
856 if wantlock and not self.lockedBecauseOfSkipping:
858 self.lockedBecauseOfSkipping = True
861 if self.seekstate == self.SEEK_STATE_EOF:
863 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
864 print "end of stream while seeking back, ignoring."
867 # if we are seeking, we try to end up ~1s before the end, and pause there.
868 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
869 self.setSeekState(self.SEEK_STATE_EOF)
870 self.seekRelativeToEnd(-90000)
872 self.setSeekState(self.SEEK_STATE_EOF)
875 self.setSeekState(self.SEEK_STATE_PLAY)
878 def seekRelative(self, diff):
879 seekable = self.getSeek()
880 if seekable is not None:
881 print "seekRelative: res:", seekable.seekRelative(1, diff)
885 def seekRelativeToEnd(self, diff):
886 assert diff <= 0, "diff is expected to be negative!"
888 # might sound like an evil hack, but:
889 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
890 # and we don't get that by passing 0 here (it would seek to begin).
894 # relative-to-end seeking is implemented as absolutes seeks with negative time
895 self.seekAbsolute(diff)
897 def seekAbsolute(self, abs):
898 seekable = self.getSeek()
899 if seekable is not None:
902 from Screens.PVRState import PVRState, TimeshiftState
904 class InfoBarPVRState:
905 def __init__(self, screen=PVRState):
906 self.onPlayStateChanged.append(self.__playStateChanged)
907 self.pvrStateDialog = self.session.instantiateDialog(screen)
908 self.onShow.append(self._mayShow)
909 self.onHide.append(self.pvrStateDialog.hide)
912 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
913 self.pvrStateDialog.show()
915 def __playStateChanged(self, state):
916 playstateString = state[3]
917 self.pvrStateDialog["state"].setText(playstateString)
920 class InfoBarTimeshiftState(InfoBarPVRState):
922 InfoBarPVRState.__init__(self, screen=TimeshiftState)
925 if self.execing and self.timeshift_enabled:
926 self.pvrStateDialog.show()
928 class InfoBarShowMovies:
930 # i don't really like this class.
931 # it calls a not further specified "movie list" on up/down/movieList,
932 # so this is not more than an action map
934 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
936 "movieList": (self.showMovies, _("movie list")),
937 "up": (self.showMovies, _("movie list")),
938 "down": (self.showMovies, _("movie list"))
941 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
945 # Timeshift works the following way:
946 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
947 # - normal playback TUNER unused PLAY enable disable disable
948 # - user presses "yellow" button. FILE record PAUSE enable disable enable
949 # - user presess pause again FILE record PLAY enable disable enable
950 # - user fast forwards FILE record FF enable disable enable
951 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
952 # - user backwards FILE record BACK # !! enable disable enable
956 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
957 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
958 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
959 # - the user can now PVR around
960 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
961 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
963 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
964 # - if the user rewinds, or press pause, timeshift will be activated again
966 # note that a timeshift can be enabled ("recording") and
967 # activated (currently time-shifting).
969 class InfoBarTimeshift:
971 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
973 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
974 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
976 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
978 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
979 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
980 }, prio=-1) # priority over record
982 self.timeshift_enabled = 0
983 self.timeshift_state = 0
984 self.ts_rewind_timer = eTimer()
985 self.ts_rewind_timer.timeout.get().append(self.rewindService)
987 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
989 iPlayableService.evStart: self.__serviceStarted,
990 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
993 def getTimeshift(self):
994 service = self.session.nav.getCurrentService()
995 return service and service.timeshift()
997 def startTimeshift(self):
998 print "enable timeshift"
999 ts = self.getTimeshift()
1001 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1002 print "no ts interface"
1005 if self.timeshift_enabled:
1006 print "hu, timeshift already enabled?"
1008 if not ts.startTimeshift():
1009 self.timeshift_enabled = 1
1011 # we remove the "relative time" for now.
1012 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1015 #self.setSeekState(self.SEEK_STATE_PAUSE)
1016 self.activateTimeshiftEnd(False)
1018 # enable the "TimeshiftEnableActions", which will override
1019 # the startTimeshift actions
1020 self.__seekableStatusChanged()
1022 print "timeshift failed"
1024 def stopTimeshift(self):
1025 if not self.timeshift_enabled:
1027 print "disable timeshift"
1028 ts = self.getTimeshift()
1031 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1033 def stopTimeshiftConfirmed(self, confirmed):
1037 ts = self.getTimeshift()
1042 self.timeshift_enabled = 0
1045 self.__seekableStatusChanged()
1047 # activates timeshift, and seeks to (almost) the end
1048 def activateTimeshiftEnd(self, back = True):
1049 ts = self.getTimeshift()
1050 print "activateTimeshiftEnd"
1055 if ts.isTimeshiftActive():
1056 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1060 ts.activateTimeshift() # activate timeshift will automatically pause
1061 self.setSeekState(self.SEEK_STATE_PAUSE)
1062 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1065 self.ts_rewind_timer.start(200, 1)
1067 def rewindService(self):
1068 self.setSeekState(self.SEEK_STATE_BACK_16X)
1070 # same as activateTimeshiftEnd, but pauses afterwards.
1071 def activateTimeshiftEndAndPause(self):
1072 print "activateTimeshiftEndAndPause"
1073 #state = self.seekstate
1074 self.activateTimeshiftEnd(False)
1076 def __seekableStatusChanged(self):
1079 print "self.isSeekable", self.isSeekable()
1080 print "self.timeshift_enabled", self.timeshift_enabled
1082 # when this service is not seekable, but timeshift
1083 # is enabled, this means we can activate
1085 if not self.isSeekable() and self.timeshift_enabled:
1088 print "timeshift activate:", enabled
1089 self["TimeshiftActivateActions"].setEnabled(enabled)
1091 def __serviceStarted(self):
1092 self.timeshift_enabled = False
1093 self.__seekableStatusChanged()
1095 from Screens.PiPSetup import PiPSetup
1097 class InfoBarExtensions:
1098 EXTENSION_SINGLE = 0
1104 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1106 "extensions": (self.showExtensionSelection, _("view extensions...")),
1109 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1110 self.list.append((type, extension, key))
1112 def updateExtension(self, extension, key = None):
1113 self.extensionsList.append(extension)
1115 if self.extensionKeys.has_key(key):
1119 for x in self.availableKeys:
1120 if not self.extensionKeys.has_key(x):
1125 self.extensionKeys[key] = len(self.extensionsList) - 1
1127 def updateExtensions(self):
1128 self.extensionsList = []
1129 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1130 self.extensionKeys = {}
1132 if x[0] == self.EXTENSION_SINGLE:
1133 self.updateExtension(x[1], x[2])
1136 self.updateExtension(y[0], y[1])
1139 def showExtensionSelection(self):
1140 self.updateExtensions()
1141 extensionsList = self.extensionsList[:]
1144 for x in self.availableKeys:
1145 if self.extensionKeys.has_key(x):
1146 entry = self.extensionKeys[x]
1147 extension = self.extensionsList[entry]
1149 name = str(extension[0]())
1150 list.append((extension[0](), extension))
1152 extensionsList.remove(extension)
1154 extensionsList.remove(extension)
1155 for x in extensionsList:
1156 list.append((x[0](), x))
1157 keys += [""] * len(extensionsList)
1158 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1160 def extensionCallback(self, answer):
1161 if answer is not None:
1164 from Tools.BoundFunction import boundFunction
1166 # depends on InfoBarExtensions
1167 from Components.PluginComponent import plugins
1169 class InfoBarPlugins:
1171 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1173 def getPluginName(self, name):
1176 def getPluginList(self):
1178 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1179 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1182 def runPlugin(self, plugin):
1183 plugin(session = self.session)
1185 # depends on InfoBarExtensions
1186 class InfoBarSleepTimer:
1188 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1190 def available(self):
1193 def getSleepTimerName(self):
1194 return _("Sleep Timer")
1196 def showSleepTimerSetup(self):
1197 self.session.open(SleepTimerEdit)
1199 # depends on InfoBarExtensions
1202 self.session.pipshown = False
1204 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1205 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1206 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1208 def available(self):
1212 return self.session.pipshown
1214 def getShowHideName(self):
1215 if self.session.pipshown:
1216 return _("Disable Picture in Picture")
1218 return _("Activate Picture in Picture")
1220 def getSwapName(self):
1221 return _("Swap Services")
1223 def getMoveName(self):
1224 return _("Move Picture in Picture")
1227 if self.session.pipshown:
1228 del self.session.pip
1229 self.session.pipshown = False
1231 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1232 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1233 if self.session.pip.playService(newservice):
1234 self.session.pipshown = True
1235 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1237 self.session.pipshown = False
1238 del self.session.pip
1239 self.session.nav.playService(newservice)
1242 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1243 if self.session.pip.servicePath:
1244 servicepath = self.servicelist.getCurrentServicePath()
1245 ref=servicepath[len(servicepath)-1]
1246 pipref=self.session.pip.getCurrentService()
1247 self.session.pip.playService(swapservice)
1248 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1249 if pipref.toString() != ref.toString(): # is a subservice ?
1250 self.session.nav.stopService() # stop portal
1251 self.session.nav.playService(pipref) # start subservice
1252 self.session.pip.servicePath=servicepath
1255 self.session.open(PiPSetup, pip = self.session.pip)
1257 from RecordTimer import parseEvent
1259 class InfoBarInstantRecord:
1260 """Instant Record - handles the instantRecord action in order to
1261 start/stop instant records"""
1263 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1265 "instantRecord": (self.instantRecord, _("Instant Record...")),
1268 self["BlinkingPoint"] = BlinkingPixmapConditional()
1269 self["BlinkingPoint"].hide()
1270 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1272 def stopCurrentRecording(self, entry = -1):
1273 if entry is not None and entry != -1:
1274 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1275 self.recording.remove(self.recording[entry])
1277 def startInstantRecording(self, limitEvent = False):
1278 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1280 # try to get event info
1283 service = self.session.nav.getCurrentService()
1284 epg = eEPGCache.getInstance()
1285 event = epg.lookupEventTime(serviceref, -1, 0)
1287 info = service.info()
1288 ev = info.getEvent(0)
1294 end = time() + 3600 * 10
1295 name = "instant record"
1299 if event is not None:
1300 curEvent = parseEvent(event)
1302 description = curEvent[3]
1303 eventid = curEvent[4]
1308 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1310 data = (begin, end, name, description, eventid)
1312 recording = self.session.nav.recordWithTimer(serviceref, *data)
1313 recording.dontSave = True
1314 self.recording.append(recording)
1316 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1318 def isInstantRecordRunning(self):
1319 print "self.recording:", self.recording
1320 if len(self.recording) > 0:
1321 for x in self.recording:
1326 def recordQuestionCallback(self, answer):
1327 print "pre:\n", self.recording
1329 if answer is None or answer[1] == "no":
1332 recording = self.recording[:]
1334 if not x in self.session.nav.RecordTimer.timer_list:
1335 self.recording.remove(x)
1336 elif x.dontSave and x.isRunning():
1337 list.append(TimerEntryComponent(x, False))
1339 if answer[1] == "changeduration":
1340 if len(self.recording) == 1:
1341 self.changeDuration(0)
1343 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1344 elif answer[1] == "changeendtime":
1345 if len(self.recording) == 1:
1348 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1349 elif answer[1] == "stop":
1350 if len(self.recording) == 1:
1351 self.stopCurrentRecording(0)
1353 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1354 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1355 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1356 if answer[1] == "manualduration":
1357 self.changeDuration(len(self.recording)-1)
1358 elif answer[1] == "manualendtime":
1359 self.setEndtime(len(self.recording)-1)
1360 print "after:\n", self.recording
1362 def setEndtime(self, entry):
1363 if entry is not None:
1364 self.selectedEntry = entry
1365 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1366 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1367 dlg.setTitle(_("Please change recording endtime"))
1369 def TimeDateInputClosed(self, ret):
1372 localendtime = localtime(ret[1])
1373 print "stopping recording at", strftime("%c", localendtime)
1374 self.recording[self.selectedEntry].end = ret[1]
1375 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1377 def changeDuration(self, entry):
1378 if entry is not None:
1379 self.selectedEntry = entry
1380 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1382 def inputCallback(self, value):
1383 if value is not None:
1384 print "stopping recording after", int(value), "minutes."
1385 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1386 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1388 def instantRecord(self):
1390 stat = os_stat(resolveFilename(SCOPE_HDD))
1392 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1395 if self.isInstantRecordRunning():
1396 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1397 title=_("A recording is currently running.\nWhat do you want to do?"), \
1398 list=[(_("stop recording"), "stop"), \
1399 (_("change recording (duration)"), "changeduration"), \
1400 (_("change recording (endtime)"), "changeendtime"), \
1401 (_("add recording (indefinitely)"), "indefinitely"), \
1402 (_("add recording (stop after current event)"), "event"), \
1403 (_("add recording (enter recording duration)"), "manualduration"), \
1404 (_("add recording (enter recording endtime)"), "manualendtime"), \
1405 (_("do nothing"), "no")])
1407 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1408 title=_("Start recording?"), \
1409 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1410 (_("add recording (stop after current event)"), "event"), \
1411 (_("add recording (enter recording duration)"), "manualduration"), \
1412 (_("add recording (enter recording endtime)"), "manualendtime"), \
1413 (_("don't record"), "no")])
1415 from Tools.ISO639 import LanguageCodes
1417 class InfoBarAudioSelection:
1419 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1421 "audioSelection": (self.audioSelection, _("Audio Options...")),
1424 def audioSelection(self):
1425 service = self.session.nav.getCurrentService()
1426 audio = service and service.audioTracks()
1427 self.audioTracks = audio
1428 n = audio and audio.getNumberOfTracks() or 0
1429 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1431 print "tlist:", tlist
1433 self.audioChannel = service.audioChannel()
1436 i = audio.getTrackInfo(x)
1437 language = i.getLanguage()
1438 description = i.getDescription()
1440 if LanguageCodes.has_key(language):
1441 language = LanguageCodes[language][0]
1443 if len(description):
1444 description += " (" + language + ")"
1446 description = language
1448 tlist.append((description, x))
1450 selectedAudio = tlist[0][1]
1451 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1455 if x[1] != selectedAudio:
1460 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1461 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1463 del self.audioTracks
1465 def audioSelected(self, audio):
1466 if audio is not None:
1467 if isinstance(audio[1], str):
1468 if audio[1] == "mode":
1469 keys = ["red", "green", "yellow"]
1470 selection = self.audioChannel.getCurrentChannel()
1471 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1472 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1474 del self.audioChannel
1475 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1476 self.audioTracks.selectTrack(audio[1])
1478 del self.audioChannel
1479 del self.audioTracks
1481 def modeSelected(self, mode):
1482 if mode is not None:
1483 self.audioChannel.selectChannel(mode[1])
1484 del self.audioChannel
1486 class InfoBarSubserviceSelection:
1488 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1490 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1493 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1495 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1496 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1498 self["SubserviceQuickzapAction"].setEnabled(False)
1500 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1504 def checkSubservicesAvail(self, ev):
1505 if ev == iPlayableService.evUpdatedEventInfo:
1506 service = self.session.nav.getCurrentService()
1507 subservices = service and service.subServices()
1508 if not subservices or subservices.getNumberOfSubservices() == 0:
1509 self["SubserviceQuickzapAction"].setEnabled(False)
1511 def nextSubservice(self):
1512 self.changeSubservice(+1)
1514 def prevSubservice(self):
1515 self.changeSubservice(-1)
1517 def changeSubservice(self, direction):
1518 service = self.session.nav.getCurrentService()
1519 subservices = service and service.subServices()
1520 n = subservices and subservices.getNumberOfSubservices()
1523 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1525 if subservices.getSubservice(x).toString() == ref.toString():
1528 selection += direction
1533 newservice = subservices.getSubservice(selection)
1534 if newservice.valid():
1537 self.session.nav.playService(newservice)
1539 def subserviceSelection(self):
1540 service = self.session.nav.getCurrentService()
1541 subservices = service and service.subServices()
1542 self.bouquets = self.servicelist.getBouquetList()
1543 n = subservices and subservices.getNumberOfSubservices()
1546 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1549 i = subservices.getSubservice(x)
1550 if i.toString() == ref.toString():
1552 tlist.append((i.getName(), i))
1554 if self.bouquets and len(self.bouquets):
1555 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1556 if config.usage.multibouquet.value:
1557 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1559 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1562 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1563 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1566 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1568 def subserviceSelected(self, service):
1570 if not service is None:
1571 if isinstance(service[1], str):
1572 if service[1] == "quickzap":
1573 from Screens.SubservicesQuickzap import SubservicesQuickzap
1574 self.session.open(SubservicesQuickzap, service[2])
1576 self["SubserviceQuickzapAction"].setEnabled(True)
1577 self.session.nav.playService(service[1])
1579 def addSubserviceToBouquetCallback(self, service):
1580 if len(service) > 1 and isinstance(service[1], eServiceReference):
1581 self.selectedSubservice = service
1582 if self.bouquets is None:
1585 cnt = len(self.bouquets)
1586 if cnt > 1: # show bouquet list
1587 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1588 elif cnt == 1: # add to only one existing bouquet
1589 self.addSubserviceToBouquet(self.bouquets[0][1])
1590 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1592 def bouquetSelClosed(self, confirmed):
1594 del self.selectedSubservice
1596 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1598 def addSubserviceToBouquet(self, dest):
1599 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1601 self.bsel.close(True)
1603 del self.selectedSubservice
1605 class InfoBarAdditionalInfo:
1607 self["NimA"] = Pixmap()
1608 self["NimB"] = Pixmap()
1609 self["NimA_Active"] = Pixmap()
1610 self["NimB_Active"] = Pixmap()
1612 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1613 self["TimeshiftPossible"] = self["RecordingPossible"]
1614 self["ExtensionsAvailable"] = Boolean(fixed=1)
1616 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1617 res_mgr = eDVBResourceManager.getInstance()
1619 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1621 def tunerUseMaskChanged(self, mask):
1623 self["NimA_Active"].show()
1625 self["NimA_Active"].hide()
1627 self["NimB_Active"].show()
1629 self["NimB_Active"].hide()
1631 def checkTunerState(self, service):
1632 info = service and service.frontendInfo()
1633 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1634 if feNumber is None:
1644 def gotServiceEvent(self, ev):
1645 service = self.session.nav.getCurrentService()
1646 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1647 self.checkTunerState(service)
1649 class InfoBarNotifications:
1651 self.onExecBegin.append(self.checkNotifications)
1652 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1653 self.onClose.append(self.__removeNotification)
1655 def __removeNotification(self):
1656 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1658 def checkNotificationsIfExecing(self):
1660 self.checkNotifications()
1662 def checkNotifications(self):
1663 if len(Notifications.notifications):
1664 n = Notifications.notifications[0]
1666 Notifications.notifications = Notifications.notifications[1:]
1669 if n[3].has_key("onSessionOpenCallback"):
1670 n[3]["onSessionOpenCallback"]()
1671 del n[3]["onSessionOpenCallback"]
1674 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1676 dlg = self.session.open(n[1], *n[2], **n[3])
1678 # remember that this notification is currently active
1680 Notifications.current_notifications.append(d)
1681 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1683 def __notificationClosed(self, d):
1684 Notifications.current_notifications.remove(d)
1686 class InfoBarServiceNotifications:
1688 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1690 iPlayableService.evEnd: self.serviceHasEnded
1693 def serviceHasEnded(self):
1694 print "service end!"
1697 self.setSeekState(self.SEEK_STATE_PLAY)
1701 class InfoBarCueSheetSupport:
1707 ENABLE_RESUME_SUPPORT = False
1710 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1712 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to next marked position")),
1713 "jumpNextMark": (self.jumpNextMark, _("jump to previous marked position")),
1714 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1718 self.is_closing = False
1719 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1721 iPlayableService.evStart: self.__serviceStarted,
1724 def __serviceStarted(self):
1727 print "new service started! trying to download cuts!"
1728 self.downloadCuesheet()
1730 if self.ENABLE_RESUME_SUPPORT:
1733 for (pts, what) in self.cut_list:
1734 if what == self.CUT_TYPE_LAST:
1737 if last is not None:
1738 self.resume_point = last
1739 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1741 def playLastCB(self, answer):
1743 seekable = self.__getSeekable()
1744 if seekable is not None:
1745 seekable.seekTo(self.resume_point)
1747 def __getSeekable(self):
1748 service = self.session.nav.getCurrentService()
1751 return service.seek()
1753 def cueGetCurrentPosition(self):
1754 seek = self.__getSeekable()
1757 r = seek.getPlayPosition()
1762 def jumpPreviousNextMark(self, cmp, alternative=None):
1763 current_pos = self.cueGetCurrentPosition()
1764 if current_pos is None:
1766 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1767 if mark is not None:
1769 elif alternative is not None:
1774 seekable = self.__getSeekable()
1775 if seekable is not None:
1776 seekable.seekTo(pts)
1778 def jumpPreviousMark(self):
1779 # we add 2 seconds, so if the play position is <2s after
1780 # the mark, the mark before will be used
1781 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1783 def jumpNextMark(self):
1784 self.jumpPreviousNextMark(lambda x: x)
1786 def getNearestCutPoint(self, pts, cmp=abs):
1789 for cp in self.cut_list:
1790 diff = cmp(cp[0] - pts)
1791 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1795 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1796 current_pos = self.cueGetCurrentPosition()
1797 if current_pos is None:
1798 print "not seekable"
1801 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1803 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1805 return nearest_cutpoint
1807 self.removeMark(nearest_cutpoint)
1808 elif not onlyremove and not onlyreturn:
1809 self.addMark((current_pos, self.CUT_TYPE_MARK))
1814 def showAfterCuesheetOperation(self):
1815 if isinstance(self, InfoBarShowHide):
1818 def addMark(self, point):
1819 insort(self.cut_list, point)
1820 self.uploadCuesheet()
1821 self.showAfterCuesheetOperation()
1823 def removeMark(self, point):
1824 self.cut_list.remove(point)
1825 self.uploadCuesheet()
1826 self.showAfterCuesheetOperation()
1828 def showAfterCuesheetOperation(self):
1829 if isinstance(self, InfoBarShowHide):
1832 def __getCuesheet(self):
1833 service = self.session.nav.getCurrentService()
1836 return service.cueSheet()
1838 def uploadCuesheet(self):
1839 cue = self.__getCuesheet()
1842 print "upload failed, no cuesheet interface"
1844 cue.setCutList(self.cut_list)
1846 def downloadCuesheet(self):
1847 cue = self.__getCuesheet()
1850 print "download failed, no cuesheet interface"
1853 self.cut_list = cue.getCutList()
1855 class InfoBarSummary(Screen):
1857 <screen position="0,0" size="132,64">
1858 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1859 <convert type="ClockToText">WithSeconds</convert>
1861 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1862 <convert type="ServiceName">Name</convert>
1866 def __init__(self, session, parent):
1867 Screen.__init__(self, session)
1868 self["CurrentService"] = CurrentService(self.session.nav)
1869 self["CurrentTime"] = Clock()
1871 class InfoBarSummarySupport:
1875 def createSummary(self):
1876 return InfoBarSummary
1878 class InfoBarTeletextPlugin:
1880 self.teletext_plugin = None
1882 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1883 self.teletext_plugin = p
1885 if self.teletext_plugin is not None:
1886 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1888 "startTeletext": (self.startTeletext, _("View teletext..."))
1891 print "no teletext plugin found!"
1893 def startTeletext(self):
1894 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1896 class InfoBarSubtitleSupport(object):
1898 object.__init__(self)
1899 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1900 self.__subtitles_enabled = False
1902 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1904 iPlayableService.evEnd: self.__serviceStopped,
1905 iPlayableService.evUpdatedInfo: self.__updatedInfo
1907 self.cached_subtitle_checked = False
1908 self.__selected_subtitle = None
1910 def __serviceStopped(self):
1911 self.subtitle_window.hide()
1912 self.__subtitles_enabled = False
1913 self.cached_subtitle_checked = False
1915 def __updatedInfo(self):
1916 if not self.cached_subtitle_checked:
1917 subtitle = self.getCurrentServiceSubtitle()
1918 self.cached_subtitle_checked = True
1919 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1920 if self.__selected_subtitle:
1921 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1922 self.subtitle_window.show()
1923 self.__subtitles_enabled = True
1925 def getCurrentServiceSubtitle(self):
1926 service = self.session.nav.getCurrentService()
1927 return service and service.subtitle()
1929 def setSubtitlesEnable(self, enable=True):
1930 subtitle = self.getCurrentServiceSubtitle()
1931 if enable and self.__selected_subtitle is not None:
1932 if subtitle and not self.__subtitles_enabled:
1933 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1934 self.subtitle_window.show()
1935 self.__subtitles_enabled = True
1938 subtitle.disableSubtitles(self.subtitle_window.instance)
1939 self.__subtitles_enabled = False
1940 self.subtitle_window.hide()
1942 def setSelectedSubtitle(self, subtitle):
1943 self.__selected_subtitle = subtitle
1945 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1946 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1948 class InfoBarServiceErrorPopupSupport:
1950 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1952 iPlayableService.evTuneFailed: self.__tuneFailed,
1953 iPlayableService.evStart: self.__serviceStarted
1955 self.__serviceStarted()
1957 def __serviceStarted(self):
1958 self.last_error = None
1959 Notifications.RemovePopup(id = "ZapError")
1961 def __tuneFailed(self):
1962 service = self.session.nav.getCurrentService()
1963 info = service and service.info()
1964 error = info and info.getInfo(iServiceInformation.sDVBState)
1966 if error == self.last_error:
1969 self.last_error = error
1972 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1973 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1974 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1975 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1976 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1977 eDVBServicePMTHandler.eventNewProgramInfo: None,
1978 eDVBServicePMTHandler.eventTuned: None,
1979 eDVBServicePMTHandler.eventSOF: None,
1980 eDVBServicePMTHandler.eventEOF: None
1983 error = errors.get(error) #this returns None when the key not exist in the dict
1985 if error is not None:
1986 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1988 Notifications.RemovePopup(id = "ZapError")