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, show_always_in_timeshift=False):
864 self.show_always_in_timeshift = show_always_in_timeshift
865 self.onPlayStateChanged.append(self.__playStateChanged)
866 self.pvrStateDialog = self.session.instantiateDialog(screen)
867 self.onShow.append(self.__mayShow)
868 self.onHide.append(self.pvrStateDialog.hide)
871 if self.execing and ((self.show_always_in_timeshift and self.timeshift_enabled) or self.seekstate != self.SEEK_STATE_PLAY):
872 self.pvrStateDialog.show()
874 def __playStateChanged(self, state):
875 playstateString = state[3]
876 self.pvrStateDialog["state"].setText(playstateString)
879 class InfoBarTimeshiftState(InfoBarPVRState):
881 InfoBarPVRState.__init__(self, screen=TimeshiftState, show_always_in_timeshift=True)
883 class InfoBarShowMovies:
885 # i don't really like this class.
886 # it calls a not further specified "movie list" on up/down/movieList,
887 # so this is not more than an action map
889 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
891 "movieList": (self.showMovies, "movie list"),
892 "up": (self.showMovies, "movie list"),
893 "down": (self.showMovies, "movie list")
896 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
900 # Timeshift works the following way:
901 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
902 # - normal playback TUNER unused PLAY enable disable disable
903 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
904 # - user presess pause again FILE record PLAY enable disable enable
905 # - user fast forwards FILE record FF enable disable enable
906 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
907 # - user backwards FILE record BACK # !! enable disable enable
911 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
912 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
913 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
914 # - the user can now PVR around
915 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
916 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
918 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
919 # - if the user rewinds, or press pause, timeshift will be activated again
921 # note that a timeshift can be enabled ("recording") and
922 # activated (currently time-shifting).
924 class InfoBarTimeshift:
926 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
928 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
929 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
931 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
933 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
934 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
935 }, prio=-1) # priority over record
937 self.timeshift_enabled = 0
938 self.timeshift_state = 0
939 self.ts_pause_timer = eTimer()
940 self.ts_pause_timer.timeout.get().append(self.pauseService)
942 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
944 iPlayableService.evStart: self.__serviceStarted,
945 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
948 def getTimeshift(self):
949 service = self.session.nav.getCurrentService()
950 return service and service.timeshift()
952 def startTimeshift(self):
953 print "enable timeshift"
954 ts = self.getTimeshift()
956 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
957 print "no ts interface"
960 if self.timeshift_enabled:
961 print "hu, timeshift already enabled?"
963 if not ts.startTimeshift():
964 self.timeshift_enabled = 1
966 # we remove the "relative time" for now.
967 #self.pvrStateDialog["timeshift"].setRelative(time.time())
970 self.setSeekState(self.SEEK_STATE_PAUSE)
972 # enable the "TimeshiftEnableActions", which will override
973 # the startTimeshift actions
974 self.__seekableStatusChanged()
976 print "timeshift failed"
978 def stopTimeshift(self):
979 if not self.timeshift_enabled:
981 print "disable timeshift"
982 ts = self.getTimeshift()
985 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
987 def stopTimeshiftConfirmed(self, confirmed):
991 ts = self.getTimeshift()
996 self.timeshift_enabled = 0
999 self.__seekableStatusChanged()
1001 # activates timeshift, and seeks to (almost) the end
1002 def activateTimeshiftEnd(self):
1003 ts = self.getTimeshift()
1008 if ts.isTimeshiftActive():
1009 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1012 self.setSeekState(self.SEEK_STATE_PLAY)
1013 ts.activateTimeshift()
1014 self.seekRelative(0)
1016 # same as activateTimeshiftEnd, but pauses afterwards.
1017 def activateTimeshiftEndAndPause(self):
1018 state = self.seekstate
1019 self.activateTimeshiftEnd()
1021 # well, this is "andPause", but it could be pressed from pause,
1022 # when pausing on the (fake-)"live" picture, so an un-pause
1025 print "now, pauseService"
1026 if state == self.SEEK_STATE_PLAY:
1027 print "is PLAYING, start pause timer"
1028 self.ts_pause_timer.start(200, 1)
1031 self.unPauseService()
1033 def __seekableStatusChanged(self):
1036 print "self.isSeekable", self.isSeekable()
1037 print "self.timeshift_enabled", self.timeshift_enabled
1039 # when this service is not seekable, but timeshift
1040 # is enabled, this means we can activate
1042 if not self.isSeekable() and self.timeshift_enabled:
1045 print "timeshift activate:", enabled
1046 self["TimeshiftActivateActions"].setEnabled(enabled)
1048 def __serviceStarted(self):
1049 self.timeshift_enabled = False
1050 self.__seekableStatusChanged()
1052 from Screens.PiPSetup import PiPSetup
1054 class InfoBarExtensions:
1055 EXTENSION_SINGLE = 0
1061 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1063 "extensions": (self.showExtensionSelection, _("view extensions...")),
1066 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1067 self.list.append((type, extension, key))
1069 def updateExtension(self, extension, key = None):
1070 self.extensionsList.append(extension)
1072 if self.extensionKeys.has_key(key):
1076 for x in self.availableKeys:
1077 if not self.extensionKeys.has_key(x):
1082 self.extensionKeys[key] = len(self.extensionsList) - 1
1084 def updateExtensions(self):
1085 self.extensionsList = []
1086 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1087 self.extensionKeys = {}
1089 if x[0] == self.EXTENSION_SINGLE:
1090 self.updateExtension(x[1], x[2])
1093 self.updateExtension(y[0], y[1])
1096 def showExtensionSelection(self):
1097 self.updateExtensions()
1098 extensionsList = self.extensionsList[:]
1101 for x in self.availableKeys:
1102 if self.extensionKeys.has_key(x):
1103 entry = self.extensionKeys[x]
1104 extension = self.extensionsList[entry]
1106 name = str(extension[0]())
1107 list.append((extension[0](), extension))
1109 extensionsList.remove(extension)
1111 extensionsList.remove(extension)
1112 for x in extensionsList:
1113 list.append((x[0](), x))
1114 keys += [""] * len(extensionsList)
1115 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1117 def extensionCallback(self, answer):
1118 if answer is not None:
1121 from Tools.BoundFunction import boundFunction
1123 # depends on InfoBarExtensions
1124 from Components.PluginComponent import plugins
1126 class InfoBarPlugins:
1128 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1130 def getPluginName(self, name):
1133 def getPluginList(self):
1135 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1136 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1139 def runPlugin(self, plugin):
1140 plugin(session = self.session)
1142 # depends on InfoBarExtensions
1143 class InfoBarSleepTimer:
1145 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1147 def available(self):
1150 def getSleepTimerName(self):
1151 return _("Sleep Timer")
1153 def showSleepTimerSetup(self):
1154 self.session.open(SleepTimerEdit)
1156 # depends on InfoBarExtensions
1159 self.session.pipshown = False
1161 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1162 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1163 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1165 def available(self):
1169 return self.session.pipshown
1171 def getShowHideName(self):
1172 if self.session.pipshown:
1173 return _("Disable Picture in Picture")
1175 return _("Activate Picture in Picture")
1177 def getSwapName(self):
1178 return _("Swap Services")
1180 def getMoveName(self):
1181 return _("Move Picture in Picture")
1184 if self.session.pipshown:
1185 del self.session.pip
1186 self.session.pipshown = False
1188 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1189 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1190 if self.session.pip.playService(newservice):
1191 self.session.pipshown = True
1192 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1194 self.session.pipshown = False
1195 del self.session.pip
1196 self.session.nav.playService(newservice)
1199 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1200 if self.session.pip.servicePath:
1201 servicepath = self.servicelist.getCurrentServicePath()
1202 ref=servicepath[len(servicepath)-1]
1203 pipref=self.session.pip.getCurrentService()
1204 self.session.pip.playService(swapservice)
1205 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1206 if pipref.toString() != ref.toString(): # is a subservice ?
1207 self.session.nav.stopService() # stop portal
1208 self.session.nav.playService(pipref) # start subservice
1209 self.session.pip.servicePath=servicepath
1212 self.session.open(PiPSetup, pip = self.session.pip)
1214 from RecordTimer import parseEvent
1216 class InfoBarInstantRecord:
1217 """Instant Record - handles the instantRecord action in order to
1218 start/stop instant records"""
1220 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1222 "instantRecord": (self.instantRecord, _("Instant Record...")),
1225 self["BlinkingPoint"] = BlinkingPixmapConditional()
1226 self["BlinkingPoint"].hide()
1227 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1229 def stopCurrentRecording(self, entry = -1):
1230 if entry is not None and entry != -1:
1231 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1232 self.recording.remove(self.recording[entry])
1234 def startInstantRecording(self, limitEvent = False):
1235 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1237 # try to get event info
1240 service = self.session.nav.getCurrentService()
1241 epg = eEPGCache.getInstance()
1242 event = epg.lookupEventTime(serviceref, -1, 0)
1244 info = service.info()
1245 ev = info.getEvent(0)
1251 end = time() + 3600 * 10
1252 name = "instant record"
1256 if event is not None:
1257 curEvent = parseEvent(event)
1259 description = curEvent[3]
1260 eventid = curEvent[4]
1265 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1267 data = (begin, end, name, description, eventid)
1269 recording = self.session.nav.recordWithTimer(serviceref, *data)
1270 recording.dontSave = True
1271 self.recording.append(recording)
1273 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1275 def isInstantRecordRunning(self):
1276 print "self.recording:", self.recording
1277 if len(self.recording) > 0:
1278 for x in self.recording:
1283 def recordQuestionCallback(self, answer):
1284 print "pre:\n", self.recording
1286 if answer is None or answer[1] == "no":
1289 recording = self.recording[:]
1291 if not x in self.session.nav.RecordTimer.timer_list:
1292 self.recording.remove(x)
1293 elif x.dontSave and x.isRunning():
1294 list.append(TimerEntryComponent(x, False))
1296 if answer[1] == "changeduration":
1297 if len(self.recording) == 1:
1298 self.changeDuration(0)
1300 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1301 elif answer[1] == "stop":
1302 if len(self.recording) == 1:
1303 self.stopCurrentRecording(0)
1305 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1306 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1308 if answer[1] == "event":
1310 if answer[1] == "manualduration":
1311 self.selectedEntry = len(self.recording)
1312 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1313 self.startInstantRecording(limitEvent = limitEvent)
1315 print "after:\n", self.recording
1317 def changeDuration(self, entry):
1318 if entry is not None:
1319 self.selectedEntry = entry
1320 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1322 def inputCallback(self, value):
1323 if value is not None:
1324 print "stopping recording after", int(value), "minutes."
1325 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1326 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1328 def instantRecord(self):
1330 stat = os_stat(resolveFilename(SCOPE_HDD))
1332 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1335 if self.isInstantRecordRunning():
1336 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")])
1338 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")])
1340 from Tools.ISO639 import LanguageCodes
1342 class InfoBarAudioSelection:
1344 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1346 "audioSelection": (self.audioSelection, _("Audio Options...")),
1349 def audioSelection(self):
1350 service = self.session.nav.getCurrentService()
1351 audio = service and service.audioTracks()
1352 self.audioTracks = audio
1353 n = audio and audio.getNumberOfTracks() or 0
1354 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1356 print "tlist:", tlist
1358 self.audioChannel = service.audioChannel()
1361 i = audio.getTrackInfo(x)
1362 language = i.getLanguage()
1363 description = i.getDescription()
1365 if LanguageCodes.has_key(language):
1366 language = LanguageCodes[language][0]
1368 if len(description):
1369 description += " (" + language + ")"
1371 description = language
1373 tlist.append((description, x))
1375 selectedAudio = tlist[0][1]
1376 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1380 if x[1] != selectedAudio:
1385 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1386 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1388 del self.audioTracks
1390 def audioSelected(self, audio):
1391 if audio is not None:
1392 if isinstance(audio[1], str):
1393 if audio[1] == "mode":
1394 keys = ["red", "green", "yellow"]
1395 selection = self.audioChannel.getCurrentChannel()
1396 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1397 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1399 del self.audioChannel
1400 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1401 self.audioTracks.selectTrack(audio[1])
1403 del self.audioChannel
1404 del self.audioTracks
1406 def modeSelected(self, mode):
1407 if mode is not None:
1408 self.audioChannel.selectChannel(mode[1])
1409 del self.audioChannel
1411 class InfoBarSubserviceSelection:
1413 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1415 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1418 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1420 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1421 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1423 self["SubserviceQuickzapAction"].setEnabled(False)
1425 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1429 def checkSubservicesAvail(self, ev):
1430 if ev == iPlayableService.evUpdatedEventInfo:
1431 service = self.session.nav.getCurrentService()
1432 subservices = service and service.subServices()
1433 if not subservices or subservices.getNumberOfSubservices() == 0:
1434 self["SubserviceQuickzapAction"].setEnabled(False)
1436 def nextSubservice(self):
1437 self.changeSubservice(+1)
1439 def prevSubservice(self):
1440 self.changeSubservice(-1)
1442 def changeSubservice(self, direction):
1443 service = self.session.nav.getCurrentService()
1444 subservices = service and service.subServices()
1445 n = subservices and subservices.getNumberOfSubservices()
1448 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1450 if subservices.getSubservice(x).toString() == ref.toString():
1453 selection += direction
1458 newservice = subservices.getSubservice(selection)
1459 if newservice.valid():
1462 if config.usage.show_infobar_on_zap.value:
1464 self.session.nav.playService(newservice)
1466 def subserviceSelection(self):
1467 service = self.session.nav.getCurrentService()
1468 subservices = service and service.subServices()
1469 self.bouquets = self.servicelist.getBouquetList()
1470 n = subservices and subservices.getNumberOfSubservices()
1473 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1476 i = subservices.getSubservice(x)
1477 if i.toString() == ref.toString():
1479 tlist.append((i.getName(), i))
1481 if self.bouquets and len(self.bouquets):
1482 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1483 if config.usage.multibouquet.value:
1484 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1486 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1489 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1490 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1493 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1495 def subserviceSelected(self, service):
1497 if not service is None:
1498 if isinstance(service[1], str):
1499 if service[1] == "quickzap":
1500 from Screens.SubservicesQuickzap import SubservicesQuickzap
1501 self.session.open(SubservicesQuickzap, service[2])
1503 self["SubserviceQuickzapAction"].setEnabled(True)
1504 if config.usage.show_infobar_on_zap.value:
1506 self.session.nav.playService(service[1])
1508 def addSubserviceToBouquetCallback(self, service):
1509 if len(service) > 1 and isinstance(service[1], eServiceReference):
1510 self.selectedSubservice = service
1511 if self.bouquets is None:
1514 cnt = len(self.bouquets)
1515 if cnt > 1: # show bouquet list
1516 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1517 elif cnt == 1: # add to only one existing bouquet
1518 self.addSubserviceToBouquet(self.bouquets[0][1])
1519 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1521 def bouquetSelClosed(self, confirmed):
1523 del self.selectedSubservice
1525 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1527 def addSubserviceToBouquet(self, dest):
1528 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1530 self.bsel.close(True)
1532 del self.selectedSubservice
1534 class InfoBarAdditionalInfo:
1536 self["NimA"] = Pixmap()
1537 self["NimB"] = Pixmap()
1538 self["NimA_Active"] = Pixmap()
1539 self["NimB_Active"] = Pixmap()
1541 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1542 self["TimeshiftPossible"] = self["RecordingPossible"]
1543 self["ExtensionsAvailable"] = Boolean(fixed=1)
1545 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1546 res_mgr = eDVBResourceManager.getInstance()
1548 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1550 def tunerUseMaskChanged(self, mask):
1552 self["NimA_Active"].show()
1554 self["NimA_Active"].hide()
1556 self["NimB_Active"].show()
1558 self["NimB_Active"].hide()
1560 def checkTunerState(self, service):
1561 info = service.frontendInfo()
1562 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1563 if feNumber is None:
1573 def gotServiceEvent(self, ev):
1574 service = self.session.nav.getCurrentService()
1575 if ev == iPlayableService.evStart:
1576 self.checkTunerState(service)
1578 class InfoBarNotifications:
1580 self.onExecBegin.append(self.checkNotifications)
1581 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1582 self.onClose.append(self.__removeNotification)
1584 def __removeNotification(self):
1585 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1587 def checkNotificationsIfExecing(self):
1589 self.checkNotifications()
1591 def checkNotifications(self):
1592 if len(Notifications.notifications):
1593 n = Notifications.notifications[0]
1595 Notifications.notifications = Notifications.notifications[1:]
1598 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1600 dlg = self.session.open(n[1], *n[2], **n[3])
1602 # remember that this notification is currently active
1604 Notifications.current_notifications.append(d)
1605 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1607 def __notificationClosed(self, d):
1608 Notifications.current_notifications.remove(d)
1610 class InfoBarServiceNotifications:
1612 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1614 iPlayableService.evEnd: self.serviceHasEnded
1617 def serviceHasEnded(self):
1618 print "service end!"
1621 self.setSeekState(self.SEEK_STATE_PLAY)
1625 class InfoBarCueSheetSupport:
1631 ENABLE_RESUME_SUPPORT = False
1634 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1636 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1637 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1638 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1642 self.is_closing = False
1643 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1645 iPlayableService.evStart: self.__serviceStarted,
1648 def __serviceStarted(self):
1651 print "new service started! trying to download cuts!"
1652 self.downloadCuesheet()
1654 if self.ENABLE_RESUME_SUPPORT:
1657 for (pts, what) in self.cut_list:
1658 if what == self.CUT_TYPE_LAST:
1661 if last is not None:
1662 self.resume_point = last
1663 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1665 def playLastCB(self, answer):
1667 seekable = self.__getSeekable()
1668 if seekable is not None:
1669 seekable.seekTo(self.resume_point)
1671 def __getSeekable(self):
1672 service = self.session.nav.getCurrentService()
1675 return service.seek()
1677 def cueGetCurrentPosition(self):
1678 seek = self.__getSeekable()
1681 r = seek.getPlayPosition()
1686 def jumpPreviousNextMark(self, cmp, alternative=None):
1687 current_pos = self.cueGetCurrentPosition()
1688 if current_pos is None:
1690 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1691 if mark is not None:
1693 elif alternative is not None:
1698 seekable = self.__getSeekable()
1699 if seekable is not None:
1700 seekable.seekTo(pts)
1702 def jumpPreviousMark(self):
1703 # we add 2 seconds, so if the play position is <2s after
1704 # the mark, the mark before will be used
1705 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1707 def jumpNextMark(self):
1708 self.jumpPreviousNextMark(lambda x: x)
1710 def getNearestCutPoint(self, pts, cmp=abs):
1713 for cp in self.cut_list:
1714 diff = cmp(cp[0] - pts)
1715 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1719 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1720 current_pos = self.cueGetCurrentPosition()
1721 if current_pos is None:
1722 print "not seekable"
1725 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1727 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1729 return nearest_cutpoint
1731 self.removeMark(nearest_cutpoint)
1732 elif not onlyremove and not onlyreturn:
1733 self.addMark((current_pos, self.CUT_TYPE_MARK))
1738 def addMark(self, point):
1739 insort(self.cut_list, point)
1740 self.uploadCuesheet()
1742 def removeMark(self, point):
1743 self.cut_list.remove(point)
1744 self.uploadCuesheet()
1746 def __getCuesheet(self):
1747 service = self.session.nav.getCurrentService()
1750 return service.cueSheet()
1752 def uploadCuesheet(self):
1753 cue = self.__getCuesheet()
1756 print "upload failed, no cuesheet interface"
1758 cue.setCutList(self.cut_list)
1760 def downloadCuesheet(self):
1761 cue = self.__getCuesheet()
1764 print "upload failed, no cuesheet interface"
1766 self.cut_list = cue.getCutList()
1768 class InfoBarSummary(Screen):
1770 <screen position="0,0" size="132,64">
1771 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1772 <convert type="ClockToText">WithSeconds</convert>
1774 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1775 <convert type="ServiceName">Name</convert>
1779 def __init__(self, session, parent):
1780 Screen.__init__(self, session)
1781 self["CurrentService"] = CurrentService(self.session.nav)
1782 self["CurrentTime"] = Clock()
1784 class InfoBarSummarySupport:
1788 def createSummary(self):
1789 return InfoBarSummary
1791 class InfoBarTeletextPlugin:
1793 self.teletext_plugin = None
1795 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1796 self.teletext_plugin = p
1798 if self.teletext_plugin is not None:
1799 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1801 "startTeletext": (self.startTeletext, _("View teletext..."))
1804 print "no teletext plugin found!"
1806 def startTeletext(self):
1807 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1809 class InfoBarSubtitleSupport(object):
1811 object.__init__(self)
1812 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1813 self.__subtitles_enabled = False
1815 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1817 iPlayableService.evEnd: self.__serviceStopped,
1818 iPlayableService.evUpdatedInfo: self.__updatedInfo
1820 self.cached_subtitle_checked = False
1822 def __serviceStopped(self):
1823 self.subtitle_window.hide()
1824 self.__subtitles_enabled = False
1825 self.cached_subtitle_checked = False
1827 def __updatedInfo(self):
1828 if not self.cached_subtitle_checked:
1829 subtitle = self.getCurrentServiceSubtitle()
1830 self.cached_subtitle_checked = True
1832 self.__selected_subtitle = subtitle.getCachedSubtitle()
1833 if self.__selected_subtitle:
1834 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1835 self.subtitle_window.show()
1836 self.__subtitles_enabled = True
1838 def getCurrentServiceSubtitle(self):
1839 service = self.session.nav.getCurrentService()
1840 return service and service.subtitle()
1842 def setSubtitlesEnable(self, enable=True):
1843 subtitle = self.getCurrentServiceSubtitle()
1844 if enable and self.__selected_subtitle is not None:
1845 if subtitle and not self.__subtitles_enabled:
1846 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1847 self.subtitle_window.show()
1848 self.__subtitles_enabled = True
1851 subtitle.disableSubtitles(self.subtitle_window.instance)
1852 self.__subtitles_enabled = False
1853 self.subtitle_window.hide()
1855 def setSelectedSubtitle(self, subtitle):
1856 self.__selected_subtitle = subtitle
1858 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1859 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1861 class InfoBarServiceErrorPopupSupport:
1863 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1865 iPlayableService.evTuneFailed: self.__tuneFailed,
1866 iPlayableService.evStart: self.__serviceStarted
1868 self.__serviceStarted()
1870 def __serviceStarted(self):
1871 self.last_error = None
1872 Notifications.RemovePopup(id = "ZapError")
1874 def __tuneFailed(self):
1875 service = self.session.nav.getCurrentService()
1876 info = service and service.info()
1877 error = info and info.getInfo(iServiceInformation.sDVBState)
1879 if error == self.last_error:
1882 self.last_error = error
1885 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1886 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1887 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1888 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1889 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1890 eDVBServicePMTHandler.eventNewProgramInfo: None,
1891 eDVBServicePMTHandler.eventTuned: None,
1892 eDVBServicePMTHandler.eventSOF: None,
1893 eDVBServicePMTHandler.eventEOF: None
1896 if error not in errors:
1899 error = error is not None and errors[error]
1901 if error is not None:
1902 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1904 Notifications.RemovePopup(id = "ZapError")