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.FrontendStatus import FrontendStatus
16 from Components.Sources.Boolean import Boolean
17 from Components.Sources.Clock import Clock
18 from Components.TimerList import TimerEntryComponent
19 from Components.config import config, ConfigBoolean
21 from EpgSelection import EPGSelection
22 from Plugins.Plugin import PluginDescriptor
24 from Screen import Screen
25 from Screens.ChoiceBox import ChoiceBox
26 from Screens.Dish import Dish
27 from Screens.EventView import EventViewEPGSelect, EventViewSimple
28 from Screens.InputBox import InputBox
29 from Screens.MessageBox import MessageBox
30 from Screens.MinuteInput import MinuteInput
31 from Screens.TimerSelection import TimerSelection
32 from Screens.PictureInPicture import PictureInPicture
33 from Screens.SubtitleDisplay import SubtitleDisplay
34 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
35 from Screens.SleepTimerEdit import SleepTimerEdit
36 from ServiceReference import ServiceReference
38 from Tools import Notifications
39 from Tools.Directories import SCOPE_HDD, resolveFilename
41 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
42 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
45 from os import stat as os_stat
46 from bisect import insort
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
69 }, 1) # lower prio to make it possible to override ok and cancel..
71 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
73 iPlayableService.evStart: self.__serviceStarted,
74 iPlayableService.evUpdatedEventInfo: self.__eventInfoChanged
77 self.__state = self.STATE_SHOWN
80 self.hideTimer = eTimer()
81 self.hideTimer.timeout.get().append(self.doTimerHide)
82 self.hideTimer.start(5000, True)
84 self.onShow.append(self.__onShow)
85 self.onHide.append(self.__onHide)
87 def __eventInfoChanged(self):
88 old_begin_time = self.current_begin_time
89 service = self.session.nav.getCurrentService()
90 info = service and service.info()
91 ptr = info and info.getEvent(0)
92 self.current_begin_time = ptr and ptr.getBeginTime() or 0
93 if config.usage.show_infobar_on_event_change.value:
94 if old_begin_time and old_begin_time != self.current_begin_time:
97 def __serviceStarted(self):
98 self.current_begin_time=0
99 if config.usage.show_infobar_on_zap.value:
103 self.__state = self.STATE_SHOWN
104 self.startHideTimer()
106 def startHideTimer(self):
107 if self.__state == self.STATE_SHOWN and not self.__locked:
108 idx = config.usage.infobar_timeout.index
110 self.hideTimer.start(idx*1000, True)
113 self.__state = self.STATE_HIDDEN
117 self.startHideTimer()
119 def doTimerHide(self):
120 self.hideTimer.stop()
121 if self.__state == self.STATE_SHOWN:
124 def toggleShow(self):
125 if self.__state == self.STATE_SHOWN:
127 self.hideTimer.stop()
128 elif self.__state == self.STATE_HIDDEN:
132 self.__locked = self.__locked + 1
135 self.hideTimer.stop()
137 def unlockShow(self):
138 self.__locked = self.__locked - 1
140 self.startHideTimer()
142 # def startShow(self):
143 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
144 # self.__state = self.STATE_SHOWN
146 # def startHide(self):
147 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
148 # self.__state = self.STATE_HIDDEN
150 class NumberZap(Screen):
157 self.close(int(self["number"].getText()))
159 def keyNumberGlobal(self, number):
160 self.Timer.start(3000, True) #reset timer
161 self.field = self.field + str(number)
162 self["number"].setText(self.field)
163 if len(self.field) >= 4:
166 def __init__(self, session, number):
167 Screen.__init__(self, session)
168 self.field = str(number)
170 self["channel"] = Label(_("Channel:"))
172 self["number"] = Label(self.field)
174 self["actions"] = NumberActionMap( [ "SetupActions" ],
178 "1": self.keyNumberGlobal,
179 "2": self.keyNumberGlobal,
180 "3": self.keyNumberGlobal,
181 "4": self.keyNumberGlobal,
182 "5": self.keyNumberGlobal,
183 "6": self.keyNumberGlobal,
184 "7": self.keyNumberGlobal,
185 "8": self.keyNumberGlobal,
186 "9": self.keyNumberGlobal,
187 "0": self.keyNumberGlobal
190 self.Timer = eTimer()
191 self.Timer.timeout.get().append(self.keyOK)
192 self.Timer.start(3000, True)
194 class InfoBarNumberZap:
195 """ Handles an initial number for NumberZapping """
197 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
199 "1": self.keyNumberGlobal,
200 "2": self.keyNumberGlobal,
201 "3": self.keyNumberGlobal,
202 "4": self.keyNumberGlobal,
203 "5": self.keyNumberGlobal,
204 "6": self.keyNumberGlobal,
205 "7": self.keyNumberGlobal,
206 "8": self.keyNumberGlobal,
207 "9": self.keyNumberGlobal,
208 "0": self.keyNumberGlobal,
211 def keyNumberGlobal(self, number):
212 # print "You pressed number " + str(number)
214 self.servicelist.recallPrevService()
216 self.session.openWithCallback(self.numberEntered, NumberZap, number)
218 def numberEntered(self, retval):
219 # print self.servicelist
221 self.zapToNumber(retval)
223 def searchNumberHelper(self, serviceHandler, num, bouquet):
224 servicelist = serviceHandler.list(bouquet)
225 if not servicelist is None:
227 serviceIterator = servicelist.getNext()
228 if not serviceIterator.valid(): #check end of list
230 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
233 if not num: #found service with searched number ?
234 return serviceIterator, 0
237 def zapToNumber(self, number):
238 bouquet = self.servicelist.bouquet_root
240 serviceHandler = eServiceCenter.getInstance()
241 if not config.usage.multibouquet.value:
242 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
244 bouquetlist = serviceHandler.list(bouquet)
245 if not bouquetlist is None:
247 bouquet = bouquetlist.getNext()
248 if not bouquet.valid(): #check end of list
250 if bouquet.flags & eServiceReference.isDirectory:
251 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
252 if not service is None:
253 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
254 self.servicelist.clearPath()
255 if self.servicelist.bouquet_root != bouquet:
256 self.servicelist.enterPath(self.servicelist.bouquet_root)
257 self.servicelist.enterPath(bouquet)
258 self.servicelist.setCurrentSelection(service) #select the service in servicelist
259 self.servicelist.zap()
261 config.misc.initialchannelselection = ConfigBoolean(default = True)
263 class InfoBarChannelSelection:
264 """ ChannelSelection - handles the channelSelection dialog and the initial
265 channelChange actions which open the channelSelection dialog """
268 self.servicelist = self.session.instantiateDialog(ChannelSelection)
270 if config.misc.initialchannelselection.value:
271 self.onShown.append(self.firstRun)
273 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
275 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
276 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
277 "zapUp": (self.zapUp, _("previous channel")),
278 "zapDown": (self.zapDown, _("next channel")),
279 "historyBack": (self.historyBack, _("previous channel in history")),
280 "historyNext": (self.historyNext, _("next channel in history")),
281 "openServiceList": (self.openServiceList, _("open servicelist")),
284 def showTvChannelList(self, zap=False):
285 self.servicelist.setModeTv()
287 self.servicelist.zap()
288 self.session.execDialog(self.servicelist)
290 def showRadioChannelList(self, zap=False):
291 self.servicelist.setModeRadio()
293 self.servicelist.zap()
294 self.session.execDialog(self.servicelist)
297 self.onShown.remove(self.firstRun)
298 config.misc.initialchannelselection.value = False
299 config.misc.initialchannelselection.save()
300 self.switchChannelDown()
302 def historyBack(self):
303 self.servicelist.historyBack()
305 def historyNext(self):
306 self.servicelist.historyNext()
308 def switchChannelUp(self):
309 self.servicelist.moveUp()
310 self.session.execDialog(self.servicelist)
312 def switchChannelDown(self):
313 self.servicelist.moveDown()
314 self.session.execDialog(self.servicelist)
316 def openServiceList(self):
317 self.session.execDialog(self.servicelist)
320 if self.servicelist.inBouquet():
321 prev = self.servicelist.getCurrentSelection()
323 prev = prev.toString()
325 if config.usage.quickzap_bouquet_change.value:
326 if self.servicelist.atBegin():
327 self.servicelist.prevBouquet()
328 self.servicelist.moveUp()
329 cur = self.servicelist.getCurrentSelection()
330 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
333 self.servicelist.moveUp()
334 self.servicelist.zap()
337 if self.servicelist.inBouquet():
338 prev = self.servicelist.getCurrentSelection()
340 prev = prev.toString()
342 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
343 self.servicelist.nextBouquet()
345 self.servicelist.moveDown()
346 cur = self.servicelist.getCurrentSelection()
347 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
350 self.servicelist.moveDown()
351 self.servicelist.zap()
354 """ Handles a menu action, to open the (main) menu """
356 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
358 "mainMenu": (self.mainMenu, _("Enter main menu...")),
360 self.session.infobar = None
363 print "loading mainmenu XML..."
364 menu = mdom.childNodes[0]
365 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
367 self.session.infobar = self
368 # so we can access the currently active infobar from screens opened from within the mainmenu
369 # at the moment used from the SubserviceSelection
371 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
373 def mainMenuClosed(self, *val):
374 self.session.infobar = None
376 class InfoBarSimpleEventView:
377 """ Opens the Eventview for now/next """
379 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
381 "showEventInfo": (self.openEventView, _("show event details")),
384 def openEventView(self):
386 service = self.session.nav.getCurrentService()
387 ref = self.session.nav.getCurrentlyPlayingServiceReference()
388 info = service.info()
391 self.epglist.append(ptr)
394 self.epglist.append(ptr)
395 if len(self.epglist) > 0:
396 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
398 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
399 if len(self.epglist) > 1:
400 tmp = self.epglist[0]
401 self.epglist[0]=self.epglist[1]
403 setEvent(self.epglist[0])
406 """ EPG - Opens an EPG list when the showEPGList action fires """
408 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
410 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
413 self.is_now_next = False
415 self.bouquetSel = None
416 self.eventView = None
417 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
419 "showEventInfo": (self.openEventView, _("show EPG...")),
422 def zapToService(self, service):
423 if not service is None:
424 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
425 self.servicelist.clearPath()
426 if self.servicelist.bouquet_root != self.epg_bouquet:
427 self.servicelist.enterPath(self.servicelist.bouquet_root)
428 self.servicelist.enterPath(self.epg_bouquet)
429 self.servicelist.setCurrentSelection(service) #select the service in servicelist
430 self.servicelist.zap()
432 def getBouquetServices(self, bouquet):
434 servicelist = eServiceCenter.getInstance().list(bouquet)
435 if not servicelist is None:
437 service = servicelist.getNext()
438 if not service.valid(): #check if end of list
440 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
442 services.append(ServiceReference(service))
445 def openBouquetEPG(self, bouquet, withCallback=True):
446 services = self.getBouquetServices(bouquet)
448 self.epg_bouquet = bouquet
450 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
452 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
454 def changeBouquetCB(self, direction, epg):
457 self.bouquetSel.down()
460 bouquet = self.bouquetSel.getCurrent()
461 services = self.getBouquetServices(bouquet)
463 self.epg_bouquet = bouquet
464 epg.setServices(services)
466 def closed(self, ret=False):
467 closedScreen = self.dlg_stack.pop()
468 if self.bouquetSel and closedScreen == self.bouquetSel:
469 self.bouquetSel = None
470 elif self.eventView and closedScreen == self.eventView:
471 self.eventView = None
473 dlgs=len(self.dlg_stack)
475 self.dlg_stack[dlgs-1].close(dlgs > 1)
477 def openMultiServiceEPG(self, withCallback=True):
478 bouquets = self.servicelist.getBouquetList()
483 if cnt > 1: # show bouquet list
485 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
486 self.dlg_stack.append(self.bouquetSel)
488 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
490 self.openBouquetEPG(bouquets[0][1], withCallback)
492 def openSingleServiceEPG(self):
493 ref=self.session.nav.getCurrentlyPlayingServiceReference()
494 self.session.open(EPGSelection, ref)
496 def openSimilarList(self, eventid, refstr):
497 self.session.open(EPGSelection, refstr, None, eventid)
499 def getNowNext(self):
501 service = self.session.nav.getCurrentService()
502 info = service and service.info()
503 ptr = info and info.getEvent(0)
505 self.epglist.append(ptr)
506 ptr = info and info.getEvent(1)
508 self.epglist.append(ptr)
510 def __evEventInfoChanged(self):
511 if self.is_now_next and len(self.dlg_stack) == 1:
513 assert self.eventView
514 if len(self.epglist):
515 self.eventView.setEvent(self.epglist[0])
517 def openEventView(self):
518 ref = self.session.nav.getCurrentlyPlayingServiceReference()
520 if len(self.epglist) == 0:
521 self.is_now_next = False
522 epg = eEPGCache.getInstance()
523 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
525 self.epglist.append(ptr)
526 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
528 self.epglist.append(ptr)
530 self.is_now_next = True
531 if len(self.epglist) > 0:
532 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
533 self.dlg_stack.append(self.eventView)
535 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
536 self.openMultiServiceEPG(False)
538 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
539 if len(self.epglist) > 1:
540 tmp = self.epglist[0]
541 self.epglist[0]=self.epglist[1]
543 setEvent(self.epglist[0])
546 """provides a snr/agc/ber display"""
548 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
551 """provides a current/next event info display"""
553 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
554 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
556 class InfoBarRdsDecoder:
557 """provides RDS and Rass support/display"""
559 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
560 self.rass_interactive = None
562 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
564 iPlayableService.evEnd: self.__serviceStopped,
565 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
568 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
570 "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
573 self["RdsActions"].setEnabled(False)
575 self.onLayoutFinish.append(self.rds_display.show)
576 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
578 def RassInteractivePossibilityChanged(self, state):
579 self["RdsActions"].setEnabled(state)
581 def RassSlidePicChanged(self):
582 if not self.rass_interactive:
583 service = self.session.nav.getCurrentService()
584 decoder = service and service.rdsDecoder()
586 decoder.showRassSlidePicture()
588 def __serviceStopped(self):
589 if self.rass_interactive is not None:
590 rass_interactive = self.rass_interactive
591 self.rass_interactive = None
592 rass_interactive.close()
594 def startRassInteractive(self):
595 self.rds_display.hide()
596 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
598 def RassInteractiveClosed(self, *val):
599 if self.rass_interactive is not None:
600 self.rass_interactive = None
601 self.RassSlidePicChanged()
602 self.rds_display.show()
604 class InfoBarServiceName:
606 self["CurrentService"] = CurrentService(self.session.nav)
609 """handles actions like seeking, pause"""
611 # ispause, isff, issm
612 SEEK_STATE_PLAY = (0, 0, 0, ">")
613 SEEK_STATE_PAUSE = (1, 0, 0, "||")
614 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
615 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
616 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
617 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
618 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
619 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
621 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
622 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
623 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
624 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
626 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
627 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
628 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
631 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
633 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
634 iPlayableService.evStart: self.__serviceStarted,
636 iPlayableService.evEOF: self.__evEOF,
637 iPlayableService.evSOF: self.__evSOF,
640 class InfoBarSeekActionMap(HelpableActionMap):
641 def __init__(self, screen, *args, **kwargs):
642 HelpableActionMap.__init__(self, screen, *args, **kwargs)
645 def action(self, contexts, action):
646 if action[:5] == "seek:":
647 time = int(action[5:])
648 self.screen.seekRelative(time * 90000)
651 return HelpableActionMap.action(self, contexts, action)
653 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
655 "playpauseService": (self.playpauseService, _("pause")),
656 "pauseService": (self.pauseService, _("pause")),
657 "unPauseService": (self.unPauseService, _("continue")),
659 "seekFwd": (self.seekFwd, _("skip forward")),
660 "seekFwdDown": self.seekFwdDown,
661 "seekFwdUp": self.seekFwdUp,
662 "seekBack": (self.seekBack, _("skip backward")),
663 "seekBackDown": self.seekBackDown,
664 "seekBackUp": self.seekBackUp,
666 # give them a little more priority to win over color buttons
668 self["SeekActions"].setEnabled(False)
670 self.seekstate = self.SEEK_STATE_PLAY
671 self.onClose.append(self.delTimer)
673 self.fwdtimer = False
674 self.fwdKeyTimer = eTimer()
675 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
677 self.rwdtimer = False
678 self.rwdKeyTimer = eTimer()
679 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
681 self.onPlayStateChanged = [ ]
683 self.lockedBecauseOfSkipping = False
696 service = self.session.nav.getCurrentService()
700 seek = service.seek()
702 if seek is None or not seek.isCurrentlySeekable():
707 def isSeekable(self):
708 if self.getSeek() is None:
712 def __seekableStatusChanged(self):
713 print "seekable status changed!"
714 if not self.isSeekable():
715 self["SeekActions"].setEnabled(False)
716 print "not seekable, return to play"
717 self.setSeekState(self.SEEK_STATE_PLAY)
719 self["SeekActions"].setEnabled(True)
722 def __serviceStarted(self):
723 self.seekstate = self.SEEK_STATE_PLAY
725 def setSeekState(self, state):
726 service = self.session.nav.getCurrentService()
731 if not self.isSeekable():
732 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
733 state = self.SEEK_STATE_PLAY
735 pauseable = service.pause()
737 if pauseable is None:
738 print "not pauseable."
739 state = self.SEEK_STATE_PLAY
741 oldstate = self.seekstate
742 self.seekstate = state
745 if oldstate[i] != self.seekstate[i]:
746 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
748 for c in self.onPlayStateChanged:
751 self.checkSkipShowHideLock()
755 def playpauseService(self):
756 if self.seekstate != self.SEEK_STATE_PLAY:
757 self.unPauseService()
761 def pauseService(self):
762 if self.seekstate == self.SEEK_STATE_PAUSE:
763 print "pause, but in fact unpause"
764 self.unPauseService()
766 if self.seekstate == self.SEEK_STATE_PLAY:
767 print "yes, playing."
769 print "no", self.seekstate
771 self.setSeekState(self.SEEK_STATE_PAUSE);
773 def unPauseService(self):
775 if self.seekstate == self.SEEK_STATE_PLAY:
777 self.setSeekState(self.SEEK_STATE_PLAY)
779 def doSeek(self, seektime):
780 print "doseek", seektime
781 service = self.session.nav.getCurrentService()
785 seekable = self.getSeek()
789 seekable.seekTo(90 * seektime)
791 def seekFwdDown(self):
792 print "start fwd timer"
794 self.fwdKeyTimer.start(1000)
796 def seekBackDown(self):
797 print "start rewind timer"
799 self.rwdKeyTimer.start(1000)
804 self.fwdKeyTimer.stop()
805 self.fwdtimer = False
810 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
811 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
812 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
813 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
814 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
815 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
816 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
817 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
818 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
819 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
820 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
821 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
822 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
823 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
824 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
826 self.setSeekState(lookup[self.seekstate])
828 def seekBackUp(self):
831 self.rwdKeyTimer.stop()
832 self.rwdtimer = False
837 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
838 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
839 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
840 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
841 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
842 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
843 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
844 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
845 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
846 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
847 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
848 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
849 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
850 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
851 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
853 self.setSeekState(lookup[self.seekstate])
855 if self.seekstate == self.SEEK_STATE_PAUSE:
856 seekable = self.getSeek()
857 if seekable is not None:
858 seekable.seekRelative(-1, 3)
860 def fwdTimerFire(self):
861 print "Display seek fwd"
862 self.fwdKeyTimer.stop()
863 self.fwdtimer = False
864 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
866 def fwdSeekTo(self, minutes):
867 print "Seek", minutes, "minutes forward"
869 seekable = self.getSeek()
870 if seekable is not None:
871 seekable.seekRelative(1, minutes * 60 * 90000)
873 def rwdTimerFire(self):
875 self.rwdKeyTimer.stop()
876 self.rwdtimer = False
877 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
879 def rwdSeekTo(self, minutes):
881 self.fwdSeekTo(0 - minutes)
883 def checkSkipShowHideLock(self):
884 wantlock = self.seekstate != self.SEEK_STATE_PLAY
886 if config.usage.show_infobar_on_zap.value:
887 if self.lockedBecauseOfSkipping and not wantlock:
889 self.lockedBecauseOfSkipping = False
891 if wantlock and not self.lockedBecauseOfSkipping:
893 self.lockedBecauseOfSkipping = True
896 if self.seekstate != self.SEEK_STATE_PLAY:
897 self.setSeekState(self.SEEK_STATE_PAUSE)
899 #self.getSeek().seekRelative(1, -90000)
900 self.setSeekState(self.SEEK_STATE_PLAY)
902 self.setSeekState(self.SEEK_STATE_PAUSE)
905 self.setSeekState(self.SEEK_STATE_PLAY)
908 def seekRelative(self, diff):
909 seekable = self.getSeek()
910 if seekable is not None:
911 seekable.seekRelative(1, diff)
913 def seekAbsolute(self, abs):
914 seekable = self.getSeek()
915 if seekable is not None:
918 from Screens.PVRState import PVRState, TimeshiftState
920 class InfoBarPVRState:
921 def __init__(self, screen=PVRState):
922 self.onPlayStateChanged.append(self.__playStateChanged)
923 self.pvrStateDialog = self.session.instantiateDialog(screen)
924 self.onShow.append(self._mayShow)
925 self.onHide.append(self.pvrStateDialog.hide)
928 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
929 self.pvrStateDialog.show()
931 def __playStateChanged(self, state):
932 playstateString = state[3]
933 self.pvrStateDialog["state"].setText(playstateString)
936 class InfoBarTimeshiftState(InfoBarPVRState):
938 InfoBarPVRState.__init__(self, screen=TimeshiftState)
941 if self.execing and self.timeshift_enabled:
942 self.pvrStateDialog.show()
944 class InfoBarShowMovies:
946 # i don't really like this class.
947 # it calls a not further specified "movie list" on up/down/movieList,
948 # so this is not more than an action map
950 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
952 "movieList": (self.showMovies, "movie list"),
953 "up": (self.showMovies, "movie list"),
954 "down": (self.showMovies, "movie list")
957 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
961 # Timeshift works the following way:
962 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
963 # - normal playback TUNER unused PLAY enable disable disable
964 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
965 # - user presess pause again FILE record PLAY enable disable enable
966 # - user fast forwards FILE record FF enable disable enable
967 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
968 # - user backwards FILE record BACK # !! enable disable enable
972 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
973 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
974 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
975 # - the user can now PVR around
976 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
977 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
979 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
980 # - if the user rewinds, or press pause, timeshift will be activated again
982 # note that a timeshift can be enabled ("recording") and
983 # activated (currently time-shifting).
985 class InfoBarTimeshift:
987 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
989 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
990 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
992 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
994 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
995 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
996 }, prio=-1) # priority over record
998 self.timeshift_enabled = 0
999 self.timeshift_state = 0
1000 self.ts_pause_timer = eTimer()
1001 self.ts_pause_timer.timeout.get().append(self.pauseService)
1003 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1005 iPlayableService.evStart: self.__serviceStarted,
1006 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
1009 def getTimeshift(self):
1010 service = self.session.nav.getCurrentService()
1011 return service and service.timeshift()
1013 def startTimeshift(self):
1014 print "enable timeshift"
1015 ts = self.getTimeshift()
1017 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1018 print "no ts interface"
1021 if self.timeshift_enabled:
1022 print "hu, timeshift already enabled?"
1024 if not ts.startTimeshift():
1025 self.timeshift_enabled = 1
1027 # we remove the "relative time" for now.
1028 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1031 self.setSeekState(self.SEEK_STATE_PAUSE)
1033 # enable the "TimeshiftEnableActions", which will override
1034 # the startTimeshift actions
1035 self.__seekableStatusChanged()
1037 print "timeshift failed"
1039 def stopTimeshift(self):
1040 if not self.timeshift_enabled:
1042 print "disable timeshift"
1043 ts = self.getTimeshift()
1046 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1048 def stopTimeshiftConfirmed(self, confirmed):
1052 ts = self.getTimeshift()
1057 self.timeshift_enabled = 0
1060 self.__seekableStatusChanged()
1062 # activates timeshift, and seeks to (almost) the end
1063 def activateTimeshiftEnd(self):
1064 ts = self.getTimeshift()
1069 if ts.isTimeshiftActive():
1070 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1073 self.setSeekState(self.SEEK_STATE_PLAY)
1074 ts.activateTimeshift()
1075 self.seekRelative(0)
1077 # same as activateTimeshiftEnd, but pauses afterwards.
1078 def activateTimeshiftEndAndPause(self):
1079 state = self.seekstate
1080 self.activateTimeshiftEnd()
1082 # well, this is "andPause", but it could be pressed from pause,
1083 # when pausing on the (fake-)"live" picture, so an un-pause
1086 print "now, pauseService"
1087 if state == self.SEEK_STATE_PLAY:
1088 print "is PLAYING, start pause timer"
1089 self.ts_pause_timer.start(200, 1)
1092 self.unPauseService()
1094 def __seekableStatusChanged(self):
1097 print "self.isSeekable", self.isSeekable()
1098 print "self.timeshift_enabled", self.timeshift_enabled
1100 # when this service is not seekable, but timeshift
1101 # is enabled, this means we can activate
1103 if not self.isSeekable() and self.timeshift_enabled:
1106 print "timeshift activate:", enabled
1107 self["TimeshiftActivateActions"].setEnabled(enabled)
1109 def __serviceStarted(self):
1110 self.timeshift_enabled = False
1111 self.__seekableStatusChanged()
1113 from Screens.PiPSetup import PiPSetup
1115 class InfoBarExtensions:
1116 EXTENSION_SINGLE = 0
1122 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1124 "extensions": (self.showExtensionSelection, _("view extensions...")),
1127 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1128 self.list.append((type, extension, key))
1130 def updateExtension(self, extension, key = None):
1131 self.extensionsList.append(extension)
1133 if self.extensionKeys.has_key(key):
1137 for x in self.availableKeys:
1138 if not self.extensionKeys.has_key(x):
1143 self.extensionKeys[key] = len(self.extensionsList) - 1
1145 def updateExtensions(self):
1146 self.extensionsList = []
1147 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1148 self.extensionKeys = {}
1150 if x[0] == self.EXTENSION_SINGLE:
1151 self.updateExtension(x[1], x[2])
1154 self.updateExtension(y[0], y[1])
1157 def showExtensionSelection(self):
1158 self.updateExtensions()
1159 extensionsList = self.extensionsList[:]
1162 for x in self.availableKeys:
1163 if self.extensionKeys.has_key(x):
1164 entry = self.extensionKeys[x]
1165 extension = self.extensionsList[entry]
1167 name = str(extension[0]())
1168 list.append((extension[0](), extension))
1170 extensionsList.remove(extension)
1172 extensionsList.remove(extension)
1173 for x in extensionsList:
1174 list.append((x[0](), x))
1175 keys += [""] * len(extensionsList)
1176 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1178 def extensionCallback(self, answer):
1179 if answer is not None:
1182 from Tools.BoundFunction import boundFunction
1184 # depends on InfoBarExtensions
1185 from Components.PluginComponent import plugins
1187 class InfoBarPlugins:
1189 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1191 def getPluginName(self, name):
1194 def getPluginList(self):
1196 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1197 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1200 def runPlugin(self, plugin):
1201 plugin(session = self.session)
1203 # depends on InfoBarExtensions
1204 class InfoBarSleepTimer:
1206 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1208 def available(self):
1211 def getSleepTimerName(self):
1212 return _("Sleep Timer")
1214 def showSleepTimerSetup(self):
1215 self.session.open(SleepTimerEdit)
1217 # depends on InfoBarExtensions
1220 self.session.pipshown = False
1222 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1223 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1224 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1226 def available(self):
1230 return self.session.pipshown
1232 def getShowHideName(self):
1233 if self.session.pipshown:
1234 return _("Disable Picture in Picture")
1236 return _("Activate Picture in Picture")
1238 def getSwapName(self):
1239 return _("Swap Services")
1241 def getMoveName(self):
1242 return _("Move Picture in Picture")
1245 if self.session.pipshown:
1246 del self.session.pip
1247 self.session.pipshown = False
1249 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1250 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1251 if self.session.pip.playService(newservice):
1252 self.session.pipshown = True
1253 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1255 self.session.pipshown = False
1256 del self.session.pip
1257 self.session.nav.playService(newservice)
1260 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1261 if self.session.pip.servicePath:
1262 servicepath = self.servicelist.getCurrentServicePath()
1263 ref=servicepath[len(servicepath)-1]
1264 pipref=self.session.pip.getCurrentService()
1265 self.session.pip.playService(swapservice)
1266 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1267 if pipref.toString() != ref.toString(): # is a subservice ?
1268 self.session.nav.stopService() # stop portal
1269 self.session.nav.playService(pipref) # start subservice
1270 self.session.pip.servicePath=servicepath
1273 self.session.open(PiPSetup, pip = self.session.pip)
1275 from RecordTimer import parseEvent
1277 class InfoBarInstantRecord:
1278 """Instant Record - handles the instantRecord action in order to
1279 start/stop instant records"""
1281 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1283 "instantRecord": (self.instantRecord, _("Instant Record...")),
1286 self["BlinkingPoint"] = BlinkingPixmapConditional()
1287 self["BlinkingPoint"].hide()
1288 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1290 def stopCurrentRecording(self, entry = -1):
1291 if entry is not None and entry != -1:
1292 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1293 self.recording.remove(self.recording[entry])
1295 def startInstantRecording(self, limitEvent = False):
1296 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1298 # try to get event info
1301 service = self.session.nav.getCurrentService()
1302 epg = eEPGCache.getInstance()
1303 event = epg.lookupEventTime(serviceref, -1, 0)
1305 info = service.info()
1306 ev = info.getEvent(0)
1312 end = time() + 3600 * 10
1313 name = "instant record"
1317 if event is not None:
1318 curEvent = parseEvent(event)
1320 description = curEvent[3]
1321 eventid = curEvent[4]
1326 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1328 data = (begin, end, name, description, eventid)
1330 recording = self.session.nav.recordWithTimer(serviceref, *data)
1331 recording.dontSave = True
1332 self.recording.append(recording)
1334 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1336 def isInstantRecordRunning(self):
1337 print "self.recording:", self.recording
1338 if len(self.recording) > 0:
1339 for x in self.recording:
1344 def recordQuestionCallback(self, answer):
1345 print "pre:\n", self.recording
1347 if answer is None or answer[1] == "no":
1350 recording = self.recording[:]
1352 if not x in self.session.nav.RecordTimer.timer_list:
1353 self.recording.remove(x)
1354 elif x.dontSave and x.isRunning():
1355 list.append(TimerEntryComponent(x, False))
1357 if answer[1] == "changeduration":
1358 if len(self.recording) == 1:
1359 self.changeDuration(0)
1361 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1362 elif answer[1] == "stop":
1363 if len(self.recording) == 1:
1364 self.stopCurrentRecording(0)
1366 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1367 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1369 if answer[1] == "event":
1371 if answer[1] == "manualduration":
1372 self.selectedEntry = len(self.recording)
1373 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1374 self.startInstantRecording(limitEvent = limitEvent)
1376 print "after:\n", self.recording
1378 def changeDuration(self, entry):
1379 if entry is not None:
1380 self.selectedEntry = entry
1381 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1383 def inputCallback(self, value):
1384 if value is not None:
1385 print "stopping recording after", int(value), "minutes."
1386 self.recording[self.selectedEntry].end = time() + 60 * int(value)
1387 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1389 def instantRecord(self):
1391 stat = os_stat(resolveFilename(SCOPE_HDD))
1393 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1396 if self.isInstantRecordRunning():
1397 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1398 title=_("A recording is currently running.\nWhat do you want to do?"), \
1399 list=[(_("stop recording"), "stop"), \
1400 (_("change recording (duration)"), "changeduration"), \
1401 (_("add recording (indefinitely)"), "indefinitely"), \
1402 (_("add recording (stop after current event)"), "event"), \
1403 (_("add recording (enter recording duration)"), "manualduration"), \
1404 (_("do nothing"), "no")])
1406 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1407 title=_("Start recording?"), \
1408 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1409 (_("add recording (stop after current event)"), "event"), \
1410 (_("add recording (enter recording duration)"), "manualduration"), \
1411 (_("don't record"), "no")])
1413 from Tools.ISO639 import LanguageCodes
1415 class InfoBarAudioSelection:
1417 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1419 "audioSelection": (self.audioSelection, _("Audio Options...")),
1422 def audioSelection(self):
1423 service = self.session.nav.getCurrentService()
1424 audio = service and service.audioTracks()
1425 self.audioTracks = audio
1426 n = audio and audio.getNumberOfTracks() or 0
1427 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1429 print "tlist:", tlist
1431 self.audioChannel = service.audioChannel()
1434 i = audio.getTrackInfo(x)
1435 language = i.getLanguage()
1436 description = i.getDescription()
1438 if LanguageCodes.has_key(language):
1439 language = LanguageCodes[language][0]
1441 if len(description):
1442 description += " (" + language + ")"
1444 description = language
1446 tlist.append((description, x))
1448 selectedAudio = tlist[0][1]
1449 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1453 if x[1] != selectedAudio:
1458 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1459 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1461 del self.audioTracks
1463 def audioSelected(self, audio):
1464 if audio is not None:
1465 if isinstance(audio[1], str):
1466 if audio[1] == "mode":
1467 keys = ["red", "green", "yellow"]
1468 selection = self.audioChannel.getCurrentChannel()
1469 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1470 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1472 del self.audioChannel
1473 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1474 self.audioTracks.selectTrack(audio[1])
1476 del self.audioChannel
1477 del self.audioTracks
1479 def modeSelected(self, mode):
1480 if mode is not None:
1481 self.audioChannel.selectChannel(mode[1])
1482 del self.audioChannel
1484 class InfoBarSubserviceSelection:
1486 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1488 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1491 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1493 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1494 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1496 self["SubserviceQuickzapAction"].setEnabled(False)
1498 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1502 def checkSubservicesAvail(self, ev):
1503 if ev == iPlayableService.evUpdatedEventInfo:
1504 service = self.session.nav.getCurrentService()
1505 subservices = service and service.subServices()
1506 if not subservices or subservices.getNumberOfSubservices() == 0:
1507 self["SubserviceQuickzapAction"].setEnabled(False)
1509 def nextSubservice(self):
1510 self.changeSubservice(+1)
1512 def prevSubservice(self):
1513 self.changeSubservice(-1)
1515 def changeSubservice(self, direction):
1516 service = self.session.nav.getCurrentService()
1517 subservices = service and service.subServices()
1518 n = subservices and subservices.getNumberOfSubservices()
1521 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1523 if subservices.getSubservice(x).toString() == ref.toString():
1526 selection += direction
1531 newservice = subservices.getSubservice(selection)
1532 if newservice.valid():
1535 self.session.nav.playService(newservice)
1537 def subserviceSelection(self):
1538 service = self.session.nav.getCurrentService()
1539 subservices = service and service.subServices()
1540 self.bouquets = self.servicelist.getBouquetList()
1541 n = subservices and subservices.getNumberOfSubservices()
1544 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1547 i = subservices.getSubservice(x)
1548 if i.toString() == ref.toString():
1550 tlist.append((i.getName(), i))
1552 if self.bouquets and len(self.bouquets):
1553 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1554 if config.usage.multibouquet.value:
1555 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1557 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1560 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1561 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1564 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1566 def subserviceSelected(self, service):
1568 if not service is None:
1569 if isinstance(service[1], str):
1570 if service[1] == "quickzap":
1571 from Screens.SubservicesQuickzap import SubservicesQuickzap
1572 self.session.open(SubservicesQuickzap, service[2])
1574 self["SubserviceQuickzapAction"].setEnabled(True)
1575 self.session.nav.playService(service[1])
1577 def addSubserviceToBouquetCallback(self, service):
1578 if len(service) > 1 and isinstance(service[1], eServiceReference):
1579 self.selectedSubservice = service
1580 if self.bouquets is None:
1583 cnt = len(self.bouquets)
1584 if cnt > 1: # show bouquet list
1585 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1586 elif cnt == 1: # add to only one existing bouquet
1587 self.addSubserviceToBouquet(self.bouquets[0][1])
1588 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1590 def bouquetSelClosed(self, confirmed):
1592 del self.selectedSubservice
1594 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1596 def addSubserviceToBouquet(self, dest):
1597 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1599 self.bsel.close(True)
1601 del self.selectedSubservice
1603 class InfoBarAdditionalInfo:
1605 self["NimA"] = Pixmap()
1606 self["NimB"] = Pixmap()
1607 self["NimA_Active"] = Pixmap()
1608 self["NimB_Active"] = Pixmap()
1610 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1611 self["TimeshiftPossible"] = self["RecordingPossible"]
1612 self["ExtensionsAvailable"] = Boolean(fixed=1)
1614 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1615 res_mgr = eDVBResourceManager.getInstance()
1617 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1619 def tunerUseMaskChanged(self, mask):
1621 self["NimA_Active"].show()
1623 self["NimA_Active"].hide()
1625 self["NimB_Active"].show()
1627 self["NimB_Active"].hide()
1629 def checkTunerState(self, service):
1630 info = service and service.frontendInfo()
1631 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1632 if feNumber is None:
1642 def gotServiceEvent(self, ev):
1643 service = self.session.nav.getCurrentService()
1644 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1645 self.checkTunerState(service)
1647 class InfoBarNotifications:
1649 self.onExecBegin.append(self.checkNotifications)
1650 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1651 self.onClose.append(self.__removeNotification)
1653 def __removeNotification(self):
1654 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1656 def checkNotificationsIfExecing(self):
1658 self.checkNotifications()
1660 def checkNotifications(self):
1661 if len(Notifications.notifications):
1662 n = Notifications.notifications[0]
1664 Notifications.notifications = Notifications.notifications[1:]
1667 if n[3].has_key("onSessionOpenCallback"):
1668 n[3]["onSessionOpenCallback"]()
1669 del n[3]["onSessionOpenCallback"]
1672 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1674 dlg = self.session.open(n[1], *n[2], **n[3])
1676 # remember that this notification is currently active
1678 Notifications.current_notifications.append(d)
1679 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1681 def __notificationClosed(self, d):
1682 Notifications.current_notifications.remove(d)
1684 class InfoBarServiceNotifications:
1686 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1688 iPlayableService.evEnd: self.serviceHasEnded
1691 def serviceHasEnded(self):
1692 print "service end!"
1695 self.setSeekState(self.SEEK_STATE_PLAY)
1699 class InfoBarCueSheetSupport:
1705 ENABLE_RESUME_SUPPORT = False
1708 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1710 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1711 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1712 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1716 self.is_closing = False
1717 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1719 iPlayableService.evStart: self.__serviceStarted,
1722 def __serviceStarted(self):
1725 print "new service started! trying to download cuts!"
1726 self.downloadCuesheet()
1728 if self.ENABLE_RESUME_SUPPORT:
1731 for (pts, what) in self.cut_list:
1732 if what == self.CUT_TYPE_LAST:
1735 if last is not None:
1736 self.resume_point = last
1737 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1739 def playLastCB(self, answer):
1741 seekable = self.__getSeekable()
1742 if seekable is not None:
1743 seekable.seekTo(self.resume_point)
1745 def __getSeekable(self):
1746 service = self.session.nav.getCurrentService()
1749 return service.seek()
1751 def cueGetCurrentPosition(self):
1752 seek = self.__getSeekable()
1755 r = seek.getPlayPosition()
1760 def jumpPreviousNextMark(self, cmp, alternative=None):
1761 current_pos = self.cueGetCurrentPosition()
1762 if current_pos is None:
1764 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1765 if mark is not None:
1767 elif alternative is not None:
1772 seekable = self.__getSeekable()
1773 if seekable is not None:
1774 seekable.seekTo(pts)
1776 def jumpPreviousMark(self):
1777 # we add 2 seconds, so if the play position is <2s after
1778 # the mark, the mark before will be used
1779 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1781 def jumpNextMark(self):
1782 self.jumpPreviousNextMark(lambda x: x)
1784 def getNearestCutPoint(self, pts, cmp=abs):
1787 for cp in self.cut_list:
1788 diff = cmp(cp[0] - pts)
1789 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1793 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1794 current_pos = self.cueGetCurrentPosition()
1795 if current_pos is None:
1796 print "not seekable"
1799 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1801 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1803 return nearest_cutpoint
1805 self.removeMark(nearest_cutpoint)
1806 elif not onlyremove and not onlyreturn:
1807 self.addMark((current_pos, self.CUT_TYPE_MARK))
1812 def addMark(self, point):
1813 insort(self.cut_list, point)
1814 self.uploadCuesheet()
1816 def removeMark(self, point):
1817 self.cut_list.remove(point)
1818 self.uploadCuesheet()
1820 def __getCuesheet(self):
1821 service = self.session.nav.getCurrentService()
1824 return service.cueSheet()
1826 def uploadCuesheet(self):
1827 cue = self.__getCuesheet()
1830 print "upload failed, no cuesheet interface"
1832 cue.setCutList(self.cut_list)
1834 def downloadCuesheet(self):
1835 cue = self.__getCuesheet()
1838 print "upload failed, no cuesheet interface"
1840 self.cut_list = cue.getCutList()
1842 class InfoBarSummary(Screen):
1844 <screen position="0,0" size="132,64">
1845 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1846 <convert type="ClockToText">WithSeconds</convert>
1848 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1849 <convert type="ServiceName">Name</convert>
1853 def __init__(self, session, parent):
1854 Screen.__init__(self, session)
1855 self["CurrentService"] = CurrentService(self.session.nav)
1856 self["CurrentTime"] = Clock()
1858 class InfoBarSummarySupport:
1862 def createSummary(self):
1863 return InfoBarSummary
1865 class InfoBarTeletextPlugin:
1867 self.teletext_plugin = None
1869 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1870 self.teletext_plugin = p
1872 if self.teletext_plugin is not None:
1873 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1875 "startTeletext": (self.startTeletext, _("View teletext..."))
1878 print "no teletext plugin found!"
1880 def startTeletext(self):
1881 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1883 class InfoBarSubtitleSupport(object):
1885 object.__init__(self)
1886 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1887 self.__subtitles_enabled = False
1889 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1891 iPlayableService.evEnd: self.__serviceStopped,
1892 iPlayableService.evUpdatedInfo: self.__updatedInfo
1894 self.cached_subtitle_checked = False
1896 def __serviceStopped(self):
1897 self.subtitle_window.hide()
1898 self.__subtitles_enabled = False
1899 self.cached_subtitle_checked = False
1901 def __updatedInfo(self):
1902 if not self.cached_subtitle_checked:
1903 subtitle = self.getCurrentServiceSubtitle()
1904 self.cached_subtitle_checked = True
1906 self.__selected_subtitle = subtitle.getCachedSubtitle()
1907 if self.__selected_subtitle:
1908 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1909 self.subtitle_window.show()
1910 self.__subtitles_enabled = True
1912 def getCurrentServiceSubtitle(self):
1913 service = self.session.nav.getCurrentService()
1914 return service and service.subtitle()
1916 def setSubtitlesEnable(self, enable=True):
1917 subtitle = self.getCurrentServiceSubtitle()
1918 if enable and self.__selected_subtitle is not None:
1919 if subtitle and not self.__subtitles_enabled:
1920 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1921 self.subtitle_window.show()
1922 self.__subtitles_enabled = True
1925 subtitle.disableSubtitles(self.subtitle_window.instance)
1926 self.__subtitles_enabled = False
1927 self.subtitle_window.hide()
1929 def setSelectedSubtitle(self, subtitle):
1930 self.__selected_subtitle = subtitle
1932 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1933 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1935 class InfoBarServiceErrorPopupSupport:
1937 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1939 iPlayableService.evTuneFailed: self.__tuneFailed,
1940 iPlayableService.evStart: self.__serviceStarted
1942 self.__serviceStarted()
1944 def __serviceStarted(self):
1945 self.last_error = None
1946 Notifications.RemovePopup(id = "ZapError")
1948 def __tuneFailed(self):
1949 service = self.session.nav.getCurrentService()
1950 info = service and service.info()
1951 error = info and info.getInfo(iServiceInformation.sDVBState)
1953 if error == self.last_error:
1956 self.last_error = error
1959 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1960 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1961 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1962 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1963 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1964 eDVBServicePMTHandler.eventNewProgramInfo: None,
1965 eDVBServicePMTHandler.eventTuned: None,
1966 eDVBServicePMTHandler.eventSOF: None,
1967 eDVBServicePMTHandler.eventEOF: None
1970 error = errors.get(error) #this returns None when the key not exist in the dict
1972 if error is not None:
1973 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1975 Notifications.RemovePopup(id = "ZapError")