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,
71 self.__state = self.STATE_SHOWN
74 self.onExecBegin.append(self.show)
76 self.hideTimer = eTimer()
77 self.hideTimer.timeout.get().append(self.doTimerHide)
78 self.hideTimer.start(5000, True)
80 self.onShow.append(self.__onShow)
81 self.onHide.append(self.__onHide)
84 self.__state = self.STATE_SHOWN
87 def startHideTimer(self):
88 if self.__state == self.STATE_SHOWN and not self.__locked:
89 idx = config.usage.infobar_timeout.index
91 self.hideTimer.start(idx*1000, True)
94 self.__state = self.STATE_HIDDEN
100 def doTimerHide(self):
101 self.hideTimer.stop()
102 if self.__state == self.STATE_SHOWN:
105 def toggleShow(self):
106 if self.__state == self.STATE_SHOWN:
108 self.hideTimer.stop()
109 elif self.__state == self.STATE_HIDDEN:
113 self.__locked = self.__locked + 1
116 self.hideTimer.stop()
118 def unlockShow(self):
119 self.__locked = self.__locked - 1
121 self.startHideTimer()
123 # def startShow(self):
124 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
125 # self.__state = self.STATE_SHOWN
127 # def startHide(self):
128 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
129 # self.__state = self.STATE_HIDDEN
131 class NumberZap(Screen):
138 self.close(int(self["number"].getText()))
140 def keyNumberGlobal(self, number):
141 self.Timer.start(3000, True) #reset timer
142 self.field = self.field + str(number)
143 self["number"].setText(self.field)
144 if len(self.field) >= 4:
147 def __init__(self, session, number):
148 Screen.__init__(self, session)
149 self.field = str(number)
151 self["channel"] = Label(_("Channel:"))
153 self["number"] = Label(self.field)
155 self["actions"] = NumberActionMap( [ "SetupActions" ],
159 "1": self.keyNumberGlobal,
160 "2": self.keyNumberGlobal,
161 "3": self.keyNumberGlobal,
162 "4": self.keyNumberGlobal,
163 "5": self.keyNumberGlobal,
164 "6": self.keyNumberGlobal,
165 "7": self.keyNumberGlobal,
166 "8": self.keyNumberGlobal,
167 "9": self.keyNumberGlobal,
168 "0": self.keyNumberGlobal
171 self.Timer = eTimer()
172 self.Timer.timeout.get().append(self.keyOK)
173 self.Timer.start(3000, True)
175 class InfoBarNumberZap:
176 """ Handles an initial number for NumberZapping """
178 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
180 "1": self.keyNumberGlobal,
181 "2": self.keyNumberGlobal,
182 "3": self.keyNumberGlobal,
183 "4": self.keyNumberGlobal,
184 "5": self.keyNumberGlobal,
185 "6": self.keyNumberGlobal,
186 "7": self.keyNumberGlobal,
187 "8": self.keyNumberGlobal,
188 "9": self.keyNumberGlobal,
189 "0": self.keyNumberGlobal,
192 def keyNumberGlobal(self, number):
193 # print "You pressed number " + str(number)
195 self.servicelist.recallPrevService()
196 if config.usage.show_infobar_on_zap.value:
199 self.session.openWithCallback(self.numberEntered, NumberZap, number)
201 def numberEntered(self, retval):
202 # print self.servicelist
204 self.zapToNumber(retval)
206 def searchNumberHelper(self, serviceHandler, num, bouquet):
207 servicelist = serviceHandler.list(bouquet)
208 if not servicelist is None:
210 serviceIterator = servicelist.getNext()
211 if not serviceIterator.valid(): #check end of list
213 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
216 if not num: #found service with searched number ?
217 return serviceIterator, 0
220 def zapToNumber(self, number):
221 bouquet = self.servicelist.bouquet_root
223 serviceHandler = eServiceCenter.getInstance()
224 if not config.usage.multibouquet.value:
225 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
227 bouquetlist = serviceHandler.list(bouquet)
228 if not bouquetlist is None:
230 bouquet = bouquetlist.getNext()
231 if not bouquet.valid(): #check end of list
233 if bouquet.flags & eServiceReference.isDirectory:
234 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
235 if not service is None:
236 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
237 self.servicelist.clearPath()
238 if self.servicelist.bouquet_root != bouquet:
239 self.servicelist.enterPath(self.servicelist.bouquet_root)
240 self.servicelist.enterPath(bouquet)
241 self.servicelist.setCurrentSelection(service) #select the service in servicelist
242 self.servicelist.zap()
244 config.misc.initialchannelselection = ConfigBoolean(default = True)
246 class InfoBarChannelSelection:
247 """ ChannelSelection - handles the channelSelection dialog and the initial
248 channelChange actions which open the channelSelection dialog """
251 self.servicelist = self.session.instantiateDialog(ChannelSelection)
253 if config.misc.initialchannelselection.value:
254 self.onShown.append(self.firstRun)
256 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
258 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
259 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
260 "zapUp": (self.zapUp, _("previous channel")),
261 "zapDown": (self.zapDown, _("next channel")),
262 "historyBack": (self.historyBack, _("previous channel in history")),
263 "historyNext": (self.historyNext, _("next channel in history")),
264 "openServiceList": (self.openServiceList, _("open servicelist")),
267 def showTvChannelList(self, zap=False):
268 self.servicelist.setModeTv()
270 self.servicelist.zap()
271 self.session.execDialog(self.servicelist)
273 def showRadioChannelList(self, zap=False):
274 self.servicelist.setModeRadio()
276 self.servicelist.zap()
277 self.session.execDialog(self.servicelist)
280 self.onShown.remove(self.firstRun)
281 config.misc.initialchannelselection.value = False
282 config.misc.initialchannelselection.save()
283 self.switchChannelDown()
285 def historyBack(self):
286 self.servicelist.historyBack()
288 def historyNext(self):
289 self.servicelist.historyNext()
291 def switchChannelUp(self):
292 self.servicelist.moveUp()
293 self.session.execDialog(self.servicelist)
295 def switchChannelDown(self):
296 self.servicelist.moveDown()
297 self.session.execDialog(self.servicelist)
299 def openServiceList(self):
300 self.session.execDialog(self.servicelist)
303 if self.servicelist.inBouquet():
304 prev = self.servicelist.getCurrentSelection()
306 prev = prev.toString()
308 if config.usage.quickzap_bouquet_change.value:
309 if self.servicelist.atBegin():
310 self.servicelist.prevBouquet()
311 self.servicelist.moveUp()
312 cur = self.servicelist.getCurrentSelection()
313 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
316 self.servicelist.moveUp()
317 self.servicelist.zap()
318 if config.usage.show_infobar_on_zap.value:
322 if self.servicelist.inBouquet():
323 prev = self.servicelist.getCurrentSelection()
325 prev = prev.toString()
327 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
328 self.servicelist.nextBouquet()
330 self.servicelist.moveDown()
331 cur = self.servicelist.getCurrentSelection()
332 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
335 self.servicelist.moveDown()
336 self.servicelist.zap()
337 if config.usage.show_infobar_on_zap.value:
341 """ Handles a menu action, to open the (main) menu """
343 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
345 "mainMenu": (self.mainMenu, _("Enter main menu...")),
347 self.session.infobar = None
350 print "loading mainmenu XML..."
351 menu = mdom.childNodes[0]
352 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
354 self.session.infobar = self
355 # so we can access the currently active infobar from screens opened from within the mainmenu
356 # at the moment used from the SubserviceSelection
358 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
360 def mainMenuClosed(self, *val):
361 self.session.infobar = None
363 class InfoBarSimpleEventView:
364 """ Opens the Eventview for now/next """
366 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
368 "showEventInfo": (self.openEventView, _("show event details")),
371 def openEventView(self):
373 service = self.session.nav.getCurrentService()
374 ref = self.session.nav.getCurrentlyPlayingServiceReference()
375 info = service.info()
378 self.epglist.append(ptr)
381 self.epglist.append(ptr)
382 if len(self.epglist) > 0:
383 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
385 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
386 if len(self.epglist) > 1:
387 tmp = self.epglist[0]
388 self.epglist[0]=self.epglist[1]
390 setEvent(self.epglist[0])
393 """ EPG - Opens an EPG list when the showEPGList action fires """
395 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
397 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
400 self.is_now_next = False
402 self.bouquetSel = None
403 self.eventView = None
404 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
406 "showEventInfo": (self.openEventView, _("show EPG...")),
409 def zapToService(self, service):
410 if not service is None:
411 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
412 self.servicelist.clearPath()
413 if self.servicelist.bouquet_root != self.epg_bouquet:
414 self.servicelist.enterPath(self.servicelist.bouquet_root)
415 self.servicelist.enterPath(self.epg_bouquet)
416 self.servicelist.setCurrentSelection(service) #select the service in servicelist
417 self.servicelist.zap()
419 def getBouquetServices(self, bouquet):
421 servicelist = eServiceCenter.getInstance().list(bouquet)
422 if not servicelist is None:
424 service = servicelist.getNext()
425 if not service.valid(): #check if end of list
427 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
429 services.append(ServiceReference(service))
432 def openBouquetEPG(self, bouquet, withCallback=True):
433 services = self.getBouquetServices(bouquet)
435 self.epg_bouquet = bouquet
437 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
439 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
441 def changeBouquetCB(self, direction, epg):
444 self.bouquetSel.down()
447 bouquet = self.bouquetSel.getCurrent()
448 services = self.getBouquetServices(bouquet)
450 self.epg_bouquet = bouquet
451 epg.setServices(services)
453 def closed(self, ret=False):
454 closedScreen = self.dlg_stack.pop()
455 if self.bouquetSel and closedScreen == self.bouquetSel:
456 self.bouquetSel = None
457 elif self.eventView and closedScreen == self.eventView:
458 self.eventView = None
460 dlgs=len(self.dlg_stack)
462 self.dlg_stack[dlgs-1].close(dlgs > 1)
464 def openMultiServiceEPG(self, withCallback=True):
465 bouquets = self.servicelist.getBouquetList()
470 if cnt > 1: # show bouquet list
472 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
473 self.dlg_stack.append(self.bouquetSel)
475 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
477 self.openBouquetEPG(bouquets[0][1], withCallback)
479 def openSingleServiceEPG(self):
480 ref=self.session.nav.getCurrentlyPlayingServiceReference()
481 self.session.open(EPGSelection, ref)
483 def openSimilarList(self, eventid, refstr):
484 self.session.open(EPGSelection, refstr, None, eventid)
486 def getNowNext(self):
488 service = self.session.nav.getCurrentService()
489 info = service and service.info()
490 ptr = info and info.getEvent(0)
492 self.epglist.append(ptr)
493 ptr = info and info.getEvent(1)
495 self.epglist.append(ptr)
497 def __evEventInfoChanged(self):
498 if self.is_now_next and len(self.dlg_stack) == 1:
500 assert self.eventView
501 if len(self.epglist):
502 self.eventView.setEvent(self.epglist[0])
504 def openEventView(self):
505 ref = self.session.nav.getCurrentlyPlayingServiceReference()
507 if len(self.epglist) == 0:
508 self.is_now_next = False
509 epg = eEPGCache.getInstance()
510 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
512 self.epglist.append(ptr)
513 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
515 self.epglist.append(ptr)
517 self.is_now_next = True
518 if len(self.epglist) > 0:
519 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
520 self.dlg_stack.append(self.eventView)
522 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
523 self.openMultiServiceEPG(False)
525 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
526 if len(self.epglist) > 1:
527 tmp = self.epglist[0]
528 self.epglist[0]=self.epglist[1]
530 setEvent(self.epglist[0])
533 """provides a snr/agc/ber display"""
535 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
538 """provides a current/next event info display"""
540 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
541 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
543 class InfoBarRadioText:
544 """provides radio (RDS) text info display"""
546 self["RadioText"] = RadioText(self.session.nav)
548 class InfoBarServiceName:
550 self["CurrentService"] = CurrentService(self.session.nav)
553 """handles actions like seeking, pause"""
555 # ispause, isff, issm
556 SEEK_STATE_PLAY = (0, 0, 0, ">")
557 SEEK_STATE_PAUSE = (1, 0, 0, "||")
558 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
559 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
560 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
561 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
562 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
563 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
565 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
566 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
567 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
568 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
570 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
571 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
572 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
575 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
577 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
578 iPlayableService.evStart: self.__serviceStarted,
580 iPlayableService.evEOF: self.__evEOF,
581 iPlayableService.evSOF: self.__evSOF,
584 class InfoBarSeekActionMap(HelpableActionMap):
585 def __init__(self, screen, *args, **kwargs):
586 HelpableActionMap.__init__(self, screen, *args, **kwargs)
589 def action(self, contexts, action):
590 if action[:5] == "seek:":
591 time = int(action[5:])
592 self.screen.seekRelative(time * 90000)
595 return HelpableActionMap.action(self, contexts, action)
597 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
599 "playpauseService": (self.playpauseService, _("pause")),
600 "pauseService": (self.pauseService, _("pause")),
601 "unPauseService": (self.unPauseService, _("continue")),
603 "seekFwd": (self.seekFwd, _("skip forward")),
604 "seekFwdDown": self.seekFwdDown,
605 "seekFwdUp": self.seekFwdUp,
606 "seekBack": (self.seekBack, _("skip backward")),
607 "seekBackDown": self.seekBackDown,
608 "seekBackUp": self.seekBackUp,
610 # give them a little more priority to win over color buttons
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.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.evStart:
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 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1615 dlg = self.session.open(n[1], *n[2], **n[3])
1617 # remember that this notification is currently active
1619 Notifications.current_notifications.append(d)
1620 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1622 def __notificationClosed(self, d):
1623 Notifications.current_notifications.remove(d)
1625 class InfoBarServiceNotifications:
1627 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1629 iPlayableService.evEnd: self.serviceHasEnded
1632 def serviceHasEnded(self):
1633 print "service end!"
1636 self.setSeekState(self.SEEK_STATE_PLAY)
1640 class InfoBarCueSheetSupport:
1646 ENABLE_RESUME_SUPPORT = False
1649 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1651 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1652 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1653 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1657 self.is_closing = False
1658 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1660 iPlayableService.evStart: self.__serviceStarted,
1663 def __serviceStarted(self):
1666 print "new service started! trying to download cuts!"
1667 self.downloadCuesheet()
1669 if self.ENABLE_RESUME_SUPPORT:
1672 for (pts, what) in self.cut_list:
1673 if what == self.CUT_TYPE_LAST:
1676 if last is not None:
1677 self.resume_point = last
1678 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1680 def playLastCB(self, answer):
1682 seekable = self.__getSeekable()
1683 if seekable is not None:
1684 seekable.seekTo(self.resume_point)
1686 def __getSeekable(self):
1687 service = self.session.nav.getCurrentService()
1690 return service.seek()
1692 def cueGetCurrentPosition(self):
1693 seek = self.__getSeekable()
1696 r = seek.getPlayPosition()
1701 def jumpPreviousNextMark(self, cmp, alternative=None):
1702 current_pos = self.cueGetCurrentPosition()
1703 if current_pos is None:
1705 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1706 if mark is not None:
1708 elif alternative is not None:
1713 seekable = self.__getSeekable()
1714 if seekable is not None:
1715 seekable.seekTo(pts)
1717 def jumpPreviousMark(self):
1718 # we add 2 seconds, so if the play position is <2s after
1719 # the mark, the mark before will be used
1720 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1722 def jumpNextMark(self):
1723 self.jumpPreviousNextMark(lambda x: x)
1725 def getNearestCutPoint(self, pts, cmp=abs):
1728 for cp in self.cut_list:
1729 diff = cmp(cp[0] - pts)
1730 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1734 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1735 current_pos = self.cueGetCurrentPosition()
1736 if current_pos is None:
1737 print "not seekable"
1740 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1742 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1744 return nearest_cutpoint
1746 self.removeMark(nearest_cutpoint)
1747 elif not onlyremove and not onlyreturn:
1748 self.addMark((current_pos, self.CUT_TYPE_MARK))
1753 def addMark(self, point):
1754 insort(self.cut_list, point)
1755 self.uploadCuesheet()
1757 def removeMark(self, point):
1758 self.cut_list.remove(point)
1759 self.uploadCuesheet()
1761 def __getCuesheet(self):
1762 service = self.session.nav.getCurrentService()
1765 return service.cueSheet()
1767 def uploadCuesheet(self):
1768 cue = self.__getCuesheet()
1771 print "upload failed, no cuesheet interface"
1773 cue.setCutList(self.cut_list)
1775 def downloadCuesheet(self):
1776 cue = self.__getCuesheet()
1779 print "upload failed, no cuesheet interface"
1781 self.cut_list = cue.getCutList()
1783 class InfoBarSummary(Screen):
1785 <screen position="0,0" size="132,64">
1786 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1787 <convert type="ClockToText">WithSeconds</convert>
1789 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1790 <convert type="ServiceName">Name</convert>
1794 def __init__(self, session, parent):
1795 Screen.__init__(self, session)
1796 self["CurrentService"] = CurrentService(self.session.nav)
1797 self["CurrentTime"] = Clock()
1799 class InfoBarSummarySupport:
1803 def createSummary(self):
1804 return InfoBarSummary
1806 class InfoBarTeletextPlugin:
1808 self.teletext_plugin = None
1810 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1811 self.teletext_plugin = p
1813 if self.teletext_plugin is not None:
1814 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1816 "startTeletext": (self.startTeletext, _("View teletext..."))
1819 print "no teletext plugin found!"
1821 def startTeletext(self):
1822 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1824 class InfoBarSubtitleSupport(object):
1826 object.__init__(self)
1827 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1828 self.__subtitles_enabled = False
1830 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1832 iPlayableService.evEnd: self.__serviceStopped,
1833 iPlayableService.evUpdatedInfo: self.__updatedInfo
1835 self.cached_subtitle_checked = False
1837 def __serviceStopped(self):
1838 self.subtitle_window.hide()
1839 self.__subtitles_enabled = False
1840 self.cached_subtitle_checked = False
1842 def __updatedInfo(self):
1843 if not self.cached_subtitle_checked:
1844 subtitle = self.getCurrentServiceSubtitle()
1845 self.cached_subtitle_checked = True
1847 self.__selected_subtitle = subtitle.getCachedSubtitle()
1848 if self.__selected_subtitle:
1849 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1850 self.subtitle_window.show()
1851 self.__subtitles_enabled = True
1853 def getCurrentServiceSubtitle(self):
1854 service = self.session.nav.getCurrentService()
1855 return service and service.subtitle()
1857 def setSubtitlesEnable(self, enable=True):
1858 subtitle = self.getCurrentServiceSubtitle()
1859 if enable and self.__selected_subtitle is not None:
1860 if subtitle and not self.__subtitles_enabled:
1861 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1862 self.subtitle_window.show()
1863 self.__subtitles_enabled = True
1866 subtitle.disableSubtitles(self.subtitle_window.instance)
1867 self.__subtitles_enabled = False
1868 self.subtitle_window.hide()
1870 def setSelectedSubtitle(self, subtitle):
1871 self.__selected_subtitle = subtitle
1873 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1874 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1876 class InfoBarServiceErrorPopupSupport:
1878 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1880 iPlayableService.evTuneFailed: self.__tuneFailed,
1881 iPlayableService.evStart: self.__serviceStarted
1883 self.__serviceStarted()
1885 def __serviceStarted(self):
1886 self.last_error = None
1887 Notifications.RemovePopup(id = "ZapError")
1889 def __tuneFailed(self):
1890 service = self.session.nav.getCurrentService()
1891 info = service and service.info()
1892 error = info and info.getInfo(iServiceInformation.sDVBState)
1894 if error == self.last_error:
1897 self.last_error = error
1900 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1901 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1902 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1903 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1904 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1905 eDVBServicePMTHandler.eventNewProgramInfo: None,
1906 eDVBServicePMTHandler.eventTuned: None,
1907 eDVBServicePMTHandler.eventSOF: None,
1908 eDVBServicePMTHandler.eventEOF: None
1911 if error not in errors:
1914 error = error is not None and errors[error]
1916 if error is not None:
1917 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1919 Notifications.RemovePopup(id = "ZapError")