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,
74 iPlayableService.evUpdatedEventInfo: self.__eventInfoChanged
77 self.__state = self.STATE_SHOWN
80 self.hideTimer = eTimer()
81 self.hideTimer.timeout.get().append(self.doTimerHide)
82 self.hideTimer.start(5000, True)
84 self.onShow.append(self.__onShow)
85 self.onHide.append(self.__onHide)
86 self.current_begin_time=0
88 def __eventInfoChanged(self):
90 service = self.session.nav.getCurrentService()
91 old_begin_time = self.current_begin_time
92 info = service and service.info()
93 ptr = info and info.getEvent(0)
94 self.current_begin_time = ptr and ptr.getBeginTime() or 0
95 if config.usage.show_infobar_on_event_change.value:
96 if old_begin_time and old_begin_time != self.current_begin_time:
99 def __serviceStarted(self):
101 self.current_begin_time=0
102 if config.usage.show_infobar_on_zap.value:
106 self.__state = self.STATE_SHOWN
107 self.startHideTimer()
109 def startHideTimer(self):
110 if self.__state == self.STATE_SHOWN and not self.__locked:
111 idx = config.usage.infobar_timeout.index
113 self.hideTimer.start(idx*1000, True)
116 self.__state = self.STATE_HIDDEN
120 self.startHideTimer()
122 def doTimerHide(self):
123 self.hideTimer.stop()
124 if self.__state == self.STATE_SHOWN:
127 def toggleShow(self):
128 if self.__state == self.STATE_SHOWN:
130 self.hideTimer.stop()
131 elif self.__state == self.STATE_HIDDEN:
135 self.__locked = self.__locked + 1
138 self.hideTimer.stop()
140 def unlockShow(self):
141 self.__locked = self.__locked - 1
143 self.startHideTimer()
145 # def startShow(self):
146 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
147 # self.__state = self.STATE_SHOWN
149 # def startHide(self):
150 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
151 # self.__state = self.STATE_HIDDEN
153 class NumberZap(Screen):
160 self.close(int(self["number"].getText()))
162 def keyNumberGlobal(self, number):
163 self.Timer.start(3000, True) #reset timer
164 self.field = self.field + str(number)
165 self["number"].setText(self.field)
166 if len(self.field) >= 4:
169 def __init__(self, session, number):
170 Screen.__init__(self, session)
171 self.field = str(number)
173 self["channel"] = Label(_("Channel:"))
175 self["number"] = Label(self.field)
177 self["actions"] = NumberActionMap( [ "SetupActions" ],
181 "1": self.keyNumberGlobal,
182 "2": self.keyNumberGlobal,
183 "3": self.keyNumberGlobal,
184 "4": self.keyNumberGlobal,
185 "5": self.keyNumberGlobal,
186 "6": self.keyNumberGlobal,
187 "7": self.keyNumberGlobal,
188 "8": self.keyNumberGlobal,
189 "9": self.keyNumberGlobal,
190 "0": self.keyNumberGlobal
193 self.Timer = eTimer()
194 self.Timer.timeout.get().append(self.keyOK)
195 self.Timer.start(3000, True)
197 class InfoBarNumberZap:
198 """ Handles an initial number for NumberZapping """
200 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
202 "1": self.keyNumberGlobal,
203 "2": self.keyNumberGlobal,
204 "3": self.keyNumberGlobal,
205 "4": self.keyNumberGlobal,
206 "5": self.keyNumberGlobal,
207 "6": self.keyNumberGlobal,
208 "7": self.keyNumberGlobal,
209 "8": self.keyNumberGlobal,
210 "9": self.keyNumberGlobal,
211 "0": self.keyNumberGlobal,
214 def keyNumberGlobal(self, number):
215 # print "You pressed number " + str(number)
217 self.servicelist.recallPrevService()
219 self.session.openWithCallback(self.numberEntered, NumberZap, number)
221 def numberEntered(self, retval):
222 # print self.servicelist
224 self.zapToNumber(retval)
226 def searchNumberHelper(self, serviceHandler, num, bouquet):
227 servicelist = serviceHandler.list(bouquet)
228 if not servicelist is None:
230 serviceIterator = servicelist.getNext()
231 if not serviceIterator.valid(): #check end of list
233 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
236 if not num: #found service with searched number ?
237 return serviceIterator, 0
240 def zapToNumber(self, number):
241 bouquet = self.servicelist.bouquet_root
243 serviceHandler = eServiceCenter.getInstance()
244 if not config.usage.multibouquet.value:
245 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
247 bouquetlist = serviceHandler.list(bouquet)
248 if not bouquetlist is None:
250 bouquet = bouquetlist.getNext()
251 if not bouquet.valid(): #check end of list
253 if bouquet.flags & eServiceReference.isDirectory:
254 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
255 if not service is None:
256 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
257 self.servicelist.clearPath()
258 if self.servicelist.bouquet_root != bouquet:
259 self.servicelist.enterPath(self.servicelist.bouquet_root)
260 self.servicelist.enterPath(bouquet)
261 self.servicelist.setCurrentSelection(service) #select the service in servicelist
262 self.servicelist.zap()
264 config.misc.initialchannelselection = ConfigBoolean(default = True)
266 class InfoBarChannelSelection:
267 """ ChannelSelection - handles the channelSelection dialog and the initial
268 channelChange actions which open the channelSelection dialog """
271 self.servicelist = self.session.instantiateDialog(ChannelSelection)
273 if config.misc.initialchannelselection.value:
274 self.onShown.append(self.firstRun)
276 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
278 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
279 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
280 "zapUp": (self.zapUp, _("previous channel")),
281 "zapDown": (self.zapDown, _("next channel")),
282 "historyBack": (self.historyBack, _("previous channel in history")),
283 "historyNext": (self.historyNext, _("next channel in history")),
284 "openServiceList": (self.openServiceList, _("open servicelist")),
287 def showTvChannelList(self, zap=False):
288 self.servicelist.setModeTv()
290 self.servicelist.zap()
291 self.session.execDialog(self.servicelist)
293 def showRadioChannelList(self, zap=False):
294 self.servicelist.setModeRadio()
296 self.servicelist.zap()
297 self.session.execDialog(self.servicelist)
300 self.onShown.remove(self.firstRun)
301 config.misc.initialchannelselection.value = False
302 config.misc.initialchannelselection.save()
303 self.switchChannelDown()
305 def historyBack(self):
306 self.servicelist.historyBack()
308 def historyNext(self):
309 self.servicelist.historyNext()
311 def switchChannelUp(self):
312 self.servicelist.moveUp()
313 self.session.execDialog(self.servicelist)
315 def switchChannelDown(self):
316 self.servicelist.moveDown()
317 self.session.execDialog(self.servicelist)
319 def openServiceList(self):
320 self.session.execDialog(self.servicelist)
323 if self.servicelist.inBouquet():
324 prev = self.servicelist.getCurrentSelection()
326 prev = prev.toString()
328 if config.usage.quickzap_bouquet_change.value:
329 if self.servicelist.atBegin():
330 self.servicelist.prevBouquet()
331 self.servicelist.moveUp()
332 cur = self.servicelist.getCurrentSelection()
333 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
336 self.servicelist.moveUp()
337 self.servicelist.zap()
340 if self.servicelist.inBouquet():
341 prev = self.servicelist.getCurrentSelection()
343 prev = prev.toString()
345 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
346 self.servicelist.nextBouquet()
348 self.servicelist.moveDown()
349 cur = self.servicelist.getCurrentSelection()
350 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
353 self.servicelist.moveDown()
354 self.servicelist.zap()
357 """ Handles a menu action, to open the (main) menu """
359 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
361 "mainMenu": (self.mainMenu, _("Enter main menu...")),
363 self.session.infobar = None
366 print "loading mainmenu XML..."
367 menu = mdom.childNodes[0]
368 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
370 self.session.infobar = self
371 # so we can access the currently active infobar from screens opened from within the mainmenu
372 # at the moment used from the SubserviceSelection
374 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
376 def mainMenuClosed(self, *val):
377 self.session.infobar = None
379 class InfoBarSimpleEventView:
380 """ Opens the Eventview for now/next """
382 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
384 "showEventInfo": (self.openEventView, _("show event details")),
387 def openEventView(self):
389 service = self.session.nav.getCurrentService()
390 ref = self.session.nav.getCurrentlyPlayingServiceReference()
391 info = service.info()
394 self.epglist.append(ptr)
397 self.epglist.append(ptr)
398 if len(self.epglist) > 0:
399 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
401 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
402 if len(self.epglist) > 1:
403 tmp = self.epglist[0]
404 self.epglist[0]=self.epglist[1]
406 setEvent(self.epglist[0])
409 """ EPG - Opens an EPG list when the showEPGList action fires """
411 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
413 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
416 self.is_now_next = False
418 self.bouquetSel = None
419 self.eventView = None
420 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
422 "showEventInfo": (self.openEventView, _("show EPG...")),
425 def zapToService(self, service):
426 if not service is None:
427 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
428 self.servicelist.clearPath()
429 if self.servicelist.bouquet_root != self.epg_bouquet:
430 self.servicelist.enterPath(self.servicelist.bouquet_root)
431 self.servicelist.enterPath(self.epg_bouquet)
432 self.servicelist.setCurrentSelection(service) #select the service in servicelist
433 self.servicelist.zap()
435 def getBouquetServices(self, bouquet):
437 servicelist = eServiceCenter.getInstance().list(bouquet)
438 if not servicelist is None:
440 service = servicelist.getNext()
441 if not service.valid(): #check if end of list
443 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
445 services.append(ServiceReference(service))
448 def openBouquetEPG(self, bouquet, withCallback=True):
449 services = self.getBouquetServices(bouquet)
451 self.epg_bouquet = bouquet
453 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
455 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
457 def changeBouquetCB(self, direction, epg):
460 self.bouquetSel.down()
463 bouquet = self.bouquetSel.getCurrent()
464 services = self.getBouquetServices(bouquet)
466 self.epg_bouquet = bouquet
467 epg.setServices(services)
469 def closed(self, ret=False):
470 closedScreen = self.dlg_stack.pop()
471 if self.bouquetSel and closedScreen == self.bouquetSel:
472 self.bouquetSel = None
473 elif self.eventView and closedScreen == self.eventView:
474 self.eventView = None
476 dlgs=len(self.dlg_stack)
478 self.dlg_stack[dlgs-1].close(dlgs > 1)
480 def openMultiServiceEPG(self, withCallback=True):
481 bouquets = self.servicelist.getBouquetList()
486 if cnt > 1: # show bouquet list
488 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
489 self.dlg_stack.append(self.bouquetSel)
491 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
493 self.openBouquetEPG(bouquets[0][1], withCallback)
495 def openSingleServiceEPG(self):
496 ref=self.session.nav.getCurrentlyPlayingServiceReference()
497 self.session.open(EPGSelection, ref)
499 def openSimilarList(self, eventid, refstr):
500 self.session.open(EPGSelection, refstr, None, eventid)
502 def getNowNext(self):
504 service = self.session.nav.getCurrentService()
505 info = service and service.info()
506 ptr = info and info.getEvent(0)
508 self.epglist.append(ptr)
509 ptr = info and info.getEvent(1)
511 self.epglist.append(ptr)
513 def __evEventInfoChanged(self):
514 if self.is_now_next and len(self.dlg_stack) == 1:
516 assert self.eventView
517 if len(self.epglist):
518 self.eventView.setEvent(self.epglist[0])
520 def openEventView(self):
521 ref = self.session.nav.getCurrentlyPlayingServiceReference()
523 if len(self.epglist) == 0:
524 self.is_now_next = False
525 epg = eEPGCache.getInstance()
526 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
528 self.epglist.append(ptr)
529 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
531 self.epglist.append(ptr)
533 self.is_now_next = True
534 if len(self.epglist) > 0:
535 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
536 self.dlg_stack.append(self.eventView)
538 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
539 self.openMultiServiceEPG(False)
541 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
542 if len(self.epglist) > 1:
543 tmp = self.epglist[0]
544 self.epglist[0]=self.epglist[1]
546 setEvent(self.epglist[0])
549 """provides a snr/agc/ber display"""
551 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
554 """provides a current/next event info display"""
556 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
557 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
559 class InfoBarRdsDecoder:
560 """provides RDS and Rass support/display"""
562 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
563 self.rass_interactive = None
565 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
567 iPlayableService.evEnd: self.__serviceStopped,
568 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
571 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
573 "startRassInteractive": self.startRassInteractive
576 self["RdsActions"].setEnabled(False)
578 self.onLayoutFinish.append(self.rds_display.show)
579 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
581 def RassInteractivePossibilityChanged(self, state):
582 self["RdsActions"].setEnabled(state)
584 def RassSlidePicChanged(self):
585 if not self.rass_interactive:
586 service = self.session.nav.getCurrentService()
587 decoder = service and service.rdsDecoder()
589 decoder.showRassSlidePicture()
591 def __serviceStopped(self):
592 if self.rass_interactive is not None:
593 rass_interactive = self.rass_interactive
594 self.rass_interactive = None
595 rass_interactive.close()
597 def startRassInteractive(self):
598 self.rds_display.hide()
599 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
601 def RassInteractiveClosed(self, *val):
602 if self.rass_interactive is not None:
603 self.rass_interactive = None
604 self.RassSlidePicChanged()
605 self.rds_display.show()
607 class InfoBarServiceName:
609 self["CurrentService"] = CurrentService(self.session.nav)
612 """handles actions like seeking, pause"""
614 # ispause, isff, issm
615 SEEK_STATE_PLAY = (0, 0, 0, ">")
616 SEEK_STATE_PAUSE = (1, 0, 0, "||")
617 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
618 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
619 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
620 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
621 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
622 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
624 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
625 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
626 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
627 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
629 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
630 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
631 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
633 SEEK_STATE_EOF = (1, 0, 0, "END")
636 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
638 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
639 iPlayableService.evStart: self.__serviceStarted,
641 iPlayableService.evEOF: self.__evEOF,
642 iPlayableService.evSOF: self.__evSOF,
645 class InfoBarSeekActionMap(HelpableActionMap):
646 def __init__(self, screen, *args, **kwargs):
647 HelpableActionMap.__init__(self, screen, *args, **kwargs)
650 def action(self, contexts, action):
651 print "action:", action
652 if action[:5] == "seek:":
653 time = int(action[5:])
654 self.screen.seekRelative(time * 90000)
658 return HelpableActionMap.action(self, contexts, action)
660 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
662 "playpauseService": (self.playpauseService, _("pause")),
663 "pauseService": (self.pauseService, _("pause")),
664 "unPauseService": (self.unPauseService, _("continue")),
666 "seekFwd": (self.seekFwd, _("skip forward")),
667 "seekFwdDown": self.seekFwdDown,
668 "seekFwdUp": self.seekFwdUp,
669 "seekBack": (self.seekBack, _("skip backward")),
670 "seekBackDown": self.seekBackDown,
671 "seekBackUp": self.seekBackUp,
673 # give them a little more priority to win over color buttons
675 self["SeekActions"].setEnabled(False)
677 self.seekstate = self.SEEK_STATE_PLAY
678 self.onClose.append(self.delTimer)
680 self.fwdtimer = False
681 self.fwdKeyTimer = eTimer()
682 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
684 self.rwdtimer = False
685 self.rwdKeyTimer = eTimer()
686 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
688 self.onPlayStateChanged = [ ]
690 self.lockedBecauseOfSkipping = False
703 service = self.session.nav.getCurrentService()
707 seek = service.seek()
709 if seek is None or not seek.isCurrentlySeekable():
714 def isSeekable(self):
715 if self.getSeek() is None:
719 def __seekableStatusChanged(self):
720 print "seekable status changed!"
721 if not self.isSeekable():
722 self["SeekActions"].setEnabled(False)
723 print "not seekable, return to play"
724 self.setSeekState(self.SEEK_STATE_PLAY)
726 self["SeekActions"].setEnabled(True)
729 def __serviceStarted(self):
730 self.seekstate = self.SEEK_STATE_PLAY
731 self.__seekableStatusChanged()
733 def setSeekState(self, state):
734 service = self.session.nav.getCurrentService()
739 if not self.isSeekable():
740 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
741 state = self.SEEK_STATE_PLAY
743 pauseable = service.pause()
745 if pauseable is None:
746 print "not pauseable."
747 state = self.SEEK_STATE_PLAY
749 oldstate = self.seekstate
750 self.seekstate = state
753 if oldstate[i] != self.seekstate[i]:
754 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
756 for c in self.onPlayStateChanged:
759 self.checkSkipShowHideLock()
763 def playpauseService(self):
764 if self.seekstate != self.SEEK_STATE_PLAY:
765 self.unPauseService()
769 def pauseService(self):
770 if self.seekstate == self.SEEK_STATE_PAUSE:
771 print "pause, but in fact unpause"
772 self.unPauseService()
774 if self.seekstate == self.SEEK_STATE_PLAY:
775 print "yes, playing."
777 print "no", self.seekstate
779 self.setSeekState(self.SEEK_STATE_PAUSE);
781 def unPauseService(self):
783 if self.seekstate == self.SEEK_STATE_PLAY:
785 self.setSeekState(self.SEEK_STATE_PLAY)
787 def doSeek(self, seektime):
788 print "doseek", seektime
789 service = self.session.nav.getCurrentService()
793 seekable = self.getSeek()
797 seekable.seekTo(90 * seektime)
799 def seekFwdDown(self):
800 print "start fwd timer"
802 self.fwdKeyTimer.start(1000)
804 def seekBackDown(self):
805 print "start rewind timer"
807 self.rwdKeyTimer.start(1000)
812 self.fwdKeyTimer.stop()
813 self.fwdtimer = False
818 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
819 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
820 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
821 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
822 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
823 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
824 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
825 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
826 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
827 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
828 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
829 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
830 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
831 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
832 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
833 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
835 self.setSeekState(lookup[self.seekstate])
837 def seekBackUp(self):
840 self.rwdKeyTimer.stop()
841 self.rwdtimer = False
846 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
847 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
848 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
849 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
850 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
851 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
852 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
853 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
854 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
855 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
856 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
857 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
858 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
859 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
860 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
861 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_16X,
863 self.setSeekState(lookup[self.seekstate])
865 if self.seekstate == self.SEEK_STATE_PAUSE:
866 seekable = self.getSeek()
867 if seekable is not None:
868 seekable.seekRelative(-1, 3)
870 def fwdTimerFire(self):
871 print "Display seek fwd"
872 self.fwdKeyTimer.stop()
873 self.fwdtimer = False
874 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
876 def fwdSeekTo(self, minutes):
877 print "Seek", minutes, "minutes forward"
879 seekable = self.getSeek()
880 if seekable is not None:
881 seekable.seekRelative(1, minutes * 60 * 90000)
883 def rwdTimerFire(self):
885 self.rwdKeyTimer.stop()
886 self.rwdtimer = False
887 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
889 def rwdSeekTo(self, minutes):
891 self.fwdSeekTo(0 - minutes)
893 def checkSkipShowHideLock(self):
894 wantlock = self.seekstate != self.SEEK_STATE_PLAY
896 if config.usage.show_infobar_on_zap.value:
897 if self.lockedBecauseOfSkipping and not wantlock:
899 self.lockedBecauseOfSkipping = False
901 if wantlock and not self.lockedBecauseOfSkipping:
903 self.lockedBecauseOfSkipping = True
906 if self.seekstate == self.SEEK_STATE_EOF:
908 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
909 print "end of stream while seeking back, ignoring."
912 # if we are seeking, we try to end up ~1s before the end, and pause there.
913 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
914 self.setSeekState(self.SEEK_STATE_EOF)
915 self.seekRelativeToEnd(-90000)
917 self.setSeekState(self.SEEK_STATE_EOF)
920 self.setSeekState(self.SEEK_STATE_PLAY)
923 def seekRelative(self, diff):
924 seekable = self.getSeek()
925 if seekable is not None:
926 print "seekRelative: res:", seekable.seekRelative(1, diff)
930 def seekRelativeToEnd(self, diff):
931 assert diff <= 0, "diff is expected to be negative!"
933 # might sound like an evil hack, but:
934 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
935 # and we don't get that by passing 0 here (it would seek to begin).
939 # relative-to-end seeking is implemented as absolutes seeks with negative time
940 self.seekAbsolute(diff)
942 def seekAbsolute(self, abs):
943 seekable = self.getSeek()
944 if seekable is not None:
947 from Screens.PVRState import PVRState, TimeshiftState
949 class InfoBarPVRState:
950 def __init__(self, screen=PVRState):
951 self.onPlayStateChanged.append(self.__playStateChanged)
952 self.pvrStateDialog = self.session.instantiateDialog(screen)
953 self.onShow.append(self._mayShow)
954 self.onHide.append(self.pvrStateDialog.hide)
957 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
958 self.pvrStateDialog.show()
960 def __playStateChanged(self, state):
961 playstateString = state[3]
962 self.pvrStateDialog["state"].setText(playstateString)
965 class InfoBarTimeshiftState(InfoBarPVRState):
967 InfoBarPVRState.__init__(self, screen=TimeshiftState)
970 if self.execing and self.timeshift_enabled:
971 self.pvrStateDialog.show()
973 class InfoBarShowMovies:
975 # i don't really like this class.
976 # it calls a not further specified "movie list" on up/down/movieList,
977 # so this is not more than an action map
979 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
981 "movieList": (self.showMovies, "movie list"),
982 "up": (self.showMovies, "movie list"),
983 "down": (self.showMovies, "movie list")
986 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
990 # Timeshift works the following way:
991 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
992 # - normal playback TUNER unused PLAY enable disable disable
993 # - user presses "yellow" button. FILE record PAUSE enable disable enable
994 # - user presess pause again FILE record PLAY enable disable enable
995 # - user fast forwards FILE record FF enable disable enable
996 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
997 # - user backwards FILE record BACK # !! enable disable enable
1001 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1002 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1003 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1004 # - the user can now PVR around
1005 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1006 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1008 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1009 # - if the user rewinds, or press pause, timeshift will be activated again
1011 # note that a timeshift can be enabled ("recording") and
1012 # activated (currently time-shifting).
1014 class InfoBarTimeshift:
1016 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1018 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1019 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1021 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1023 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1024 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1025 }, prio=-1) # priority over record
1027 self.timeshift_enabled = 0
1028 self.timeshift_state = 0
1029 self.ts_rewind_timer = eTimer()
1030 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1032 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1034 iPlayableService.evStart: self.__serviceStarted,
1035 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1038 def getTimeshift(self):
1039 service = self.session.nav.getCurrentService()
1040 return service and service.timeshift()
1042 def startTimeshift(self):
1043 print "enable timeshift"
1044 ts = self.getTimeshift()
1046 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1047 print "no ts interface"
1050 if self.timeshift_enabled:
1051 print "hu, timeshift already enabled?"
1053 if not ts.startTimeshift():
1054 self.timeshift_enabled = 1
1056 # we remove the "relative time" for now.
1057 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1060 #self.setSeekState(self.SEEK_STATE_PAUSE)
1061 self.activateTimeshiftEnd(False)
1063 # enable the "TimeshiftEnableActions", which will override
1064 # the startTimeshift actions
1065 self.__seekableStatusChanged()
1067 print "timeshift failed"
1069 def stopTimeshift(self):
1070 if not self.timeshift_enabled:
1072 print "disable timeshift"
1073 ts = self.getTimeshift()
1076 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1078 def stopTimeshiftConfirmed(self, confirmed):
1082 ts = self.getTimeshift()
1087 self.timeshift_enabled = 0
1090 self.__seekableStatusChanged()
1092 # activates timeshift, and seeks to (almost) the end
1093 def activateTimeshiftEnd(self, back = True):
1094 ts = self.getTimeshift()
1095 print "activateTimeshiftEnd"
1100 if ts.isTimeshiftActive():
1101 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1105 ts.activateTimeshift() # activate timeshift will automatically pause
1106 self.setSeekState(self.SEEK_STATE_PAUSE)
1107 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1110 self.ts_rewind_timer.start(200, 1)
1112 def rewindService(self):
1113 self.setSeekState(self.SEEK_STATE_BACK_16X)
1115 # same as activateTimeshiftEnd, but pauses afterwards.
1116 def activateTimeshiftEndAndPause(self):
1117 print "activateTimeshiftEndAndPause"
1118 #state = self.seekstate
1119 self.activateTimeshiftEnd(False)
1121 def __seekableStatusChanged(self):
1124 print "self.isSeekable", self.isSeekable()
1125 print "self.timeshift_enabled", self.timeshift_enabled
1127 # when this service is not seekable, but timeshift
1128 # is enabled, this means we can activate
1130 if not self.isSeekable() and self.timeshift_enabled:
1133 print "timeshift activate:", enabled
1134 self["TimeshiftActivateActions"].setEnabled(enabled)
1136 def __serviceStarted(self):
1137 self.timeshift_enabled = False
1138 self.__seekableStatusChanged()
1140 from Screens.PiPSetup import PiPSetup
1142 class InfoBarExtensions:
1143 EXTENSION_SINGLE = 0
1149 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1151 "extensions": (self.showExtensionSelection, _("view extensions...")),
1154 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1155 self.list.append((type, extension, key))
1157 def updateExtension(self, extension, key = None):
1158 self.extensionsList.append(extension)
1160 if self.extensionKeys.has_key(key):
1164 for x in self.availableKeys:
1165 if not self.extensionKeys.has_key(x):
1170 self.extensionKeys[key] = len(self.extensionsList) - 1
1172 def updateExtensions(self):
1173 self.extensionsList = []
1174 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1175 self.extensionKeys = {}
1177 if x[0] == self.EXTENSION_SINGLE:
1178 self.updateExtension(x[1], x[2])
1181 self.updateExtension(y[0], y[1])
1184 def showExtensionSelection(self):
1185 self.updateExtensions()
1186 extensionsList = self.extensionsList[:]
1189 for x in self.availableKeys:
1190 if self.extensionKeys.has_key(x):
1191 entry = self.extensionKeys[x]
1192 extension = self.extensionsList[entry]
1194 name = str(extension[0]())
1195 list.append((extension[0](), extension))
1197 extensionsList.remove(extension)
1199 extensionsList.remove(extension)
1200 for x in extensionsList:
1201 list.append((x[0](), x))
1202 keys += [""] * len(extensionsList)
1203 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1205 def extensionCallback(self, answer):
1206 if answer is not None:
1209 from Tools.BoundFunction import boundFunction
1211 # depends on InfoBarExtensions
1212 from Components.PluginComponent import plugins
1214 class InfoBarPlugins:
1216 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1218 def getPluginName(self, name):
1221 def getPluginList(self):
1223 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1224 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1227 def runPlugin(self, plugin):
1228 plugin(session = self.session)
1230 # depends on InfoBarExtensions
1231 class InfoBarSleepTimer:
1233 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1235 def available(self):
1238 def getSleepTimerName(self):
1239 return _("Sleep Timer")
1241 def showSleepTimerSetup(self):
1242 self.session.open(SleepTimerEdit)
1244 # depends on InfoBarExtensions
1247 self.session.pipshown = False
1249 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1250 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1251 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1253 def available(self):
1257 return self.session.pipshown
1259 def getShowHideName(self):
1260 if self.session.pipshown:
1261 return _("Disable Picture in Picture")
1263 return _("Activate Picture in Picture")
1265 def getSwapName(self):
1266 return _("Swap Services")
1268 def getMoveName(self):
1269 return _("Move Picture in Picture")
1272 if self.session.pipshown:
1273 del self.session.pip
1274 self.session.pipshown = False
1276 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1277 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1278 if self.session.pip.playService(newservice):
1279 self.session.pipshown = True
1280 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1282 self.session.pipshown = False
1283 del self.session.pip
1284 self.session.nav.playService(newservice)
1287 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1288 if self.session.pip.servicePath:
1289 servicepath = self.servicelist.getCurrentServicePath()
1290 ref=servicepath[len(servicepath)-1]
1291 pipref=self.session.pip.getCurrentService()
1292 self.session.pip.playService(swapservice)
1293 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1294 if pipref.toString() != ref.toString(): # is a subservice ?
1295 self.session.nav.stopService() # stop portal
1296 self.session.nav.playService(pipref) # start subservice
1297 self.session.pip.servicePath=servicepath
1300 self.session.open(PiPSetup, pip = self.session.pip)
1302 from RecordTimer import parseEvent
1304 class InfoBarInstantRecord:
1305 """Instant Record - handles the instantRecord action in order to
1306 start/stop instant records"""
1308 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1310 "instantRecord": (self.instantRecord, _("Instant Record...")),
1313 self["BlinkingPoint"] = BlinkingPixmapConditional()
1314 self["BlinkingPoint"].hide()
1315 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1317 def stopCurrentRecording(self, entry = -1):
1318 if entry is not None and entry != -1:
1319 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1320 self.recording.remove(self.recording[entry])
1322 def startInstantRecording(self, limitEvent = False):
1323 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1325 # try to get event info
1328 service = self.session.nav.getCurrentService()
1329 epg = eEPGCache.getInstance()
1330 event = epg.lookupEventTime(serviceref, -1, 0)
1332 info = service.info()
1333 ev = info.getEvent(0)
1339 end = time() + 3600 * 10
1340 name = "instant record"
1344 if event is not None:
1345 curEvent = parseEvent(event)
1347 description = curEvent[3]
1348 eventid = curEvent[4]
1353 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1355 data = (begin, end, name, description, eventid)
1357 recording = self.session.nav.recordWithTimer(serviceref, *data)
1358 recording.dontSave = True
1359 self.recording.append(recording)
1361 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1363 def isInstantRecordRunning(self):
1364 print "self.recording:", self.recording
1365 if len(self.recording) > 0:
1366 for x in self.recording:
1371 def recordQuestionCallback(self, answer):
1372 print "pre:\n", self.recording
1374 if answer is None or answer[1] == "no":
1377 recording = self.recording[:]
1379 if not x in self.session.nav.RecordTimer.timer_list:
1380 self.recording.remove(x)
1381 elif x.dontSave and x.isRunning():
1382 list.append(TimerEntryComponent(x, False))
1384 if answer[1] == "changeduration":
1385 if len(self.recording) == 1:
1386 self.changeDuration(0)
1388 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1389 elif answer[1] == "changeendtime":
1390 if len(self.recording) == 1:
1393 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1394 elif answer[1] == "stop":
1395 if len(self.recording) == 1:
1396 self.stopCurrentRecording(0)
1398 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1399 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1400 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1401 if answer[1] == "manualduration":
1402 self.changeDuration(len(self.recording)-1)
1403 elif answer[1] == "manualendtime":
1404 self.setEndtime(len(self.recording)-1)
1405 print "after:\n", self.recording
1407 def setEndtime(self, entry):
1408 if entry is not None:
1409 self.selectedEntry = entry
1410 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1411 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1412 dlg.setTitle(_("Please change recording endtime"))
1414 def TimeDateInputClosed(self, ret):
1417 localendtime = localtime(ret[1])
1418 print "stopping recording at", strftime("%c", localendtime)
1419 self.recording[self.selectedEntry].end = ret[1]
1420 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1422 def changeDuration(self, entry):
1423 if entry is not None:
1424 self.selectedEntry = entry
1425 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1427 def inputCallback(self, value):
1428 if value is not None:
1429 print "stopping recording after", int(value), "minutes."
1430 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1431 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1433 def instantRecord(self):
1435 stat = os_stat(resolveFilename(SCOPE_HDD))
1437 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1440 if self.isInstantRecordRunning():
1441 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1442 title=_("A recording is currently running.\nWhat do you want to do?"), \
1443 list=[(_("stop recording"), "stop"), \
1444 (_("change recording (duration)"), "changeduration"), \
1445 (_("change recording (endtime)"), "changeendtime"), \
1446 (_("add recording (indefinitely)"), "indefinitely"), \
1447 (_("add recording (stop after current event)"), "event"), \
1448 (_("add recording (enter recording duration)"), "manualduration"), \
1449 (_("add recording (enter recording endtime)"), "manualendtime"), \
1450 (_("do nothing"), "no")])
1452 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1453 title=_("Start recording?"), \
1454 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1455 (_("add recording (stop after current event)"), "event"), \
1456 (_("add recording (enter recording duration)"), "manualduration"), \
1457 (_("add recording (enter recording endtime)"), "manualendtime"), \
1458 (_("don't record"), "no")])
1460 from Tools.ISO639 import LanguageCodes
1462 class InfoBarAudioSelection:
1464 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1466 "audioSelection": (self.audioSelection, _("Audio Options...")),
1469 def audioSelection(self):
1470 service = self.session.nav.getCurrentService()
1471 audio = service and service.audioTracks()
1472 self.audioTracks = audio
1473 n = audio and audio.getNumberOfTracks() or 0
1474 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1476 print "tlist:", tlist
1478 self.audioChannel = service.audioChannel()
1481 i = audio.getTrackInfo(x)
1482 language = i.getLanguage()
1483 description = i.getDescription()
1485 if LanguageCodes.has_key(language):
1486 language = LanguageCodes[language][0]
1488 if len(description):
1489 description += " (" + language + ")"
1491 description = language
1493 tlist.append((description, x))
1495 selectedAudio = tlist[0][1]
1496 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1500 if x[1] != selectedAudio:
1505 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1506 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1508 del self.audioTracks
1510 def audioSelected(self, audio):
1511 if audio is not None:
1512 if isinstance(audio[1], str):
1513 if audio[1] == "mode":
1514 keys = ["red", "green", "yellow"]
1515 selection = self.audioChannel.getCurrentChannel()
1516 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1517 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1519 del self.audioChannel
1520 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1521 self.audioTracks.selectTrack(audio[1])
1523 del self.audioChannel
1524 del self.audioTracks
1526 def modeSelected(self, mode):
1527 if mode is not None:
1528 self.audioChannel.selectChannel(mode[1])
1529 del self.audioChannel
1531 class InfoBarSubserviceSelection:
1533 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1535 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1538 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1540 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1541 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1543 self["SubserviceQuickzapAction"].setEnabled(False)
1545 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1549 def checkSubservicesAvail(self, ev):
1550 if ev == iPlayableService.evUpdatedEventInfo:
1551 service = self.session.nav.getCurrentService()
1552 subservices = service and service.subServices()
1553 if not subservices or subservices.getNumberOfSubservices() == 0:
1554 self["SubserviceQuickzapAction"].setEnabled(False)
1556 def nextSubservice(self):
1557 self.changeSubservice(+1)
1559 def prevSubservice(self):
1560 self.changeSubservice(-1)
1562 def changeSubservice(self, direction):
1563 service = self.session.nav.getCurrentService()
1564 subservices = service and service.subServices()
1565 n = subservices and subservices.getNumberOfSubservices()
1568 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1570 if subservices.getSubservice(x).toString() == ref.toString():
1573 selection += direction
1578 newservice = subservices.getSubservice(selection)
1579 if newservice.valid():
1582 self.session.nav.playService(newservice)
1584 def subserviceSelection(self):
1585 service = self.session.nav.getCurrentService()
1586 subservices = service and service.subServices()
1587 self.bouquets = self.servicelist.getBouquetList()
1588 n = subservices and subservices.getNumberOfSubservices()
1591 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1594 i = subservices.getSubservice(x)
1595 if i.toString() == ref.toString():
1597 tlist.append((i.getName(), i))
1599 if self.bouquets and len(self.bouquets):
1600 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1601 if config.usage.multibouquet.value:
1602 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1604 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1607 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1608 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1611 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1613 def subserviceSelected(self, service):
1615 if not service is None:
1616 if isinstance(service[1], str):
1617 if service[1] == "quickzap":
1618 from Screens.SubservicesQuickzap import SubservicesQuickzap
1619 self.session.open(SubservicesQuickzap, service[2])
1621 self["SubserviceQuickzapAction"].setEnabled(True)
1622 self.session.nav.playService(service[1])
1624 def addSubserviceToBouquetCallback(self, service):
1625 if len(service) > 1 and isinstance(service[1], eServiceReference):
1626 self.selectedSubservice = service
1627 if self.bouquets is None:
1630 cnt = len(self.bouquets)
1631 if cnt > 1: # show bouquet list
1632 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1633 elif cnt == 1: # add to only one existing bouquet
1634 self.addSubserviceToBouquet(self.bouquets[0][1])
1635 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1637 def bouquetSelClosed(self, confirmed):
1639 del self.selectedSubservice
1641 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1643 def addSubserviceToBouquet(self, dest):
1644 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1646 self.bsel.close(True)
1648 del self.selectedSubservice
1650 class InfoBarAdditionalInfo:
1652 self["NimA"] = Pixmap()
1653 self["NimB"] = Pixmap()
1654 self["NimA_Active"] = Pixmap()
1655 self["NimB_Active"] = Pixmap()
1657 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1658 self["TimeshiftPossible"] = self["RecordingPossible"]
1659 self["ExtensionsAvailable"] = Boolean(fixed=1)
1661 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1662 res_mgr = eDVBResourceManager.getInstance()
1664 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1666 def tunerUseMaskChanged(self, mask):
1668 self["NimA_Active"].show()
1670 self["NimA_Active"].hide()
1672 self["NimB_Active"].show()
1674 self["NimB_Active"].hide()
1676 def checkTunerState(self, service):
1677 info = service and service.frontendInfo()
1678 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1679 if feNumber is None:
1689 def gotServiceEvent(self, ev):
1690 service = self.session.nav.getCurrentService()
1691 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1692 self.checkTunerState(service)
1694 class InfoBarNotifications:
1696 self.onExecBegin.append(self.checkNotifications)
1697 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1698 self.onClose.append(self.__removeNotification)
1700 def __removeNotification(self):
1701 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1703 def checkNotificationsIfExecing(self):
1705 self.checkNotifications()
1707 def checkNotifications(self):
1708 if len(Notifications.notifications):
1709 n = Notifications.notifications[0]
1711 Notifications.notifications = Notifications.notifications[1:]
1714 if n[3].has_key("onSessionOpenCallback"):
1715 n[3]["onSessionOpenCallback"]()
1716 del n[3]["onSessionOpenCallback"]
1719 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1721 dlg = self.session.open(n[1], *n[2], **n[3])
1723 # remember that this notification is currently active
1725 Notifications.current_notifications.append(d)
1726 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1728 def __notificationClosed(self, d):
1729 Notifications.current_notifications.remove(d)
1731 class InfoBarServiceNotifications:
1733 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1735 iPlayableService.evEnd: self.serviceHasEnded
1738 def serviceHasEnded(self):
1739 print "service end!"
1742 self.setSeekState(self.SEEK_STATE_PLAY)
1746 class InfoBarCueSheetSupport:
1752 ENABLE_RESUME_SUPPORT = False
1755 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1757 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1758 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1759 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1763 self.is_closing = False
1764 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1766 iPlayableService.evStart: self.__serviceStarted,
1769 def __serviceStarted(self):
1772 print "new service started! trying to download cuts!"
1773 self.downloadCuesheet()
1775 if self.ENABLE_RESUME_SUPPORT:
1778 for (pts, what) in self.cut_list:
1779 if what == self.CUT_TYPE_LAST:
1782 if last is not None:
1783 self.resume_point = last
1784 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1786 def playLastCB(self, answer):
1788 seekable = self.__getSeekable()
1789 if seekable is not None:
1790 seekable.seekTo(self.resume_point)
1792 def __getSeekable(self):
1793 service = self.session.nav.getCurrentService()
1796 return service.seek()
1798 def cueGetCurrentPosition(self):
1799 seek = self.__getSeekable()
1802 r = seek.getPlayPosition()
1807 def jumpPreviousNextMark(self, cmp, alternative=None):
1808 current_pos = self.cueGetCurrentPosition()
1809 if current_pos is None:
1811 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1812 if mark is not None:
1814 elif alternative is not None:
1819 seekable = self.__getSeekable()
1820 if seekable is not None:
1821 seekable.seekTo(pts)
1823 def jumpPreviousMark(self):
1824 # we add 2 seconds, so if the play position is <2s after
1825 # the mark, the mark before will be used
1826 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1828 def jumpNextMark(self):
1829 self.jumpPreviousNextMark(lambda x: x)
1831 def getNearestCutPoint(self, pts, cmp=abs):
1834 for cp in self.cut_list:
1835 diff = cmp(cp[0] - pts)
1836 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1840 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1841 current_pos = self.cueGetCurrentPosition()
1842 if current_pos is None:
1843 print "not seekable"
1846 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1848 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1850 return nearest_cutpoint
1852 self.removeMark(nearest_cutpoint)
1853 elif not onlyremove and not onlyreturn:
1854 self.addMark((current_pos, self.CUT_TYPE_MARK))
1859 def addMark(self, point):
1860 insort(self.cut_list, point)
1861 self.uploadCuesheet()
1863 def removeMark(self, point):
1864 self.cut_list.remove(point)
1865 self.uploadCuesheet()
1867 def __getCuesheet(self):
1868 service = self.session.nav.getCurrentService()
1871 return service.cueSheet()
1873 def uploadCuesheet(self):
1874 cue = self.__getCuesheet()
1877 print "upload failed, no cuesheet interface"
1879 cue.setCutList(self.cut_list)
1881 def downloadCuesheet(self):
1882 cue = self.__getCuesheet()
1885 print "upload failed, no cuesheet interface"
1887 self.cut_list = cue.getCutList()
1889 class InfoBarSummary(Screen):
1891 <screen position="0,0" size="132,64">
1892 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1893 <convert type="ClockToText">WithSeconds</convert>
1895 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1896 <convert type="ServiceName">Name</convert>
1900 def __init__(self, session, parent):
1901 Screen.__init__(self, session)
1902 self["CurrentService"] = CurrentService(self.session.nav)
1903 self["CurrentTime"] = Clock()
1905 class InfoBarSummarySupport:
1909 def createSummary(self):
1910 return InfoBarSummary
1912 class InfoBarTeletextPlugin:
1914 self.teletext_plugin = None
1916 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1917 self.teletext_plugin = p
1919 if self.teletext_plugin is not None:
1920 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1922 "startTeletext": (self.startTeletext, _("View teletext..."))
1925 print "no teletext plugin found!"
1927 def startTeletext(self):
1928 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1930 class InfoBarSubtitleSupport(object):
1932 object.__init__(self)
1933 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1934 self.__subtitles_enabled = False
1936 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1938 iPlayableService.evEnd: self.__serviceStopped,
1939 iPlayableService.evUpdatedInfo: self.__updatedInfo
1941 self.cached_subtitle_checked = False
1942 self.__selected_subtitle = None
1944 def __serviceStopped(self):
1945 self.subtitle_window.hide()
1946 self.__subtitles_enabled = False
1947 self.cached_subtitle_checked = False
1949 def __updatedInfo(self):
1950 if not self.cached_subtitle_checked:
1951 subtitle = self.getCurrentServiceSubtitle()
1952 self.cached_subtitle_checked = True
1953 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1954 if self.__selected_subtitle:
1955 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1956 self.subtitle_window.show()
1957 self.__subtitles_enabled = True
1959 def getCurrentServiceSubtitle(self):
1960 service = self.session.nav.getCurrentService()
1961 return service and service.subtitle()
1963 def setSubtitlesEnable(self, enable=True):
1964 subtitle = self.getCurrentServiceSubtitle()
1965 if enable and self.__selected_subtitle is not None:
1966 if subtitle and not self.__subtitles_enabled:
1967 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1968 self.subtitle_window.show()
1969 self.__subtitles_enabled = True
1972 subtitle.disableSubtitles(self.subtitle_window.instance)
1973 self.__subtitles_enabled = False
1974 self.subtitle_window.hide()
1976 def setSelectedSubtitle(self, subtitle):
1977 self.__selected_subtitle = subtitle
1979 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1980 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1982 class InfoBarServiceErrorPopupSupport:
1984 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1986 iPlayableService.evTuneFailed: self.__tuneFailed,
1987 iPlayableService.evStart: self.__serviceStarted
1989 self.__serviceStarted()
1991 def __serviceStarted(self):
1992 self.last_error = None
1993 Notifications.RemovePopup(id = "ZapError")
1995 def __tuneFailed(self):
1996 service = self.session.nav.getCurrentService()
1997 info = service and service.info()
1998 error = info and info.getInfo(iServiceInformation.sDVBState)
2000 if error == self.last_error:
2003 self.last_error = error
2006 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2007 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2008 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2009 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2010 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2011 eDVBServicePMTHandler.eventNewProgramInfo: None,
2012 eDVBServicePMTHandler.eventTuned: None,
2013 eDVBServicePMTHandler.eventSOF: None,
2014 eDVBServicePMTHandler.eventEOF: None
2017 error = errors.get(error) #this returns None when the key not exist in the dict
2019 if error is not None:
2020 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2022 Notifications.RemovePopup(id = "ZapError")