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 Label
9 from Components.Pixmap import Pixmap
10 from Components.PluginComponent import plugins
11 from Components.ServiceEventTracker import ServiceEventTracker
12 from Components.Sources.Source import ObsoleteSource
13 from Components.Sources.Boolean import Boolean
14 from Components.Sources.Clock import Clock
15 from Components.config import config, ConfigBoolean, ConfigClock
16 from EpgSelection import EPGSelection
17 from Plugins.Plugin import PluginDescriptor
19 from Screen import Screen
20 from Screens.ChoiceBox import ChoiceBox
21 from Screens.Dish import Dish
22 from Screens.EventView import EventViewEPGSelect, EventViewSimple
23 from Screens.InputBox import InputBox
24 from Screens.MessageBox import MessageBox
25 from Screens.MinuteInput import MinuteInput
26 from Screens.TimerSelection import TimerSelection
27 from Screens.PictureInPicture import PictureInPicture
28 from Screens.SubtitleDisplay import SubtitleDisplay
29 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
30 from Screens.SleepTimerEdit import SleepTimerEdit
31 from Screens.TimeDateInput import TimeDateInput
32 from ServiceReference import ServiceReference
34 from Tools import Notifications
35 from Tools.Directories import SCOPE_HDD, resolveFilename
37 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
38 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
40 from time import time, localtime, strftime
41 from os import stat as os_stat
42 from bisect import insort
45 from Menu import MainMenu, mdom
49 self.dishDialog = self.session.instantiateDialog(Dish)
50 self.onLayoutFinish.append(self.dishDialog.show)
52 class InfoBarShowHide:
53 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
61 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
63 "toggleShow": self.toggleShow,
65 }, 1) # lower prio to make it possible to override ok and cancel..
67 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
69 iPlayableService.evStart: self.serviceStarted,
72 self.__state = self.STATE_SHOWN
75 self.hideTimer = eTimer()
76 self.hideTimer.timeout.get().append(self.doTimerHide)
77 self.hideTimer.start(5000, True)
79 self.onShow.append(self.__onShow)
80 self.onHide.append(self.__onHide)
82 def serviceStarted(self):
84 if config.usage.show_infobar_on_zap.value:
88 self.__state = self.STATE_SHOWN
91 def startHideTimer(self):
92 if self.__state == self.STATE_SHOWN and not self.__locked:
93 idx = config.usage.infobar_timeout.index
95 self.hideTimer.start(idx*1000, True)
98 self.__state = self.STATE_HIDDEN
102 self.startHideTimer()
104 def doTimerHide(self):
105 self.hideTimer.stop()
106 if self.__state == self.STATE_SHOWN:
109 def toggleShow(self):
110 if self.__state == self.STATE_SHOWN:
112 self.hideTimer.stop()
113 elif self.__state == self.STATE_HIDDEN:
117 self.__locked = self.__locked + 1
120 self.hideTimer.stop()
122 def unlockShow(self):
123 self.__locked = self.__locked - 1
125 self.startHideTimer()
127 # def startShow(self):
128 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
129 # self.__state = self.STATE_SHOWN
131 # def startHide(self):
132 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
133 # self.__state = self.STATE_HIDDEN
135 class NumberZap(Screen):
142 self.close(int(self["number"].getText()))
144 def keyNumberGlobal(self, number):
145 self.Timer.start(3000, True) #reset timer
146 self.field = self.field + str(number)
147 self["number"].setText(self.field)
148 if len(self.field) >= 4:
151 def __init__(self, session, number):
152 Screen.__init__(self, session)
153 self.field = str(number)
155 self["channel"] = Label(_("Channel:"))
157 self["number"] = Label(self.field)
159 self["actions"] = NumberActionMap( [ "SetupActions" ],
163 "1": self.keyNumberGlobal,
164 "2": self.keyNumberGlobal,
165 "3": self.keyNumberGlobal,
166 "4": self.keyNumberGlobal,
167 "5": self.keyNumberGlobal,
168 "6": self.keyNumberGlobal,
169 "7": self.keyNumberGlobal,
170 "8": self.keyNumberGlobal,
171 "9": self.keyNumberGlobal,
172 "0": self.keyNumberGlobal
175 self.Timer = eTimer()
176 self.Timer.timeout.get().append(self.keyOK)
177 self.Timer.start(3000, True)
179 class InfoBarNumberZap:
180 """ Handles an initial number for NumberZapping """
182 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
184 "1": self.keyNumberGlobal,
185 "2": self.keyNumberGlobal,
186 "3": self.keyNumberGlobal,
187 "4": self.keyNumberGlobal,
188 "5": self.keyNumberGlobal,
189 "6": self.keyNumberGlobal,
190 "7": self.keyNumberGlobal,
191 "8": self.keyNumberGlobal,
192 "9": self.keyNumberGlobal,
193 "0": self.keyNumberGlobal,
196 def keyNumberGlobal(self, number):
197 # print "You pressed number " + str(number)
199 if isinstance(self, InfoBarPiP) and self.pipHandles0Action():
200 self.pipDoHandle0Action()
202 self.servicelist.recallPrevService()
204 self.session.openWithCallback(self.numberEntered, NumberZap, number)
206 def numberEntered(self, retval):
207 # print self.servicelist
209 self.zapToNumber(retval)
211 def searchNumberHelper(self, serviceHandler, num, bouquet):
212 servicelist = serviceHandler.list(bouquet)
213 if not servicelist is None:
215 serviceIterator = servicelist.getNext()
216 if not serviceIterator.valid(): #check end of list
218 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
221 if not num: #found service with searched number ?
222 return serviceIterator, 0
225 def zapToNumber(self, number):
226 bouquet = self.servicelist.bouquet_root
228 serviceHandler = eServiceCenter.getInstance()
229 if not config.usage.multibouquet.value:
230 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
232 bouquetlist = serviceHandler.list(bouquet)
233 if not bouquetlist is None:
235 bouquet = bouquetlist.getNext()
236 if not bouquet.valid(): #check end of list
238 if bouquet.flags & eServiceReference.isDirectory:
239 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
240 if not service is None:
241 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
242 self.servicelist.clearPath()
243 if self.servicelist.bouquet_root != bouquet:
244 self.servicelist.enterPath(self.servicelist.bouquet_root)
245 self.servicelist.enterPath(bouquet)
246 self.servicelist.setCurrentSelection(service) #select the service in servicelist
247 self.servicelist.zap()
249 config.misc.initialchannelselection = ConfigBoolean(default = True)
251 class InfoBarChannelSelection:
252 """ ChannelSelection - handles the channelSelection dialog and the initial
253 channelChange actions which open the channelSelection dialog """
256 self.servicelist = self.session.instantiateDialog(ChannelSelection)
258 if config.misc.initialchannelselection.value:
259 self.onShown.append(self.firstRun)
261 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
263 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
264 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
265 "zapUp": (self.zapUp, _("previous channel")),
266 "zapDown": (self.zapDown, _("next channel")),
267 "historyBack": (self.historyBack, _("previous channel in history")),
268 "historyNext": (self.historyNext, _("next channel in history")),
269 "openServiceList": (self.openServiceList, _("open servicelist")),
272 def showTvChannelList(self, zap=False):
273 self.servicelist.setModeTv()
275 self.servicelist.zap()
276 self.session.execDialog(self.servicelist)
278 def showRadioChannelList(self, zap=False):
279 self.servicelist.setModeRadio()
281 self.servicelist.zap()
282 self.session.execDialog(self.servicelist)
285 self.onShown.remove(self.firstRun)
286 config.misc.initialchannelselection.value = False
287 config.misc.initialchannelselection.save()
288 self.switchChannelDown()
290 def historyBack(self):
291 self.servicelist.historyBack()
293 def historyNext(self):
294 self.servicelist.historyNext()
296 def switchChannelUp(self):
297 self.servicelist.moveUp()
298 self.session.execDialog(self.servicelist)
300 def switchChannelDown(self):
301 self.servicelist.moveDown()
302 self.session.execDialog(self.servicelist)
304 def openServiceList(self):
305 self.session.execDialog(self.servicelist)
308 if self.servicelist.inBouquet():
309 prev = self.servicelist.getCurrentSelection()
311 prev = prev.toString()
313 if config.usage.quickzap_bouquet_change.value:
314 if self.servicelist.atBegin():
315 self.servicelist.prevBouquet()
316 self.servicelist.moveUp()
317 cur = self.servicelist.getCurrentSelection()
318 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
321 self.servicelist.moveUp()
322 self.servicelist.zap()
325 if self.servicelist.inBouquet():
326 prev = self.servicelist.getCurrentSelection()
328 prev = prev.toString()
330 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
331 self.servicelist.nextBouquet()
333 self.servicelist.moveDown()
334 cur = self.servicelist.getCurrentSelection()
335 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
338 self.servicelist.moveDown()
339 self.servicelist.zap()
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...")),
408 "showSingleServiceEPG": (self.openSingleServiceEPG, _("show single service EPG...")),
409 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
412 def showEventInfoWhenNotVisible(self):
419 def zapToService(self, service):
420 if not service is None:
421 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
422 self.servicelist.clearPath()
423 if self.servicelist.bouquet_root != self.epg_bouquet:
424 self.servicelist.enterPath(self.servicelist.bouquet_root)
425 self.servicelist.enterPath(self.epg_bouquet)
426 self.servicelist.setCurrentSelection(service) #select the service in servicelist
427 self.servicelist.zap()
429 def getBouquetServices(self, bouquet):
431 servicelist = eServiceCenter.getInstance().list(bouquet)
432 if not servicelist is None:
434 service = servicelist.getNext()
435 if not service.valid(): #check if end of list
437 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
439 services.append(ServiceReference(service))
442 def openBouquetEPG(self, bouquet, withCallback=True):
443 services = self.getBouquetServices(bouquet)
445 self.epg_bouquet = bouquet
447 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
449 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
451 def changeBouquetCB(self, direction, epg):
454 self.bouquetSel.down()
457 bouquet = self.bouquetSel.getCurrent()
458 services = self.getBouquetServices(bouquet)
460 self.epg_bouquet = bouquet
461 epg.setServices(services)
463 def closed(self, ret=False):
464 closedScreen = self.dlg_stack.pop()
465 if self.bouquetSel and closedScreen == self.bouquetSel:
466 self.bouquetSel = None
467 elif self.eventView and closedScreen == self.eventView:
468 self.eventView = None
470 dlgs=len(self.dlg_stack)
472 self.dlg_stack[dlgs-1].close(dlgs > 1)
474 def openMultiServiceEPG(self, withCallback=True):
475 bouquets = self.servicelist.getBouquetList()
480 if cnt > 1: # show bouquet list
482 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
483 self.dlg_stack.append(self.bouquetSel)
485 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
487 self.openBouquetEPG(bouquets[0][1], withCallback)
489 def openSingleServiceEPG(self):
490 ref=self.session.nav.getCurrentlyPlayingServiceReference()
491 self.session.open(EPGSelection, ref)
493 def openSimilarList(self, eventid, refstr):
494 self.session.open(EPGSelection, refstr, None, eventid)
496 def getNowNext(self):
498 service = self.session.nav.getCurrentService()
499 info = service and service.info()
500 ptr = info and info.getEvent(0)
502 self.epglist.append(ptr)
503 ptr = info and info.getEvent(1)
505 self.epglist.append(ptr)
507 def __evEventInfoChanged(self):
508 if self.is_now_next and len(self.dlg_stack) == 1:
510 assert self.eventView
511 if len(self.epglist):
512 self.eventView.setEvent(self.epglist[0])
514 def openEventView(self):
515 ref = self.session.nav.getCurrentlyPlayingServiceReference()
517 if len(self.epglist) == 0:
518 self.is_now_next = False
519 epg = eEPGCache.getInstance()
520 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
522 self.epglist.append(ptr)
523 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
525 self.epglist.append(ptr)
527 self.is_now_next = True
528 if len(self.epglist) > 0:
529 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
530 self.dlg_stack.append(self.eventView)
532 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
533 self.openMultiServiceEPG(False)
535 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
536 if len(self.epglist) > 1:
537 tmp = self.epglist[0]
538 self.epglist[0]=self.epglist[1]
540 setEvent(self.epglist[0])
543 """provides a snr/agc/ber display"""
545 self["FrontendStatus"] = ObsoleteSource(new_source = "session.FrontendStatus", removal_date = "2008-01")
548 """provides a current/next event info display"""
550 self["Event_Now"] = ObsoleteSource(new_source = "session.Event_Now", removal_date = "2008-01")
551 self["Event_Next"] = ObsoleteSource(new_source = "session.Event_Next", removal_date = "2008-01")
553 class InfoBarRdsDecoder:
554 """provides RDS and Rass support/display"""
556 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
557 self.rass_interactive = None
559 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
561 iPlayableService.evEnd: self.__serviceStopped,
562 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
565 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
567 "startRassInteractive": self.startRassInteractive
570 self["RdsActions"].setEnabled(False)
572 self.onLayoutFinish.append(self.rds_display.show)
573 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
575 def RassInteractivePossibilityChanged(self, state):
576 self["RdsActions"].setEnabled(state)
578 def RassSlidePicChanged(self):
579 if not self.rass_interactive:
580 service = self.session.nav.getCurrentService()
581 decoder = service and service.rdsDecoder()
583 decoder.showRassSlidePicture()
585 def __serviceStopped(self):
586 if self.rass_interactive is not None:
587 rass_interactive = self.rass_interactive
588 self.rass_interactive = None
589 rass_interactive.close()
591 def startRassInteractive(self):
592 self.rds_display.hide()
593 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
595 def RassInteractiveClosed(self, *val):
596 if self.rass_interactive is not None:
597 self.rass_interactive = None
598 self.RassSlidePicChanged()
599 self.rds_display.show()
601 class InfoBarServiceName:
603 self["CurrentService"] = ObsoleteSource(new_source = "session.CurrentService", removal_date = "2008-01")
606 """handles actions like seeking, pause"""
608 # ispause, isff, issm
609 SEEK_STATE_PLAY = (0, 0, 0, ">")
610 SEEK_STATE_PAUSE = (1, 0, 0, "||")
611 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
612 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
613 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
614 SEEK_STATE_FF_16X = (0, 16, 0, ">> 16x")
615 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
616 SEEK_STATE_FF_48X = (0, 48, 0, ">> 48x")
617 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
618 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
620 SEEK_STATE_BACK_8X = (0, -8, 0, "<< 8x")
621 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
622 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
623 SEEK_STATE_BACK_48X = (0, -48, 0, "<< 48x")
624 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
625 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
627 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
628 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
629 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
631 SEEK_STATE_EOF = (1, 0, 0, "END")
633 def __init__(self, actionmap = "InfobarSeekActions"):
634 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
636 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
637 iPlayableService.evStart: self.__serviceStarted,
639 iPlayableService.evEOF: self.__evEOF,
640 iPlayableService.evSOF: self.__evSOF,
643 class InfoBarSeekActionMap(HelpableActionMap):
644 def __init__(self, screen, *args, **kwargs):
645 HelpableActionMap.__init__(self, screen, *args, **kwargs)
648 def action(self, contexts, action):
649 print "action:", action
650 if action[:5] == "seek:":
651 time = int(action[5:])
652 self.screen.seekRelative(time * 90000)
653 if config.usage.show_infobar_on_skip.value:
654 self.screen.showAfterSeek()
657 return HelpableActionMap.action(self, contexts, action)
659 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
661 "playpauseService": self.playpauseService,
662 "pauseService": (self.pauseService, _("pause")),
663 "unPauseService": (self.unPauseService, _("continue")),
665 "seekFwd": (self.seekFwd, _("skip forward")),
666 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
667 "seekBack": (self.seekBack, _("skip backward")),
668 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
670 "seekFwdDef": (self.seekFwdDef, _("skip forward (self defined)")),
671 "seekBackDef": (self.seekBackDef, _("skip backward (self defined)"))
673 # give them a little more priority to win over color buttons
675 self["SeekActions"].setEnabled(False)
677 self.seekstate = self.SEEK_STATE_PLAY
679 self.seek_flag = True
681 self.onPlayStateChanged = [ ]
683 self.lockedBecauseOfSkipping = False
685 self.__seekableStatusChanged()
687 def showAfterSeek(self):
688 if isinstance(self, InfoBarShowHide):
698 service = self.session.nav.getCurrentService()
702 seek = service.seek()
704 if seek is None or not seek.isCurrentlySeekable():
709 def isSeekable(self):
710 if self.getSeek() is None:
714 def __seekableStatusChanged(self):
715 print "seekable status changed!"
716 if not self.isSeekable():
717 self["SeekActions"].setEnabled(False)
718 print "not seekable, return to play"
719 self.setSeekState(self.SEEK_STATE_PLAY)
721 self["SeekActions"].setEnabled(True)
724 def __serviceStarted(self):
725 self.seekstate = self.SEEK_STATE_PLAY
726 self.__seekableStatusChanged()
728 def setSeekState(self, state):
729 service = self.session.nav.getCurrentService()
734 if not self.isSeekable():
735 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
736 state = self.SEEK_STATE_PLAY
738 pauseable = service.pause()
740 if pauseable is None:
741 print "not pauseable."
742 state = self.SEEK_STATE_PLAY
744 oldstate = self.seekstate
745 self.seekstate = state
748 if oldstate[i] != self.seekstate[i]:
749 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
751 for c in self.onPlayStateChanged:
754 self.checkSkipShowHideLock()
758 def playpauseService(self):
759 if self.seekstate != self.SEEK_STATE_PLAY:
760 self.unPauseService()
764 def pauseService(self):
765 if self.seekstate == self.SEEK_STATE_PAUSE:
766 print "pause, but in fact unpause"
767 self.unPauseService()
769 if self.seekstate == self.SEEK_STATE_PLAY:
770 print "yes, playing."
772 print "no", self.seekstate
774 self.setSeekState(self.SEEK_STATE_PAUSE);
776 def unPauseService(self):
778 if self.seekstate == self.SEEK_STATE_PLAY:
780 self.setSeekState(self.SEEK_STATE_PLAY)
782 def doSeek(self, seektime):
783 print "doseek", seektime
784 service = self.session.nav.getCurrentService()
788 seekable = self.getSeek()
792 seekable.seekTo(90 * seektime)
796 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
797 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
798 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
799 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
800 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_16X,
801 self.SEEK_STATE_FF_16X: self.SEEK_STATE_FF_32X,
802 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_48X,
803 self.SEEK_STATE_FF_48X: self.SEEK_STATE_FF_64X,
804 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
805 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
806 self.SEEK_STATE_BACK_8X: self.SEEK_STATE_PLAY,
807 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_8X,
808 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
809 self.SEEK_STATE_BACK_48X: self.SEEK_STATE_BACK_32X,
810 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_48X,
811 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
812 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
813 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
814 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER,
815 self.SEEK_STATE_EOF: self.SEEK_STATE_EOF,
817 self.setSeekState(lookup[self.seekstate])
821 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_8X,
822 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
823 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
824 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
825 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
826 self.SEEK_STATE_FF_16X: self.SEEK_STATE_FF_8X,
827 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_16X,
828 self.SEEK_STATE_FF_48X: self.SEEK_STATE_FF_32X,
829 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_48X,
830 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
831 self.SEEK_STATE_BACK_8X: self.SEEK_STATE_BACK_16X,
832 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
833 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_48X,
834 self.SEEK_STATE_BACK_48X: self.SEEK_STATE_BACK_64X,
835 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
836 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
837 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
838 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
839 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE,
840 self.SEEK_STATE_EOF: self.SEEK_STATE_BACK_8X,
842 self.setSeekState(lookup[self.seekstate])
844 if self.seekstate == self.SEEK_STATE_PAUSE:
845 seekable = self.getSeek()
846 if seekable is not None:
847 seekable.seekRelative(-1, 3)
849 def seekFwdDef(self):
850 self.seek_flag = False
851 seconds = config.usage.self_defined_seek.value
852 print "Seek", seconds, "seconds self defined forward"
853 seekable = self.getSeek()
854 if seekable is not None:
855 seekable.seekRelative(1, seconds * 90000)
857 def seekBackDef(self):
858 self.seek_flag = False
859 seconds = config.usage.self_defined_seek.value
860 print "Seek", seconds, "seconds self defined backward"
861 seekable = self.getSeek()
862 if seekable is not None:
863 seekable.seekRelative(1, 0 - seconds * 90000)
865 def seekFwdManual(self):
866 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
868 def fwdSeekTo(self, minutes):
869 print "Seek", minutes, "minutes forward"
871 seekable = self.getSeek()
872 if seekable is not None:
873 seekable.seekRelative(1, minutes * 60 * 90000)
875 def seekBackManual(self):
876 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
878 def rwdSeekTo(self, minutes):
880 self.fwdSeekTo(0 - minutes)
882 def checkSkipShowHideLock(self):
883 wantlock = self.seekstate != self.SEEK_STATE_PLAY
885 if config.usage.show_infobar_on_skip.value:
886 if self.lockedBecauseOfSkipping and not wantlock:
888 self.lockedBecauseOfSkipping = False
890 if wantlock and not self.lockedBecauseOfSkipping:
892 self.lockedBecauseOfSkipping = True
895 if self.seekstate == self.SEEK_STATE_EOF:
897 if self.seekstate[1] < 0: # SEEK_STATE_BACK_*X
898 print "end of stream while seeking back, ignoring."
901 # if we are seeking, we try to end up ~1s before the end, and pause there.
902 if not self.seekstate in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
903 self.setSeekState(self.SEEK_STATE_EOF)
904 self.seekRelativeToEnd(-90000)
906 self.setSeekState(self.SEEK_STATE_EOF)
909 self.setSeekState(self.SEEK_STATE_PLAY)
912 def seekRelative(self, diff):
913 if self.seek_flag == True:
914 seekable = self.getSeek()
915 if seekable is not None:
916 print "seekRelative: res:", seekable.seekRelative(1, diff)
920 self.seek_flag = True
922 def seekRelativeToEnd(self, diff):
923 assert diff <= 0, "diff is expected to be negative!"
925 # might sound like an evil hack, but:
926 # if we seekRelativeToEnd(0), we expect to be at the end, which is what we want,
927 # and we don't get that by passing 0 here (it would seek to begin).
931 # relative-to-end seeking is implemented as absolutes seeks with negative time
932 self.seekAbsolute(diff)
934 def seekAbsolute(self, abs):
935 seekable = self.getSeek()
936 if seekable is not None:
939 from Screens.PVRState import PVRState, TimeshiftState
941 class InfoBarPVRState:
942 def __init__(self, screen=PVRState):
943 self.onPlayStateChanged.append(self.__playStateChanged)
944 self.pvrStateDialog = self.session.instantiateDialog(screen)
945 self.onShow.append(self._mayShow)
946 self.onHide.append(self.pvrStateDialog.hide)
949 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
950 self.pvrStateDialog.show()
952 def __playStateChanged(self, state):
953 playstateString = state[3]
954 self.pvrStateDialog["state"].setText(playstateString)
957 class InfoBarTimeshiftState(InfoBarPVRState):
959 InfoBarPVRState.__init__(self, screen=TimeshiftState)
962 if self.execing and self.timeshift_enabled:
963 self.pvrStateDialog.show()
965 class InfoBarShowMovies:
967 # i don't really like this class.
968 # it calls a not further specified "movie list" on up/down/movieList,
969 # so this is not more than an action map
971 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
973 "movieList": (self.showMovies, _("movie list")),
974 "up": (self.showMovies, _("movie list")),
975 "down": (self.showMovies, _("movie list"))
978 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
982 # Timeshift works the following way:
983 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
984 # - normal playback TUNER unused PLAY enable disable disable
985 # - user presses "yellow" button. FILE record PAUSE enable disable enable
986 # - user presess pause again FILE record PLAY enable disable enable
987 # - user fast forwards FILE record FF enable disable enable
988 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
989 # - user backwards FILE record BACK # !! enable disable enable
993 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
994 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
995 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
996 # - the user can now PVR around
997 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
998 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1000 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1001 # - if the user rewinds, or press pause, timeshift will be activated again
1003 # note that a timeshift can be enabled ("recording") and
1004 # activated (currently time-shifting).
1006 class InfoBarTimeshift:
1008 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1010 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
1011 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
1013 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1015 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1016 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "pause key"
1017 }, prio=-1) # priority over record
1019 self.timeshift_enabled = 0
1020 self.timeshift_state = 0
1021 self.ts_rewind_timer = eTimer()
1022 self.ts_rewind_timer.timeout.get().append(self.rewindService)
1024 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1026 iPlayableService.evStart: self.__serviceStarted,
1027 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1030 def getTimeshift(self):
1031 service = self.session.nav.getCurrentService()
1032 return service and service.timeshift()
1034 def startTimeshift(self):
1035 print "enable timeshift"
1036 ts = self.getTimeshift()
1038 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1039 print "no ts interface"
1042 if self.timeshift_enabled:
1043 print "hu, timeshift already enabled?"
1045 if not ts.startTimeshift():
1046 self.timeshift_enabled = 1
1048 # we remove the "relative time" for now.
1049 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1052 #self.setSeekState(self.SEEK_STATE_PAUSE)
1053 self.activateTimeshiftEnd(False)
1055 # enable the "TimeshiftEnableActions", which will override
1056 # the startTimeshift actions
1057 self.__seekableStatusChanged()
1059 print "timeshift failed"
1061 def stopTimeshift(self):
1062 if not self.timeshift_enabled:
1064 print "disable timeshift"
1065 ts = self.getTimeshift()
1068 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1070 def stopTimeshiftConfirmed(self, confirmed):
1074 ts = self.getTimeshift()
1079 self.timeshift_enabled = 0
1082 self.__seekableStatusChanged()
1084 # activates timeshift, and seeks to (almost) the end
1085 def activateTimeshiftEnd(self, back = True):
1086 ts = self.getTimeshift()
1087 print "activateTimeshiftEnd"
1092 if ts.isTimeshiftActive():
1093 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1097 ts.activateTimeshift() # activate timeshift will automatically pause
1098 self.setSeekState(self.SEEK_STATE_PAUSE)
1099 self.seekRelativeToEnd(-90000) # seek approx. 1 sec before end
1102 self.ts_rewind_timer.start(200, 1)
1104 def rewindService(self):
1105 self.setSeekState(self.SEEK_STATE_BACK_16X)
1107 # same as activateTimeshiftEnd, but pauses afterwards.
1108 def activateTimeshiftEndAndPause(self):
1109 print "activateTimeshiftEndAndPause"
1110 #state = self.seekstate
1111 self.activateTimeshiftEnd(False)
1113 def __seekableStatusChanged(self):
1116 print "self.isSeekable", self.isSeekable()
1117 print "self.timeshift_enabled", self.timeshift_enabled
1119 # when this service is not seekable, but timeshift
1120 # is enabled, this means we can activate
1122 if not self.isSeekable() and self.timeshift_enabled:
1125 print "timeshift activate:", enabled
1126 self["TimeshiftActivateActions"].setEnabled(enabled)
1128 def __serviceStarted(self):
1129 self.timeshift_enabled = False
1130 self.__seekableStatusChanged()
1132 from Screens.PiPSetup import PiPSetup
1134 class InfoBarExtensions:
1135 EXTENSION_SINGLE = 0
1141 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1143 "extensions": (self.showExtensionSelection, _("view extensions...")),
1146 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1147 self.list.append((type, extension, key))
1149 def updateExtension(self, extension, key = None):
1150 self.extensionsList.append(extension)
1152 if self.extensionKeys.has_key(key):
1156 for x in self.availableKeys:
1157 if not self.extensionKeys.has_key(x):
1162 self.extensionKeys[key] = len(self.extensionsList) - 1
1164 def updateExtensions(self):
1165 self.extensionsList = []
1166 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1167 self.extensionKeys = {}
1169 if x[0] == self.EXTENSION_SINGLE:
1170 self.updateExtension(x[1], x[2])
1173 self.updateExtension(y[0], y[1])
1176 def showExtensionSelection(self):
1177 self.updateExtensions()
1178 extensionsList = self.extensionsList[:]
1181 for x in self.availableKeys:
1182 if self.extensionKeys.has_key(x):
1183 entry = self.extensionKeys[x]
1184 extension = self.extensionsList[entry]
1186 name = str(extension[0]())
1187 list.append((extension[0](), extension))
1189 extensionsList.remove(extension)
1191 extensionsList.remove(extension)
1192 for x in extensionsList:
1193 list.append((x[0](), x))
1194 keys += [""] * len(extensionsList)
1195 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1197 def extensionCallback(self, answer):
1198 if answer is not None:
1201 from Tools.BoundFunction import boundFunction
1203 # depends on InfoBarExtensions
1204 from Components.PluginComponent import plugins
1206 class InfoBarPlugins:
1208 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1210 def getPluginName(self, name):
1213 def getPluginList(self):
1215 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1216 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1219 def runPlugin(self, plugin):
1220 plugin(session = self.session, servicelist = self.servicelist)
1222 # depends on InfoBarExtensions
1223 class InfoBarSleepTimer:
1225 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1227 def available(self):
1230 def getSleepTimerName(self):
1231 return _("Sleep Timer")
1233 def showSleepTimerSetup(self):
1234 self.session.open(SleepTimerEdit)
1236 # depends on InfoBarExtensions
1239 self.session.pipshown = False
1241 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1242 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1243 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1245 def available(self):
1249 return self.session.pipshown
1251 def pipHandles0Action(self):
1252 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1254 def getShowHideName(self):
1255 if self.session.pipshown:
1256 return _("Disable Picture in Picture")
1258 return _("Activate Picture in Picture")
1260 def getSwapName(self):
1261 return _("Swap Services")
1263 def getMoveName(self):
1264 return _("Move Picture in Picture")
1267 if self.session.pipshown:
1268 del self.session.pip
1269 self.session.pipshown = False
1271 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1272 self.session.pip.show()
1273 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1274 if self.session.pip.playService(newservice):
1275 self.session.pipshown = True
1276 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1278 self.session.pipshown = False
1279 del self.session.pip
1280 self.session.nav.playService(newservice)
1283 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1284 if self.session.pip.servicePath:
1285 servicepath = self.servicelist.getCurrentServicePath()
1286 ref=servicepath[len(servicepath)-1]
1287 pipref=self.session.pip.getCurrentService()
1288 self.session.pip.playService(swapservice)
1289 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1290 if pipref.toString() != ref.toString(): # is a subservice ?
1291 self.session.nav.stopService() # stop portal
1292 self.session.nav.playService(pipref) # start subservice
1293 self.session.pip.servicePath=servicepath
1296 self.session.open(PiPSetup, pip = self.session.pip)
1298 def pipDoHandle0Action(self):
1299 use = config.usage.pip_zero_button.value
1302 elif "swapstop" == use:
1308 from RecordTimer import parseEvent
1310 class InfoBarInstantRecord:
1311 """Instant Record - handles the instantRecord action in order to
1312 start/stop instant records"""
1314 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1316 "instantRecord": (self.instantRecord, _("Instant Record...")),
1319 self["BlinkingPoint"] = BlinkingPixmapConditional()
1320 self["BlinkingPoint"].hide()
1321 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1323 def stopCurrentRecording(self, entry = -1):
1324 if entry is not None and entry != -1:
1325 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1326 self.recording.remove(self.recording[entry])
1328 def startInstantRecording(self, limitEvent = False):
1329 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1331 # try to get event info
1334 service = self.session.nav.getCurrentService()
1335 epg = eEPGCache.getInstance()
1336 event = epg.lookupEventTime(serviceref, -1, 0)
1338 info = service.info()
1339 ev = info.getEvent(0)
1345 end = time() + 3600 * 10
1346 name = "instant record"
1350 if event is not None:
1351 curEvent = parseEvent(event)
1353 description = curEvent[3]
1354 eventid = curEvent[4]
1359 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1361 data = (begin, end, name, description, eventid)
1363 recording = self.session.nav.recordWithTimer(serviceref, *data)
1364 recording.dontSave = True
1365 self.recording.append(recording)
1367 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1369 def isInstantRecordRunning(self):
1370 print "self.recording:", self.recording
1371 if len(self.recording) > 0:
1372 for x in self.recording:
1377 def recordQuestionCallback(self, answer):
1378 print "pre:\n", self.recording
1380 if answer is None or answer[1] == "no":
1383 recording = self.recording[:]
1385 if not x in self.session.nav.RecordTimer.timer_list:
1386 self.recording.remove(x)
1387 elif x.dontSave and x.isRunning():
1388 list.append((x, False))
1390 if answer[1] == "changeduration":
1391 if len(self.recording) == 1:
1392 self.changeDuration(0)
1394 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1395 elif answer[1] == "changeendtime":
1396 if len(self.recording) == 1:
1399 self.session.openWithCallback(self.setEndTime, TimerSelection, list)
1400 elif answer[1] == "stop":
1401 if len(self.recording) == 1:
1402 self.stopCurrentRecording(0)
1404 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1405 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1406 self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1407 if answer[1] == "manualduration":
1408 self.changeDuration(len(self.recording)-1)
1409 elif answer[1] == "manualendtime":
1410 self.setEndtime(len(self.recording)-1)
1411 print "after:\n", self.recording
1413 def setEndtime(self, entry):
1414 if entry is not None:
1415 self.selectedEntry = entry
1416 self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1417 dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1418 dlg.setTitle(_("Please change recording endtime"))
1420 def TimeDateInputClosed(self, ret):
1423 localendtime = localtime(ret[1])
1424 print "stopping recording at", strftime("%c", localendtime)
1425 self.recording[self.selectedEntry].end = ret[1]
1426 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1428 def changeDuration(self, entry):
1429 if entry is not None:
1430 self.selectedEntry = entry
1431 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1433 def inputCallback(self, value):
1434 if value is not None:
1435 print "stopping recording after", int(value), "minutes."
1436 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1437 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1439 def instantRecord(self):
1441 stat = os_stat(resolveFilename(SCOPE_HDD))
1443 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1446 if self.isInstantRecordRunning():
1447 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1448 title=_("A recording is currently running.\nWhat do you want to do?"), \
1449 list=[(_("stop recording"), "stop"), \
1450 (_("change recording (duration)"), "changeduration"), \
1451 (_("change recording (endtime)"), "changeendtime"), \
1452 (_("add recording (indefinitely)"), "indefinitely"), \
1453 (_("add recording (stop after current event)"), "event"), \
1454 (_("add recording (enter recording duration)"), "manualduration"), \
1455 (_("add recording (enter recording endtime)"), "manualendtime"), \
1456 (_("do nothing"), "no")])
1458 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1459 title=_("Start recording?"), \
1460 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1461 (_("add recording (stop after current event)"), "event"), \
1462 (_("add recording (enter recording duration)"), "manualduration"), \
1463 (_("add recording (enter recording endtime)"), "manualendtime"), \
1464 (_("don't record"), "no")])
1466 from Tools.ISO639 import LanguageCodes
1468 class InfoBarAudioSelection:
1470 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1472 "audioSelection": (self.audioSelection, _("Audio Options...")),
1475 def audioSelection(self):
1476 service = self.session.nav.getCurrentService()
1477 audio = service and service.audioTracks()
1478 self.audioTracks = audio
1479 n = audio and audio.getNumberOfTracks() or 0
1480 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1483 self.audioChannel = service.audioChannel()
1486 i = audio.getTrackInfo(x)
1487 language = i.getLanguage()
1488 description = i.getDescription()
1490 if LanguageCodes.has_key(language):
1491 language = LanguageCodes[language][0]
1493 if len(description):
1494 description += " (" + language + ")"
1496 description = language
1498 tlist.append((description, x))
1500 selectedAudio = audio.getCurrentTrack()
1501 tlist.sort(key=lambda x: x[0])
1505 if x[1] != selectedAudio:
1510 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1511 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1513 del self.audioTracks
1515 def audioSelected(self, audio):
1516 if audio is not None:
1517 if isinstance(audio[1], str):
1518 if audio[1] == "mode":
1519 keys = ["red", "green", "yellow"]
1520 selection = self.audioChannel.getCurrentChannel()
1521 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1522 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1524 del self.audioChannel
1525 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1526 self.audioTracks.selectTrack(audio[1])
1528 del self.audioChannel
1529 del self.audioTracks
1531 def modeSelected(self, mode):
1532 if mode is not None:
1533 self.audioChannel.selectChannel(mode[1])
1534 del self.audioChannel
1536 class InfoBarSubserviceSelection:
1538 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1540 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1543 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1545 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1546 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1548 self["SubserviceQuickzapAction"].setEnabled(False)
1550 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1554 def checkSubservicesAvail(self, ev):
1555 if ev == iPlayableService.evUpdatedEventInfo:
1556 service = self.session.nav.getCurrentService()
1557 subservices = service and service.subServices()
1558 if not subservices or subservices.getNumberOfSubservices() == 0:
1559 self["SubserviceQuickzapAction"].setEnabled(False)
1561 def nextSubservice(self):
1562 self.changeSubservice(+1)
1564 def prevSubservice(self):
1565 self.changeSubservice(-1)
1567 def changeSubservice(self, direction):
1568 service = self.session.nav.getCurrentService()
1569 subservices = service and service.subServices()
1570 n = subservices and subservices.getNumberOfSubservices()
1573 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1575 if subservices.getSubservice(x).toString() == ref.toString():
1578 selection += direction
1583 newservice = subservices.getSubservice(selection)
1584 if newservice.valid():
1587 self.session.nav.playService(newservice)
1589 def subserviceSelection(self):
1590 service = self.session.nav.getCurrentService()
1591 subservices = service and service.subServices()
1592 self.bouquets = self.servicelist.getBouquetList()
1593 n = subservices and subservices.getNumberOfSubservices()
1596 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1599 i = subservices.getSubservice(x)
1600 if i.toString() == ref.toString():
1602 tlist.append((i.getName(), i))
1604 if self.bouquets and len(self.bouquets):
1605 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1606 if config.usage.multibouquet.value:
1607 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1609 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1612 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1613 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1616 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1618 def subserviceSelected(self, service):
1620 if not service is None:
1621 if isinstance(service[1], str):
1622 if service[1] == "quickzap":
1623 from Screens.SubservicesQuickzap import SubservicesQuickzap
1624 self.session.open(SubservicesQuickzap, service[2])
1626 self["SubserviceQuickzapAction"].setEnabled(True)
1627 self.session.nav.playService(service[1])
1629 def addSubserviceToBouquetCallback(self, service):
1630 if len(service) > 1 and isinstance(service[1], eServiceReference):
1631 self.selectedSubservice = service
1632 if self.bouquets is None:
1635 cnt = len(self.bouquets)
1636 if cnt > 1: # show bouquet list
1637 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1638 elif cnt == 1: # add to only one existing bouquet
1639 self.addSubserviceToBouquet(self.bouquets[0][1])
1640 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1642 def bouquetSelClosed(self, confirmed):
1644 del self.selectedSubservice
1646 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1648 def addSubserviceToBouquet(self, dest):
1649 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1651 self.bsel.close(True)
1653 del self.selectedSubservice
1655 class InfoBarAdditionalInfo:
1657 self["NimA"] = Pixmap()
1658 self["NimB"] = Pixmap()
1659 self["NimA_Active"] = Pixmap()
1660 self["NimB_Active"] = Pixmap()
1662 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1663 self["TimeshiftPossible"] = self["RecordingPossible"]
1664 self["ExtensionsAvailable"] = Boolean(fixed=1)
1666 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1667 res_mgr = eDVBResourceManager.getInstance()
1669 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1671 def tunerUseMaskChanged(self, mask):
1673 self["NimA_Active"].show()
1675 self["NimA_Active"].hide()
1677 self["NimB_Active"].show()
1679 self["NimB_Active"].hide()
1681 def checkTunerState(self, service):
1682 info = service and service.frontendInfo()
1683 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1684 if feNumber is None:
1694 def gotServiceEvent(self, ev):
1695 service = self.session.nav.getCurrentService()
1696 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1697 self.checkTunerState(service)
1699 class InfoBarNotifications:
1701 self.onExecBegin.append(self.checkNotifications)
1702 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1703 self.onClose.append(self.__removeNotification)
1705 def __removeNotification(self):
1706 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1708 def checkNotificationsIfExecing(self):
1710 self.checkNotifications()
1712 def checkNotifications(self):
1713 if len(Notifications.notifications):
1714 n = Notifications.notifications[0]
1716 Notifications.notifications = Notifications.notifications[1:]
1719 if n[3].has_key("onSessionOpenCallback"):
1720 n[3]["onSessionOpenCallback"]()
1721 del n[3]["onSessionOpenCallback"]
1724 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1726 dlg = self.session.open(n[1], *n[2], **n[3])
1728 # remember that this notification is currently active
1730 Notifications.current_notifications.append(d)
1731 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1733 def __notificationClosed(self, d):
1734 Notifications.current_notifications.remove(d)
1736 class InfoBarServiceNotifications:
1738 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1740 iPlayableService.evEnd: self.serviceHasEnded
1743 def serviceHasEnded(self):
1744 print "service end!"
1747 self.setSeekState(self.SEEK_STATE_PLAY)
1751 class InfoBarCueSheetSupport:
1757 ENABLE_RESUME_SUPPORT = False
1759 def __init__(self, actionmap = "InfobarCueSheetActions"):
1760 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1762 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1763 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1764 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1768 self.is_closing = False
1769 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1771 iPlayableService.evStart: self.__serviceStarted,
1774 def __serviceStarted(self):
1777 print "new service started! trying to download cuts!"
1778 self.downloadCuesheet()
1780 if self.ENABLE_RESUME_SUPPORT:
1783 for (pts, what) in self.cut_list:
1784 if what == self.CUT_TYPE_LAST:
1787 if last is not None:
1788 self.resume_point = last
1789 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1791 def playLastCB(self, answer):
1793 seekable = self.__getSeekable()
1794 if seekable is not None:
1795 seekable.seekTo(self.resume_point)
1796 self.hideAfterResume()
1798 def hideAfterResume(self):
1799 if isinstance(self, InfoBarShowHide):
1802 def __getSeekable(self):
1803 service = self.session.nav.getCurrentService()
1806 return service.seek()
1808 def cueGetCurrentPosition(self):
1809 seek = self.__getSeekable()
1812 r = seek.getPlayPosition()
1817 def jumpPreviousNextMark(self, cmp, alternative=None):
1818 current_pos = self.cueGetCurrentPosition()
1819 if current_pos is None:
1821 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1822 if mark is not None:
1824 elif alternative is not None:
1829 seekable = self.__getSeekable()
1830 if seekable is not None:
1831 seekable.seekTo(pts)
1833 def jumpPreviousMark(self):
1834 # we add 2 seconds, so if the play position is <2s after
1835 # the mark, the mark before will be used
1836 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1838 def jumpNextMark(self):
1839 self.jumpPreviousNextMark(lambda x: x)
1841 def getNearestCutPoint(self, pts, cmp=abs):
1844 for cp in self.cut_list:
1845 diff = cmp(cp[0] - pts)
1846 if cp[1] == self.CUT_TYPE_MARK and diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1850 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1851 current_pos = self.cueGetCurrentPosition()
1852 if current_pos is None:
1853 print "not seekable"
1856 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1858 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1860 return nearest_cutpoint
1862 self.removeMark(nearest_cutpoint)
1863 elif not onlyremove and not onlyreturn:
1864 self.addMark((current_pos, self.CUT_TYPE_MARK))
1869 def addMark(self, point):
1870 insort(self.cut_list, point)
1871 self.uploadCuesheet()
1872 self.showAfterCuesheetOperation()
1874 def removeMark(self, point):
1875 self.cut_list.remove(point)
1876 self.uploadCuesheet()
1877 self.showAfterCuesheetOperation()
1879 def showAfterCuesheetOperation(self):
1880 if isinstance(self, InfoBarShowHide):
1883 def __getCuesheet(self):
1884 service = self.session.nav.getCurrentService()
1887 return service.cueSheet()
1889 def uploadCuesheet(self):
1890 cue = self.__getCuesheet()
1893 print "upload failed, no cuesheet interface"
1895 cue.setCutList(self.cut_list)
1897 def downloadCuesheet(self):
1898 cue = self.__getCuesheet()
1901 print "download failed, no cuesheet interface"
1904 self.cut_list = cue.getCutList()
1906 class InfoBarSummary(Screen):
1908 <screen position="0,0" size="132,64">
1909 <widget source="global.CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1910 <convert type="ClockToText">WithSeconds</convert>
1912 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1913 <convert type="ServiceName">Name</convert>
1917 def __init__(self, session, parent):
1918 Screen.__init__(self, session)
1920 class InfoBarSummarySupport:
1924 def createSummary(self):
1925 return InfoBarSummary
1927 class InfoBarTeletextPlugin:
1929 self.teletext_plugin = None
1931 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1932 self.teletext_plugin = p
1934 if self.teletext_plugin is not None:
1935 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1937 "startTeletext": (self.startTeletext, _("View teletext..."))
1940 print "no teletext plugin found!"
1942 def startTeletext(self):
1943 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1945 class InfoBarSubtitleSupport(object):
1947 object.__init__(self)
1948 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1949 self.__subtitles_enabled = False
1951 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1953 iPlayableService.evEnd: self.__serviceStopped,
1954 iPlayableService.evUpdatedInfo: self.__updatedInfo
1956 self.cached_subtitle_checked = False
1957 self.__selected_subtitle = None
1959 def __serviceStopped(self):
1960 self.subtitle_window.hide()
1961 self.__subtitles_enabled = False
1962 self.cached_subtitle_checked = False
1964 def __updatedInfo(self):
1965 if not self.cached_subtitle_checked:
1966 subtitle = self.getCurrentServiceSubtitle()
1967 self.cached_subtitle_checked = True
1968 self.__selected_subtitle = subtitle and subtitle.getCachedSubtitle()
1969 if self.__selected_subtitle:
1970 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1971 self.subtitle_window.show()
1972 self.__subtitles_enabled = True
1974 def getCurrentServiceSubtitle(self):
1975 service = self.session.nav.getCurrentService()
1976 return service and service.subtitle()
1978 def setSubtitlesEnable(self, enable=True):
1979 subtitle = self.getCurrentServiceSubtitle()
1980 if enable and self.__selected_subtitle is not None:
1981 if subtitle and not self.__subtitles_enabled:
1982 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1983 self.subtitle_window.show()
1984 self.__subtitles_enabled = True
1987 subtitle.disableSubtitles(self.subtitle_window.instance)
1988 self.__subtitles_enabled = False
1989 self.subtitle_window.hide()
1991 def setSelectedSubtitle(self, subtitle):
1992 self.__selected_subtitle = subtitle
1994 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1995 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1997 class InfoBarServiceErrorPopupSupport:
1999 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2001 iPlayableService.evTuneFailed: self.__tuneFailed,
2002 iPlayableService.evStart: self.__serviceStarted
2004 self.__serviceStarted()
2006 def __serviceStarted(self):
2007 self.last_error = None
2008 Notifications.RemovePopup(id = "ZapError")
2010 def __tuneFailed(self):
2011 service = self.session.nav.getCurrentService()
2012 info = service and service.info()
2013 error = info and info.getInfo(iServiceInformation.sDVBState)
2015 if error == self.last_error:
2018 self.last_error = error
2021 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2022 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2023 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2024 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2025 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2026 eDVBServicePMTHandler.eventNewProgramInfo: None,
2027 eDVBServicePMTHandler.eventTuned: None,
2028 eDVBServicePMTHandler.eventSOF: None,
2029 eDVBServicePMTHandler.eventEOF: None
2032 error = errors.get(error) #this returns None when the key not exist in the dict
2034 if error is not None:
2035 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2037 Notifications.RemovePopup(id = "ZapError")