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.execing and self.seekstate != self.SEEK_STATE_PLAY:
871 self.pvrStateDialog.show()
873 def __playStateChanged(self, state):
874 playstateString = state[3]
875 self.pvrStateDialog["state"].setText(playstateString)
878 class InfoBarTimeshiftState(InfoBarPVRState):
880 InfoBarPVRState.__init__(self, screen=TimeshiftState)
883 if self.execing and self.timeshift_enabled:
884 self.pvrStateDialog.show()
886 class InfoBarShowMovies:
888 # i don't really like this class.
889 # it calls a not further specified "movie list" on up/down/movieList,
890 # so this is not more than an action map
892 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
894 "movieList": (self.showMovies, "movie list"),
895 "up": (self.showMovies, "movie list"),
896 "down": (self.showMovies, "movie list")
899 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
903 # Timeshift works the following way:
904 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
905 # - normal playback TUNER unused PLAY enable disable disable
906 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
907 # - user presess pause again FILE record PLAY enable disable enable
908 # - user fast forwards FILE record FF enable disable enable
909 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
910 # - user backwards FILE record BACK # !! enable disable enable
914 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
915 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
916 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
917 # - the user can now PVR around
918 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
919 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
921 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
922 # - if the user rewinds, or press pause, timeshift will be activated again
924 # note that a timeshift can be enabled ("recording") and
925 # activated (currently time-shifting).
927 class InfoBarTimeshift:
929 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
931 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
932 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
934 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
936 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
937 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
938 }, prio=-1) # priority over record
940 self.timeshift_enabled = 0
941 self.timeshift_state = 0
942 self.ts_pause_timer = eTimer()
943 self.ts_pause_timer.timeout.get().append(self.pauseService)
945 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
947 iPlayableService.evStart: self.__serviceStarted,
948 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
951 def getTimeshift(self):
952 service = self.session.nav.getCurrentService()
953 return service and service.timeshift()
955 def startTimeshift(self):
956 print "enable timeshift"
957 ts = self.getTimeshift()
959 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
960 print "no ts interface"
963 if self.timeshift_enabled:
964 print "hu, timeshift already enabled?"
966 if not ts.startTimeshift():
967 self.timeshift_enabled = 1
969 # we remove the "relative time" for now.
970 #self.pvrStateDialog["timeshift"].setRelative(time.time())
973 self.setSeekState(self.SEEK_STATE_PAUSE)
975 # enable the "TimeshiftEnableActions", which will override
976 # the startTimeshift actions
977 self.__seekableStatusChanged()
979 print "timeshift failed"
981 def stopTimeshift(self):
982 if not self.timeshift_enabled:
984 print "disable timeshift"
985 ts = self.getTimeshift()
988 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
990 def stopTimeshiftConfirmed(self, confirmed):
994 ts = self.getTimeshift()
999 self.timeshift_enabled = 0
1002 self.__seekableStatusChanged()
1004 # activates timeshift, and seeks to (almost) the end
1005 def activateTimeshiftEnd(self):
1006 ts = self.getTimeshift()
1011 if ts.isTimeshiftActive():
1012 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1015 self.setSeekState(self.SEEK_STATE_PLAY)
1016 ts.activateTimeshift()
1017 self.seekRelative(0)
1019 # same as activateTimeshiftEnd, but pauses afterwards.
1020 def activateTimeshiftEndAndPause(self):
1021 state = self.seekstate
1022 self.activateTimeshiftEnd()
1024 # well, this is "andPause", but it could be pressed from pause,
1025 # when pausing on the (fake-)"live" picture, so an un-pause
1028 print "now, pauseService"
1029 if state == self.SEEK_STATE_PLAY:
1030 print "is PLAYING, start pause timer"
1031 self.ts_pause_timer.start(200, 1)
1034 self.unPauseService()
1036 def __seekableStatusChanged(self):
1039 print "self.isSeekable", self.isSeekable()
1040 print "self.timeshift_enabled", self.timeshift_enabled
1042 # when this service is not seekable, but timeshift
1043 # is enabled, this means we can activate
1045 if not self.isSeekable() and self.timeshift_enabled:
1048 print "timeshift activate:", enabled
1049 self["TimeshiftActivateActions"].setEnabled(enabled)
1051 def __serviceStarted(self):
1052 self.timeshift_enabled = False
1053 self.__seekableStatusChanged()
1055 from Screens.PiPSetup import PiPSetup
1057 class InfoBarExtensions:
1058 EXTENSION_SINGLE = 0
1064 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1066 "extensions": (self.showExtensionSelection, _("view extensions...")),
1069 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1070 self.list.append((type, extension, key))
1072 def updateExtension(self, extension, key = None):
1073 self.extensionsList.append(extension)
1075 if self.extensionKeys.has_key(key):
1079 for x in self.availableKeys:
1080 if not self.extensionKeys.has_key(x):
1085 self.extensionKeys[key] = len(self.extensionsList) - 1
1087 def updateExtensions(self):
1088 self.extensionsList = []
1089 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1090 self.extensionKeys = {}
1092 if x[0] == self.EXTENSION_SINGLE:
1093 self.updateExtension(x[1], x[2])
1096 self.updateExtension(y[0], y[1])
1099 def showExtensionSelection(self):
1100 self.updateExtensions()
1101 extensionsList = self.extensionsList[:]
1104 for x in self.availableKeys:
1105 if self.extensionKeys.has_key(x):
1106 entry = self.extensionKeys[x]
1107 extension = self.extensionsList[entry]
1109 name = str(extension[0]())
1110 list.append((extension[0](), extension))
1112 extensionsList.remove(extension)
1114 extensionsList.remove(extension)
1115 for x in extensionsList:
1116 list.append((x[0](), x))
1117 keys += [""] * len(extensionsList)
1118 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1120 def extensionCallback(self, answer):
1121 if answer is not None:
1124 from Tools.BoundFunction import boundFunction
1126 # depends on InfoBarExtensions
1127 from Components.PluginComponent import plugins
1129 class InfoBarPlugins:
1131 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1133 def getPluginName(self, name):
1136 def getPluginList(self):
1138 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1139 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1142 def runPlugin(self, plugin):
1143 plugin(session = self.session)
1145 # depends on InfoBarExtensions
1146 class InfoBarSleepTimer:
1148 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1150 def available(self):
1153 def getSleepTimerName(self):
1154 return _("Sleep Timer")
1156 def showSleepTimerSetup(self):
1157 self.session.open(SleepTimerEdit)
1159 # depends on InfoBarExtensions
1162 self.session.pipshown = False
1164 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1165 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1166 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1168 def available(self):
1172 return self.session.pipshown
1174 def getShowHideName(self):
1175 if self.session.pipshown:
1176 return _("Disable Picture in Picture")
1178 return _("Activate Picture in Picture")
1180 def getSwapName(self):
1181 return _("Swap Services")
1183 def getMoveName(self):
1184 return _("Move Picture in Picture")
1187 if self.session.pipshown:
1188 del self.session.pip
1189 self.session.pipshown = False
1191 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1192 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1193 if self.session.pip.playService(newservice):
1194 self.session.pipshown = True
1195 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1197 self.session.pipshown = False
1198 del self.session.pip
1199 self.session.nav.playService(newservice)
1202 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1203 if self.session.pip.servicePath:
1204 servicepath = self.servicelist.getCurrentServicePath()
1205 ref=servicepath[len(servicepath)-1]
1206 pipref=self.session.pip.getCurrentService()
1207 self.session.pip.playService(swapservice)
1208 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1209 if pipref.toString() != ref.toString(): # is a subservice ?
1210 self.session.nav.stopService() # stop portal
1211 self.session.nav.playService(pipref) # start subservice
1212 self.session.pip.servicePath=servicepath
1215 self.session.open(PiPSetup, pip = self.session.pip)
1217 from RecordTimer import parseEvent
1219 class InfoBarInstantRecord:
1220 """Instant Record - handles the instantRecord action in order to
1221 start/stop instant records"""
1223 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1225 "instantRecord": (self.instantRecord, _("Instant Record...")),
1228 self["BlinkingPoint"] = BlinkingPixmapConditional()
1229 self["BlinkingPoint"].hide()
1230 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1232 def stopCurrentRecording(self, entry = -1):
1233 if entry is not None and entry != -1:
1234 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1235 self.recording.remove(self.recording[entry])
1237 def startInstantRecording(self, limitEvent = False):
1238 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1240 # try to get event info
1243 service = self.session.nav.getCurrentService()
1244 epg = eEPGCache.getInstance()
1245 event = epg.lookupEventTime(serviceref, -1, 0)
1247 info = service.info()
1248 ev = info.getEvent(0)
1254 end = time() + 3600 * 10
1255 name = "instant record"
1259 if event is not None:
1260 curEvent = parseEvent(event)
1262 description = curEvent[3]
1263 eventid = curEvent[4]
1268 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1270 data = (begin, end, name, description, eventid)
1272 recording = self.session.nav.recordWithTimer(serviceref, *data)
1273 recording.dontSave = True
1274 self.recording.append(recording)
1276 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1278 def isInstantRecordRunning(self):
1279 print "self.recording:", self.recording
1280 if len(self.recording) > 0:
1281 for x in self.recording:
1286 def recordQuestionCallback(self, answer):
1287 print "pre:\n", self.recording
1289 if answer is None or answer[1] == "no":
1292 recording = self.recording[:]
1294 if not x in self.session.nav.RecordTimer.timer_list:
1295 self.recording.remove(x)
1296 elif x.dontSave and x.isRunning():
1297 list.append(TimerEntryComponent(x, False))
1299 if answer[1] == "changeduration":
1300 if len(self.recording) == 1:
1301 self.changeDuration(0)
1303 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1304 elif answer[1] == "stop":
1305 if len(self.recording) == 1:
1306 self.stopCurrentRecording(0)
1308 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1309 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1311 if answer[1] == "event":
1313 if answer[1] == "manualduration":
1314 self.selectedEntry = len(self.recording)
1315 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1316 self.startInstantRecording(limitEvent = limitEvent)
1318 print "after:\n", self.recording
1320 def changeDuration(self, entry):
1321 if entry is not None:
1322 self.selectedEntry = entry
1323 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1325 def inputCallback(self, value):
1326 if value is not None:
1327 print "stopping recording after", int(value), "minutes."
1328 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1329 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1331 def instantRecord(self):
1333 stat = os_stat(resolveFilename(SCOPE_HDD))
1335 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1338 if self.isInstantRecordRunning():
1339 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, 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")])
1341 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")])
1343 from Tools.ISO639 import LanguageCodes
1345 class InfoBarAudioSelection:
1347 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1349 "audioSelection": (self.audioSelection, _("Audio Options...")),
1352 def audioSelection(self):
1353 service = self.session.nav.getCurrentService()
1354 audio = service and service.audioTracks()
1355 self.audioTracks = audio
1356 n = audio and audio.getNumberOfTracks() or 0
1357 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1359 print "tlist:", tlist
1361 self.audioChannel = service.audioChannel()
1364 i = audio.getTrackInfo(x)
1365 language = i.getLanguage()
1366 description = i.getDescription()
1368 if LanguageCodes.has_key(language):
1369 language = LanguageCodes[language][0]
1371 if len(description):
1372 description += " (" + language + ")"
1374 description = language
1376 tlist.append((description, x))
1378 selectedAudio = tlist[0][1]
1379 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1383 if x[1] != selectedAudio:
1388 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1389 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1391 del self.audioTracks
1393 def audioSelected(self, audio):
1394 if audio is not None:
1395 if isinstance(audio[1], str):
1396 if audio[1] == "mode":
1397 keys = ["red", "green", "yellow"]
1398 selection = self.audioChannel.getCurrentChannel()
1399 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1400 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1402 del self.audioChannel
1403 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1404 self.audioTracks.selectTrack(audio[1])
1406 del self.audioChannel
1407 del self.audioTracks
1409 def modeSelected(self, mode):
1410 if mode is not None:
1411 self.audioChannel.selectChannel(mode[1])
1412 del self.audioChannel
1414 class InfoBarSubserviceSelection:
1416 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1418 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1421 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1423 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1424 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1426 self["SubserviceQuickzapAction"].setEnabled(False)
1428 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1432 def checkSubservicesAvail(self, ev):
1433 if ev == iPlayableService.evUpdatedEventInfo:
1434 service = self.session.nav.getCurrentService()
1435 subservices = service and service.subServices()
1436 if not subservices or subservices.getNumberOfSubservices() == 0:
1437 self["SubserviceQuickzapAction"].setEnabled(False)
1439 def nextSubservice(self):
1440 self.changeSubservice(+1)
1442 def prevSubservice(self):
1443 self.changeSubservice(-1)
1445 def changeSubservice(self, direction):
1446 service = self.session.nav.getCurrentService()
1447 subservices = service and service.subServices()
1448 n = subservices and subservices.getNumberOfSubservices()
1451 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1453 if subservices.getSubservice(x).toString() == ref.toString():
1456 selection += direction
1461 newservice = subservices.getSubservice(selection)
1462 if newservice.valid():
1465 if config.usage.show_infobar_on_zap.value:
1467 self.session.nav.playService(newservice)
1469 def subserviceSelection(self):
1470 service = self.session.nav.getCurrentService()
1471 subservices = service and service.subServices()
1472 self.bouquets = self.servicelist.getBouquetList()
1473 n = subservices and subservices.getNumberOfSubservices()
1476 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1479 i = subservices.getSubservice(x)
1480 if i.toString() == ref.toString():
1482 tlist.append((i.getName(), i))
1484 if self.bouquets and len(self.bouquets):
1485 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1486 if config.usage.multibouquet.value:
1487 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1489 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1492 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1493 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1496 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1498 def subserviceSelected(self, service):
1500 if not service is None:
1501 if isinstance(service[1], str):
1502 if service[1] == "quickzap":
1503 from Screens.SubservicesQuickzap import SubservicesQuickzap
1504 self.session.open(SubservicesQuickzap, service[2])
1506 self["SubserviceQuickzapAction"].setEnabled(True)
1507 if config.usage.show_infobar_on_zap.value:
1509 self.session.nav.playService(service[1])
1511 def addSubserviceToBouquetCallback(self, service):
1512 if len(service) > 1 and isinstance(service[1], eServiceReference):
1513 self.selectedSubservice = service
1514 if self.bouquets is None:
1517 cnt = len(self.bouquets)
1518 if cnt > 1: # show bouquet list
1519 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1520 elif cnt == 1: # add to only one existing bouquet
1521 self.addSubserviceToBouquet(self.bouquets[0][1])
1522 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1524 def bouquetSelClosed(self, confirmed):
1526 del self.selectedSubservice
1528 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1530 def addSubserviceToBouquet(self, dest):
1531 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1533 self.bsel.close(True)
1535 del self.selectedSubservice
1537 class InfoBarAdditionalInfo:
1539 self["NimA"] = Pixmap()
1540 self["NimB"] = Pixmap()
1541 self["NimA_Active"] = Pixmap()
1542 self["NimB_Active"] = Pixmap()
1544 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1545 self["TimeshiftPossible"] = self["RecordingPossible"]
1546 self["ExtensionsAvailable"] = Boolean(fixed=1)
1548 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1549 res_mgr = eDVBResourceManager.getInstance()
1551 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1553 def tunerUseMaskChanged(self, mask):
1555 self["NimA_Active"].show()
1557 self["NimA_Active"].hide()
1559 self["NimB_Active"].show()
1561 self["NimB_Active"].hide()
1563 def checkTunerState(self, service):
1564 info = service.frontendInfo()
1565 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1566 if feNumber is None:
1576 def gotServiceEvent(self, ev):
1577 service = self.session.nav.getCurrentService()
1578 if ev == iPlayableService.evStart:
1579 self.checkTunerState(service)
1581 class InfoBarNotifications:
1583 self.onExecBegin.append(self.checkNotifications)
1584 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1585 self.onClose.append(self.__removeNotification)
1587 def __removeNotification(self):
1588 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1590 def checkNotificationsIfExecing(self):
1592 self.checkNotifications()
1594 def checkNotifications(self):
1595 if len(Notifications.notifications):
1596 n = Notifications.notifications[0]
1598 Notifications.notifications = Notifications.notifications[1:]
1601 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1603 dlg = self.session.open(n[1], *n[2], **n[3])
1605 # remember that this notification is currently active
1607 Notifications.current_notifications.append(d)
1608 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1610 def __notificationClosed(self, d):
1611 Notifications.current_notifications.remove(d)
1613 class InfoBarServiceNotifications:
1615 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1617 iPlayableService.evEnd: self.serviceHasEnded
1620 def serviceHasEnded(self):
1621 print "service end!"
1624 self.setSeekState(self.SEEK_STATE_PLAY)
1628 class InfoBarCueSheetSupport:
1634 ENABLE_RESUME_SUPPORT = False
1637 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1639 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1640 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1641 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1645 self.is_closing = False
1646 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1648 iPlayableService.evStart: self.__serviceStarted,
1651 def __serviceStarted(self):
1654 print "new service started! trying to download cuts!"
1655 self.downloadCuesheet()
1657 if self.ENABLE_RESUME_SUPPORT:
1660 for (pts, what) in self.cut_list:
1661 if what == self.CUT_TYPE_LAST:
1664 if last is not None:
1665 self.resume_point = last
1666 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1668 def playLastCB(self, answer):
1670 seekable = self.__getSeekable()
1671 if seekable is not None:
1672 seekable.seekTo(self.resume_point)
1674 def __getSeekable(self):
1675 service = self.session.nav.getCurrentService()
1678 return service.seek()
1680 def cueGetCurrentPosition(self):
1681 seek = self.__getSeekable()
1684 r = seek.getPlayPosition()
1689 def jumpPreviousNextMark(self, cmp, alternative=None):
1690 current_pos = self.cueGetCurrentPosition()
1691 if current_pos is None:
1693 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1694 if mark is not None:
1696 elif alternative is not None:
1701 seekable = self.__getSeekable()
1702 if seekable is not None:
1703 seekable.seekTo(pts)
1705 def jumpPreviousMark(self):
1706 # we add 2 seconds, so if the play position is <2s after
1707 # the mark, the mark before will be used
1708 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1710 def jumpNextMark(self):
1711 self.jumpPreviousNextMark(lambda x: x)
1713 def getNearestCutPoint(self, pts, cmp=abs):
1716 for cp in self.cut_list:
1717 diff = cmp(cp[0] - pts)
1718 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1722 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1723 current_pos = self.cueGetCurrentPosition()
1724 if current_pos is None:
1725 print "not seekable"
1728 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1730 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1732 return nearest_cutpoint
1734 self.removeMark(nearest_cutpoint)
1735 elif not onlyremove and not onlyreturn:
1736 self.addMark((current_pos, self.CUT_TYPE_MARK))
1741 def addMark(self, point):
1742 insort(self.cut_list, point)
1743 self.uploadCuesheet()
1745 def removeMark(self, point):
1746 self.cut_list.remove(point)
1747 self.uploadCuesheet()
1749 def __getCuesheet(self):
1750 service = self.session.nav.getCurrentService()
1753 return service.cueSheet()
1755 def uploadCuesheet(self):
1756 cue = self.__getCuesheet()
1759 print "upload failed, no cuesheet interface"
1761 cue.setCutList(self.cut_list)
1763 def downloadCuesheet(self):
1764 cue = self.__getCuesheet()
1767 print "upload failed, no cuesheet interface"
1769 self.cut_list = cue.getCutList()
1771 class InfoBarSummary(Screen):
1773 <screen position="0,0" size="132,64">
1774 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1775 <convert type="ClockToText">WithSeconds</convert>
1777 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1778 <convert type="ServiceName">Name</convert>
1782 def __init__(self, session, parent):
1783 Screen.__init__(self, session)
1784 self["CurrentService"] = CurrentService(self.session.nav)
1785 self["CurrentTime"] = Clock()
1787 class InfoBarSummarySupport:
1791 def createSummary(self):
1792 return InfoBarSummary
1794 class InfoBarTeletextPlugin:
1796 self.teletext_plugin = None
1798 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1799 self.teletext_plugin = p
1801 if self.teletext_plugin is not None:
1802 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1804 "startTeletext": (self.startTeletext, _("View teletext..."))
1807 print "no teletext plugin found!"
1809 def startTeletext(self):
1810 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1812 class InfoBarSubtitleSupport(object):
1814 object.__init__(self)
1815 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1816 self.__subtitles_enabled = False
1818 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1820 iPlayableService.evEnd: self.__serviceStopped,
1821 iPlayableService.evUpdatedInfo: self.__updatedInfo
1823 self.cached_subtitle_checked = False
1825 def __serviceStopped(self):
1826 self.subtitle_window.hide()
1827 self.__subtitles_enabled = False
1828 self.cached_subtitle_checked = False
1830 def __updatedInfo(self):
1831 if not self.cached_subtitle_checked:
1832 subtitle = self.getCurrentServiceSubtitle()
1833 self.cached_subtitle_checked = True
1835 self.__selected_subtitle = subtitle.getCachedSubtitle()
1836 if self.__selected_subtitle:
1837 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1838 self.subtitle_window.show()
1839 self.__subtitles_enabled = True
1841 def getCurrentServiceSubtitle(self):
1842 service = self.session.nav.getCurrentService()
1843 return service and service.subtitle()
1845 def setSubtitlesEnable(self, enable=True):
1846 subtitle = self.getCurrentServiceSubtitle()
1847 if enable and self.__selected_subtitle is not None:
1848 if subtitle and not self.__subtitles_enabled:
1849 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1850 self.subtitle_window.show()
1851 self.__subtitles_enabled = True
1854 subtitle.disableSubtitles(self.subtitle_window.instance)
1855 self.__subtitles_enabled = False
1856 self.subtitle_window.hide()
1858 def setSelectedSubtitle(self, subtitle):
1859 self.__selected_subtitle = subtitle
1861 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1862 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1864 class InfoBarServiceErrorPopupSupport:
1866 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1868 iPlayableService.evTuneFailed: self.__tuneFailed,
1869 iPlayableService.evStart: self.__serviceStarted
1871 self.__serviceStarted()
1873 def __serviceStarted(self):
1874 self.last_error = None
1875 Notifications.RemovePopup(id = "ZapError")
1877 def __tuneFailed(self):
1878 service = self.session.nav.getCurrentService()
1879 info = service and service.info()
1880 error = info and info.getInfo(iServiceInformation.sDVBState)
1882 if error == self.last_error:
1885 self.last_error = error
1888 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1889 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1890 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1891 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1892 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1893 eDVBServicePMTHandler.eventNewProgramInfo: None,
1894 eDVBServicePMTHandler.eventTuned: None,
1895 eDVBServicePMTHandler.eventSOF: None,
1896 eDVBServicePMTHandler.eventEOF: None
1899 if error not in errors:
1902 error = error is not None and errors[error]
1904 if error is not None:
1905 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1907 Notifications.RemovePopup(id = "ZapError")