1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import *
9 from Components.Pixmap import Pixmap, PixmapConditional
10 from Components.PluginComponent import plugins
11 from Components.ProgressBar import *
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.Sources.CurrentService import CurrentService
14 from Components.Sources.EventInfo import EventInfo
15 from Components.Sources.RadioText import RadioText
16 from Components.Sources.FrontendStatus import FrontendStatus
17 from Components.Sources.Boolean import Boolean
18 from Components.Sources.Clock import Clock
19 from Components.TimerList import TimerEntryComponent
20 from Components.config import config, ConfigBoolean
22 from EpgSelection import EPGSelection
23 from Plugins.Plugin import PluginDescriptor
25 from Screen import Screen
26 from Screens.ChoiceBox import ChoiceBox
27 from Screens.Dish import Dish
28 from Screens.EventView import EventViewEPGSelect, EventViewSimple
29 from Screens.InputBox import InputBox
30 from Screens.MessageBox import MessageBox
31 from Screens.MinuteInput import MinuteInput
32 from Screens.TimerSelection import TimerSelection
33 from Screens.PictureInPicture import PictureInPicture
34 from Screens.SubtitleDisplay import SubtitleDisplay
35 from Screens.SleepTimerEdit import SleepTimerEdit
36 from ServiceReference import ServiceReference
38 from Tools import Notifications
39 from Tools.Directories import SCOPE_HDD, resolveFilename
41 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
42 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
45 from os import stat as os_stat
46 from bisect import insort
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
69 }, 1) # lower prio to make it possible to override ok and cancel..
71 self.__state = self.STATE_SHOWN
74 self.hideTimer = eTimer()
75 self.hideTimer.timeout.get().append(self.doTimerHide)
76 self.hideTimer.start(5000, True)
78 self.onShow.append(self.__onShow)
79 self.onHide.append(self.__onHide)
82 self.__state = self.STATE_SHOWN
85 def startHideTimer(self):
86 if self.__state == self.STATE_SHOWN and not self.__locked:
87 idx = config.usage.infobar_timeout.index
89 self.hideTimer.start(idx*1000, True)
92 self.__state = self.STATE_HIDDEN
98 def doTimerHide(self):
100 if self.__state == self.STATE_SHOWN:
103 def toggleShow(self):
104 if self.__state == self.STATE_SHOWN:
106 self.hideTimer.stop()
107 elif self.__state == self.STATE_HIDDEN:
111 self.__locked = self.__locked + 1
114 self.hideTimer.stop()
116 def unlockShow(self):
117 self.__locked = self.__locked - 1
119 self.startHideTimer()
121 # def startShow(self):
122 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
123 # self.__state = self.STATE_SHOWN
125 # def startHide(self):
126 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
127 # self.__state = self.STATE_HIDDEN
129 class NumberZap(Screen):
136 self.close(int(self["number"].getText()))
138 def keyNumberGlobal(self, number):
139 self.Timer.start(3000, True) #reset timer
140 self.field = self.field + str(number)
141 self["number"].setText(self.field)
142 if len(self.field) >= 4:
145 def __init__(self, session, number):
146 Screen.__init__(self, session)
147 self.field = str(number)
149 self["channel"] = Label(_("Channel:"))
151 self["number"] = Label(self.field)
153 self["actions"] = NumberActionMap( [ "SetupActions" ],
157 "1": self.keyNumberGlobal,
158 "2": self.keyNumberGlobal,
159 "3": self.keyNumberGlobal,
160 "4": self.keyNumberGlobal,
161 "5": self.keyNumberGlobal,
162 "6": self.keyNumberGlobal,
163 "7": self.keyNumberGlobal,
164 "8": self.keyNumberGlobal,
165 "9": self.keyNumberGlobal,
166 "0": self.keyNumberGlobal
169 self.Timer = eTimer()
170 self.Timer.timeout.get().append(self.keyOK)
171 self.Timer.start(3000, True)
173 class InfoBarNumberZap:
174 """ Handles an initial number for NumberZapping """
176 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
178 "1": self.keyNumberGlobal,
179 "2": self.keyNumberGlobal,
180 "3": self.keyNumberGlobal,
181 "4": self.keyNumberGlobal,
182 "5": self.keyNumberGlobal,
183 "6": self.keyNumberGlobal,
184 "7": self.keyNumberGlobal,
185 "8": self.keyNumberGlobal,
186 "9": self.keyNumberGlobal,
187 "0": self.keyNumberGlobal,
190 def keyNumberGlobal(self, number):
191 # print "You pressed number " + str(number)
193 self.servicelist.recallPrevService()
194 if config.usage.show_infobar_on_zap.value:
197 self.session.openWithCallback(self.numberEntered, NumberZap, number)
199 def numberEntered(self, retval):
200 # print self.servicelist
202 self.zapToNumber(retval)
204 def searchNumberHelper(self, serviceHandler, num, bouquet):
205 servicelist = serviceHandler.list(bouquet)
206 if not servicelist is None:
208 serviceIterator = servicelist.getNext()
209 if not serviceIterator.valid(): #check end of list
211 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
214 if not num: #found service with searched number ?
215 return serviceIterator, 0
218 def zapToNumber(self, number):
219 bouquet = self.servicelist.bouquet_root
221 serviceHandler = eServiceCenter.getInstance()
222 if not config.usage.multibouquet.value:
223 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
225 bouquetlist = serviceHandler.list(bouquet)
226 if not bouquetlist is None:
228 bouquet = bouquetlist.getNext()
229 if not bouquet.valid(): #check end of list
231 if bouquet.flags & eServiceReference.isDirectory:
232 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
233 if not service is None:
234 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
235 self.servicelist.clearPath()
236 if self.servicelist.bouquet_root != bouquet:
237 self.servicelist.enterPath(self.servicelist.bouquet_root)
238 self.servicelist.enterPath(bouquet)
239 self.servicelist.setCurrentSelection(service) #select the service in servicelist
240 self.servicelist.zap()
242 config.misc.initialchannelselection = ConfigBoolean(default = True)
244 class InfoBarChannelSelection:
245 """ ChannelSelection - handles the channelSelection dialog and the initial
246 channelChange actions which open the channelSelection dialog """
249 self.servicelist = self.session.instantiateDialog(ChannelSelection)
251 if config.misc.initialchannelselection.value:
252 self.onShown.append(self.firstRun)
254 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
256 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
257 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
258 "zapUp": (self.zapUp, _("previous channel")),
259 "zapDown": (self.zapDown, _("next channel")),
260 "historyBack": (self.historyBack, _("previous channel in history")),
261 "historyNext": (self.historyNext, _("next channel in history")),
262 "openServiceList": (self.openServiceList, _("open servicelist")),
265 def showTvChannelList(self, zap=False):
266 self.servicelist.setModeTv()
268 self.servicelist.zap()
269 self.session.execDialog(self.servicelist)
271 def showRadioChannelList(self, zap=False):
272 self.servicelist.setModeRadio()
274 self.servicelist.zap()
275 self.session.execDialog(self.servicelist)
278 self.onShown.remove(self.firstRun)
279 config.misc.initialchannelselection.value = False
280 config.misc.initialchannelselection.save()
281 self.switchChannelDown()
283 def historyBack(self):
284 self.servicelist.historyBack()
286 def historyNext(self):
287 self.servicelist.historyNext()
289 def switchChannelUp(self):
290 self.servicelist.moveUp()
291 self.session.execDialog(self.servicelist)
293 def switchChannelDown(self):
294 self.servicelist.moveDown()
295 self.session.execDialog(self.servicelist)
297 def openServiceList(self):
298 self.session.execDialog(self.servicelist)
301 if self.servicelist.inBouquet():
302 prev = self.servicelist.getCurrentSelection()
304 prev = prev.toString()
306 if config.usage.quickzap_bouquet_change.value:
307 if self.servicelist.atBegin():
308 self.servicelist.prevBouquet()
309 self.servicelist.moveUp()
310 cur = self.servicelist.getCurrentSelection()
311 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
314 self.servicelist.moveUp()
315 self.servicelist.zap()
316 if config.usage.show_infobar_on_zap.value:
320 if self.servicelist.inBouquet():
321 prev = self.servicelist.getCurrentSelection()
323 prev = prev.toString()
325 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
326 self.servicelist.nextBouquet()
328 self.servicelist.moveDown()
329 cur = self.servicelist.getCurrentSelection()
330 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
333 self.servicelist.moveDown()
334 self.servicelist.zap()
335 if config.usage.show_infobar_on_zap.value:
339 """ Handles a menu action, to open the (main) menu """
341 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
343 "mainMenu": (self.mainMenu, _("Enter main menu...")),
345 self.session.infobar = None
348 print "loading mainmenu XML..."
349 menu = mdom.childNodes[0]
350 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
352 self.session.infobar = self
353 # so we can access the currently active infobar from screens opened from within the mainmenu
354 # at the moment used from the SubserviceSelection
356 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
358 def mainMenuClosed(self, *val):
359 self.session.infobar = None
361 class InfoBarSimpleEventView:
362 """ Opens the Eventview for now/next """
364 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
366 "showEventInfo": (self.openEventView, _("show event details")),
369 def openEventView(self):
371 service = self.session.nav.getCurrentService()
372 ref = self.session.nav.getCurrentlyPlayingServiceReference()
373 info = service.info()
376 self.epglist.append(ptr)
379 self.epglist.append(ptr)
380 if len(self.epglist) > 0:
381 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
383 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
384 if len(self.epglist) > 1:
385 tmp = self.epglist[0]
386 self.epglist[0]=self.epglist[1]
388 setEvent(self.epglist[0])
391 """ EPG - Opens an EPG list when the showEPGList action fires """
393 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
395 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
398 self.is_now_next = False
400 self.bouquetSel = None
401 self.eventView = None
402 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
404 "showEventInfo": (self.openEventView, _("show EPG...")),
407 def zapToService(self, service):
408 if not service is None:
409 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
410 self.servicelist.clearPath()
411 if self.servicelist.bouquet_root != self.epg_bouquet:
412 self.servicelist.enterPath(self.servicelist.bouquet_root)
413 self.servicelist.enterPath(self.epg_bouquet)
414 self.servicelist.setCurrentSelection(service) #select the service in servicelist
415 self.servicelist.zap()
417 def getBouquetServices(self, bouquet):
419 servicelist = eServiceCenter.getInstance().list(bouquet)
420 if not servicelist is None:
422 service = servicelist.getNext()
423 if not service.valid(): #check if end of list
425 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
427 services.append(ServiceReference(service))
430 def openBouquetEPG(self, bouquet, withCallback=True):
431 services = self.getBouquetServices(bouquet)
433 self.epg_bouquet = bouquet
435 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
437 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
439 def changeBouquetCB(self, direction, epg):
442 self.bouquetSel.down()
445 bouquet = self.bouquetSel.getCurrent()
446 services = self.getBouquetServices(bouquet)
448 self.epg_bouquet = bouquet
449 epg.setServices(services)
451 def closed(self, ret=False):
452 closedScreen = self.dlg_stack.pop()
453 if self.bouquetSel and closedScreen == self.bouquetSel:
454 self.bouquetSel = None
455 elif self.eventView and closedScreen == self.eventView:
456 self.eventView = None
458 dlgs=len(self.dlg_stack)
460 self.dlg_stack[dlgs-1].close(dlgs > 1)
462 def openMultiServiceEPG(self, withCallback=True):
463 bouquets = self.servicelist.getBouquetList()
468 if cnt > 1: # show bouquet list
470 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
471 self.dlg_stack.append(self.bouquetSel)
473 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
475 self.openBouquetEPG(bouquets[0][1], withCallback)
477 def openSingleServiceEPG(self):
478 ref=self.session.nav.getCurrentlyPlayingServiceReference()
479 self.session.open(EPGSelection, ref)
481 def openSimilarList(self, eventid, refstr):
482 self.session.open(EPGSelection, refstr, None, eventid)
484 def getNowNext(self):
486 service = self.session.nav.getCurrentService()
487 info = service and service.info()
488 ptr = info and info.getEvent(0)
490 self.epglist.append(ptr)
491 ptr = info and info.getEvent(1)
493 self.epglist.append(ptr)
495 def __evEventInfoChanged(self):
496 if self.is_now_next and len(self.dlg_stack) == 1:
498 assert self.eventView
499 if len(self.epglist):
500 self.eventView.setEvent(self.epglist[0])
502 def openEventView(self):
503 ref = self.session.nav.getCurrentlyPlayingServiceReference()
505 if len(self.epglist) == 0:
506 self.is_now_next = False
507 epg = eEPGCache.getInstance()
508 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
510 self.epglist.append(ptr)
511 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
513 self.epglist.append(ptr)
515 self.is_now_next = True
516 if len(self.epglist) > 0:
517 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
518 self.dlg_stack.append(self.eventView)
520 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
521 self.openMultiServiceEPG(False)
523 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
524 if len(self.epglist) > 1:
525 tmp = self.epglist[0]
526 self.epglist[0]=self.epglist[1]
528 setEvent(self.epglist[0])
531 """provides a snr/agc/ber display"""
533 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
536 """provides a current/next event info display"""
538 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
539 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
541 class InfoBarRadioText:
542 """provides radio (RDS) text info display"""
544 self["RadioText"] = RadioText(self.session.nav)
546 class InfoBarServiceName:
548 self["CurrentService"] = CurrentService(self.session.nav)
551 """handles actions like seeking, pause"""
553 # ispause, isff, issm
554 SEEK_STATE_PLAY = (0, 0, 0, ">")
555 SEEK_STATE_PAUSE = (1, 0, 0, "||")
556 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
557 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
558 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
559 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
560 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
561 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
563 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
564 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
565 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
566 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
568 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
569 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
570 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
573 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
575 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
576 iPlayableService.evStart: self.__serviceStarted,
578 iPlayableService.evEOF: self.__evEOF,
579 iPlayableService.evSOF: self.__evSOF,
582 class InfoBarSeekActionMap(HelpableActionMap):
583 def __init__(self, screen, *args, **kwargs):
584 HelpableActionMap.__init__(self, screen, *args, **kwargs)
587 def action(self, contexts, action):
588 if action[:5] == "seek:":
589 time = int(action[5:])
590 self.screen.seekRelative(time * 90000)
593 return HelpableActionMap.action(self, contexts, action)
595 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
597 "playpauseService": (self.playpauseService, _("pause")),
598 "pauseService": (self.pauseService, _("pause")),
599 "unPauseService": (self.unPauseService, _("continue")),
601 "seekFwd": (self.seekFwd, _("skip forward")),
602 "seekFwdDown": self.seekFwdDown,
603 "seekFwdUp": self.seekFwdUp,
604 "seekBack": (self.seekBack, _("skip backward")),
605 "seekBackDown": self.seekBackDown,
606 "seekBackUp": self.seekBackUp,
608 # give them a little more priority to win over color buttons
610 self["SeekActions"].setEnabled(False)
612 self.seekstate = self.SEEK_STATE_PLAY
613 self.onClose.append(self.delTimer)
615 self.fwdtimer = False
616 self.fwdKeyTimer = eTimer()
617 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
619 self.rwdtimer = False
620 self.rwdKeyTimer = eTimer()
621 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
623 self.onPlayStateChanged = [ ]
625 self.lockedBecauseOfSkipping = False
638 service = self.session.nav.getCurrentService()
642 seek = service.seek()
644 if seek is None or not seek.isCurrentlySeekable():
649 def isSeekable(self):
650 if self.getSeek() is None:
654 def __seekableStatusChanged(self):
655 print "seekable status changed!"
656 if not self.isSeekable():
657 self["SeekActions"].setEnabled(False)
658 print "not seekable, return to play"
659 self.setSeekState(self.SEEK_STATE_PLAY)
661 self["SeekActions"].setEnabled(True)
664 def __serviceStarted(self):
665 self.seekstate = self.SEEK_STATE_PLAY
667 def setSeekState(self, state):
668 service = self.session.nav.getCurrentService()
673 if not self.isSeekable():
674 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
675 state = self.SEEK_STATE_PLAY
677 pauseable = service.pause()
679 if pauseable is None:
680 print "not pauseable."
681 state = self.SEEK_STATE_PLAY
683 oldstate = self.seekstate
684 self.seekstate = state
687 if oldstate[i] != self.seekstate[i]:
688 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
690 for c in self.onPlayStateChanged:
693 self.checkSkipShowHideLock()
697 def playpauseService(self):
698 if self.seekstate != self.SEEK_STATE_PLAY:
699 self.unPauseService()
703 def pauseService(self):
704 if self.seekstate == self.SEEK_STATE_PAUSE:
705 print "pause, but in fact unpause"
706 self.unPauseService()
708 if self.seekstate == self.SEEK_STATE_PLAY:
709 print "yes, playing."
711 print "no", self.seekstate
713 self.setSeekState(self.SEEK_STATE_PAUSE);
715 def unPauseService(self):
717 if self.seekstate == self.SEEK_STATE_PLAY:
719 self.setSeekState(self.SEEK_STATE_PLAY)
721 def doSeek(self, seektime):
722 print "doseek", seektime
723 service = self.session.nav.getCurrentService()
727 seekable = self.getSeek()
731 seekable.seekTo(90 * seektime)
733 def seekFwdDown(self):
734 print "start fwd timer"
736 self.fwdKeyTimer.start(1000)
738 def seekBackDown(self):
739 print "start rewind timer"
741 self.rwdKeyTimer.start(1000)
746 self.fwdKeyTimer.stop()
747 self.fwdtimer = False
752 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
753 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
754 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
755 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
756 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
757 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
758 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
759 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
760 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
761 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
762 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
763 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
764 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
765 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
766 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
768 self.setSeekState(lookup[self.seekstate])
770 def seekBackUp(self):
773 self.rwdKeyTimer.stop()
774 self.rwdtimer = False
779 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
780 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
781 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
782 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
783 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
784 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
785 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
786 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
787 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
788 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
789 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
790 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
791 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
792 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
793 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
795 self.setSeekState(lookup[self.seekstate])
797 if self.seekstate == self.SEEK_STATE_PAUSE:
798 seekable = self.getSeek()
799 if seekable is not None:
800 seekable.seekRelative(-1, 3)
802 def fwdTimerFire(self):
803 print "Display seek fwd"
804 self.fwdKeyTimer.stop()
805 self.fwdtimer = False
806 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
808 def fwdSeekTo(self, minutes):
809 print "Seek", minutes, "minutes forward"
811 seekable = self.getSeek()
812 if seekable is not None:
813 seekable.seekRelative(1, minutes * 60 * 90000)
815 def rwdTimerFire(self):
817 self.rwdKeyTimer.stop()
818 self.rwdtimer = False
819 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
821 def rwdSeekTo(self, minutes):
823 self.fwdSeekTo(0 - minutes)
825 def checkSkipShowHideLock(self):
826 wantlock = self.seekstate != self.SEEK_STATE_PLAY
828 if config.usage.show_infobar_on_zap.value:
829 if self.lockedBecauseOfSkipping and not wantlock:
831 self.lockedBecauseOfSkipping = False
833 if wantlock and not self.lockedBecauseOfSkipping:
835 self.lockedBecauseOfSkipping = True
838 if self.seekstate != self.SEEK_STATE_PLAY:
839 self.setSeekState(self.SEEK_STATE_PAUSE)
841 #self.getSeek().seekRelative(1, -90000)
842 self.setSeekState(self.SEEK_STATE_PLAY)
844 self.setSeekState(self.SEEK_STATE_PAUSE)
847 self.setSeekState(self.SEEK_STATE_PLAY)
850 def seekRelative(self, diff):
851 seekable = self.getSeek()
852 if seekable is not None:
853 seekable.seekRelative(1, diff)
855 def seekAbsolute(self, abs):
856 seekable = self.getSeek()
857 if seekable is not None:
860 from Screens.PVRState import PVRState, TimeshiftState
862 class InfoBarPVRState:
863 def __init__(self, screen=PVRState):
864 self.onPlayStateChanged.append(self.__playStateChanged)
865 self.pvrStateDialog = self.session.instantiateDialog(screen)
866 self.onShow.append(self._mayShow)
867 self.onHide.append(self.pvrStateDialog.hide)
870 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
871 self.pvrStateDialog.show()
873 def __playStateChanged(self, state):
874 playstateString = state[3]
875 self.pvrStateDialog["state"].setText(playstateString)
878 class InfoBarTimeshiftState(InfoBarPVRState):
880 InfoBarPVRState.__init__(self, screen=TimeshiftState)
883 if self.execing and self.timeshift_enabled:
884 self.pvrStateDialog.show()
886 class InfoBarShowMovies:
888 # i don't really like this class.
889 # it calls a not further specified "movie list" on up/down/movieList,
890 # so this is not more than an action map
892 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
894 "movieList": (self.showMovies, "movie list"),
895 "up": (self.showMovies, "movie list"),
896 "down": (self.showMovies, "movie list")
899 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
903 # Timeshift works the following way:
904 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
905 # - normal playback TUNER unused PLAY enable disable disable
906 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
907 # - user presess pause again FILE record PLAY enable disable enable
908 # - user fast forwards FILE record FF enable disable enable
909 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
910 # - user backwards FILE record BACK # !! enable disable enable
914 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
915 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
916 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
917 # - the user can now PVR around
918 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
919 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
921 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
922 # - if the user rewinds, or press pause, timeshift will be activated again
924 # note that a timeshift can be enabled ("recording") and
925 # activated (currently time-shifting).
927 class InfoBarTimeshift:
929 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
931 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
932 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
934 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
936 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
937 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
938 }, prio=-1) # priority over record
940 self.timeshift_enabled = 0
941 self.timeshift_state = 0
942 self.ts_pause_timer = eTimer()
943 self.ts_pause_timer.timeout.get().append(self.pauseService)
945 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
947 iPlayableService.evStart: self.__serviceStarted,
948 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
951 def getTimeshift(self):
952 service = self.session.nav.getCurrentService()
953 return service and service.timeshift()
955 def startTimeshift(self):
956 print "enable timeshift"
957 ts = self.getTimeshift()
959 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
960 print "no ts interface"
963 if self.timeshift_enabled:
964 print "hu, timeshift already enabled?"
966 if not ts.startTimeshift():
967 self.timeshift_enabled = 1
969 # we remove the "relative time" for now.
970 #self.pvrStateDialog["timeshift"].setRelative(time.time())
973 self.setSeekState(self.SEEK_STATE_PAUSE)
975 # enable the "TimeshiftEnableActions", which will override
976 # the startTimeshift actions
977 self.__seekableStatusChanged()
979 print "timeshift failed"
981 def stopTimeshift(self):
982 if not self.timeshift_enabled:
984 print "disable timeshift"
985 ts = self.getTimeshift()
988 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
990 def stopTimeshiftConfirmed(self, confirmed):
994 ts = self.getTimeshift()
999 self.timeshift_enabled = 0
1002 self.__seekableStatusChanged()
1004 # activates timeshift, and seeks to (almost) the end
1005 def activateTimeshiftEnd(self):
1006 ts = self.getTimeshift()
1011 if ts.isTimeshiftActive():
1012 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1015 self.setSeekState(self.SEEK_STATE_PLAY)
1016 ts.activateTimeshift()
1017 self.seekRelative(0)
1019 # same as activateTimeshiftEnd, but pauses afterwards.
1020 def activateTimeshiftEndAndPause(self):
1021 state = self.seekstate
1022 self.activateTimeshiftEnd()
1024 # well, this is "andPause", but it could be pressed from pause,
1025 # when pausing on the (fake-)"live" picture, so an un-pause
1028 print "now, pauseService"
1029 if state == self.SEEK_STATE_PLAY:
1030 print "is PLAYING, start pause timer"
1031 self.ts_pause_timer.start(200, 1)
1034 self.unPauseService()
1036 def __seekableStatusChanged(self):
1039 print "self.isSeekable", self.isSeekable()
1040 print "self.timeshift_enabled", self.timeshift_enabled
1042 # when this service is not seekable, but timeshift
1043 # is enabled, this means we can activate
1045 if not self.isSeekable() and self.timeshift_enabled:
1048 print "timeshift activate:", enabled
1049 self["TimeshiftActivateActions"].setEnabled(enabled)
1051 def __serviceStarted(self):
1052 self.timeshift_enabled = False
1053 self.__seekableStatusChanged()
1055 from Screens.PiPSetup import PiPSetup
1057 class InfoBarExtensions:
1058 EXTENSION_SINGLE = 0
1064 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1066 "extensions": (self.showExtensionSelection, _("view extensions...")),
1069 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1070 self.list.append((type, extension, key))
1072 def updateExtension(self, extension, key = None):
1073 self.extensionsList.append(extension)
1075 if self.extensionKeys.has_key(key):
1079 for x in self.availableKeys:
1080 if not self.extensionKeys.has_key(x):
1085 self.extensionKeys[key] = len(self.extensionsList) - 1
1087 def updateExtensions(self):
1088 self.extensionsList = []
1089 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1090 self.extensionKeys = {}
1092 if x[0] == self.EXTENSION_SINGLE:
1093 self.updateExtension(x[1], x[2])
1096 self.updateExtension(y[0], y[1])
1099 def showExtensionSelection(self):
1100 self.updateExtensions()
1101 extensionsList = self.extensionsList[:]
1104 for x in self.availableKeys:
1105 if self.extensionKeys.has_key(x):
1106 entry = self.extensionKeys[x]
1107 extension = self.extensionsList[entry]
1109 name = str(extension[0]())
1110 list.append((extension[0](), extension))
1112 extensionsList.remove(extension)
1114 extensionsList.remove(extension)
1115 for x in extensionsList:
1116 list.append((x[0](), x))
1117 keys += [""] * len(extensionsList)
1118 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1120 def extensionCallback(self, answer):
1121 if answer is not None:
1124 from Tools.BoundFunction import boundFunction
1126 # depends on InfoBarExtensions
1127 from Components.PluginComponent import plugins
1129 class InfoBarPlugins:
1131 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1133 def getPluginName(self, name):
1136 def getPluginList(self):
1138 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1139 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1142 def runPlugin(self, plugin):
1143 plugin(session = self.session)
1145 # depends on InfoBarExtensions
1146 class InfoBarSleepTimer:
1148 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1150 def available(self):
1153 def getSleepTimerName(self):
1154 return _("Sleep Timer")
1156 def showSleepTimerSetup(self):
1157 self.session.open(SleepTimerEdit)
1159 # depends on InfoBarExtensions
1162 self.session.pipshown = False
1164 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1165 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1166 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1168 def available(self):
1172 return self.session.pipshown
1174 def getShowHideName(self):
1175 if self.session.pipshown:
1176 return _("Disable Picture in Picture")
1178 return _("Activate Picture in Picture")
1180 def getSwapName(self):
1181 return _("Swap Services")
1183 def getMoveName(self):
1184 return _("Move Picture in Picture")
1187 if self.session.pipshown:
1188 del self.session.pip
1189 self.session.pipshown = False
1191 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1192 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1193 if self.session.pip.playService(newservice):
1194 self.session.pipshown = True
1195 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1197 self.session.pipshown = False
1198 del self.session.pip
1199 self.session.nav.playService(newservice)
1202 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1203 if self.session.pip.servicePath:
1204 servicepath = self.servicelist.getCurrentServicePath()
1205 ref=servicepath[len(servicepath)-1]
1206 pipref=self.session.pip.getCurrentService()
1207 self.session.pip.playService(swapservice)
1208 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1209 if pipref.toString() != ref.toString(): # is a subservice ?
1210 self.session.nav.stopService() # stop portal
1211 self.session.nav.playService(pipref) # start subservice
1212 self.session.pip.servicePath=servicepath
1215 self.session.open(PiPSetup, pip = self.session.pip)
1217 from RecordTimer import parseEvent
1219 class InfoBarInstantRecord:
1220 """Instant Record - handles the instantRecord action in order to
1221 start/stop instant records"""
1223 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1225 "instantRecord": (self.instantRecord, _("Instant Record...")),
1228 self["BlinkingPoint"] = BlinkingPixmapConditional()
1229 self["BlinkingPoint"].hide()
1230 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1232 def stopCurrentRecording(self, entry = -1):
1233 if entry is not None and entry != -1:
1234 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1235 self.recording.remove(self.recording[entry])
1237 def startInstantRecording(self, limitEvent = False):
1238 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1240 # try to get event info
1243 service = self.session.nav.getCurrentService()
1244 epg = eEPGCache.getInstance()
1245 event = epg.lookupEventTime(serviceref, -1, 0)
1247 info = service.info()
1248 ev = info.getEvent(0)
1254 end = time() + 3600 * 10
1255 name = "instant record"
1259 if event is not None:
1260 curEvent = parseEvent(event)
1262 description = curEvent[3]
1263 eventid = curEvent[4]
1268 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1270 data = (begin, end, name, description, eventid)
1272 recording = self.session.nav.recordWithTimer(serviceref, *data)
1273 recording.dontSave = True
1274 self.recording.append(recording)
1276 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1278 def isInstantRecordRunning(self):
1279 print "self.recording:", self.recording
1280 if len(self.recording) > 0:
1281 for x in self.recording:
1286 def recordQuestionCallback(self, answer):
1287 print "pre:\n", self.recording
1289 if answer is None or answer[1] == "no":
1292 recording = self.recording[:]
1294 if not x in self.session.nav.RecordTimer.timer_list:
1295 self.recording.remove(x)
1296 elif x.dontSave and x.isRunning():
1297 list.append(TimerEntryComponent(x, False))
1299 if answer[1] == "changeduration":
1300 if len(self.recording) == 1:
1301 self.changeDuration(0)
1303 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1304 elif answer[1] == "stop":
1305 if len(self.recording) == 1:
1306 self.stopCurrentRecording(0)
1308 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1309 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1311 if answer[1] == "event":
1313 if answer[1] == "manualduration":
1314 self.selectedEntry = len(self.recording)
1315 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1316 self.startInstantRecording(limitEvent = limitEvent)
1318 print "after:\n", self.recording
1320 def changeDuration(self, entry):
1321 if entry is not None:
1322 self.selectedEntry = entry
1323 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1325 def inputCallback(self, value):
1326 if value is not None:
1327 print "stopping recording after", int(value), "minutes."
1328 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1329 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1331 def instantRecord(self):
1333 stat = os_stat(resolveFilename(SCOPE_HDD))
1335 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1338 if self.isInstantRecordRunning():
1339 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1340 title=_("A recording is currently running.\nWhat do you want to do?"), \
1341 list=[(_("stop recording"), "stop"), \
1342 (_("change recording (duration)"), "changeduration"), \
1343 (_("add recording (indefinitely)"), "indefinitely"), \
1344 (_("add recording (stop after current event)"), "event"), \
1345 (_("add recording (enter recording duration)"), "manualduration"), \
1346 (_("do nothing"), "no")])
1348 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1349 title=_("Start recording?"), \
1350 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1351 (_("add recording (stop after current event)"), "event"), \
1352 (_("add recording (enter recording duration)"), "manualduration"), \
1353 (_("don't record"), "no")])
1355 from Tools.ISO639 import LanguageCodes
1357 class InfoBarAudioSelection:
1359 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1361 "audioSelection": (self.audioSelection, _("Audio Options...")),
1364 def audioSelection(self):
1365 service = self.session.nav.getCurrentService()
1366 audio = service and service.audioTracks()
1367 self.audioTracks = audio
1368 n = audio and audio.getNumberOfTracks() or 0
1369 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1371 print "tlist:", tlist
1373 self.audioChannel = service.audioChannel()
1376 i = audio.getTrackInfo(x)
1377 language = i.getLanguage()
1378 description = i.getDescription()
1380 if LanguageCodes.has_key(language):
1381 language = LanguageCodes[language][0]
1383 if len(description):
1384 description += " (" + language + ")"
1386 description = language
1388 tlist.append((description, x))
1390 selectedAudio = tlist[0][1]
1391 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1395 if x[1] != selectedAudio:
1400 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1401 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1403 del self.audioTracks
1405 def audioSelected(self, audio):
1406 if audio is not None:
1407 if isinstance(audio[1], str):
1408 if audio[1] == "mode":
1409 keys = ["red", "green", "yellow"]
1410 selection = self.audioChannel.getCurrentChannel()
1411 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1412 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1414 del self.audioChannel
1415 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1416 self.audioTracks.selectTrack(audio[1])
1418 del self.audioChannel
1419 del self.audioTracks
1421 def modeSelected(self, mode):
1422 if mode is not None:
1423 self.audioChannel.selectChannel(mode[1])
1424 del self.audioChannel
1426 class InfoBarSubserviceSelection:
1428 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1430 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1433 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1435 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1436 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1438 self["SubserviceQuickzapAction"].setEnabled(False)
1440 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1444 def checkSubservicesAvail(self, ev):
1445 if ev == iPlayableService.evUpdatedEventInfo:
1446 service = self.session.nav.getCurrentService()
1447 subservices = service and service.subServices()
1448 if not subservices or subservices.getNumberOfSubservices() == 0:
1449 self["SubserviceQuickzapAction"].setEnabled(False)
1451 def nextSubservice(self):
1452 self.changeSubservice(+1)
1454 def prevSubservice(self):
1455 self.changeSubservice(-1)
1457 def changeSubservice(self, direction):
1458 service = self.session.nav.getCurrentService()
1459 subservices = service and service.subServices()
1460 n = subservices and subservices.getNumberOfSubservices()
1463 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1465 if subservices.getSubservice(x).toString() == ref.toString():
1468 selection += direction
1473 newservice = subservices.getSubservice(selection)
1474 if newservice.valid():
1477 if config.usage.show_infobar_on_zap.value:
1479 self.session.nav.playService(newservice)
1481 def subserviceSelection(self):
1482 service = self.session.nav.getCurrentService()
1483 subservices = service and service.subServices()
1484 self.bouquets = self.servicelist.getBouquetList()
1485 n = subservices and subservices.getNumberOfSubservices()
1488 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1491 i = subservices.getSubservice(x)
1492 if i.toString() == ref.toString():
1494 tlist.append((i.getName(), i))
1496 if self.bouquets and len(self.bouquets):
1497 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1498 if config.usage.multibouquet.value:
1499 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1501 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1504 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1505 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1508 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1510 def subserviceSelected(self, service):
1512 if not service is None:
1513 if isinstance(service[1], str):
1514 if service[1] == "quickzap":
1515 from Screens.SubservicesQuickzap import SubservicesQuickzap
1516 self.session.open(SubservicesQuickzap, service[2])
1518 self["SubserviceQuickzapAction"].setEnabled(True)
1519 if config.usage.show_infobar_on_zap.value:
1521 self.session.nav.playService(service[1])
1523 def addSubserviceToBouquetCallback(self, service):
1524 if len(service) > 1 and isinstance(service[1], eServiceReference):
1525 self.selectedSubservice = service
1526 if self.bouquets is None:
1529 cnt = len(self.bouquets)
1530 if cnt > 1: # show bouquet list
1531 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1532 elif cnt == 1: # add to only one existing bouquet
1533 self.addSubserviceToBouquet(self.bouquets[0][1])
1534 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1536 def bouquetSelClosed(self, confirmed):
1538 del self.selectedSubservice
1540 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1542 def addSubserviceToBouquet(self, dest):
1543 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1545 self.bsel.close(True)
1547 del self.selectedSubservice
1549 class InfoBarAdditionalInfo:
1551 self["NimA"] = Pixmap()
1552 self["NimB"] = Pixmap()
1553 self["NimA_Active"] = Pixmap()
1554 self["NimB_Active"] = Pixmap()
1556 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1557 self["TimeshiftPossible"] = self["RecordingPossible"]
1558 self["ExtensionsAvailable"] = Boolean(fixed=1)
1560 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1561 res_mgr = eDVBResourceManager.getInstance()
1563 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1565 def tunerUseMaskChanged(self, mask):
1567 self["NimA_Active"].show()
1569 self["NimA_Active"].hide()
1571 self["NimB_Active"].show()
1573 self["NimB_Active"].hide()
1575 def checkTunerState(self, service):
1576 info = service and service.frontendInfo()
1577 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1578 if feNumber is None:
1588 def gotServiceEvent(self, ev):
1589 service = self.session.nav.getCurrentService()
1590 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1591 self.checkTunerState(service)
1593 class InfoBarNotifications:
1595 self.onExecBegin.append(self.checkNotifications)
1596 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1597 self.onClose.append(self.__removeNotification)
1599 def __removeNotification(self):
1600 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1602 def checkNotificationsIfExecing(self):
1604 self.checkNotifications()
1606 def checkNotifications(self):
1607 if len(Notifications.notifications):
1608 n = Notifications.notifications[0]
1610 Notifications.notifications = Notifications.notifications[1:]
1613 if n[3].has_key("onSessionOpenCallback"):
1614 n[3]["onSessionOpenCallback"]()
1615 del n[3]["onSessionOpenCallback"]
1618 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1620 dlg = self.session.open(n[1], *n[2], **n[3])
1622 # remember that this notification is currently active
1624 Notifications.current_notifications.append(d)
1625 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1627 def __notificationClosed(self, d):
1628 Notifications.current_notifications.remove(d)
1630 class InfoBarServiceNotifications:
1632 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1634 iPlayableService.evEnd: self.serviceHasEnded
1637 def serviceHasEnded(self):
1638 print "service end!"
1641 self.setSeekState(self.SEEK_STATE_PLAY)
1645 class InfoBarCueSheetSupport:
1651 ENABLE_RESUME_SUPPORT = False
1654 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1656 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1657 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1658 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1662 self.is_closing = False
1663 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1665 iPlayableService.evStart: self.__serviceStarted,
1668 def __serviceStarted(self):
1671 print "new service started! trying to download cuts!"
1672 self.downloadCuesheet()
1674 if self.ENABLE_RESUME_SUPPORT:
1677 for (pts, what) in self.cut_list:
1678 if what == self.CUT_TYPE_LAST:
1681 if last is not None:
1682 self.resume_point = last
1683 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1685 def playLastCB(self, answer):
1687 seekable = self.__getSeekable()
1688 if seekable is not None:
1689 seekable.seekTo(self.resume_point)
1691 def __getSeekable(self):
1692 service = self.session.nav.getCurrentService()
1695 return service.seek()
1697 def cueGetCurrentPosition(self):
1698 seek = self.__getSeekable()
1701 r = seek.getPlayPosition()
1706 def jumpPreviousNextMark(self, cmp, alternative=None):
1707 current_pos = self.cueGetCurrentPosition()
1708 if current_pos is None:
1710 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1711 if mark is not None:
1713 elif alternative is not None:
1718 seekable = self.__getSeekable()
1719 if seekable is not None:
1720 seekable.seekTo(pts)
1722 def jumpPreviousMark(self):
1723 # we add 2 seconds, so if the play position is <2s after
1724 # the mark, the mark before will be used
1725 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1727 def jumpNextMark(self):
1728 self.jumpPreviousNextMark(lambda x: x)
1730 def getNearestCutPoint(self, pts, cmp=abs):
1733 for cp in self.cut_list:
1734 diff = cmp(cp[0] - pts)
1735 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1739 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1740 current_pos = self.cueGetCurrentPosition()
1741 if current_pos is None:
1742 print "not seekable"
1745 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1747 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1749 return nearest_cutpoint
1751 self.removeMark(nearest_cutpoint)
1752 elif not onlyremove and not onlyreturn:
1753 self.addMark((current_pos, self.CUT_TYPE_MARK))
1758 def addMark(self, point):
1759 insort(self.cut_list, point)
1760 self.uploadCuesheet()
1762 def removeMark(self, point):
1763 self.cut_list.remove(point)
1764 self.uploadCuesheet()
1766 def __getCuesheet(self):
1767 service = self.session.nav.getCurrentService()
1770 return service.cueSheet()
1772 def uploadCuesheet(self):
1773 cue = self.__getCuesheet()
1776 print "upload failed, no cuesheet interface"
1778 cue.setCutList(self.cut_list)
1780 def downloadCuesheet(self):
1781 cue = self.__getCuesheet()
1784 print "upload failed, no cuesheet interface"
1786 self.cut_list = cue.getCutList()
1788 class InfoBarSummary(Screen):
1790 <screen position="0,0" size="132,64">
1791 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1792 <convert type="ClockToText">WithSeconds</convert>
1794 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1795 <convert type="ServiceName">Name</convert>
1799 def __init__(self, session, parent):
1800 Screen.__init__(self, session)
1801 self["CurrentService"] = CurrentService(self.session.nav)
1802 self["CurrentTime"] = Clock()
1804 class InfoBarSummarySupport:
1808 def createSummary(self):
1809 return InfoBarSummary
1811 class InfoBarTeletextPlugin:
1813 self.teletext_plugin = None
1815 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1816 self.teletext_plugin = p
1818 if self.teletext_plugin is not None:
1819 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1821 "startTeletext": (self.startTeletext, _("View teletext..."))
1824 print "no teletext plugin found!"
1826 def startTeletext(self):
1827 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1829 class InfoBarSubtitleSupport(object):
1831 object.__init__(self)
1832 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1833 self.__subtitles_enabled = False
1835 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1837 iPlayableService.evEnd: self.__serviceStopped,
1838 iPlayableService.evUpdatedInfo: self.__updatedInfo
1840 self.cached_subtitle_checked = False
1842 def __serviceStopped(self):
1843 self.subtitle_window.hide()
1844 self.__subtitles_enabled = False
1845 self.cached_subtitle_checked = False
1847 def __updatedInfo(self):
1848 if not self.cached_subtitle_checked:
1849 subtitle = self.getCurrentServiceSubtitle()
1850 self.cached_subtitle_checked = True
1852 self.__selected_subtitle = subtitle.getCachedSubtitle()
1853 if self.__selected_subtitle:
1854 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1855 self.subtitle_window.show()
1856 self.__subtitles_enabled = True
1858 def getCurrentServiceSubtitle(self):
1859 service = self.session.nav.getCurrentService()
1860 return service and service.subtitle()
1862 def setSubtitlesEnable(self, enable=True):
1863 subtitle = self.getCurrentServiceSubtitle()
1864 if enable and self.__selected_subtitle is not None:
1865 if subtitle and not self.__subtitles_enabled:
1866 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1867 self.subtitle_window.show()
1868 self.__subtitles_enabled = True
1871 subtitle.disableSubtitles(self.subtitle_window.instance)
1872 self.__subtitles_enabled = False
1873 self.subtitle_window.hide()
1875 def setSelectedSubtitle(self, subtitle):
1876 self.__selected_subtitle = subtitle
1878 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1879 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1881 class InfoBarServiceErrorPopupSupport:
1883 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1885 iPlayableService.evTuneFailed: self.__tuneFailed,
1886 iPlayableService.evStart: self.__serviceStarted
1888 self.__serviceStarted()
1890 def __serviceStarted(self):
1891 self.last_error = None
1892 Notifications.RemovePopup(id = "ZapError")
1894 def __tuneFailed(self):
1895 service = self.session.nav.getCurrentService()
1896 info = service and service.info()
1897 error = info and info.getInfo(iServiceInformation.sDVBState)
1899 if error == self.last_error:
1902 self.last_error = error
1905 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1906 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1907 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1908 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1909 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1910 eDVBServicePMTHandler.eventNewProgramInfo: None,
1911 eDVBServicePMTHandler.eventTuned: None,
1912 eDVBServicePMTHandler.eventSOF: None,
1913 eDVBServicePMTHandler.eventEOF: None
1916 error = errors.get(error) #this returns None when the key not exist in the dict
1918 if error is not None:
1919 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1921 Notifications.RemovePopup(id = "ZapError")