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 *
41 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
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 if serviceIterator.flags: #assume normal dvb service have no flags set
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 bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
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.flagDirectory) != eServiceReference.flagDirectory:
235 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
236 if not service is None:
237 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
238 self.servicelist.clearPath()
239 if self.servicelist.bouquet_root != bouquet:
240 self.servicelist.enterPath(self.servicelist.bouquet_root)
241 self.servicelist.enterPath(bouquet)
242 self.servicelist.setCurrentSelection(service) #select the service in servicelist
243 self.servicelist.zap()
245 config.misc.initialchannelselection = ConfigBoolean(default = True)
247 class InfoBarChannelSelection:
248 """ ChannelSelection - handles the channelSelection dialog and the initial
249 channelChange actions which open the channelSelection dialog """
252 self.servicelist = self.session.instantiateDialog(ChannelSelection)
254 if config.misc.initialchannelselection.value:
255 self.onShown.append(self.firstRun)
257 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
259 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
260 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
261 "zapUp": (self.zapUp, _("previous channel")),
262 "zapDown": (self.zapDown, _("next channel")),
263 "historyBack": (self.historyBack, _("previous channel in history")),
264 "historyNext": (self.historyNext, _("next channel in history")),
265 "openServiceList": (self.openServiceList, _("open servicelist")),
268 def showTvChannelList(self, zap=False):
269 self.servicelist.setModeTv()
271 self.servicelist.zap()
272 self.session.execDialog(self.servicelist)
274 def showRadioChannelList(self, zap=False):
275 self.servicelist.setModeRadio()
277 self.servicelist.zap()
278 self.session.execDialog(self.servicelist)
281 self.onShown.remove(self.firstRun)
282 config.misc.initialchannelselection.value = False
283 config.misc.initialchannelselection.save()
284 self.switchChannelDown()
286 def historyBack(self):
287 self.servicelist.historyBack()
289 def historyNext(self):
290 self.servicelist.historyNext()
292 def switchChannelUp(self):
293 self.servicelist.moveUp()
294 self.session.execDialog(self.servicelist)
296 def switchChannelDown(self):
297 self.servicelist.moveDown()
298 self.session.execDialog(self.servicelist)
300 def openServiceList(self):
301 self.session.execDialog(self.servicelist)
304 if self.servicelist.inBouquet():
305 prev = self.servicelist.getCurrentSelection()
307 prev = prev.toString()
309 if config.usage.quickzap_bouquet_change.value:
310 if self.servicelist.atBegin():
311 self.servicelist.prevBouquet()
312 self.servicelist.moveUp()
313 cur = self.servicelist.getCurrentSelection()
314 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
317 self.servicelist.moveUp()
318 self.servicelist.zap()
319 if config.usage.show_infobar_on_zap.value:
323 if self.servicelist.inBouquet():
324 prev = self.servicelist.getCurrentSelection()
326 prev = prev.toString()
328 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
329 self.servicelist.nextBouquet()
331 self.servicelist.moveDown()
332 cur = self.servicelist.getCurrentSelection()
333 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
336 self.servicelist.moveDown()
337 self.servicelist.zap()
338 if config.usage.show_infobar_on_zap.value:
342 """ Handles a menu action, to open the (main) menu """
344 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
346 "mainMenu": (self.mainMenu, _("Enter main menu...")),
348 self.session.infobar = None
351 print "loading mainmenu XML..."
352 menu = mdom.childNodes[0]
353 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
355 self.session.infobar = self
356 # so we can access the currently active infobar from screens opened from within the mainmenu
357 # at the moment used from the SubserviceSelection
359 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
361 def mainMenuClosed(self, *val):
362 self.session.infobar = None
364 class InfoBarSimpleEventView:
365 """ Opens the Eventview for now/next """
367 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
369 "showEventInfo": (self.openEventView, _("show event details")),
372 def openEventView(self):
374 service = self.session.nav.getCurrentService()
375 ref = self.session.nav.getCurrentlyPlayingServiceReference()
376 info = service.info()
379 self.epglist.append(ptr)
382 self.epglist.append(ptr)
383 if len(self.epglist) > 0:
384 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
386 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
387 if len(self.epglist) > 1:
388 tmp = self.epglist[0]
389 self.epglist[0]=self.epglist[1]
391 setEvent(self.epglist[0])
394 """ EPG - Opens an EPG list when the showEPGList action fires """
396 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
398 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
401 self.is_now_next = False
403 self.bouquetSel = None
404 self.eventView = None
405 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
407 "showEventInfo": (self.openEventView, _("show EPG...")),
410 def zapToService(self, service):
411 if not service is None:
412 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
413 self.servicelist.clearPath()
414 if self.servicelist.bouquet_root != self.epg_bouquet:
415 self.servicelist.enterPath(self.servicelist.bouquet_root)
416 self.servicelist.enterPath(self.epg_bouquet)
417 self.servicelist.setCurrentSelection(service) #select the service in servicelist
418 self.servicelist.zap()
420 def getBouquetServices(self, bouquet):
422 servicelist = eServiceCenter.getInstance().list(bouquet)
423 if not servicelist is None:
425 service = servicelist.getNext()
426 if not service.valid(): #check if end of list
428 if service.flags: #ignore non playable services
430 services.append(ServiceReference(service))
433 def openBouquetEPG(self, bouquet, withCallback=True):
434 services = self.getBouquetServices(bouquet)
436 self.epg_bouquet = bouquet
438 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
440 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
442 def changeBouquetCB(self, direction, epg):
445 self.bouquetSel.down()
448 bouquet = self.bouquetSel.getCurrent()
449 services = self.getBouquetServices(bouquet)
451 self.epg_bouquet = bouquet
452 epg.setServices(services)
454 def closed(self, ret=False):
455 closedScreen = self.dlg_stack.pop()
456 if self.bouquetSel and closedScreen == self.bouquetSel:
457 self.bouquetSel = None
458 elif self.eventView and closedScreen == self.eventView:
459 self.eventView = None
461 dlgs=len(self.dlg_stack)
463 self.dlg_stack[dlgs-1].close(dlgs > 1)
465 def openMultiServiceEPG(self, withCallback=True):
466 bouquets = self.servicelist.getBouquetList()
471 if cnt > 1: # show bouquet list
473 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
474 self.dlg_stack.append(self.bouquetSel)
476 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
478 self.openBouquetEPG(bouquets[0][1], withCallback)
480 def openSingleServiceEPG(self):
481 ref=self.session.nav.getCurrentlyPlayingServiceReference()
482 self.session.open(EPGSelection, ref)
484 def openSimilarList(self, eventid, refstr):
485 self.session.open(EPGSelection, refstr, None, eventid)
487 def getNowNext(self):
489 service = self.session.nav.getCurrentService()
490 info = service and service.info()
491 ptr = info and info.getEvent(0)
493 self.epglist.append(ptr)
494 ptr = info and info.getEvent(1)
496 self.epglist.append(ptr)
498 def __evEventInfoChanged(self):
499 if self.is_now_next and len(self.dlg_stack) == 1:
501 assert self.eventView
502 if len(self.epglist):
503 self.eventView.setEvent(self.epglist[0])
505 def openEventView(self):
506 ref = self.session.nav.getCurrentlyPlayingServiceReference()
508 if len(self.epglist) == 0:
509 self.is_now_next = False
510 epg = eEPGCache.getInstance()
511 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
513 self.epglist.append(ptr)
514 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
516 self.epglist.append(ptr)
518 self.is_now_next = True
519 if len(self.epglist) > 0:
520 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
521 self.dlg_stack.append(self.eventView)
523 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
524 self.openMultiServiceEPG(False)
526 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
527 if len(self.epglist) > 1:
528 tmp = self.epglist[0]
529 self.epglist[0]=self.epglist[1]
531 setEvent(self.epglist[0])
534 """provides a snr/agc/ber display"""
536 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
539 """provides a current/next event info display"""
541 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
542 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
544 class InfoBarRadioText:
545 """provides radio (RDS) text info display"""
547 self["RadioText"] = RadioText(self.session.nav)
549 class InfoBarServiceName:
551 self["CurrentService"] = CurrentService(self.session.nav)
554 """handles actions like seeking, pause"""
556 # ispause, isff, issm
557 SEEK_STATE_PLAY = (0, 0, 0, ">")
558 SEEK_STATE_PAUSE = (1, 0, 0, "||")
559 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
560 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
561 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
562 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
563 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
564 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
566 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
567 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
568 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
569 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
571 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
572 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
573 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
576 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
578 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
579 iPlayableService.evStart: self.__serviceStarted,
581 iPlayableService.evEOF: self.__evEOF,
582 iPlayableService.evSOF: self.__evSOF,
585 class InfoBarSeekActionMap(HelpableActionMap):
586 def __init__(self, screen, *args, **kwargs):
587 HelpableActionMap.__init__(self, screen, *args, **kwargs)
590 def action(self, contexts, action):
591 if action[:5] == "seek:":
592 time = int(action[5:])
593 self.screen.seekRelative(time * 90000)
596 return HelpableActionMap.action(self, contexts, action)
598 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
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 pauseService(self):
698 if self.seekstate == self.SEEK_STATE_PAUSE:
699 print "pause, but in fact unpause"
700 self.unPauseService()
702 if self.seekstate == self.SEEK_STATE_PLAY:
703 print "yes, playing."
705 print "no", self.seekstate
707 self.setSeekState(self.SEEK_STATE_PAUSE);
709 def unPauseService(self):
711 if self.seekstate == self.SEEK_STATE_PLAY:
713 self.setSeekState(self.SEEK_STATE_PLAY)
715 def doSeek(self, seektime):
716 print "doseek", seektime
717 service = self.session.nav.getCurrentService()
721 seekable = self.getSeek()
725 seekable.seekTo(90 * seektime)
727 def seekFwdDown(self):
728 print "start fwd timer"
730 self.fwdKeyTimer.start(1000)
732 def seekBackDown(self):
733 print "start rewind timer"
735 self.rwdKeyTimer.start(1000)
740 self.fwdKeyTimer.stop()
741 self.fwdtimer = False
746 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
747 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
748 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
749 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
750 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
751 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
752 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
753 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
754 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
755 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
756 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
757 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
758 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
759 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
760 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
762 self.setSeekState(lookup[self.seekstate])
764 def seekBackUp(self):
767 self.rwdKeyTimer.stop()
768 self.rwdtimer = False
773 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
774 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
775 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
776 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
777 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
778 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
779 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
780 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
781 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
782 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
783 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
784 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
785 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
786 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
787 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
789 self.setSeekState(lookup[self.seekstate])
791 if self.seekstate == self.SEEK_STATE_PAUSE:
792 seekable = self.getSeek()
793 if seekable is not None:
794 seekable.seekRelative(-1, 3)
796 def fwdTimerFire(self):
797 print "Display seek fwd"
798 self.fwdKeyTimer.stop()
799 self.fwdtimer = False
800 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
802 def fwdSeekTo(self, minutes):
803 print "Seek", minutes, "minutes forward"
805 seekable = self.getSeek()
806 if seekable is not None:
807 seekable.seekRelative(1, minutes * 60 * 90000)
809 def rwdTimerFire(self):
811 self.rwdKeyTimer.stop()
812 self.rwdtimer = False
813 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
815 def rwdSeekTo(self, minutes):
817 self.fwdSeekTo(0 - minutes)
819 def checkSkipShowHideLock(self):
820 wantlock = self.seekstate != self.SEEK_STATE_PLAY
822 if config.usage.show_infobar_on_zap.value:
823 if self.lockedBecauseOfSkipping and not wantlock:
825 self.lockedBecauseOfSkipping = False
827 if wantlock and not self.lockedBecauseOfSkipping:
829 self.lockedBecauseOfSkipping = True
832 if self.seekstate != self.SEEK_STATE_PLAY:
833 self.setSeekState(self.SEEK_STATE_PAUSE)
835 #self.getSeek().seekRelative(1, -90000)
836 self.setSeekState(self.SEEK_STATE_PLAY)
838 self.setSeekState(self.SEEK_STATE_PAUSE)
841 self.setSeekState(self.SEEK_STATE_PLAY)
844 def seekRelative(self, diff):
845 seekable = self.getSeek()
846 if seekable is not None:
847 seekable.seekRelative(1, diff)
849 def seekAbsolute(self, abs):
850 seekable = self.getSeek()
851 if seekable is not None:
854 from Screens.PVRState import PVRState, TimeshiftState
856 class InfoBarPVRState:
857 def __init__(self, screen=PVRState):
858 self.onPlayStateChanged.append(self.__playStateChanged)
859 self.pvrStateDialog = self.session.instantiateDialog(screen)
860 self.onShow.append(self.__mayShow)
861 self.onHide.append(self.pvrStateDialog.hide)
864 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
865 self.pvrStateDialog.show()
867 def __playStateChanged(self, state):
868 playstateString = state[3]
869 self.pvrStateDialog["state"].setText(playstateString)
872 class InfoBarTimeshiftState(InfoBarPVRState):
874 InfoBarPVRState.__init__(self, screen=TimeshiftState)
876 class InfoBarShowMovies:
878 # i don't really like this class.
879 # it calls a not further specified "movie list" on up/down/movieList,
880 # so this is not more than an action map
882 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
884 "movieList": (self.showMovies, "movie list"),
885 "up": (self.showMovies, "movie list"),
886 "down": (self.showMovies, "movie list")
889 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
893 # Timeshift works the following way:
894 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
895 # - normal playback TUNER unused PLAY enable disable disable
896 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
897 # - user presess pause again FILE record PLAY enable disable enable
898 # - user fast forwards FILE record FF enable disable enable
899 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
900 # - user backwards FILE record BACK # !! enable disable enable
904 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
905 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
906 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
907 # - the user can now PVR around
908 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
909 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
911 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
912 # - if the user rewinds, or press pause, timeshift will be activated again
914 # note that a timeshift can be enabled ("recording") and
915 # activated (currently time-shifting).
917 class InfoBarTimeshift:
919 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
921 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
922 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
924 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
926 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
927 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
928 }, prio=-1) # priority over record
930 self.timeshift_enabled = 0
931 self.timeshift_state = 0
932 self.ts_pause_timer = eTimer()
933 self.ts_pause_timer.timeout.get().append(self.pauseService)
935 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
937 iPlayableService.evStart: self.__serviceStarted,
938 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
941 def getTimeshift(self):
942 service = self.session.nav.getCurrentService()
943 return service and service.timeshift()
945 def startTimeshift(self):
946 print "enable timeshift"
947 ts = self.getTimeshift()
949 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
950 print "no ts interface"
953 if self.timeshift_enabled:
954 print "hu, timeshift already enabled?"
956 if not ts.startTimeshift():
958 self.timeshift_enabled = 1
960 # we remove the "relative time" for now.
961 #self.pvrStateDialog["timeshift"].setRelative(time.time())
964 self.setSeekState(self.SEEK_STATE_PAUSE)
966 # enable the "TimeshiftEnableActions", which will override
967 # the startTimeshift actions
968 self.__seekableStatusChanged()
970 print "timeshift failed"
972 def stopTimeshift(self):
973 if not self.timeshift_enabled:
975 print "disable timeshift"
976 ts = self.getTimeshift()
979 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
981 def stopTimeshiftConfirmed(self, confirmed):
985 ts = self.getTimeshift()
990 self.timeshift_enabled = 0
993 self.__seekableStatusChanged()
995 # activates timeshift, and seeks to (almost) the end
996 def activateTimeshiftEnd(self):
997 ts = self.getTimeshift()
1002 if ts.isTimeshiftActive():
1003 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1006 self.setSeekState(self.SEEK_STATE_PLAY)
1007 ts.activateTimeshift()
1008 self.seekRelative(0)
1010 # same as activateTimeshiftEnd, but pauses afterwards.
1011 def activateTimeshiftEndAndPause(self):
1012 state = self.seekstate
1013 self.activateTimeshiftEnd()
1015 # well, this is "andPause", but it could be pressed from pause,
1016 # when pausing on the (fake-)"live" picture, so an un-pause
1019 print "now, pauseService"
1020 if state == self.SEEK_STATE_PLAY:
1021 print "is PLAYING, start pause timer"
1022 self.ts_pause_timer.start(200, 1)
1025 self.unPauseService()
1027 def __seekableStatusChanged(self):
1030 print "self.isSeekable", self.isSeekable()
1031 print "self.timeshift_enabled", self.timeshift_enabled
1033 # when this service is not seekable, but timeshift
1034 # is enabled, this means we can activate
1036 if not self.isSeekable() and self.timeshift_enabled:
1039 print "timeshift activate:", enabled
1040 self["TimeshiftActivateActions"].setEnabled(enabled)
1042 def __serviceStarted(self):
1043 self.timeshift_enabled = False
1044 self.__seekableStatusChanged()
1046 from Screens.PiPSetup import PiPSetup
1048 class InfoBarExtensions:
1049 EXTENSION_SINGLE = 0
1055 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1057 "extensions": (self.showExtensionSelection, _("view extensions...")),
1060 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1061 self.list.append((type, extension, key))
1063 def updateExtension(self, extension, key = None):
1064 self.extensionsList.append(extension)
1066 if self.extensionKeys.has_key(key):
1070 for x in self.availableKeys:
1071 if not self.extensionKeys.has_key(x):
1076 self.extensionKeys[key] = len(self.extensionsList) - 1
1078 def updateExtensions(self):
1079 self.extensionsList = []
1080 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1081 self.extensionKeys = {}
1083 if x[0] == self.EXTENSION_SINGLE:
1084 self.updateExtension(x[1], x[2])
1087 self.updateExtension(y[0], y[1])
1090 def showExtensionSelection(self):
1091 self.updateExtensions()
1092 extensionsList = self.extensionsList[:]
1095 for x in self.availableKeys:
1096 if self.extensionKeys.has_key(x):
1097 entry = self.extensionKeys[x]
1098 extension = self.extensionsList[entry]
1100 name = str(extension[0]())
1101 list.append((extension[0](), extension))
1103 extensionsList.remove(extension)
1105 extensionsList.remove(extension)
1106 for x in extensionsList:
1107 list.append((x[0](), x))
1108 keys += [""] * len(extensionsList)
1109 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1111 def extensionCallback(self, answer):
1112 if answer is not None:
1115 from Tools.BoundFunction import boundFunction
1117 # depends on InfoBarExtensions
1118 from Components.PluginComponent import plugins
1120 class InfoBarPlugins:
1122 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1124 def getPluginName(self, name):
1127 def getPluginList(self):
1129 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1130 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1133 def runPlugin(self, plugin):
1134 plugin(session = self.session)
1136 # depends on InfoBarExtensions
1137 class InfoBarSleepTimer:
1139 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1141 def available(self):
1144 def getSleepTimerName(self):
1145 return _("Sleep Timer")
1147 def showSleepTimerSetup(self):
1148 self.session.open(SleepTimerEdit)
1150 # depends on InfoBarExtensions
1153 self.session.pipshown = False
1155 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1156 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1157 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1159 def available(self):
1163 return self.session.pipshown
1165 def getShowHideName(self):
1166 if self.session.pipshown:
1167 return _("Disable Picture in Picture")
1169 return _("Activate Picture in Picture")
1171 def getSwapName(self):
1172 return _("Swap Services")
1174 def getMoveName(self):
1175 return _("Move Picture in Picture")
1178 if self.session.pipshown:
1179 del self.session.pip
1180 self.session.pipshown = False
1182 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1183 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1184 if self.session.pip.playService(newservice):
1185 self.session.pipshown = True
1186 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1188 self.session.pipshown = False
1189 del self.session.pip
1190 self.session.nav.playService(newservice)
1193 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1194 if self.session.pip.servicePath:
1195 servicepath = self.servicelist.getCurrentServicePath()
1196 ref=servicepath[len(servicepath)-1]
1197 pipref=self.session.pip.getCurrentService()
1198 self.session.pip.playService(swapservice)
1199 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1200 if pipref.toString() != ref.toString(): # is a subservice ?
1201 self.session.nav.stopService() # stop portal
1202 self.session.nav.playService(pipref) # start subservice
1203 self.session.pip.servicePath=servicepath
1206 self.session.open(PiPSetup, pip = self.session.pip)
1208 from RecordTimer import parseEvent
1210 class InfoBarInstantRecord:
1211 """Instant Record - handles the instantRecord action in order to
1212 start/stop instant records"""
1214 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1216 "instantRecord": (self.instantRecord, _("Instant Record...")),
1219 self["BlinkingPoint"] = BlinkingPixmapConditional()
1220 self["BlinkingPoint"].hide()
1221 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1223 def stopCurrentRecording(self, entry = -1):
1224 if entry is not None and entry != -1:
1225 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1226 self.recording.remove(self.recording[entry])
1228 def startInstantRecording(self, limitEvent = False):
1229 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1231 # try to get event info
1234 service = self.session.nav.getCurrentService()
1235 epg = eEPGCache.getInstance()
1236 event = epg.lookupEventTime(serviceref, -1, 0)
1238 info = service.info()
1239 ev = info.getEvent(0)
1245 end = time.time() + 3600 * 10
1246 name = "instant record"
1250 if event is not None:
1251 curEvent = parseEvent(event)
1253 description = curEvent[3]
1254 eventid = curEvent[4]
1259 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1261 data = (begin, end, name, description, eventid)
1263 recording = self.session.nav.recordWithTimer(serviceref, *data)
1264 recording.dontSave = True
1265 self.recording.append(recording)
1267 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1269 def isInstantRecordRunning(self):
1270 print "self.recording:", self.recording
1271 if len(self.recording) > 0:
1272 for x in self.recording:
1277 def recordQuestionCallback(self, answer):
1278 print "pre:\n", self.recording
1280 if answer is None or answer[1] == "no":
1283 recording = self.recording[:]
1285 if not x in self.session.nav.RecordTimer.timer_list:
1286 self.recording.remove(x)
1287 elif x.dontSave and x.isRunning():
1288 list.append(TimerEntryComponent(x, False))
1290 if answer[1] == "changeduration":
1291 if len(self.recording) == 1:
1292 self.changeDuration(0)
1294 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1295 elif answer[1] == "stop":
1296 if len(self.recording) == 1:
1297 self.stopCurrentRecording(0)
1299 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1300 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1302 if answer[1] == "event":
1304 if answer[1] == "manualduration":
1305 self.selectedEntry = len(self.recording)
1306 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1307 self.startInstantRecording(limitEvent = limitEvent)
1309 print "after:\n", self.recording
1311 def changeDuration(self, entry):
1312 if entry is not None:
1313 self.selectedEntry = entry
1314 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1316 def inputCallback(self, value):
1317 if value is not None:
1318 print "stopping recording after", int(value), "minutes."
1319 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1320 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1322 def instantRecord(self):
1324 stat = os.stat(resolveFilename(SCOPE_HDD))
1326 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1329 if self.isInstantRecordRunning():
1330 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")])
1332 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")])
1334 from Tools.ISO639 import LanguageCodes
1336 class InfoBarAudioSelection:
1338 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1340 "audioSelection": (self.audioSelection, _("Audio Options...")),
1343 def audioSelection(self):
1344 service = self.session.nav.getCurrentService()
1345 audio = service and service.audioTracks()
1346 self.audioTracks = audio
1347 n = audio and audio.getNumberOfTracks() or 0
1348 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1350 print "tlist:", tlist
1352 self.audioChannel = service.audioChannel()
1355 i = audio.getTrackInfo(x)
1356 language = i.getLanguage()
1357 description = i.getDescription()
1359 if LanguageCodes.has_key(language):
1360 language = LanguageCodes[language][0]
1362 if len(description):
1363 description += " (" + language + ")"
1365 description = language
1367 tlist.append((description, x))
1369 selectedAudio = tlist[0][1]
1370 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1374 if x[1] != selectedAudio:
1379 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1380 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1382 del self.audioTracks
1384 def audioSelected(self, audio):
1385 if audio is not None:
1386 if isinstance(audio[1], str):
1387 if audio[1] == "mode":
1388 keys = ["red", "green", "yellow"]
1389 selection = self.audioChannel.getCurrentChannel()
1390 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1391 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1393 del self.audioChannel
1394 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1395 self.audioTracks.selectTrack(audio[1])
1397 del self.audioChannel
1398 del self.audioTracks
1400 def modeSelected(self, mode):
1401 if mode is not None:
1402 self.audioChannel.selectChannel(mode[1])
1403 del self.audioChannel
1405 class InfoBarSubserviceSelection:
1407 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1409 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1412 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1414 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1415 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1417 self["SubserviceQuickzapAction"].setEnabled(False)
1419 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1423 def checkSubservicesAvail(self, ev):
1424 if ev == iPlayableService.evUpdatedEventInfo:
1425 service = self.session.nav.getCurrentService()
1426 subservices = service and service.subServices()
1427 if not subservices or subservices.getNumberOfSubservices() == 0:
1428 self["SubserviceQuickzapAction"].setEnabled(False)
1430 def nextSubservice(self):
1431 self.changeSubservice(+1)
1433 def prevSubservice(self):
1434 self.changeSubservice(-1)
1436 def changeSubservice(self, direction):
1437 service = self.session.nav.getCurrentService()
1438 subservices = service and service.subServices()
1439 n = subservices and subservices.getNumberOfSubservices()
1442 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1444 if subservices.getSubservice(x).toString() == ref.toString():
1447 selection += direction
1452 newservice = subservices.getSubservice(selection)
1453 if newservice.valid():
1456 if config.usage.show_infobar_on_zap.value:
1458 self.session.nav.playService(newservice)
1460 def subserviceSelection(self):
1461 service = self.session.nav.getCurrentService()
1462 subservices = service and service.subServices()
1463 self.bouquets = self.servicelist.getBouquetList()
1464 n = subservices and subservices.getNumberOfSubservices()
1467 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1470 i = subservices.getSubservice(x)
1471 if i.toString() == ref.toString():
1473 tlist.append((i.getName(), i))
1475 if self.bouquets and len(self.bouquets):
1476 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1477 if config.usage.multibouquet.value:
1478 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1480 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1483 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1484 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1487 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1489 def subserviceSelected(self, service):
1491 if not service is None:
1492 if isinstance(service[1], str):
1493 if service[1] == "quickzap":
1494 from Screens.SubservicesQuickzap import SubservicesQuickzap
1495 self.session.open(SubservicesQuickzap, service[2])
1497 self["SubserviceQuickzapAction"].setEnabled(True)
1498 if config.usage.show_infobar_on_zap.value:
1500 self.session.nav.playService(service[1])
1502 def addSubserviceToBouquetCallback(self, service):
1503 if len(service) > 1 and isinstance(service[1], eServiceReference):
1504 self.selectedSubservice = service
1505 if self.bouquets is None:
1508 cnt = len(self.bouquets)
1509 if cnt > 1: # show bouquet list
1510 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1511 elif cnt == 1: # add to only one existing bouquet
1512 self.addSubserviceToBouquet(self.bouquets[0][1])
1514 def bouquetSelClosed(self, **args):
1516 del self.selectedSubservice
1518 def addSubserviceToBouquet(self, dest):
1519 serviceHandler = eServiceCenter.getInstance()
1520 list = dest and serviceHandler.list(dest)
1521 mutableList = dest and list and list.startEdit()
1523 if not mutableList.addService(self.selectedSubservice[1]):
1524 mutableList.flushChanges()
1525 # do some voodoo to check if the subservice is added to the
1526 # current selected bouquet in channellist
1527 cur_root = self.servicelist.getRoot();
1528 str1 = cur_root.toString()
1529 str2 = dest.toString()
1530 pos1 = str1.find("FROM BOUQUET")
1531 pos2 = str2.find("FROM BOUQUET")
1532 if pos1 != -1 and pos2 != -1 and str1[pos1:] == str2[pos2:]:
1533 self.servicelist.setMode()
1537 del self.selectedSubservice
1539 class InfoBarAdditionalInfo:
1541 self["NimA"] = Pixmap()
1542 self["NimB"] = Pixmap()
1543 self["NimA_Active"] = Pixmap()
1544 self["NimB_Active"] = Pixmap()
1546 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1547 self["TimeshiftPossible"] = self["RecordingPossible"]
1548 self["ExtensionsAvailable"] = Boolean(fixed=1)
1550 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1551 res_mgr = eDVBResourceManagerPtr()
1552 if eDVBResourceManager.getInstance(res_mgr) == 0:
1553 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1555 def tunerUseMaskChanged(self, mask):
1557 self["NimA_Active"].show()
1559 self["NimA_Active"].hide()
1561 self["NimB_Active"].show()
1563 self["NimB_Active"].hide()
1565 def checkTunerState(self, service):
1566 info = service.frontendInfo()
1567 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1568 if feNumber is None:
1578 def gotServiceEvent(self, ev):
1579 service = self.session.nav.getCurrentService()
1580 if ev == iPlayableService.evStart:
1581 self.checkTunerState(service)
1583 class InfoBarNotifications:
1585 self.onExecBegin.append(self.checkNotifications)
1586 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1587 self.onClose.append(self.__removeNotification)
1589 def __removeNotification(self):
1590 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1592 def checkNotificationsIfExecing(self):
1594 self.checkNotifications()
1596 def checkNotifications(self):
1597 if len(Notifications.notifications):
1598 n = Notifications.notifications[0]
1599 Notifications.notifications = Notifications.notifications[1:]
1602 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1604 self.session.open(n[1], *n[2], **n[3])
1606 class InfoBarServiceNotifications:
1608 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1610 iPlayableService.evEnd: self.serviceHasEnded
1613 def serviceHasEnded(self):
1614 print "service end!"
1617 self.setSeekState(self.SEEK_STATE_PLAY)
1621 class InfoBarCueSheetSupport:
1627 ENABLE_RESUME_SUPPORT = False
1630 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1632 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1633 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1634 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1638 self.is_closing = False
1639 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1641 iPlayableService.evStart: self.__serviceStarted,
1644 def __serviceStarted(self):
1647 print "new service started! trying to download cuts!"
1648 self.downloadCuesheet()
1650 if self.ENABLE_RESUME_SUPPORT:
1653 for (pts, what) in self.cut_list:
1654 if what == self.CUT_TYPE_LAST:
1657 if last is not None:
1658 self.resume_point = last
1659 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1661 def playLastCB(self, answer):
1663 seekable = self.__getSeekable()
1664 if seekable is not None:
1665 seekable.seekTo(self.resume_point)
1667 def __getSeekable(self):
1668 service = self.session.nav.getCurrentService()
1671 return service.seek()
1673 def cueGetCurrentPosition(self):
1674 seek = self.__getSeekable()
1677 r = seek.getPlayPosition()
1682 def jumpPreviousNextMark(self, cmp, alternative=None):
1683 current_pos = self.cueGetCurrentPosition()
1684 if current_pos is None:
1686 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1687 if mark is not None:
1689 elif alternative is not None:
1694 seekable = self.__getSeekable()
1695 if seekable is not None:
1696 seekable.seekTo(pts)
1698 def jumpPreviousMark(self):
1699 # we add 2 seconds, so if the play position is <2s after
1700 # the mark, the mark before will be used
1701 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1703 def jumpNextMark(self):
1704 self.jumpPreviousNextMark(lambda x: x)
1706 def getNearestCutPoint(self, pts, cmp=abs):
1709 for cp in self.cut_list:
1710 diff = cmp(cp[0] - pts)
1711 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1715 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1716 current_pos = self.cueGetCurrentPosition()
1717 if current_pos is None:
1718 print "not seekable"
1721 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1723 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1725 return nearest_cutpoint
1727 self.removeMark(nearest_cutpoint)
1728 elif not onlyremove and not onlyreturn:
1729 self.addMark((current_pos, self.CUT_TYPE_MARK))
1734 def addMark(self, point):
1735 bisect.insort(self.cut_list, point)
1736 self.uploadCuesheet()
1738 def removeMark(self, point):
1739 self.cut_list.remove(point)
1740 self.uploadCuesheet()
1742 def __getCuesheet(self):
1743 service = self.session.nav.getCurrentService()
1746 return service.cueSheet()
1748 def uploadCuesheet(self):
1749 cue = self.__getCuesheet()
1752 print "upload failed, no cuesheet interface"
1754 cue.setCutList(self.cut_list)
1756 def downloadCuesheet(self):
1757 cue = self.__getCuesheet()
1760 print "upload failed, no cuesheet interface"
1762 self.cut_list = cue.getCutList()
1764 class InfoBarSummary(Screen):
1766 <screen position="0,0" size="132,64">
1767 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1768 <convert type="ClockToText">WithSeconds</convert>
1770 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1771 <convert type="ServiceName">Name</convert>
1775 def __init__(self, session, parent):
1776 Screen.__init__(self, session)
1777 self["CurrentService"] = CurrentService(self.session.nav)
1778 self["CurrentTime"] = Clock()
1780 class InfoBarSummarySupport:
1784 def createSummary(self):
1785 return InfoBarSummary
1787 class InfoBarTeletextPlugin:
1789 self.teletext_plugin = None
1791 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1792 self.teletext_plugin = p
1794 if self.teletext_plugin is not None:
1795 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1797 "startTeletext": (self.startTeletext, _("View teletext..."))
1800 print "no teletext plugin found!"
1802 def startTeletext(self):
1803 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1805 class InfoBarSubtitleSupport(object):
1807 object.__init__(self)
1808 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1809 self.__subtitles_enabled = False
1811 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1813 iPlayableService.evEnd: self.__serviceStopped,
1814 iPlayableService.evUpdatedInfo: self.__updatedInfo
1816 self.cached_subtitle_checked = False
1818 def __serviceStopped(self):
1819 self.subtitle_window.hide()
1820 self.__subtitles_enabled = False
1821 self.cached_subtitle_checked = False
1823 def __updatedInfo(self):
1824 if not self.cached_subtitle_checked:
1825 subtitle = self.getCurrentServiceSubtitle()
1826 self.cached_subtitle_checked = True
1828 self.__selected_subtitle = subtitle.getCachedSubtitle()
1829 if self.__selected_subtitle:
1830 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1831 self.subtitle_window.show()
1832 self.__subtitles_enabled = True
1834 def getCurrentServiceSubtitle(self):
1835 service = self.session.nav.getCurrentService()
1836 return service and service.subtitle()
1838 def setSubtitlesEnable(self, enable=True):
1839 subtitle = self.getCurrentServiceSubtitle()
1840 if enable and self.__selected_subtitle is not None:
1841 if subtitle and not self.__subtitles_enabled:
1842 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1843 self.subtitle_window.show()
1844 self.__subtitles_enabled = True
1847 subtitle.disableSubtitles(self.subtitle_window.instance)
1848 self.__subtitles_enabled = False
1849 self.subtitle_window.hide()
1851 def setSelectedSubtitle(self, subtitle):
1852 self.__selected_subtitle = subtitle
1854 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1855 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)