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
21 from EpgSelection import EPGSelection
22 from Plugins.Plugin import PluginDescriptor
24 from Screen import Screen
25 from Screens.ChoiceBox import ChoiceBox
26 from Screens.Dish import Dish
27 from Screens.EventView import EventViewEPGSelect, EventViewSimple
28 from Screens.InputBox import InputBox
29 from Screens.MessageBox import MessageBox
30 from Screens.MinuteInput import MinuteInput
31 from Screens.TimerSelection import TimerSelection
32 from Screens.PictureInPicture import PictureInPicture
33 from Screens.SubtitleDisplay import SubtitleDisplay
34 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
35 from Screens.SleepTimerEdit import SleepTimerEdit
36 from ServiceReference import ServiceReference
38 from Tools import Notifications
39 from Tools.Directories import SCOPE_HDD, resolveFilename
41 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
42 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
45 from os import stat as os_stat
46 from bisect import insort
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
69 }, 1) # lower prio to make it possible to override ok and cancel..
71 self.__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)
87 def __eventInfoChanged(self):
88 ref = self.session.nav.getCurrentlyPlayingServiceReference()
89 service_type = ref and ref.type
90 if service_type and service_type == eServiceReference.idDVB and not len(ref.getPath()):
91 service = self.session.nav.getCurrentService()
92 old_begin_time = self.current_begin_time
93 info = service and service.info()
94 ptr = info and info.getEvent(0)
95 self.current_begin_time = ptr and ptr.getBeginTime() or 0
96 if config.usage.show_infobar_on_event_change.value:
97 if old_begin_time and old_begin_time != self.current_begin_time:
100 def __serviceStarted(self):
101 self.current_begin_time=0
102 if config.usage.show_infobar_on_zap.value:
103 ref = self.session.nav.getCurrentlyPlayingServiceReference()
104 ref_type = ref and ref.type
105 if ref_type and ref_type == eServiceReference.idDVB and not len(ref.getPath()):
109 self.__state = self.STATE_SHOWN
110 self.startHideTimer()
112 def startHideTimer(self):
113 if self.__state == self.STATE_SHOWN and not self.__locked:
114 idx = config.usage.infobar_timeout.index
116 self.hideTimer.start(idx*1000, True)
119 self.__state = self.STATE_HIDDEN
123 self.startHideTimer()
125 def doTimerHide(self):
126 self.hideTimer.stop()
127 if self.__state == self.STATE_SHOWN:
130 def toggleShow(self):
131 if self.__state == self.STATE_SHOWN:
133 self.hideTimer.stop()
134 elif self.__state == self.STATE_HIDDEN:
138 self.__locked = self.__locked + 1
141 self.hideTimer.stop()
143 def unlockShow(self):
144 self.__locked = self.__locked - 1
146 self.startHideTimer()
148 # def startShow(self):
149 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
150 # self.__state = self.STATE_SHOWN
152 # def startHide(self):
153 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
154 # self.__state = self.STATE_HIDDEN
156 class NumberZap(Screen):
163 self.close(int(self["number"].getText()))
165 def keyNumberGlobal(self, number):
166 self.Timer.start(3000, True) #reset timer
167 self.field = self.field + str(number)
168 self["number"].setText(self.field)
169 if len(self.field) >= 4:
172 def __init__(self, session, number):
173 Screen.__init__(self, session)
174 self.field = str(number)
176 self["channel"] = Label(_("Channel:"))
178 self["number"] = Label(self.field)
180 self["actions"] = NumberActionMap( [ "SetupActions" ],
184 "1": self.keyNumberGlobal,
185 "2": self.keyNumberGlobal,
186 "3": self.keyNumberGlobal,
187 "4": self.keyNumberGlobal,
188 "5": self.keyNumberGlobal,
189 "6": self.keyNumberGlobal,
190 "7": self.keyNumberGlobal,
191 "8": self.keyNumberGlobal,
192 "9": self.keyNumberGlobal,
193 "0": self.keyNumberGlobal
196 self.Timer = eTimer()
197 self.Timer.timeout.get().append(self.keyOK)
198 self.Timer.start(3000, True)
200 class InfoBarNumberZap:
201 """ Handles an initial number for NumberZapping """
203 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
205 "1": self.keyNumberGlobal,
206 "2": self.keyNumberGlobal,
207 "3": self.keyNumberGlobal,
208 "4": self.keyNumberGlobal,
209 "5": self.keyNumberGlobal,
210 "6": self.keyNumberGlobal,
211 "7": self.keyNumberGlobal,
212 "8": self.keyNumberGlobal,
213 "9": self.keyNumberGlobal,
214 "0": self.keyNumberGlobal,
217 def keyNumberGlobal(self, number):
218 # print "You pressed number " + str(number)
220 self.servicelist.recallPrevService()
222 self.session.openWithCallback(self.numberEntered, NumberZap, number)
224 def numberEntered(self, retval):
225 # print self.servicelist
227 self.zapToNumber(retval)
229 def searchNumberHelper(self, serviceHandler, num, bouquet):
230 servicelist = serviceHandler.list(bouquet)
231 if not servicelist is None:
233 serviceIterator = servicelist.getNext()
234 if not serviceIterator.valid(): #check end of list
236 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
239 if not num: #found service with searched number ?
240 return serviceIterator, 0
243 def zapToNumber(self, number):
244 bouquet = self.servicelist.bouquet_root
246 serviceHandler = eServiceCenter.getInstance()
247 if not config.usage.multibouquet.value:
248 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
250 bouquetlist = serviceHandler.list(bouquet)
251 if not bouquetlist is None:
253 bouquet = bouquetlist.getNext()
254 if not bouquet.valid(): #check end of list
256 if bouquet.flags & eServiceReference.isDirectory:
257 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
258 if not service is None:
259 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
260 self.servicelist.clearPath()
261 if self.servicelist.bouquet_root != bouquet:
262 self.servicelist.enterPath(self.servicelist.bouquet_root)
263 self.servicelist.enterPath(bouquet)
264 self.servicelist.setCurrentSelection(service) #select the service in servicelist
265 self.servicelist.zap()
267 config.misc.initialchannelselection = ConfigBoolean(default = True)
269 class InfoBarChannelSelection:
270 """ ChannelSelection - handles the channelSelection dialog and the initial
271 channelChange actions which open the channelSelection dialog """
274 self.servicelist = self.session.instantiateDialog(ChannelSelection)
276 if config.misc.initialchannelselection.value:
277 self.onShown.append(self.firstRun)
279 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
281 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
282 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
283 "zapUp": (self.zapUp, _("previous channel")),
284 "zapDown": (self.zapDown, _("next channel")),
285 "historyBack": (self.historyBack, _("previous channel in history")),
286 "historyNext": (self.historyNext, _("next channel in history")),
287 "openServiceList": (self.openServiceList, _("open servicelist")),
290 def showTvChannelList(self, zap=False):
291 self.servicelist.setModeTv()
293 self.servicelist.zap()
294 self.session.execDialog(self.servicelist)
296 def showRadioChannelList(self, zap=False):
297 self.servicelist.setModeRadio()
299 self.servicelist.zap()
300 self.session.execDialog(self.servicelist)
303 self.onShown.remove(self.firstRun)
304 config.misc.initialchannelselection.value = False
305 config.misc.initialchannelselection.save()
306 self.switchChannelDown()
308 def historyBack(self):
309 self.servicelist.historyBack()
311 def historyNext(self):
312 self.servicelist.historyNext()
314 def switchChannelUp(self):
315 self.servicelist.moveUp()
316 self.session.execDialog(self.servicelist)
318 def switchChannelDown(self):
319 self.servicelist.moveDown()
320 self.session.execDialog(self.servicelist)
322 def openServiceList(self):
323 self.session.execDialog(self.servicelist)
326 if self.servicelist.inBouquet():
327 prev = self.servicelist.getCurrentSelection()
329 prev = prev.toString()
331 if config.usage.quickzap_bouquet_change.value:
332 if self.servicelist.atBegin():
333 self.servicelist.prevBouquet()
334 self.servicelist.moveUp()
335 cur = self.servicelist.getCurrentSelection()
336 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
339 self.servicelist.moveUp()
340 self.servicelist.zap()
343 if self.servicelist.inBouquet():
344 prev = self.servicelist.getCurrentSelection()
346 prev = prev.toString()
348 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
349 self.servicelist.nextBouquet()
351 self.servicelist.moveDown()
352 cur = self.servicelist.getCurrentSelection()
353 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
356 self.servicelist.moveDown()
357 self.servicelist.zap()
360 """ Handles a menu action, to open the (main) menu """
362 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
364 "mainMenu": (self.mainMenu, _("Enter main menu...")),
366 self.session.infobar = None
369 print "loading mainmenu XML..."
370 menu = mdom.childNodes[0]
371 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
373 self.session.infobar = self
374 # so we can access the currently active infobar from screens opened from within the mainmenu
375 # at the moment used from the SubserviceSelection
377 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
379 def mainMenuClosed(self, *val):
380 self.session.infobar = None
382 class InfoBarSimpleEventView:
383 """ Opens the Eventview for now/next """
385 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
387 "showEventInfo": (self.openEventView, _("show event details")),
390 def openEventView(self):
392 service = self.session.nav.getCurrentService()
393 ref = self.session.nav.getCurrentlyPlayingServiceReference()
394 info = service.info()
397 self.epglist.append(ptr)
400 self.epglist.append(ptr)
401 if len(self.epglist) > 0:
402 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
404 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
405 if len(self.epglist) > 1:
406 tmp = self.epglist[0]
407 self.epglist[0]=self.epglist[1]
409 setEvent(self.epglist[0])
412 """ EPG - Opens an EPG list when the showEPGList action fires """
414 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
416 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
419 self.is_now_next = False
421 self.bouquetSel = None
422 self.eventView = None
423 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
425 "showEventInfo": (self.openEventView, _("show EPG...")),
428 def zapToService(self, service):
429 if not service is None:
430 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
431 self.servicelist.clearPath()
432 if self.servicelist.bouquet_root != self.epg_bouquet:
433 self.servicelist.enterPath(self.servicelist.bouquet_root)
434 self.servicelist.enterPath(self.epg_bouquet)
435 self.servicelist.setCurrentSelection(service) #select the service in servicelist
436 self.servicelist.zap()
438 def getBouquetServices(self, bouquet):
440 servicelist = eServiceCenter.getInstance().list(bouquet)
441 if not servicelist is None:
443 service = servicelist.getNext()
444 if not service.valid(): #check if end of list
446 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
448 services.append(ServiceReference(service))
451 def openBouquetEPG(self, bouquet, withCallback=True):
452 services = self.getBouquetServices(bouquet)
454 self.epg_bouquet = bouquet
456 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
458 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
460 def changeBouquetCB(self, direction, epg):
463 self.bouquetSel.down()
466 bouquet = self.bouquetSel.getCurrent()
467 services = self.getBouquetServices(bouquet)
469 self.epg_bouquet = bouquet
470 epg.setServices(services)
472 def closed(self, ret=False):
473 closedScreen = self.dlg_stack.pop()
474 if self.bouquetSel and closedScreen == self.bouquetSel:
475 self.bouquetSel = None
476 elif self.eventView and closedScreen == self.eventView:
477 self.eventView = None
479 dlgs=len(self.dlg_stack)
481 self.dlg_stack[dlgs-1].close(dlgs > 1)
483 def openMultiServiceEPG(self, withCallback=True):
484 bouquets = self.servicelist.getBouquetList()
489 if cnt > 1: # show bouquet list
491 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
492 self.dlg_stack.append(self.bouquetSel)
494 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
496 self.openBouquetEPG(bouquets[0][1], withCallback)
498 def openSingleServiceEPG(self):
499 ref=self.session.nav.getCurrentlyPlayingServiceReference()
500 self.session.open(EPGSelection, ref)
502 def openSimilarList(self, eventid, refstr):
503 self.session.open(EPGSelection, refstr, None, eventid)
505 def getNowNext(self):
507 service = self.session.nav.getCurrentService()
508 info = service and service.info()
509 ptr = info and info.getEvent(0)
511 self.epglist.append(ptr)
512 ptr = info and info.getEvent(1)
514 self.epglist.append(ptr)
516 def __evEventInfoChanged(self):
517 if self.is_now_next and len(self.dlg_stack) == 1:
519 assert self.eventView
520 if len(self.epglist):
521 self.eventView.setEvent(self.epglist[0])
523 def openEventView(self):
524 ref = self.session.nav.getCurrentlyPlayingServiceReference()
526 if len(self.epglist) == 0:
527 self.is_now_next = False
528 epg = eEPGCache.getInstance()
529 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
531 self.epglist.append(ptr)
532 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
534 self.epglist.append(ptr)
536 self.is_now_next = True
537 if len(self.epglist) > 0:
538 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
539 self.dlg_stack.append(self.eventView)
541 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
542 self.openMultiServiceEPG(False)
544 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
545 if len(self.epglist) > 1:
546 tmp = self.epglist[0]
547 self.epglist[0]=self.epglist[1]
549 setEvent(self.epglist[0])
552 """provides a snr/agc/ber display"""
554 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
557 """provides a current/next event info display"""
559 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
560 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
562 class InfoBarRdsDecoder:
563 """provides RDS and Rass support/display"""
565 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
566 self.rass_interactive = None
568 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
570 iPlayableService.evEnd: self.__serviceStopped,
571 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
574 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
576 "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
579 self["RdsActions"].setEnabled(False)
581 self.onLayoutFinish.append(self.rds_display.show)
582 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
584 def RassInteractivePossibilityChanged(self, state):
585 self["RdsActions"].setEnabled(state)
587 def RassSlidePicChanged(self):
588 if not self.rass_interactive:
589 service = self.session.nav.getCurrentService()
590 decoder = service and service.rdsDecoder()
592 decoder.showRassSlidePicture()
594 def __serviceStopped(self):
595 if self.rass_interactive is not None:
596 rass_interactive = self.rass_interactive
597 self.rass_interactive = None
598 rass_interactive.close()
600 def startRassInteractive(self):
601 self.rds_display.hide()
602 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
604 def RassInteractiveClosed(self, *val):
605 if self.rass_interactive is not None:
606 self.rass_interactive = None
607 self.RassSlidePicChanged()
608 self.rds_display.show()
610 class InfoBarServiceName:
612 self["CurrentService"] = CurrentService(self.session.nav)
615 """handles actions like seeking, pause"""
617 # ispause, isff, issm
618 SEEK_STATE_PLAY = (0, 0, 0, ">")
619 SEEK_STATE_PAUSE = (1, 0, 0, "||")
620 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
621 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
622 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
623 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
624 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
625 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
627 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
628 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
629 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
630 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
632 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
633 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
634 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
637 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
639 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
640 iPlayableService.evStart: self.__serviceStarted,
642 iPlayableService.evEOF: self.__evEOF,
643 iPlayableService.evSOF: self.__evSOF,
646 class InfoBarSeekActionMap(HelpableActionMap):
647 def __init__(self, screen, *args, **kwargs):
648 HelpableActionMap.__init__(self, screen, *args, **kwargs)
651 def action(self, contexts, action):
652 if action[:5] == "seek:":
653 time = int(action[5:])
654 self.screen.seekRelative(time * 90000)
657 return HelpableActionMap.action(self, contexts, action)
659 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
661 "playpauseService": (self.playpauseService, _("pause")),
662 "pauseService": (self.pauseService, _("pause")),
663 "unPauseService": (self.unPauseService, _("continue")),
665 "seekFwd": (self.seekFwd, _("skip forward")),
666 "seekFwdDown": self.seekFwdDown,
667 "seekFwdUp": self.seekFwdUp,
668 "seekBack": (self.seekBack, _("skip backward")),
669 "seekBackDown": self.seekBackDown,
670 "seekBackUp": self.seekBackUp,
672 # give them a little more priority to win over color buttons
674 self["SeekActions"].setEnabled(False)
676 self.seekstate = self.SEEK_STATE_PLAY
677 self.onClose.append(self.delTimer)
679 self.fwdtimer = False
680 self.fwdKeyTimer = eTimer()
681 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
683 self.rwdtimer = False
684 self.rwdKeyTimer = eTimer()
685 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
687 self.onPlayStateChanged = [ ]
689 self.lockedBecauseOfSkipping = False
702 service = self.session.nav.getCurrentService()
706 seek = service.seek()
708 if seek is None or not seek.isCurrentlySeekable():
713 def isSeekable(self):
714 if self.getSeek() is None:
718 def __seekableStatusChanged(self):
719 print "seekable status changed!"
720 if not self.isSeekable():
721 self["SeekActions"].setEnabled(False)
722 print "not seekable, return to play"
723 self.setSeekState(self.SEEK_STATE_PLAY)
725 self["SeekActions"].setEnabled(True)
728 def __serviceStarted(self):
729 self.seekstate = self.SEEK_STATE_PLAY
731 def setSeekState(self, state):
732 service = self.session.nav.getCurrentService()
737 if not self.isSeekable():
738 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
739 state = self.SEEK_STATE_PLAY
741 pauseable = service.pause()
743 if pauseable is None:
744 print "not pauseable."
745 state = self.SEEK_STATE_PLAY
747 oldstate = self.seekstate
748 self.seekstate = state
751 if oldstate[i] != self.seekstate[i]:
752 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
754 for c in self.onPlayStateChanged:
757 self.checkSkipShowHideLock()
761 def playpauseService(self):
762 if self.seekstate != self.SEEK_STATE_PLAY:
763 self.unPauseService()
767 def pauseService(self):
768 if self.seekstate == self.SEEK_STATE_PAUSE:
769 print "pause, but in fact unpause"
770 self.unPauseService()
772 if self.seekstate == self.SEEK_STATE_PLAY:
773 print "yes, playing."
775 print "no", self.seekstate
777 self.setSeekState(self.SEEK_STATE_PAUSE);
779 def unPauseService(self):
781 if self.seekstate == self.SEEK_STATE_PLAY:
783 self.setSeekState(self.SEEK_STATE_PLAY)
785 def doSeek(self, seektime):
786 print "doseek", seektime
787 service = self.session.nav.getCurrentService()
791 seekable = self.getSeek()
795 seekable.seekTo(90 * seektime)
797 def seekFwdDown(self):
798 print "start fwd timer"
800 self.fwdKeyTimer.start(1000)
802 def seekBackDown(self):
803 print "start rewind timer"
805 self.rwdKeyTimer.start(1000)
810 self.fwdKeyTimer.stop()
811 self.fwdtimer = False
816 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
817 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
818 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
819 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
820 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
821 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
822 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
823 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
824 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
825 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
826 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
827 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
828 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
829 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
830 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
832 self.setSeekState(lookup[self.seekstate])
834 def seekBackUp(self):
837 self.rwdKeyTimer.stop()
838 self.rwdtimer = False
843 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
844 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
845 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
846 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
847 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
848 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
849 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
850 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
851 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
852 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
853 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
854 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
855 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
856 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
857 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
859 self.setSeekState(lookup[self.seekstate])
861 if self.seekstate == self.SEEK_STATE_PAUSE:
862 seekable = self.getSeek()
863 if seekable is not None:
864 seekable.seekRelative(-1, 3)
866 def fwdTimerFire(self):
867 print "Display seek fwd"
868 self.fwdKeyTimer.stop()
869 self.fwdtimer = False
870 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
872 def fwdSeekTo(self, minutes):
873 print "Seek", minutes, "minutes forward"
875 seekable = self.getSeek()
876 if seekable is not None:
877 seekable.seekRelative(1, minutes * 60 * 90000)
879 def rwdTimerFire(self):
881 self.rwdKeyTimer.stop()
882 self.rwdtimer = False
883 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
885 def rwdSeekTo(self, minutes):
887 self.fwdSeekTo(0 - minutes)
889 def checkSkipShowHideLock(self):
890 wantlock = self.seekstate != self.SEEK_STATE_PLAY
892 if config.usage.show_infobar_on_zap.value:
893 if self.lockedBecauseOfSkipping and not wantlock:
895 self.lockedBecauseOfSkipping = False
897 if wantlock and not self.lockedBecauseOfSkipping:
899 self.lockedBecauseOfSkipping = True
902 if self.seekstate != self.SEEK_STATE_PLAY:
903 self.setSeekState(self.SEEK_STATE_PAUSE)
905 #self.getSeek().seekRelative(1, -90000)
906 self.setSeekState(self.SEEK_STATE_PLAY)
908 self.setSeekState(self.SEEK_STATE_PAUSE)
911 self.setSeekState(self.SEEK_STATE_PLAY)
914 def seekRelative(self, diff):
915 seekable = self.getSeek()
916 if seekable is not None:
917 seekable.seekRelative(1, diff)
919 def seekAbsolute(self, abs):
920 seekable = self.getSeek()
921 if seekable is not None:
924 from Screens.PVRState import PVRState, TimeshiftState
926 class InfoBarPVRState:
927 def __init__(self, screen=PVRState):
928 self.onPlayStateChanged.append(self.__playStateChanged)
929 self.pvrStateDialog = self.session.instantiateDialog(screen)
930 self.onShow.append(self._mayShow)
931 self.onHide.append(self.pvrStateDialog.hide)
934 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
935 self.pvrStateDialog.show()
937 def __playStateChanged(self, state):
938 playstateString = state[3]
939 self.pvrStateDialog["state"].setText(playstateString)
942 class InfoBarTimeshiftState(InfoBarPVRState):
944 InfoBarPVRState.__init__(self, screen=TimeshiftState)
947 if self.execing and self.timeshift_enabled:
948 self.pvrStateDialog.show()
950 class InfoBarShowMovies:
952 # i don't really like this class.
953 # it calls a not further specified "movie list" on up/down/movieList,
954 # so this is not more than an action map
956 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
958 "movieList": (self.showMovies, "movie list"),
959 "up": (self.showMovies, "movie list"),
960 "down": (self.showMovies, "movie list")
963 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
967 # Timeshift works the following way:
968 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
969 # - normal playback TUNER unused PLAY enable disable disable
970 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
971 # - user presess pause again FILE record PLAY enable disable enable
972 # - user fast forwards FILE record FF enable disable enable
973 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
974 # - user backwards FILE record BACK # !! enable disable enable
978 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
979 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
980 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
981 # - the user can now PVR around
982 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
983 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
985 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
986 # - if the user rewinds, or press pause, timeshift will be activated again
988 # note that a timeshift can be enabled ("recording") and
989 # activated (currently time-shifting).
991 class InfoBarTimeshift:
993 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
995 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
996 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
998 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1000 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
1001 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
1002 }, prio=-1) # priority over record
1004 self.timeshift_enabled = 0
1005 self.timeshift_state = 0
1006 self.ts_pause_timer = eTimer()
1007 self.ts_pause_timer.timeout.get().append(self.pauseService)
1009 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1011 iPlayableService.evStart: self.__serviceStarted,
1012 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1015 def getTimeshift(self):
1016 service = self.session.nav.getCurrentService()
1017 return service and service.timeshift()
1019 def startTimeshift(self):
1020 print "enable timeshift"
1021 ts = self.getTimeshift()
1023 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1024 print "no ts interface"
1027 if self.timeshift_enabled:
1028 print "hu, timeshift already enabled?"
1030 if not ts.startTimeshift():
1031 self.timeshift_enabled = 1
1033 # we remove the "relative time" for now.
1034 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1037 self.setSeekState(self.SEEK_STATE_PAUSE)
1039 # enable the "TimeshiftEnableActions", which will override
1040 # the startTimeshift actions
1041 self.__seekableStatusChanged()
1043 print "timeshift failed"
1045 def stopTimeshift(self):
1046 if not self.timeshift_enabled:
1048 print "disable timeshift"
1049 ts = self.getTimeshift()
1052 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1054 def stopTimeshiftConfirmed(self, confirmed):
1058 ts = self.getTimeshift()
1063 self.timeshift_enabled = 0
1066 self.__seekableStatusChanged()
1068 # activates timeshift, and seeks to (almost) the end
1069 def activateTimeshiftEnd(self):
1070 ts = self.getTimeshift()
1075 if ts.isTimeshiftActive():
1076 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1079 self.setSeekState(self.SEEK_STATE_PLAY)
1080 ts.activateTimeshift()
1081 self.seekRelative(0)
1083 # same as activateTimeshiftEnd, but pauses afterwards.
1084 def activateTimeshiftEndAndPause(self):
1085 state = self.seekstate
1086 self.activateTimeshiftEnd()
1088 # well, this is "andPause", but it could be pressed from pause,
1089 # when pausing on the (fake-)"live" picture, so an un-pause
1092 print "now, pauseService"
1093 if state == self.SEEK_STATE_PLAY:
1094 print "is PLAYING, start pause timer"
1095 self.ts_pause_timer.start(200, 1)
1098 self.unPauseService()
1100 def __seekableStatusChanged(self):
1103 print "self.isSeekable", self.isSeekable()
1104 print "self.timeshift_enabled", self.timeshift_enabled
1106 # when this service is not seekable, but timeshift
1107 # is enabled, this means we can activate
1109 if not self.isSeekable() and self.timeshift_enabled:
1112 print "timeshift activate:", enabled
1113 self["TimeshiftActivateActions"].setEnabled(enabled)
1115 def __serviceStarted(self):
1116 self.timeshift_enabled = False
1117 self.__seekableStatusChanged()
1119 from Screens.PiPSetup import PiPSetup
1121 class InfoBarExtensions:
1122 EXTENSION_SINGLE = 0
1128 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1130 "extensions": (self.showExtensionSelection, _("view extensions...")),
1133 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1134 self.list.append((type, extension, key))
1136 def updateExtension(self, extension, key = None):
1137 self.extensionsList.append(extension)
1139 if self.extensionKeys.has_key(key):
1143 for x in self.availableKeys:
1144 if not self.extensionKeys.has_key(x):
1149 self.extensionKeys[key] = len(self.extensionsList) - 1
1151 def updateExtensions(self):
1152 self.extensionsList = []
1153 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1154 self.extensionKeys = {}
1156 if x[0] == self.EXTENSION_SINGLE:
1157 self.updateExtension(x[1], x[2])
1160 self.updateExtension(y[0], y[1])
1163 def showExtensionSelection(self):
1164 self.updateExtensions()
1165 extensionsList = self.extensionsList[:]
1168 for x in self.availableKeys:
1169 if self.extensionKeys.has_key(x):
1170 entry = self.extensionKeys[x]
1171 extension = self.extensionsList[entry]
1173 name = str(extension[0]())
1174 list.append((extension[0](), extension))
1176 extensionsList.remove(extension)
1178 extensionsList.remove(extension)
1179 for x in extensionsList:
1180 list.append((x[0](), x))
1181 keys += [""] * len(extensionsList)
1182 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1184 def extensionCallback(self, answer):
1185 if answer is not None:
1188 from Tools.BoundFunction import boundFunction
1190 # depends on InfoBarExtensions
1191 from Components.PluginComponent import plugins
1193 class InfoBarPlugins:
1195 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1197 def getPluginName(self, name):
1200 def getPluginList(self):
1202 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1203 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1206 def runPlugin(self, plugin):
1207 plugin(session = self.session)
1209 # depends on InfoBarExtensions
1210 class InfoBarSleepTimer:
1212 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1214 def available(self):
1217 def getSleepTimerName(self):
1218 return _("Sleep Timer")
1220 def showSleepTimerSetup(self):
1221 self.session.open(SleepTimerEdit)
1223 # depends on InfoBarExtensions
1226 self.session.pipshown = False
1228 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1229 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1230 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1232 def available(self):
1236 return self.session.pipshown
1238 def getShowHideName(self):
1239 if self.session.pipshown:
1240 return _("Disable Picture in Picture")
1242 return _("Activate Picture in Picture")
1244 def getSwapName(self):
1245 return _("Swap Services")
1247 def getMoveName(self):
1248 return _("Move Picture in Picture")
1251 if self.session.pipshown:
1252 del self.session.pip
1253 self.session.pipshown = False
1255 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1256 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1257 if self.session.pip.playService(newservice):
1258 self.session.pipshown = True
1259 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1261 self.session.pipshown = False
1262 del self.session.pip
1263 self.session.nav.playService(newservice)
1266 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1267 if self.session.pip.servicePath:
1268 servicepath = self.servicelist.getCurrentServicePath()
1269 ref=servicepath[len(servicepath)-1]
1270 pipref=self.session.pip.getCurrentService()
1271 self.session.pip.playService(swapservice)
1272 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1273 if pipref.toString() != ref.toString(): # is a subservice ?
1274 self.session.nav.stopService() # stop portal
1275 self.session.nav.playService(pipref) # start subservice
1276 self.session.pip.servicePath=servicepath
1279 self.session.open(PiPSetup, pip = self.session.pip)
1281 from RecordTimer import parseEvent
1283 class InfoBarInstantRecord:
1284 """Instant Record - handles the instantRecord action in order to
1285 start/stop instant records"""
1287 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1289 "instantRecord": (self.instantRecord, _("Instant Record...")),
1292 self["BlinkingPoint"] = BlinkingPixmapConditional()
1293 self["BlinkingPoint"].hide()
1294 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1296 def stopCurrentRecording(self, entry = -1):
1297 if entry is not None and entry != -1:
1298 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1299 self.recording.remove(self.recording[entry])
1301 def startInstantRecording(self, limitEvent = False):
1302 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1304 # try to get event info
1307 service = self.session.nav.getCurrentService()
1308 epg = eEPGCache.getInstance()
1309 event = epg.lookupEventTime(serviceref, -1, 0)
1311 info = service.info()
1312 ev = info.getEvent(0)
1318 end = time() + 3600 * 10
1319 name = "instant record"
1323 if event is not None:
1324 curEvent = parseEvent(event)
1326 description = curEvent[3]
1327 eventid = curEvent[4]
1332 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1334 data = (begin, end, name, description, eventid)
1336 recording = self.session.nav.recordWithTimer(serviceref, *data)
1337 recording.dontSave = True
1338 self.recording.append(recording)
1340 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1342 def isInstantRecordRunning(self):
1343 print "self.recording:", self.recording
1344 if len(self.recording) > 0:
1345 for x in self.recording:
1350 def recordQuestionCallback(self, answer):
1351 print "pre:\n", self.recording
1353 if answer is None or answer[1] == "no":
1356 recording = self.recording[:]
1358 if not x in self.session.nav.RecordTimer.timer_list:
1359 self.recording.remove(x)
1360 elif x.dontSave and x.isRunning():
1361 list.append(TimerEntryComponent(x, False))
1363 if answer[1] == "changeduration":
1364 if len(self.recording) == 1:
1365 self.changeDuration(0)
1367 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1368 elif answer[1] == "stop":
1369 if len(self.recording) == 1:
1370 self.stopCurrentRecording(0)
1372 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1373 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1375 if answer[1] == "event":
1377 if answer[1] == "manualduration":
1378 self.selectedEntry = len(self.recording)
1379 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1380 self.startInstantRecording(limitEvent = limitEvent)
1382 print "after:\n", self.recording
1384 def changeDuration(self, entry):
1385 if entry is not None:
1386 self.selectedEntry = entry
1387 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1389 def inputCallback(self, value):
1390 if value is not None:
1391 print "stopping recording after", int(value), "minutes."
1392 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1393 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1395 def instantRecord(self):
1397 stat = os_stat(resolveFilename(SCOPE_HDD))
1399 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1402 if self.isInstantRecordRunning():
1403 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1404 title=_("A recording is currently running.\nWhat do you want to do?"), \
1405 list=[(_("stop recording"), "stop"), \
1406 (_("change recording (duration)"), "changeduration"), \
1407 (_("add recording (indefinitely)"), "indefinitely"), \
1408 (_("add recording (stop after current event)"), "event"), \
1409 (_("add recording (enter recording duration)"), "manualduration"), \
1410 (_("do nothing"), "no")])
1412 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1413 title=_("Start recording?"), \
1414 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1415 (_("add recording (stop after current event)"), "event"), \
1416 (_("add recording (enter recording duration)"), "manualduration"), \
1417 (_("don't record"), "no")])
1419 from Tools.ISO639 import LanguageCodes
1421 class InfoBarAudioSelection:
1423 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1425 "audioSelection": (self.audioSelection, _("Audio Options...")),
1428 def audioSelection(self):
1429 service = self.session.nav.getCurrentService()
1430 audio = service and service.audioTracks()
1431 self.audioTracks = audio
1432 n = audio and audio.getNumberOfTracks() or 0
1433 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1435 print "tlist:", tlist
1437 self.audioChannel = service.audioChannel()
1440 i = audio.getTrackInfo(x)
1441 language = i.getLanguage()
1442 description = i.getDescription()
1444 if LanguageCodes.has_key(language):
1445 language = LanguageCodes[language][0]
1447 if len(description):
1448 description += " (" + language + ")"
1450 description = language
1452 tlist.append((description, x))
1454 selectedAudio = tlist[0][1]
1455 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1459 if x[1] != selectedAudio:
1464 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1465 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1467 del self.audioTracks
1469 def audioSelected(self, audio):
1470 if audio is not None:
1471 if isinstance(audio[1], str):
1472 if audio[1] == "mode":
1473 keys = ["red", "green", "yellow"]
1474 selection = self.audioChannel.getCurrentChannel()
1475 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1476 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1478 del self.audioChannel
1479 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1480 self.audioTracks.selectTrack(audio[1])
1482 del self.audioChannel
1483 del self.audioTracks
1485 def modeSelected(self, mode):
1486 if mode is not None:
1487 self.audioChannel.selectChannel(mode[1])
1488 del self.audioChannel
1490 class InfoBarSubserviceSelection:
1492 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1494 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1497 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1499 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1500 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1502 self["SubserviceQuickzapAction"].setEnabled(False)
1504 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1508 def checkSubservicesAvail(self, ev):
1509 if ev == iPlayableService.evUpdatedEventInfo:
1510 service = self.session.nav.getCurrentService()
1511 subservices = service and service.subServices()
1512 if not subservices or subservices.getNumberOfSubservices() == 0:
1513 self["SubserviceQuickzapAction"].setEnabled(False)
1515 def nextSubservice(self):
1516 self.changeSubservice(+1)
1518 def prevSubservice(self):
1519 self.changeSubservice(-1)
1521 def changeSubservice(self, direction):
1522 service = self.session.nav.getCurrentService()
1523 subservices = service and service.subServices()
1524 n = subservices and subservices.getNumberOfSubservices()
1527 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1529 if subservices.getSubservice(x).toString() == ref.toString():
1532 selection += direction
1537 newservice = subservices.getSubservice(selection)
1538 if newservice.valid():
1541 self.session.nav.playService(newservice)
1543 def subserviceSelection(self):
1544 service = self.session.nav.getCurrentService()
1545 subservices = service and service.subServices()
1546 self.bouquets = self.servicelist.getBouquetList()
1547 n = subservices and subservices.getNumberOfSubservices()
1550 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1553 i = subservices.getSubservice(x)
1554 if i.toString() == ref.toString():
1556 tlist.append((i.getName(), i))
1558 if self.bouquets and len(self.bouquets):
1559 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1560 if config.usage.multibouquet.value:
1561 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1563 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1566 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1567 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1570 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1572 def subserviceSelected(self, service):
1574 if not service is None:
1575 if isinstance(service[1], str):
1576 if service[1] == "quickzap":
1577 from Screens.SubservicesQuickzap import SubservicesQuickzap
1578 self.session.open(SubservicesQuickzap, service[2])
1580 self["SubserviceQuickzapAction"].setEnabled(True)
1581 self.session.nav.playService(service[1])
1583 def addSubserviceToBouquetCallback(self, service):
1584 if len(service) > 1 and isinstance(service[1], eServiceReference):
1585 self.selectedSubservice = service
1586 if self.bouquets is None:
1589 cnt = len(self.bouquets)
1590 if cnt > 1: # show bouquet list
1591 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1592 elif cnt == 1: # add to only one existing bouquet
1593 self.addSubserviceToBouquet(self.bouquets[0][1])
1594 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1596 def bouquetSelClosed(self, confirmed):
1598 del self.selectedSubservice
1600 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1602 def addSubserviceToBouquet(self, dest):
1603 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1605 self.bsel.close(True)
1607 del self.selectedSubservice
1609 class InfoBarAdditionalInfo:
1611 self["NimA"] = Pixmap()
1612 self["NimB"] = Pixmap()
1613 self["NimA_Active"] = Pixmap()
1614 self["NimB_Active"] = Pixmap()
1616 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1617 self["TimeshiftPossible"] = self["RecordingPossible"]
1618 self["ExtensionsAvailable"] = Boolean(fixed=1)
1620 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1621 res_mgr = eDVBResourceManager.getInstance()
1623 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1625 def tunerUseMaskChanged(self, mask):
1627 self["NimA_Active"].show()
1629 self["NimA_Active"].hide()
1631 self["NimB_Active"].show()
1633 self["NimB_Active"].hide()
1635 def checkTunerState(self, service):
1636 info = service and service.frontendInfo()
1637 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1638 if feNumber is None:
1648 def gotServiceEvent(self, ev):
1649 service = self.session.nav.getCurrentService()
1650 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1651 self.checkTunerState(service)
1653 class InfoBarNotifications:
1655 self.onExecBegin.append(self.checkNotifications)
1656 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1657 self.onClose.append(self.__removeNotification)
1659 def __removeNotification(self):
1660 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1662 def checkNotificationsIfExecing(self):
1664 self.checkNotifications()
1666 def checkNotifications(self):
1667 if len(Notifications.notifications):
1668 n = Notifications.notifications[0]
1670 Notifications.notifications = Notifications.notifications[1:]
1673 if n[3].has_key("onSessionOpenCallback"):
1674 n[3]["onSessionOpenCallback"]()
1675 del n[3]["onSessionOpenCallback"]
1678 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1680 dlg = self.session.open(n[1], *n[2], **n[3])
1682 # remember that this notification is currently active
1684 Notifications.current_notifications.append(d)
1685 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1687 def __notificationClosed(self, d):
1688 Notifications.current_notifications.remove(d)
1690 class InfoBarServiceNotifications:
1692 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1694 iPlayableService.evEnd: self.serviceHasEnded
1697 def serviceHasEnded(self):
1698 print "service end!"
1701 self.setSeekState(self.SEEK_STATE_PLAY)
1705 class InfoBarCueSheetSupport:
1711 ENABLE_RESUME_SUPPORT = False
1714 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1716 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1717 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1718 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1722 self.is_closing = False
1723 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1725 iPlayableService.evStart: self.__serviceStarted,
1728 def __serviceStarted(self):
1731 print "new service started! trying to download cuts!"
1732 self.downloadCuesheet()
1734 if self.ENABLE_RESUME_SUPPORT:
1737 for (pts, what) in self.cut_list:
1738 if what == self.CUT_TYPE_LAST:
1741 if last is not None:
1742 self.resume_point = last
1743 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1745 def playLastCB(self, answer):
1747 seekable = self.__getSeekable()
1748 if seekable is not None:
1749 seekable.seekTo(self.resume_point)
1751 def __getSeekable(self):
1752 service = self.session.nav.getCurrentService()
1755 return service.seek()
1757 def cueGetCurrentPosition(self):
1758 seek = self.__getSeekable()
1761 r = seek.getPlayPosition()
1766 def jumpPreviousNextMark(self, cmp, alternative=None):
1767 current_pos = self.cueGetCurrentPosition()
1768 if current_pos is None:
1770 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1771 if mark is not None:
1773 elif alternative is not None:
1778 seekable = self.__getSeekable()
1779 if seekable is not None:
1780 seekable.seekTo(pts)
1782 def jumpPreviousMark(self):
1783 # we add 2 seconds, so if the play position is <2s after
1784 # the mark, the mark before will be used
1785 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1787 def jumpNextMark(self):
1788 self.jumpPreviousNextMark(lambda x: x)
1790 def getNearestCutPoint(self, pts, cmp=abs):
1793 for cp in self.cut_list:
1794 diff = cmp(cp[0] - pts)
1795 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1799 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1800 current_pos = self.cueGetCurrentPosition()
1801 if current_pos is None:
1802 print "not seekable"
1805 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1807 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1809 return nearest_cutpoint
1811 self.removeMark(nearest_cutpoint)
1812 elif not onlyremove and not onlyreturn:
1813 self.addMark((current_pos, self.CUT_TYPE_MARK))
1818 def addMark(self, point):
1819 insort(self.cut_list, point)
1820 self.uploadCuesheet()
1822 def removeMark(self, point):
1823 self.cut_list.remove(point)
1824 self.uploadCuesheet()
1826 def __getCuesheet(self):
1827 service = self.session.nav.getCurrentService()
1830 return service.cueSheet()
1832 def uploadCuesheet(self):
1833 cue = self.__getCuesheet()
1836 print "upload failed, no cuesheet interface"
1838 cue.setCutList(self.cut_list)
1840 def downloadCuesheet(self):
1841 cue = self.__getCuesheet()
1844 print "upload failed, no cuesheet interface"
1846 self.cut_list = cue.getCutList()
1848 class InfoBarSummary(Screen):
1850 <screen position="0,0" size="132,64">
1851 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1852 <convert type="ClockToText">WithSeconds</convert>
1854 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1855 <convert type="ServiceName">Name</convert>
1859 def __init__(self, session, parent):
1860 Screen.__init__(self, session)
1861 self["CurrentService"] = CurrentService(self.session.nav)
1862 self["CurrentTime"] = Clock()
1864 class InfoBarSummarySupport:
1868 def createSummary(self):
1869 return InfoBarSummary
1871 class InfoBarTeletextPlugin:
1873 self.teletext_plugin = None
1875 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1876 self.teletext_plugin = p
1878 if self.teletext_plugin is not None:
1879 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1881 "startTeletext": (self.startTeletext, _("View teletext..."))
1884 print "no teletext plugin found!"
1886 def startTeletext(self):
1887 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1889 class InfoBarSubtitleSupport(object):
1891 object.__init__(self)
1892 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1893 self.__subtitles_enabled = False
1895 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1897 iPlayableService.evEnd: self.__serviceStopped,
1898 iPlayableService.evUpdatedInfo: self.__updatedInfo
1900 self.cached_subtitle_checked = False
1902 def __serviceStopped(self):
1903 self.subtitle_window.hide()
1904 self.__subtitles_enabled = False
1905 self.cached_subtitle_checked = False
1907 def __updatedInfo(self):
1908 if not self.cached_subtitle_checked:
1909 subtitle = self.getCurrentServiceSubtitle()
1910 self.cached_subtitle_checked = True
1912 self.__selected_subtitle = subtitle.getCachedSubtitle()
1913 if self.__selected_subtitle:
1914 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1915 self.subtitle_window.show()
1916 self.__subtitles_enabled = True
1918 def getCurrentServiceSubtitle(self):
1919 service = self.session.nav.getCurrentService()
1920 return service and service.subtitle()
1922 def setSubtitlesEnable(self, enable=True):
1923 subtitle = self.getCurrentServiceSubtitle()
1924 if enable and self.__selected_subtitle is not None:
1925 if subtitle and not self.__subtitles_enabled:
1926 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1927 self.subtitle_window.show()
1928 self.__subtitles_enabled = True
1931 subtitle.disableSubtitles(self.subtitle_window.instance)
1932 self.__subtitles_enabled = False
1933 self.subtitle_window.hide()
1935 def setSelectedSubtitle(self, subtitle):
1936 self.__selected_subtitle = subtitle
1938 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1939 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1941 class InfoBarServiceErrorPopupSupport:
1943 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1945 iPlayableService.evTuneFailed: self.__tuneFailed,
1946 iPlayableService.evStart: self.__serviceStarted
1948 self.__serviceStarted()
1950 def __serviceStarted(self):
1951 self.last_error = None
1952 Notifications.RemovePopup(id = "ZapError")
1954 def __tuneFailed(self):
1955 service = self.session.nav.getCurrentService()
1956 info = service and service.info()
1957 error = info and info.getInfo(iServiceInformation.sDVBState)
1959 if error == self.last_error:
1962 self.last_error = error
1965 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1966 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1967 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1968 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1969 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1970 eDVBServicePMTHandler.eventNewProgramInfo: None,
1971 eDVBServicePMTHandler.eventTuned: None,
1972 eDVBServicePMTHandler.eventSOF: None,
1973 eDVBServicePMTHandler.eventEOF: None
1976 error = errors.get(error) #this returns None when the key not exist in the dict
1978 if error is not None:
1979 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1981 Notifications.RemovePopup(id = "ZapError")