1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import *
9 from Components.Pixmap import Pixmap, PixmapConditional
10 from Components.PluginComponent import plugins
11 from Components.ProgressBar import *
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.Sources.CurrentService import CurrentService
14 from Components.Sources.EventInfo import EventInfo
15 from Components.Sources.FrontendStatus import FrontendStatus
16 from Components.Sources.Boolean import Boolean
17 from Components.Sources.Clock import Clock
18 from Components.TimerList import TimerEntryComponent
19 from Components.config import config, ConfigBoolean, ConfigClock
20 from EpgSelection import EPGSelection
21 from Plugins.Plugin import PluginDescriptor
23 from Screen import Screen
24 from Screens.ChoiceBox import ChoiceBox
25 from Screens.Dish import Dish
26 from Screens.EventView import EventViewEPGSelect, EventViewSimple
27 from Screens.InputBox import InputBox
28 from Screens.MessageBox import MessageBox
29 from Screens.MinuteInput import MinuteInput
30 from Screens.TimerSelection import TimerSelection
31 from Screens.PictureInPicture import PictureInPicture
32 from Screens.SubtitleDisplay import SubtitleDisplay
33 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
34 from Screens.SleepTimerEdit import SleepTimerEdit
35 from Screens.TimeDateInput import TimeDateInput
36 from ServiceReference import ServiceReference
38 from Tools import Notifications
39 from Tools.Directories import SCOPE_HDD, resolveFilename
41 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
42 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
44 from time import time, localtime, strftime
45 from os import stat as os_stat
46 from bisect import insort
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
69 }, 1) # lower prio to make it possible to override ok and cancel..
71 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
73 iPlayableService.evStart: self.serviceStarted,
76 self.__state = self.STATE_SHOWN
79 self.hideTimer = eTimer()
80 self.hideTimer.timeout.get().append(self.doTimerHide)
81 self.hideTimer.start(5000, True)
83 self.onShow.append(self.__onShow)
84 self.onHide.append(self.__onHide)
86 def serviceStarted(self):
88 if config.usage.show_infobar_on_zap.value:
92 self.__state = self.STATE_SHOWN
95 def startHideTimer(self):
96 if self.__state == self.STATE_SHOWN and not self.__locked:
97 idx = config.usage.infobar_timeout.index
99 self.hideTimer.start(idx*1000, True)
102 self.__state = self.STATE_HIDDEN
106 self.startHideTimer()
108 def doTimerHide(self):
109 self.hideTimer.stop()
110 if self.__state == self.STATE_SHOWN:
113 def toggleShow(self):
114 if self.__state == self.STATE_SHOWN:
116 self.hideTimer.stop()
117 elif self.__state == self.STATE_HIDDEN:
121 self.__locked = self.__locked + 1
124 self.hideTimer.stop()
126 def unlockShow(self):
127 self.__locked = self.__locked - 1
129 self.startHideTimer()
131 # def startShow(self):
132 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
133 # self.__state = self.STATE_SHOWN
135 # def startHide(self):
136 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
137 # self.__state = self.STATE_HIDDEN
139 class NumberZap(Screen):
146 self.close(int(self["number"].getText()))
148 def keyNumberGlobal(self, number):
149 self.Timer.start(3000, True) #reset timer
150 self.field = self.field + str(number)
151 self["number"].setText(self.field)
152 if len(self.field) >= 4:
155 def __init__(self, session, number):
156 Screen.__init__(self, session)
157 self.field = str(number)
159 self["channel"] = Label(_("Channel:"))
161 self["number"] = Label(self.field)
163 self["actions"] = NumberActionMap( [ "SetupActions" ],
167 "1": self.keyNumberGlobal,
168 "2": self.keyNumberGlobal,
169 "3": self.keyNumberGlobal,
170 "4": self.keyNumberGlobal,
171 "5": self.keyNumberGlobal,
172 "6": self.keyNumberGlobal,
173 "7": self.keyNumberGlobal,
174 "8": self.keyNumberGlobal,
175 "9": self.keyNumberGlobal,
176 "0": self.keyNumberGlobal
179 self.Timer = eTimer()
180 self.Timer.timeout.get().append(self.keyOK)
181 self.Timer.start(3000, True)
183 class InfoBarNumberZap:
184 """ Handles an initial number for NumberZapping """
186 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
188 "1": self.keyNumberGlobal,
189 "2": self.keyNumberGlobal,
190 "3": self.keyNumberGlobal,
191 "4": self.keyNumberGlobal,
192 "5": self.keyNumberGlobal,
193 "6": self.keyNumberGlobal,
194 "7": self.keyNumberGlobal,
195 "8": self.keyNumberGlobal,
196 "9": self.keyNumberGlobal,
197 "0": self.keyNumberGlobal,
200 def keyNumberGlobal(self, number):
201 # print "You pressed number " + str(number)
203 self.servicelist.recallPrevService()
205 self.session.openWithCallback(self.numberEntered, NumberZap, number)
207 def numberEntered(self, retval):
208 # print self.servicelist
210 self.zapToNumber(retval)
212 def searchNumberHelper(self, serviceHandler, num, bouquet):
213 servicelist = serviceHandler.list(bouquet)
214 if not servicelist is None:
216 serviceIterator = servicelist.getNext()
217 if not serviceIterator.valid(): #check end of list
219 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
222 if not num: #found service with searched number ?
223 return serviceIterator, 0
226 def zapToNumber(self, number):
227 bouquet = self.servicelist.bouquet_root
229 serviceHandler = eServiceCenter.getInstance()
230 if not config.usage.multibouquet.value:
231 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
233 bouquetlist = serviceHandler.list(bouquet)
234 if not bouquetlist is None:
236 bouquet = bouquetlist.getNext()
237 if not bouquet.valid(): #check end of list
239 if bouquet.flags & eServiceReference.isDirectory:
240 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
241 if not service is None:
242 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
243 self.servicelist.clearPath()
244 if self.servicelist.bouquet_root != bouquet:
245 self.servicelist.enterPath(self.servicelist.bouquet_root)
246 self.servicelist.enterPath(bouquet)
247 self.servicelist.setCurrentSelection(service) #select the service in servicelist
248 self.servicelist.zap()
250 config.misc.initialchannelselection = ConfigBoolean(default = True)
252 class InfoBarChannelSelection:
253 """ ChannelSelection - handles the channelSelection dialog and the initial
254 channelChange actions which open the channelSelection dialog """
257 self.servicelist = self.session.instantiateDialog(ChannelSelection)
259 if config.misc.initialchannelselection.value:
260 self.onShown.append(self.firstRun)
262 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
264 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
265 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
266 "zapUp": (self.zapUp, _("previous channel")),
267 "zapDown": (self.zapDown, _("next channel")),
268 "historyBack": (self.historyBack, _("previous channel in history")),
269 "historyNext": (self.historyNext, _("next channel in history")),
270 "openServiceList": (self.openServiceList, _("open servicelist")),
273 def showTvChannelList(self, zap=False):
274 self.servicelist.setModeTv()
276 self.servicelist.zap()
277 self.session.execDialog(self.servicelist)
279 def showRadioChannelList(self, zap=False):
280 self.servicelist.setModeRadio()
282 self.servicelist.zap()
283 self.session.execDialog(self.servicelist)
286 self.onShown.remove(self.firstRun)
287 config.misc.initialchannelselection.value = False
288 config.misc.initialchannelselection.save()
289 self.switchChannelDown()
291 def historyBack(self):
292 self.servicelist.historyBack()
294 def historyNext(self):
295 self.servicelist.historyNext()
297 def switchChannelUp(self):
298 self.servicelist.moveUp()
299 self.session.execDialog(self.servicelist)
301 def switchChannelDown(self):
302 self.servicelist.moveDown()
303 self.session.execDialog(self.servicelist)
305 def openServiceList(self):
306 self.session.execDialog(self.servicelist)
309 if self.servicelist.inBouquet():
310 prev = self.servicelist.getCurrentSelection()
312 prev = prev.toString()
314 if config.usage.quickzap_bouquet_change.value:
315 if self.servicelist.atBegin():
316 self.servicelist.prevBouquet()
317 self.servicelist.moveUp()
318 cur = self.servicelist.getCurrentSelection()
319 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
322 self.servicelist.moveUp()
323 self.servicelist.zap()
326 if self.servicelist.inBouquet():
327 prev = self.servicelist.getCurrentSelection()
329 prev = prev.toString()
331 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
332 self.servicelist.nextBouquet()
334 self.servicelist.moveDown()
335 cur = self.servicelist.getCurrentSelection()
336 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
339 self.servicelist.moveDown()
340 self.servicelist.zap()
343 """ Handles a menu action, to open the (main) menu """
345 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
347 "mainMenu": (self.mainMenu, _("Enter main menu...")),
349 self.session.infobar = None
352 print "loading mainmenu XML..."
353 menu = mdom.childNodes[0]
354 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
356 self.session.infobar = self
357 # so we can access the currently active infobar from screens opened from within the mainmenu
358 # at the moment used from the SubserviceSelection
360 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
362 def mainMenuClosed(self, *val):
363 self.session.infobar = None
365 class InfoBarSimpleEventView:
366 """ Opens the Eventview for now/next """
368 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
370 "showEventInfo": (self.openEventView, _("show event details")),
373 def openEventView(self):
375 service = self.session.nav.getCurrentService()
376 ref = self.session.nav.getCurrentlyPlayingServiceReference()
377 info = service.info()
380 self.epglist.append(ptr)
383 self.epglist.append(ptr)
384 if len(self.epglist) > 0:
385 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
387 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
388 if len(self.epglist) > 1:
389 tmp = self.epglist[0]
390 self.epglist[0]=self.epglist[1]
392 setEvent(self.epglist[0])
395 """ EPG - Opens an EPG list when the showEPGList action fires """
397 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
399 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
402 self.is_now_next = False
404 self.bouquetSel = None
405 self.eventView = None
406 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
408 "showEventInfo": (self.openEventView, _("show EPG...")),
411 def zapToService(self, service):
412 if not service is None:
413 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
414 self.servicelist.clearPath()
415 if self.servicelist.bouquet_root != self.epg_bouquet:
416 self.servicelist.enterPath(self.servicelist.bouquet_root)
417 self.servicelist.enterPath(self.epg_bouquet)
418 self.servicelist.setCurrentSelection(service) #select the service in servicelist
419 self.servicelist.zap()
421 def getBouquetServices(self, bouquet):
423 servicelist = eServiceCenter.getInstance().list(bouquet)
424 if not servicelist is None:
426 service = servicelist.getNext()
427 if not service.valid(): #check if end of list
429 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
431 services.append(ServiceReference(service))
434 def openBouquetEPG(self, bouquet, withCallback=True):
435 services = self.getBouquetServices(bouquet)
437 self.epg_bouquet = bouquet
439 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
441 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
443 def changeBouquetCB(self, direction, epg):
446 self.bouquetSel.down()
449 bouquet = self.bouquetSel.getCurrent()
450 services = self.getBouquetServices(bouquet)
452 self.epg_bouquet = bouquet
453 epg.setServices(services)
455 def closed(self, ret=False):
456 closedScreen = self.dlg_stack.pop()
457 if self.bouquetSel and closedScreen == self.bouquetSel:
458 self.bouquetSel = None
459 elif self.eventView and closedScreen == self.eventView:
460 self.eventView = None
462 dlgs=len(self.dlg_stack)
464 self.dlg_stack[dlgs-1].close(dlgs > 1)
466 def openMultiServiceEPG(self, withCallback=True):
467 bouquets = self.servicelist.getBouquetList()
472 if cnt > 1: # show bouquet list
474 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
475 self.dlg_stack.append(self.bouquetSel)
477 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
479 self.openBouquetEPG(bouquets[0][1], withCallback)
481 def openSingleServiceEPG(self):
482 ref=self.session.nav.getCurrentlyPlayingServiceReference()
483 self.session.open(EPGSelection, ref)
485 def openSimilarList(self, eventid, refstr):
486 self.session.open(EPGSelection, refstr, None, eventid)
488 def getNowNext(self):
490 service = self.session.nav.getCurrentService()
491 info = service and service.info()
492 ptr = info and info.getEvent(0)
494 self.epglist.append(ptr)
495 ptr = info and info.getEvent(1)
497 self.epglist.append(ptr)
499 def __evEventInfoChanged(self):
500 if self.is_now_next and len(self.dlg_stack) == 1:
502 assert self.eventView
503 if len(self.epglist):
504 self.eventView.setEvent(self.epglist[0])
506 def openEventView(self):
507 ref = self.session.nav.getCurrentlyPlayingServiceReference()
509 if len(self.epglist) == 0:
510 self.is_now_next = False
511 epg = eEPGCache.getInstance()
512 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
514 self.epglist.append(ptr)
515 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
517 self.epglist.append(ptr)
519 self.is_now_next = True
520 if len(self.epglist) > 0:
521 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
522 self.dlg_stack.append(self.eventView)
524 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
525 self.openMultiServiceEPG(False)
527 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
528 if len(self.epglist) > 1:
529 tmp = self.epglist[0]
530 self.epglist[0]=self.epglist[1]
532 setEvent(self.epglist[0])
535 """provides a snr/agc/ber display"""
537 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
540 """provides a current/next event info display"""
542 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
543 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
545 class InfoBarRdsDecoder:
546 """provides RDS and Rass support/display"""
548 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
549 self.rass_interactive = None
551 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
553 iPlayableService.evEnd: self.__serviceStopped,
554 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
557 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
559 "startRassInteractive": self.startRassInteractive
562 self["RdsActions"].setEnabled(False)
564 self.onLayoutFinish.append(self.rds_display.show)
565 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
567 def RassInteractivePossibilityChanged(self, state):
568 self["RdsActions"].setEnabled(state)
570 def RassSlidePicChanged(self):
571 if not self.rass_interactive:
572 service = self.session.nav.getCurrentService()
573 decoder = service and service.rdsDecoder()
575 decoder.showRassSlidePicture()
577 def __serviceStopped(self):
578 if self.rass_interactive is not None:
579 rass_interactive = self.rass_interactive
580 self.rass_interactive = None
581 rass_interactive.close()
583 def startRassInteractive(self):
584 self.rds_display.hide()
585 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
587 def RassInteractiveClosed(self, *val):
588 if self.rass_interactive is not None:
589 self.rass_interactive = None
590 self.RassSlidePicChanged()
591 self.rds_display.show()
593 class InfoBarServiceName:
595 self["CurrentService"] = CurrentService(self.session.nav)
598 """handles actions like seeking, pause"""
600 # ispause, isff, issm
601 SEEK_STATE_PLAY = (0, 0, 0, ">")
602 SEEK_STATE_PAUSE = (1, 0, 0, "||")
603 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
604 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
605 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
606 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
607 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
608 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
610 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
611 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
612 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
613 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
615 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
616 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
617 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
619 SEEK_STATE_EOF = (1, 0, 0, "END")
621 def __init__(self, actionmap = "InfobarSeekActions"):
622 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
624 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
625 iPlayableService.evStart: self.__serviceStarted,
627 iPlayableService.evEOF: self.__evEOF,
628 iPlayableService.evSOF: self.__evSOF,
631 class InfoBarSeekActionMap(HelpableActionMap):
632 def __init__(self, screen, *args, **kwargs):
633 HelpableActionMap.__init__(self, screen, *args, **kwargs)
636 def action(self, contexts, action):
637 print "action:", action
638 if action[:5] == "seek:":
639 time = int(action[5:])
640 self.screen.seekRelative(time * 90000)
641 if isinstance(self.screen, InfoBarShowHide):
645 return HelpableActionMap.action(self, contexts, action)
647 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
649 "playpauseService": (self.playpauseService, _("pause")),
650 "pauseService": (self.pauseService, _("pause")),
651 "unPauseService": (self.unPauseService, _("continue")),
653 "seekFwd": (self.seekFwd, _("skip forward")),
654 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
655 "seekBack": (self.seekBack, _("skip backward")),
656 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
658 # give them a little more priority to win over color buttons
660 self["SeekActions"].setEnabled(False)
662 self.seekstate = self.SEEK_STATE_PLAY
664 self.onPlayStateChanged = [ ]
666 self.lockedBecauseOfSkipping = False
668 self.__seekableStatusChanged()
677 service = self.session.nav.getCurrentService()
681 seek = service.seek()
683 if seek is None or not seek.isCurrentlySeekable():
688 def isSeekable(self):
689 if self.getSeek() is None:
693 def __seekableStatusChanged(self):
694 print "seekable status changed!"
695 if not self.isSeekable():
696 self["SeekActions"].setEnabled(False)
697 print "not seekable, return to play"
698 self.setSeekState(self.SEEK_STATE_PLAY)
700 self["SeekActions"].setEnabled(True)
703 def __serviceStarted(self):
704 self.seekstate = self.SEEK_STATE_PLAY
705 self.__seekableStatusChanged()
707 def setSeekState(self, state):
708 service = self.session.nav.getCurrentService()
713 if not self.isSeekable():
714 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
715 state = self.SEEK_STATE_PLAY
717 pauseable = service.pause()
719 if pauseable is None:
720 print "not pauseable."
721 state = self.SEEK_STATE_PLAY
723 oldstate = self.seekstate
724 self.seekstate = state
727 if oldstate[i] != self.seekstate[i]:
728 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
730 for c in self.onPlayStateChanged:
733 self.checkSkipShowHideLock()
737 def playpauseService(self):
738 if self.seekstate != self.SEEK_STATE_PLAY:
739 self.unPauseService()
743 def pauseService(self):
744 if self.seekstate == self.SEEK_STATE_PAUSE:
745 print "pause, but in fact unpause"
746 self.unPauseService()
748 if self.seekstate == self.SEEK_STATE_PLAY:
749 print "yes, playing."
751 print "no", self.seekstate
753 self.setSeekState(self.SEEK_STATE_PAUSE);
755 def unPauseService(self):
757 if self.seekstate == self.SEEK_STATE_PLAY:
759 self.setSeekState(self.SEEK_STATE_PLAY)
761 def doSeek(self, seektime):
762 print "doseek", seektime
763 service = self.session.nav.getCurrentService()
767 seekable = self.getSeek()
771 seekable.seekTo(90 * seektime)
775 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
776 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
777 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
778 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
779 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
780 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
781 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
782 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
783 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
784 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
785 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
786 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
787 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
788 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
789 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
790 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
792 self.setSeekState(lookup[self.seekstate])
796 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
797 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
798 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
799 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
800 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
801 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
802 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
803 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
804 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
805 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
806 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
807 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
808 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
809 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
810 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
811 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
813 self.setSeekState(lookup[self.seekstate])
815 if self.seekstate == self.SEEK_STATE_PAUSE:
816 seekable = self.getSeek()
817 if seekable is not None:
818 seekable.seekRelative(-1, 3)
820 def seekFwdManual(self):
821 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
823 def fwdSeekTo(self, minutes):
824 print "Seek", minutes, "minutes forward"
826 seekable = self.getSeek()
827 if seekable is not None:
828 seekable.seekRelative(1, minutes * 60 * 90000)
830 def seekBackManual(self):
831 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
833 def rwdSeekTo(self, minutes):
835 self.fwdSeekTo(0 - minutes)
837 def checkSkipShowHideLock(self):
838 wantlock = self.seekstate != self.SEEK_STATE_PLAY
840 if config.usage.show_infobar_on_zap.value:
841 if self.lockedBecauseOfSkipping and not wantlock:
843 self.lockedBecauseOfSkipping = False
845 if wantlock and not self.lockedBecauseOfSkipping:
847 self.lockedBecauseOfSkipping = True
850 if self.seekstate == self.SEEK_STATE_EOF:
852 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
853 print "end of stream while seeking back, ignoring."
856 # if we are seeking, we try to end up ~1s before the end, and pause there.
857 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
858 self.setSeekState(self.SEEK_STATE_EOF)
859 self.seekRelativeToEnd(-90000)
861 self.setSeekState(self.SEEK_STATE_EOF)
864 self.setSeekState(self.SEEK_STATE_PLAY)
867 def seekRelative(self, diff):
868 seekable = self.getSeek()
869 if seekable is not None:
870 print "seekRelative: res:", seekable.seekRelative(1, diff)
874 def seekRelativeToEnd(self, diff):
875 assert diff <= 0, "diff is expected to be negative!"
877 # might sound like an evil hack, but:
878 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
879 # and we don't get that by passing 0 here (it would seek to begin).
883 # relative-to-end seeking is implemented as absolutes seeks with negative time
884 self.seekAbsolute(diff)
886 def seekAbsolute(self, abs):
887 seekable = self.getSeek()
888 if seekable is not None:
891 from Screens.PVRState import PVRState, TimeshiftState
893 class InfoBarPVRState:
894 def __init__(self, screen=PVRState):
895 self.onPlayStateChanged.append(self.__playStateChanged)
896 self.pvrStateDialog = self.session.instantiateDialog(screen)
897 self.onShow.append(self._mayShow)
898 self.onHide.append(self.pvrStateDialog.hide)
901 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
902 self.pvrStateDialog.show()
904 def __playStateChanged(self, state):
905 playstateString = state[3]
906 self.pvrStateDialog["state"].setText(playstateString)
909 class InfoBarTimeshiftState(InfoBarPVRState):
911 InfoBarPVRState.__init__(self, screen=TimeshiftState)
914 if self.execing and self.timeshift_enabled:
915 self.pvrStateDialog.show()
917 class InfoBarShowMovies:
919 # i don't really like this class.
920 # it calls a not further specified "movie list" on up/down/movieList,
921 # so this is not more than an action map
923 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
925 "movieList": (self.showMovies, "movie list"),
926 "up": (self.showMovies, "movie list"),
927 "down": (self.showMovies, "movie list")
930 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
934 # Timeshift works the following way:
935 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
936 # - normal playback TUNER unused PLAY enable disable disable
937 # - user presses "yellow" button. FILE record PAUSE enable disable enable
938 # - user presess pause again FILE record PLAY enable disable enable
939 # - user fast forwards FILE record FF enable disable enable
940 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
941 # - user backwards FILE record BACK # !! enable disable enable
945 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
946 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
947 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
948 # - the user can now PVR around
949 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
950 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
952 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
953 # - if the user rewinds, or press pause, timeshift will be activated again
955 # note that a timeshift can be enabled ("recording") and
956 # activated (currently time-shifting).
958 class InfoBarTimeshift:
960 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
962 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
963 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
965 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
967 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
968 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
969 }, prio=-1) # priority over record
971 self.timeshift_enabled = 0
972 self.timeshift_state = 0
973 self.ts_rewind_timer = eTimer()
974 self.ts_rewind_timer.timeout.get().append(self.rewindService)
976 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
978 iPlayableService.evStart: self.__serviceStarted,
979 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
982 def getTimeshift(self):
983 service = self.session.nav.getCurrentService()
984 return service and service.timeshift()
986 def startTimeshift(self):
987 print "enable timeshift"
988 ts = self.getTimeshift()
990 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
991 print "no ts interface"
994 if self.timeshift_enabled:
995 print "hu, timeshift already enabled?"
997 if not ts.startTimeshift():
998 self.timeshift_enabled = 1
1000 # we remove the "relative time" for now.
1001 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1004 #self.setSeekState(self.SEEK_STATE_PAUSE)
1005 self.activateTimeshiftEnd(False)
1007 # enable the "TimeshiftEnableActions", which will override
1008 # the startTimeshift actions
1009 self.__seekableStatusChanged()
1011 print "timeshift failed"
1013 def stopTimeshift(self):
1014 if not self.timeshift_enabled:
1016 print "disable timeshift"
1017 ts = self.getTimeshift()
1020 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1022 def stopTimeshiftConfirmed(self, confirmed):
1026 ts = self.getTimeshift()
1031 self.timeshift_enabled = 0
1034 self.__seekableStatusChanged()
1036 # activates timeshift, and seeks to (almost) the end
1037 def activateTimeshiftEnd(self, back = True):
1038 ts = self.getTimeshift()
1039 print "activateTimeshiftEnd"
1044 if ts.isTimeshiftActive():
1045 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1049 ts.activateTimeshift() # activate timeshift will automatically pause
1050 self.setSeekState(self.SEEK_STATE_PAUSE)
1051 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1054 self.ts_rewind_timer.start(200, 1)
1056 def rewindService(self):
1057 self.setSeekState(self.SEEK_STATE_BACK_16X)
1059 # same as activateTimeshiftEnd, but pauses afterwards.
1060 def activateTimeshiftEndAndPause(self):
1061 print "activateTimeshiftEndAndPause"
1062 #state = self.seekstate
1063 self.activateTimeshiftEnd(False)
1065 def __seekableStatusChanged(self):
1068 print "self.isSeekable", self.isSeekable()
1069 print "self.timeshift_enabled", self.timeshift_enabled
1071 # when this service is not seekable, but timeshift
1072 # is enabled, this means we can activate
1074 if not self.isSeekable() and self.timeshift_enabled:
1077 print "timeshift activate:", enabled
1078 self["TimeshiftActivateActions"].setEnabled(enabled)
1080 def __serviceStarted(self):
1081 self.timeshift_enabled = False
1082 self.__seekableStatusChanged()
1084 from Screens.PiPSetup import PiPSetup
1086 class InfoBarExtensions:
1087 EXTENSION_SINGLE = 0
1093 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1095 "extensions": (self.showExtensionSelection, _("view extensions...")),
1098 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1099 self.list.append((type, extension, key))
1101 def updateExtension(self, extension, key = None):
1102 self.extensionsList.append(extension)
1104 if self.extensionKeys.has_key(key):
1108 for x in self.availableKeys:
1109 if not self.extensionKeys.has_key(x):
1114 self.extensionKeys[key] = len(self.extensionsList) - 1
1116 def updateExtensions(self):
1117 self.extensionsList = []
1118 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1119 self.extensionKeys = {}
1121 if x[0] == self.EXTENSION_SINGLE:
1122 self.updateExtension(x[1], x[2])
1125 self.updateExtension(y[0], y[1])
1128 def showExtensionSelection(self):
1129 self.updateExtensions()
1130 extensionsList = self.extensionsList[:]
1133 for x in self.availableKeys:
1134 if self.extensionKeys.has_key(x):
1135 entry = self.extensionKeys[x]
1136 extension = self.extensionsList[entry]
1138 name = str(extension[0]())
1139 list.append((extension[0](), extension))
1141 extensionsList.remove(extension)
1143 extensionsList.remove(extension)
1144 for x in extensionsList:
1145 list.append((x[0](), x))
1146 keys += [""] * len(extensionsList)
1147 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1149 def extensionCallback(self, answer):
1150 if answer is not None:
1153 from Tools.BoundFunction import boundFunction
1155 # depends on InfoBarExtensions
1156 from Components.PluginComponent import plugins
1158 class InfoBarPlugins:
1160 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1162 def getPluginName(self, name):
1165 def getPluginList(self):
1167 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1168 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1171 def runPlugin(self, plugin):
1172 plugin(session = self.session)
1174 # depends on InfoBarExtensions
1175 class InfoBarSleepTimer:
1177 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1179 def available(self):
1182 def getSleepTimerName(self):
1183 return _("Sleep Timer")
1185 def showSleepTimerSetup(self):
1186 self.session.open(SleepTimerEdit)
1188 # depends on InfoBarExtensions
1191 self.session.pipshown = False
1193 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1194 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1195 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1197 def available(self):
1201 return self.session.pipshown
1203 def getShowHideName(self):
1204 if self.session.pipshown:
1205 return _("Disable Picture in Picture")
1207 return _("Activate Picture in Picture")
1209 def getSwapName(self):
1210 return _("Swap Services")
1212 def getMoveName(self):
1213 return _("Move Picture in Picture")
1216 if self.session.pipshown:
1217 del self.session.pip
1218 self.session.pipshown = False
1220 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1221 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1222 if self.session.pip.playService(newservice):
1223 self.session.pipshown = True
1224 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1226 self.session.pipshown = False
1227 del self.session.pip
1228 self.session.nav.playService(newservice)
1231 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1232 if self.session.pip.servicePath:
1233 servicepath = self.servicelist.getCurrentServicePath()
1234 ref=servicepath[len(servicepath)-1]
1235 pipref=self.session.pip.getCurrentService()
1236 self.session.pip.playService(swapservice)
1237 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1238 if pipref.toString() != ref.toString(): # is a subservice ?
1239 self.session.nav.stopService() # stop portal
1240 self.session.nav.playService(pipref) # start subservice
1241 self.session.pip.servicePath=servicepath
1244 self.session.open(PiPSetup, pip = self.session.pip)
1246 from RecordTimer import parseEvent
1248 class InfoBarInstantRecord:
1249 """Instant Record - handles the instantRecord action in order to
1250 start/stop instant records"""
1252 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1254 "instantRecord": (self.instantRecord, _("Instant Record...")),
1257 self["BlinkingPoint"] = BlinkingPixmapConditional()
1258 self["BlinkingPoint"].hide()
1259 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1261 def stopCurrentRecording(self, entry = -1):
1262 if entry is not None and entry != -1:
1263 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1264 self.recording.remove(self.recording[entry])
1266 def startInstantRecording(self, limitEvent = False):
1267 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1269 # try to get event info
1272 service = self.session.nav.getCurrentService()
1273 epg = eEPGCache.getInstance()
1274 event = epg.lookupEventTime(serviceref, -1, 0)
1276 info = service.info()
1277 ev = info.getEvent(0)
1283 end = time() + 3600 * 10
1284 name = "instant record"
1288 if event is not None:
1289 curEvent = parseEvent(event)
1291 description = curEvent[3]
1292 eventid = curEvent[4]
1297 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1299 data = (begin, end, name, description, eventid)
1301 recording = self.session.nav.recordWithTimer(serviceref, *data)
1302 recording.dontSave = True
1303 self.recording.append(recording)
1305 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1307 def isInstantRecordRunning(self):
1308 print "self.recording:", self.recording
1309 if len(self.recording) > 0:
1310 for x in self.recording:
1315 def recordQuestionCallback(self, answer):
1316 print "pre:\n", self.recording
1318 if answer is None or answer[1] == "no":
1321 recording = self.recording[:]
1323 if not x in self.session.nav.RecordTimer.timer_list:
1324 self.recording.remove(x)
1325 elif x.dontSave and x.isRunning():
1326 list.append(TimerEntryComponent(x, False))
1328 if answer[1] == "changeduration":
1329 if len(self.recording) == 1:
1330 self.changeDuration(0)
1332 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1333 elif answer[1] == "changeendtime":
1334 if len(self.recording) == 1:
1337 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1338 elif answer[1] == "stop":
1339 if len(self.recording) == 1:
1340 self.stopCurrentRecording(0)
1342 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1343 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1344 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1345 if answer[1] == "manualduration":
1346 self.changeDuration(len(self.recording)-1)
1347 elif answer[1] == "manualendtime":
1348 self.setEndtime(len(self.recording)-1)
1349 print "after:\n", self.recording
1351 def setEndtime(self, entry):
1352 if entry is not None:
1353 self.selectedEntry = entry
1354 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1355 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1356 dlg.setTitle(_("Please change recording endtime"))
1358 def TimeDateInputClosed(self, ret):
1361 localendtime = localtime(ret[1])
1362 print "stopping recording at", strftime("%c", localendtime)
1363 self.recording[self.selectedEntry].end = ret[1]
1364 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1366 def changeDuration(self, entry):
1367 if entry is not None:
1368 self.selectedEntry = entry
1369 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1371 def inputCallback(self, value):
1372 if value is not None:
1373 print "stopping recording after", int(value), "minutes."
1374 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1375 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1377 def instantRecord(self):
1379 stat = os_stat(resolveFilename(SCOPE_HDD))
1381 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1384 if self.isInstantRecordRunning():
1385 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1386 title=_("A recording is currently running.\nWhat do you want to do?"), \
1387 list=[(_("stop recording"), "stop"), \
1388 (_("change recording (duration)"), "changeduration"), \
1389 (_("change recording (endtime)"), "changeendtime"), \
1390 (_("add recording (indefinitely)"), "indefinitely"), \
1391 (_("add recording (stop after current event)"), "event"), \
1392 (_("add recording (enter recording duration)"), "manualduration"), \
1393 (_("add recording (enter recording endtime)"), "manualendtime"), \
1394 (_("do nothing"), "no")])
1396 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1397 title=_("Start recording?"), \
1398 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1399 (_("add recording (stop after current event)"), "event"), \
1400 (_("add recording (enter recording duration)"), "manualduration"), \
1401 (_("add recording (enter recording endtime)"), "manualendtime"), \
1402 (_("don't record"), "no")])
1404 from Tools.ISO639 import LanguageCodes
1406 class InfoBarAudioSelection:
1408 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1410 "audioSelection": (self.audioSelection, _("Audio Options...")),
1413 def audioSelection(self):
1414 service = self.session.nav.getCurrentService()
1415 audio = service and service.audioTracks()
1416 self.audioTracks = audio
1417 n = audio and audio.getNumberOfTracks() or 0
1418 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1420 print "tlist:", tlist
1422 self.audioChannel = service.audioChannel()
1425 i = audio.getTrackInfo(x)
1426 language = i.getLanguage()
1427 description = i.getDescription()
1429 if LanguageCodes.has_key(language):
1430 language = LanguageCodes[language][0]
1432 if len(description):
1433 description += " (" + language + ")"
1435 description = language
1437 tlist.append((description, x))
1439 selectedAudio = tlist[0][1]
1440 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1444 if x[1] != selectedAudio:
1449 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1450 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1452 del self.audioTracks
1454 def audioSelected(self, audio):
1455 if audio is not None:
1456 if isinstance(audio[1], str):
1457 if audio[1] == "mode":
1458 keys = ["red", "green", "yellow"]
1459 selection = self.audioChannel.getCurrentChannel()
1460 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1461 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1463 del self.audioChannel
1464 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1465 self.audioTracks.selectTrack(audio[1])
1467 del self.audioChannel
1468 del self.audioTracks
1470 def modeSelected(self, mode):
1471 if mode is not None:
1472 self.audioChannel.selectChannel(mode[1])
1473 del self.audioChannel
1475 class InfoBarSubserviceSelection:
1477 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1479 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1482 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1484 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1485 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1487 self["SubserviceQuickzapAction"].setEnabled(False)
1489 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1493 def checkSubservicesAvail(self, ev):
1494 if ev == iPlayableService.evUpdatedEventInfo:
1495 service = self.session.nav.getCurrentService()
1496 subservices = service and service.subServices()
1497 if not subservices or subservices.getNumberOfSubservices() == 0:
1498 self["SubserviceQuickzapAction"].setEnabled(False)
1500 def nextSubservice(self):
1501 self.changeSubservice(+1)
1503 def prevSubservice(self):
1504 self.changeSubservice(-1)
1506 def changeSubservice(self, direction):
1507 service = self.session.nav.getCurrentService()
1508 subservices = service and service.subServices()
1509 n = subservices and subservices.getNumberOfSubservices()
1512 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1514 if subservices.getSubservice(x).toString() == ref.toString():
1517 selection += direction
1522 newservice = subservices.getSubservice(selection)
1523 if newservice.valid():
1526 self.session.nav.playService(newservice)
1528 def subserviceSelection(self):
1529 service = self.session.nav.getCurrentService()
1530 subservices = service and service.subServices()
1531 self.bouquets = self.servicelist.getBouquetList()
1532 n = subservices and subservices.getNumberOfSubservices()
1535 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1538 i = subservices.getSubservice(x)
1539 if i.toString() == ref.toString():
1541 tlist.append((i.getName(), i))
1543 if self.bouquets and len(self.bouquets):
1544 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1545 if config.usage.multibouquet.value:
1546 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1548 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1551 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1552 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1555 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1557 def subserviceSelected(self, service):
1559 if not service is None:
1560 if isinstance(service[1], str):
1561 if service[1] == "quickzap":
1562 from Screens.SubservicesQuickzap import SubservicesQuickzap
1563 self.session.open(SubservicesQuickzap, service[2])
1565 self["SubserviceQuickzapAction"].setEnabled(True)
1566 self.session.nav.playService(service[1])
1568 def addSubserviceToBouquetCallback(self, service):
1569 if len(service) > 1 and isinstance(service[1], eServiceReference):
1570 self.selectedSubservice = service
1571 if self.bouquets is None:
1574 cnt = len(self.bouquets)
1575 if cnt > 1: # show bouquet list
1576 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1577 elif cnt == 1: # add to only one existing bouquet
1578 self.addSubserviceToBouquet(self.bouquets[0][1])
1579 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1581 def bouquetSelClosed(self, confirmed):
1583 del self.selectedSubservice
1585 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1587 def addSubserviceToBouquet(self, dest):
1588 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1590 self.bsel.close(True)
1592 del self.selectedSubservice
1594 class InfoBarAdditionalInfo:
1596 self["NimA"] = Pixmap()
1597 self["NimB"] = Pixmap()
1598 self["NimA_Active"] = Pixmap()
1599 self["NimB_Active"] = Pixmap()
1601 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1602 self["TimeshiftPossible"] = self["RecordingPossible"]
1603 self["ExtensionsAvailable"] = Boolean(fixed=1)
1605 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1606 res_mgr = eDVBResourceManager.getInstance()
1608 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1610 def tunerUseMaskChanged(self, mask):
1612 self["NimA_Active"].show()
1614 self["NimA_Active"].hide()
1616 self["NimB_Active"].show()
1618 self["NimB_Active"].hide()
1620 def checkTunerState(self, service):
1621 info = service and service.frontendInfo()
1622 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1623 if feNumber is None:
1633 def gotServiceEvent(self, ev):
1634 service = self.session.nav.getCurrentService()
1635 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1636 self.checkTunerState(service)
1638 class InfoBarNotifications:
1640 self.onExecBegin.append(self.checkNotifications)
1641 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1642 self.onClose.append(self.__removeNotification)
1644 def __removeNotification(self):
1645 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1647 def checkNotificationsIfExecing(self):
1649 self.checkNotifications()
1651 def checkNotifications(self):
1652 if len(Notifications.notifications):
1653 n = Notifications.notifications[0]
1655 Notifications.notifications = Notifications.notifications[1:]
1658 if n[3].has_key("onSessionOpenCallback"):
1659 n[3]["onSessionOpenCallback"]()
1660 del n[3]["onSessionOpenCallback"]
1663 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1665 dlg = self.session.open(n[1], *n[2], **n[3])
1667 # remember that this notification is currently active
1669 Notifications.current_notifications.append(d)
1670 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1672 def __notificationClosed(self, d):
1673 Notifications.current_notifications.remove(d)
1675 class InfoBarServiceNotifications:
1677 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1679 iPlayableService.evEnd: self.serviceHasEnded
1682 def serviceHasEnded(self):
1683 print "service end!"
1686 self.setSeekState(self.SEEK_STATE_PLAY)
1690 class InfoBarCueSheetSupport:
1696 ENABLE_RESUME_SUPPORT = False
1699 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1701 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1702 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1703 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1707 self.is_closing = False
1708 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1710 iPlayableService.evStart: self.__serviceStarted,
1713 def __serviceStarted(self):
1716 print "new service started! trying to download cuts!"
1717 self.downloadCuesheet()
1719 if self.ENABLE_RESUME_SUPPORT:
1722 for (pts, what) in self.cut_list:
1723 if what == self.CUT_TYPE_LAST:
1726 if last is not None:
1727 self.resume_point = last
1728 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1730 def playLastCB(self, answer):
1732 seekable = self.__getSeekable()
1733 if seekable is not None:
1734 seekable.seekTo(self.resume_point)
1736 def __getSeekable(self):
1737 service = self.session.nav.getCurrentService()
1740 return service.seek()
1742 def cueGetCurrentPosition(self):
1743 seek = self.__getSeekable()
1746 r = seek.getPlayPosition()
1751 def jumpPreviousNextMark(self, cmp, alternative=None):
1752 current_pos = self.cueGetCurrentPosition()
1753 if current_pos is None:
1755 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1756 if mark is not None:
1758 elif alternative is not None:
1763 seekable = self.__getSeekable()
1764 if seekable is not None:
1765 seekable.seekTo(pts)
1767 def jumpPreviousMark(self):
1768 # we add 2 seconds, so if the play position is <2s after
1769 # the mark, the mark before will be used
1770 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1772 def jumpNextMark(self):
1773 self.jumpPreviousNextMark(lambda x: x)
1775 def getNearestCutPoint(self, pts, cmp=abs):
1778 for cp in self.cut_list:
1779 diff = cmp(cp[0] - pts)
1780 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1784 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1785 current_pos = self.cueGetCurrentPosition()
1786 if current_pos is None:
1787 print "not seekable"
1790 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1792 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1794 return nearest_cutpoint
1796 self.removeMark(nearest_cutpoint)
1797 elif not onlyremove and not onlyreturn:
1798 self.addMark((current_pos, self.CUT_TYPE_MARK))
1803 def addMark(self, point):
1804 insort(self.cut_list, point)
1805 self.uploadCuesheet()
1807 def removeMark(self, point):
1808 self.cut_list.remove(point)
1809 self.uploadCuesheet()
1811 def __getCuesheet(self):
1812 service = self.session.nav.getCurrentService()
1815 return service.cueSheet()
1817 def uploadCuesheet(self):
1818 cue = self.__getCuesheet()
1821 print "upload failed, no cuesheet interface"
1823 cue.setCutList(self.cut_list)
1825 def downloadCuesheet(self):
1826 cue = self.__getCuesheet()
1829 print "upload failed, no cuesheet interface"
1831 self.cut_list = cue.getCutList()
1833 class InfoBarSummary(Screen):
1835 <screen position="0,0" size="132,64">
1836 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1837 <convert type="ClockToText">WithSeconds</convert>
1839 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1840 <convert type="ServiceName">Name</convert>
1844 def __init__(self, session, parent):
1845 Screen.__init__(self, session)
1846 self["CurrentService"] = CurrentService(self.session.nav)
1847 self["CurrentTime"] = Clock()
1849 class InfoBarSummarySupport:
1853 def createSummary(self):
1854 return InfoBarSummary
1856 class InfoBarTeletextPlugin:
1858 self.teletext_plugin = None
1860 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1861 self.teletext_plugin = p
1863 if self.teletext_plugin is not None:
1864 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1866 "startTeletext": (self.startTeletext, _("View teletext..."))
1869 print "no teletext plugin found!"
1871 def startTeletext(self):
1872 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1874 class InfoBarSubtitleSupport(object):
1876 object.__init__(self)
1877 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1878 self.__subtitles_enabled = False
1880 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1882 iPlayableService.evEnd: self.__serviceStopped,
1883 iPlayableService.evUpdatedInfo: self.__updatedInfo
1885 self.cached_subtitle_checked = False
1886 self.__selected_subtitle = None
1888 def __serviceStopped(self):
1889 self.subtitle_window.hide()
1890 self.__subtitles_enabled = False
1891 self.cached_subtitle_checked = False
1893 def __updatedInfo(self):
1894 if not self.cached_subtitle_checked:
1895 subtitle = self.getCurrentServiceSubtitle()
1896 self.cached_subtitle_checked = True
1897 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1898 if self.__selected_subtitle:
1899 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1900 self.subtitle_window.show()
1901 self.__subtitles_enabled = True
1903 def getCurrentServiceSubtitle(self):
1904 service = self.session.nav.getCurrentService()
1905 return service and service.subtitle()
1907 def setSubtitlesEnable(self, enable=True):
1908 subtitle = self.getCurrentServiceSubtitle()
1909 if enable and self.__selected_subtitle is not None:
1910 if subtitle and not self.__subtitles_enabled:
1911 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1912 self.subtitle_window.show()
1913 self.__subtitles_enabled = True
1916 subtitle.disableSubtitles(self.subtitle_window.instance)
1917 self.__subtitles_enabled = False
1918 self.subtitle_window.hide()
1920 def setSelectedSubtitle(self, subtitle):
1921 self.__selected_subtitle = subtitle
1923 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1924 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1926 class InfoBarServiceErrorPopupSupport:
1928 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1930 iPlayableService.evTuneFailed: self.__tuneFailed,
1931 iPlayableService.evStart: self.__serviceStarted
1933 self.__serviceStarted()
1935 def __serviceStarted(self):
1936 self.last_error = None
1937 Notifications.RemovePopup(id = "ZapError")
1939 def __tuneFailed(self):
1940 service = self.session.nav.getCurrentService()
1941 info = service and service.info()
1942 error = info and info.getInfo(iServiceInformation.sDVBState)
1944 if error == self.last_error:
1947 self.last_error = error
1950 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1951 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1952 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1953 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1954 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1955 eDVBServicePMTHandler.eventNewProgramInfo: None,
1956 eDVBServicePMTHandler.eventTuned: None,
1957 eDVBServicePMTHandler.eventSOF: None,
1958 eDVBServicePMTHandler.eventEOF: None
1961 error = errors.get(error) #this returns None when the key not exist in the dict
1963 if error is not None:
1964 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1966 Notifications.RemovePopup(id = "ZapError")