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 = self.servicelist.appendDVBTypes(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.seekstate != self.SEEK_STATE_PLAY and self.execing:
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)
882 class InfoBarShowMovies:
884 # i don't really like this class.
885 # it calls a not further specified "movie list" on up/down/movieList,
886 # so this is not more than an action map
888 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
890 "movieList": (self.showMovies, "movie list"),
891 "up": (self.showMovies, "movie list"),
892 "down": (self.showMovies, "movie list")
895 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
899 # Timeshift works the following way:
900 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
901 # - normal playback TUNER unused PLAY enable disable disable
902 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
903 # - user presess pause again FILE record PLAY enable disable enable
904 # - user fast forwards FILE record FF enable disable enable
905 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
906 # - user backwards FILE record BACK # !! enable disable enable
910 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
911 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
912 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
913 # - the user can now PVR around
914 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
915 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
917 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
918 # - if the user rewinds, or press pause, timeshift will be activated again
920 # note that a timeshift can be enabled ("recording") and
921 # activated (currently time-shifting).
923 class InfoBarTimeshift:
925 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
927 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
928 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
930 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
932 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
933 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
934 }, prio=-1) # priority over record
936 self.timeshift_enabled = 0
937 self.timeshift_state = 0
938 self.ts_pause_timer = eTimer()
939 self.ts_pause_timer.timeout.get().append(self.pauseService)
941 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
943 iPlayableService.evStart: self.__serviceStarted,
944 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
947 def getTimeshift(self):
948 service = self.session.nav.getCurrentService()
949 return service and service.timeshift()
951 def startTimeshift(self):
952 print "enable timeshift"
953 ts = self.getTimeshift()
955 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
956 print "no ts interface"
959 if self.timeshift_enabled:
960 print "hu, timeshift already enabled?"
962 if not ts.startTimeshift():
963 self.timeshift_enabled = 1
965 # we remove the "relative time" for now.
966 #self.pvrStateDialog["timeshift"].setRelative(time.time())
969 self.setSeekState(self.SEEK_STATE_PAUSE)
971 # enable the "TimeshiftEnableActions", which will override
972 # the startTimeshift actions
973 self.__seekableStatusChanged()
975 print "timeshift failed"
977 def stopTimeshift(self):
978 if not self.timeshift_enabled:
980 print "disable timeshift"
981 ts = self.getTimeshift()
984 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
986 def stopTimeshiftConfirmed(self, confirmed):
990 ts = self.getTimeshift()
995 self.timeshift_enabled = 0
998 self.__seekableStatusChanged()
1000 # activates timeshift, and seeks to (almost) the end
1001 def activateTimeshiftEnd(self):
1002 ts = self.getTimeshift()
1007 if ts.isTimeshiftActive():
1008 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1011 self.setSeekState(self.SEEK_STATE_PLAY)
1012 ts.activateTimeshift()
1013 self.seekRelative(0)
1015 # same as activateTimeshiftEnd, but pauses afterwards.
1016 def activateTimeshiftEndAndPause(self):
1017 state = self.seekstate
1018 self.activateTimeshiftEnd()
1020 # well, this is "andPause", but it could be pressed from pause,
1021 # when pausing on the (fake-)"live" picture, so an un-pause
1024 print "now, pauseService"
1025 if state == self.SEEK_STATE_PLAY:
1026 print "is PLAYING, start pause timer"
1027 self.ts_pause_timer.start(200, 1)
1030 self.unPauseService()
1032 def __seekableStatusChanged(self):
1035 print "self.isSeekable", self.isSeekable()
1036 print "self.timeshift_enabled", self.timeshift_enabled
1038 # when this service is not seekable, but timeshift
1039 # is enabled, this means we can activate
1041 if not self.isSeekable() and self.timeshift_enabled:
1044 print "timeshift activate:", enabled
1045 self["TimeshiftActivateActions"].setEnabled(enabled)
1047 def __serviceStarted(self):
1048 self.timeshift_enabled = False
1049 self.__seekableStatusChanged()
1051 from Screens.PiPSetup import PiPSetup
1053 class InfoBarExtensions:
1054 EXTENSION_SINGLE = 0
1060 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1062 "extensions": (self.showExtensionSelection, _("view extensions...")),
1065 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1066 self.list.append((type, extension, key))
1068 def updateExtension(self, extension, key = None):
1069 self.extensionsList.append(extension)
1071 if self.extensionKeys.has_key(key):
1075 for x in self.availableKeys:
1076 if not self.extensionKeys.has_key(x):
1081 self.extensionKeys[key] = len(self.extensionsList) - 1
1083 def updateExtensions(self):
1084 self.extensionsList = []
1085 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1086 self.extensionKeys = {}
1088 if x[0] == self.EXTENSION_SINGLE:
1089 self.updateExtension(x[1], x[2])
1092 self.updateExtension(y[0], y[1])
1095 def showExtensionSelection(self):
1096 self.updateExtensions()
1097 extensionsList = self.extensionsList[:]
1100 for x in self.availableKeys:
1101 if self.extensionKeys.has_key(x):
1102 entry = self.extensionKeys[x]
1103 extension = self.extensionsList[entry]
1105 name = str(extension[0]())
1106 list.append((extension[0](), extension))
1108 extensionsList.remove(extension)
1110 extensionsList.remove(extension)
1111 for x in extensionsList:
1112 list.append((x[0](), x))
1113 keys += [""] * len(extensionsList)
1114 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1116 def extensionCallback(self, answer):
1117 if answer is not None:
1120 from Tools.BoundFunction import boundFunction
1122 # depends on InfoBarExtensions
1123 from Components.PluginComponent import plugins
1125 class InfoBarPlugins:
1127 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1129 def getPluginName(self, name):
1132 def getPluginList(self):
1134 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1135 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1138 def runPlugin(self, plugin):
1139 plugin(session = self.session)
1141 # depends on InfoBarExtensions
1142 class InfoBarSleepTimer:
1144 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1146 def available(self):
1149 def getSleepTimerName(self):
1150 return _("Sleep Timer")
1152 def showSleepTimerSetup(self):
1153 self.session.open(SleepTimerEdit)
1155 # depends on InfoBarExtensions
1158 self.session.pipshown = False
1160 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1161 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1162 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1164 def available(self):
1168 return self.session.pipshown
1170 def getShowHideName(self):
1171 if self.session.pipshown:
1172 return _("Disable Picture in Picture")
1174 return _("Activate Picture in Picture")
1176 def getSwapName(self):
1177 return _("Swap Services")
1179 def getMoveName(self):
1180 return _("Move Picture in Picture")
1183 if self.session.pipshown:
1184 del self.session.pip
1185 self.session.pipshown = False
1187 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1188 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1189 if self.session.pip.playService(newservice):
1190 self.session.pipshown = True
1191 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1193 self.session.pipshown = False
1194 del self.session.pip
1195 self.session.nav.playService(newservice)
1198 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1199 if self.session.pip.servicePath:
1200 servicepath = self.servicelist.getCurrentServicePath()
1201 ref=servicepath[len(servicepath)-1]
1202 pipref=self.session.pip.getCurrentService()
1203 self.session.pip.playService(swapservice)
1204 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1205 if pipref.toString() != ref.toString(): # is a subservice ?
1206 self.session.nav.stopService() # stop portal
1207 self.session.nav.playService(pipref) # start subservice
1208 self.session.pip.servicePath=servicepath
1211 self.session.open(PiPSetup, pip = self.session.pip)
1213 from RecordTimer import parseEvent
1215 class InfoBarInstantRecord:
1216 """Instant Record - handles the instantRecord action in order to
1217 start/stop instant records"""
1219 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1221 "instantRecord": (self.instantRecord, _("Instant Record...")),
1224 self["BlinkingPoint"] = BlinkingPixmapConditional()
1225 self["BlinkingPoint"].hide()
1226 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1228 def stopCurrentRecording(self, entry = -1):
1229 if entry is not None and entry != -1:
1230 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1231 self.recording.remove(self.recording[entry])
1233 def startInstantRecording(self, limitEvent = False):
1234 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1236 # try to get event info
1239 service = self.session.nav.getCurrentService()
1240 epg = eEPGCache.getInstance()
1241 event = epg.lookupEventTime(serviceref, -1, 0)
1243 info = service.info()
1244 ev = info.getEvent(0)
1250 end = time() + 3600 * 10
1251 name = "instant record"
1255 if event is not None:
1256 curEvent = parseEvent(event)
1258 description = curEvent[3]
1259 eventid = curEvent[4]
1264 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1266 data = (begin, end, name, description, eventid)
1268 recording = self.session.nav.recordWithTimer(serviceref, *data)
1269 recording.dontSave = True
1270 self.recording.append(recording)
1272 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1274 def isInstantRecordRunning(self):
1275 print "self.recording:", self.recording
1276 if len(self.recording) > 0:
1277 for x in self.recording:
1282 def recordQuestionCallback(self, answer):
1283 print "pre:\n", self.recording
1285 if answer is None or answer[1] == "no":
1288 recording = self.recording[:]
1290 if not x in self.session.nav.RecordTimer.timer_list:
1291 self.recording.remove(x)
1292 elif x.dontSave and x.isRunning():
1293 list.append(TimerEntryComponent(x, False))
1295 if answer[1] == "changeduration":
1296 if len(self.recording) == 1:
1297 self.changeDuration(0)
1299 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1300 elif answer[1] == "stop":
1301 if len(self.recording) == 1:
1302 self.stopCurrentRecording(0)
1304 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1305 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1307 if answer[1] == "event":
1309 if answer[1] == "manualduration":
1310 self.selectedEntry = len(self.recording)
1311 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1312 self.startInstantRecording(limitEvent = limitEvent)
1314 print "after:\n", self.recording
1316 def changeDuration(self, entry):
1317 if entry is not None:
1318 self.selectedEntry = entry
1319 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1321 def inputCallback(self, value):
1322 if value is not None:
1323 print "stopping recording after", int(value), "minutes."
1324 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1325 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1327 def instantRecord(self):
1329 stat = os_stat(resolveFilename(SCOPE_HDD))
1331 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1334 if self.isInstantRecordRunning():
1335 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("A recording is currently running.\nWhat do you want to do?"), list=[(_("stop recording"), "stop"), (_("change recording (duration)"), "changeduration"), (_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"), (_("do nothing"), "no")])
1337 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Start recording?"), list=[(_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"),(_("don't record"), "no")])
1339 from Tools.ISO639 import LanguageCodes
1341 class InfoBarAudioSelection:
1343 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1345 "audioSelection": (self.audioSelection, _("Audio Options...")),
1348 def audioSelection(self):
1349 service = self.session.nav.getCurrentService()
1350 audio = service and service.audioTracks()
1351 self.audioTracks = audio
1352 n = audio and audio.getNumberOfTracks() or 0
1353 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1355 print "tlist:", tlist
1357 self.audioChannel = service.audioChannel()
1360 i = audio.getTrackInfo(x)
1361 language = i.getLanguage()
1362 description = i.getDescription()
1364 if LanguageCodes.has_key(language):
1365 language = LanguageCodes[language][0]
1367 if len(description):
1368 description += " (" + language + ")"
1370 description = language
1372 tlist.append((description, x))
1374 selectedAudio = tlist[0][1]
1375 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1379 if x[1] != selectedAudio:
1384 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1385 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1387 del self.audioTracks
1389 def audioSelected(self, audio):
1390 if audio is not None:
1391 if isinstance(audio[1], str):
1392 if audio[1] == "mode":
1393 keys = ["red", "green", "yellow"]
1394 selection = self.audioChannel.getCurrentChannel()
1395 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1396 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1398 del self.audioChannel
1399 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1400 self.audioTracks.selectTrack(audio[1])
1402 del self.audioChannel
1403 del self.audioTracks
1405 def modeSelected(self, mode):
1406 if mode is not None:
1407 self.audioChannel.selectChannel(mode[1])
1408 del self.audioChannel
1410 class InfoBarSubserviceSelection:
1412 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1414 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1417 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1419 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1420 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1422 self["SubserviceQuickzapAction"].setEnabled(False)
1424 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1428 def checkSubservicesAvail(self, ev):
1429 if ev == iPlayableService.evUpdatedEventInfo:
1430 service = self.session.nav.getCurrentService()
1431 subservices = service and service.subServices()
1432 if not subservices or subservices.getNumberOfSubservices() == 0:
1433 self["SubserviceQuickzapAction"].setEnabled(False)
1435 def nextSubservice(self):
1436 self.changeSubservice(+1)
1438 def prevSubservice(self):
1439 self.changeSubservice(-1)
1441 def changeSubservice(self, direction):
1442 service = self.session.nav.getCurrentService()
1443 subservices = service and service.subServices()
1444 n = subservices and subservices.getNumberOfSubservices()
1447 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1449 if subservices.getSubservice(x).toString() == ref.toString():
1452 selection += direction
1457 newservice = subservices.getSubservice(selection)
1458 if newservice.valid():
1461 if config.usage.show_infobar_on_zap.value:
1463 self.session.nav.playService(newservice)
1465 def subserviceSelection(self):
1466 service = self.session.nav.getCurrentService()
1467 subservices = service and service.subServices()
1468 self.bouquets = self.servicelist.getBouquetList()
1469 n = subservices and subservices.getNumberOfSubservices()
1472 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1475 i = subservices.getSubservice(x)
1476 if i.toString() == ref.toString():
1478 tlist.append((i.getName(), i))
1480 if self.bouquets and len(self.bouquets):
1481 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1482 if config.usage.multibouquet.value:
1483 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1485 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1488 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1489 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1492 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1494 def subserviceSelected(self, service):
1496 if not service is None:
1497 if isinstance(service[1], str):
1498 if service[1] == "quickzap":
1499 from Screens.SubservicesQuickzap import SubservicesQuickzap
1500 self.session.open(SubservicesQuickzap, service[2])
1502 self["SubserviceQuickzapAction"].setEnabled(True)
1503 if config.usage.show_infobar_on_zap.value:
1505 self.session.nav.playService(service[1])
1507 def addSubserviceToBouquetCallback(self, service):
1508 if len(service) > 1 and isinstance(service[1], eServiceReference):
1509 self.selectedSubservice = service
1510 if self.bouquets is None:
1513 cnt = len(self.bouquets)
1514 if cnt > 1: # show bouquet list
1515 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1516 elif cnt == 1: # add to only one existing bouquet
1517 self.addSubserviceToBouquet(self.bouquets[0][1])
1518 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1520 def bouquetSelClosed(self, confirmed):
1522 del self.selectedSubservice
1524 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1526 def addSubserviceToBouquet(self, dest):
1527 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1529 self.bsel.close(True)
1531 del self.selectedSubservice
1533 class InfoBarAdditionalInfo:
1535 self["NimA"] = Pixmap()
1536 self["NimB"] = Pixmap()
1537 self["NimA_Active"] = Pixmap()
1538 self["NimB_Active"] = Pixmap()
1540 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1541 self["TimeshiftPossible"] = self["RecordingPossible"]
1542 self["ExtensionsAvailable"] = Boolean(fixed=1)
1544 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1545 res_mgr = eDVBResourceManager.getInstance()
1547 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1549 def tunerUseMaskChanged(self, mask):
1551 self["NimA_Active"].show()
1553 self["NimA_Active"].hide()
1555 self["NimB_Active"].show()
1557 self["NimB_Active"].hide()
1559 def checkTunerState(self, service):
1560 info = service.frontendInfo()
1561 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1562 if feNumber is None:
1572 def gotServiceEvent(self, ev):
1573 service = self.session.nav.getCurrentService()
1574 if ev == iPlayableService.evStart:
1575 self.checkTunerState(service)
1577 class InfoBarNotifications:
1579 self.onExecBegin.append(self.checkNotifications)
1580 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1581 self.onClose.append(self.__removeNotification)
1583 def __removeNotification(self):
1584 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1586 def checkNotificationsIfExecing(self):
1588 self.checkNotifications()
1590 def checkNotifications(self):
1591 if len(Notifications.notifications):
1592 n = Notifications.notifications[0]
1594 Notifications.notifications = Notifications.notifications[1:]
1597 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1599 dlg = self.session.open(n[1], *n[2], **n[3])
1601 # remember that this notification is currently active
1603 Notifications.current_notifications.append(d)
1604 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1606 def __notificationClosed(self, d):
1607 Notifications.current_notifications.remove(d)
1609 class InfoBarServiceNotifications:
1611 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1613 iPlayableService.evEnd: self.serviceHasEnded
1616 def serviceHasEnded(self):
1617 print "service end!"
1620 self.setSeekState(self.SEEK_STATE_PLAY)
1624 class InfoBarCueSheetSupport:
1630 ENABLE_RESUME_SUPPORT = False
1633 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1635 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1636 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1637 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1641 self.is_closing = False
1642 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1644 iPlayableService.evStart: self.__serviceStarted,
1647 def __serviceStarted(self):
1650 print "new service started! trying to download cuts!"
1651 self.downloadCuesheet()
1653 if self.ENABLE_RESUME_SUPPORT:
1656 for (pts, what) in self.cut_list:
1657 if what == self.CUT_TYPE_LAST:
1660 if last is not None:
1661 self.resume_point = last
1662 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1664 def playLastCB(self, answer):
1666 seekable = self.__getSeekable()
1667 if seekable is not None:
1668 seekable.seekTo(self.resume_point)
1670 def __getSeekable(self):
1671 service = self.session.nav.getCurrentService()
1674 return service.seek()
1676 def cueGetCurrentPosition(self):
1677 seek = self.__getSeekable()
1680 r = seek.getPlayPosition()
1685 def jumpPreviousNextMark(self, cmp, alternative=None):
1686 current_pos = self.cueGetCurrentPosition()
1687 if current_pos is None:
1689 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1690 if mark is not None:
1692 elif alternative is not None:
1697 seekable = self.__getSeekable()
1698 if seekable is not None:
1699 seekable.seekTo(pts)
1701 def jumpPreviousMark(self):
1702 # we add 2 seconds, so if the play position is <2s after
1703 # the mark, the mark before will be used
1704 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1706 def jumpNextMark(self):
1707 self.jumpPreviousNextMark(lambda x: x)
1709 def getNearestCutPoint(self, pts, cmp=abs):
1712 for cp in self.cut_list:
1713 diff = cmp(cp[0] - pts)
1714 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1718 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1719 current_pos = self.cueGetCurrentPosition()
1720 if current_pos is None:
1721 print "not seekable"
1724 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1726 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1728 return nearest_cutpoint
1730 self.removeMark(nearest_cutpoint)
1731 elif not onlyremove and not onlyreturn:
1732 self.addMark((current_pos, self.CUT_TYPE_MARK))
1737 def addMark(self, point):
1738 insort(self.cut_list, point)
1739 self.uploadCuesheet()
1741 def removeMark(self, point):
1742 self.cut_list.remove(point)
1743 self.uploadCuesheet()
1745 def __getCuesheet(self):
1746 service = self.session.nav.getCurrentService()
1749 return service.cueSheet()
1751 def uploadCuesheet(self):
1752 cue = self.__getCuesheet()
1755 print "upload failed, no cuesheet interface"
1757 cue.setCutList(self.cut_list)
1759 def downloadCuesheet(self):
1760 cue = self.__getCuesheet()
1763 print "upload failed, no cuesheet interface"
1765 self.cut_list = cue.getCutList()
1767 class InfoBarSummary(Screen):
1769 <screen position="0,0" size="132,64">
1770 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1771 <convert type="ClockToText">WithSeconds</convert>
1773 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1774 <convert type="ServiceName">Name</convert>
1778 def __init__(self, session, parent):
1779 Screen.__init__(self, session)
1780 self["CurrentService"] = CurrentService(self.session.nav)
1781 self["CurrentTime"] = Clock()
1783 class InfoBarSummarySupport:
1787 def createSummary(self):
1788 return InfoBarSummary
1790 class InfoBarTeletextPlugin:
1792 self.teletext_plugin = None
1794 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1795 self.teletext_plugin = p
1797 if self.teletext_plugin is not None:
1798 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1800 "startTeletext": (self.startTeletext, _("View teletext..."))
1803 print "no teletext plugin found!"
1805 def startTeletext(self):
1806 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1808 class InfoBarSubtitleSupport(object):
1810 object.__init__(self)
1811 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1812 self.__subtitles_enabled = False
1814 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1816 iPlayableService.evEnd: self.__serviceStopped,
1817 iPlayableService.evUpdatedInfo: self.__updatedInfo
1819 self.cached_subtitle_checked = False
1821 def __serviceStopped(self):
1822 self.subtitle_window.hide()
1823 self.__subtitles_enabled = False
1824 self.cached_subtitle_checked = False
1826 def __updatedInfo(self):
1827 if not self.cached_subtitle_checked:
1828 subtitle = self.getCurrentServiceSubtitle()
1829 self.cached_subtitle_checked = True
1831 self.__selected_subtitle = subtitle.getCachedSubtitle()
1832 if self.__selected_subtitle:
1833 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1834 self.subtitle_window.show()
1835 self.__subtitles_enabled = True
1837 def getCurrentServiceSubtitle(self):
1838 service = self.session.nav.getCurrentService()
1839 return service and service.subtitle()
1841 def setSubtitlesEnable(self, enable=True):
1842 subtitle = self.getCurrentServiceSubtitle()
1843 if enable and self.__selected_subtitle is not None:
1844 if subtitle and not self.__subtitles_enabled:
1845 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1846 self.subtitle_window.show()
1847 self.__subtitles_enabled = True
1850 subtitle.disableSubtitles(self.subtitle_window.instance)
1851 self.__subtitles_enabled = False
1852 self.subtitle_window.hide()
1854 def setSelectedSubtitle(self, subtitle):
1855 self.__selected_subtitle = subtitle
1857 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1858 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1860 class InfoBarServiceErrorPopupSupport:
1862 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1864 iPlayableService.evTuneFailed: self.__tuneFailed,
1865 iPlayableService.evStart: self.__serviceStarted
1867 self.__serviceStarted()
1869 def __serviceStarted(self):
1870 self.last_error = None
1871 Notifications.RemovePopup(id = "ZapError")
1873 def __tuneFailed(self):
1874 service = self.session.nav.getCurrentService()
1875 info = service and service.info()
1876 error = info and info.getInfo(iServiceInformation.sDVBState)
1878 if error == self.last_error:
1881 self.last_error = error
1884 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1885 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1886 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1887 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1888 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1889 eDVBServicePMTHandler.eventNewProgramInfo: None,
1890 eDVBServicePMTHandler.eventTuned: None,
1891 eDVBServicePMTHandler.eventSOF: None,
1892 eDVBServicePMTHandler.eventEOF: None
1895 if error not in errors:
1898 error = error and errors[error]
1900 if error is not None:
1901 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1903 Notifications.RemovePopup(id = "ZapError")