1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import *
9 from Components.Pixmap import Pixmap, PixmapConditional
10 from Components.PluginComponent import plugins
11 from Components.ProgressBar import *
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.Sources.CurrentService import CurrentService
14 from Components.Sources.EventInfo import EventInfo
15 from Components.Sources.RadioText import RadioText
16 from Components.Sources.FrontendStatus import FrontendStatus
17 from Components.Sources.Boolean import Boolean
18 from Components.Sources.Clock import Clock
19 from Components.TimerList import TimerEntryComponent
20 from Components.config import config, ConfigBoolean
22 from EpgSelection import EPGSelection
23 from Plugins.Plugin import PluginDescriptor
25 from Screen import Screen
26 from Screens.ChoiceBox import ChoiceBox
27 from Screens.Dish import Dish
28 from Screens.EventView import EventViewEPGSelect, EventViewSimple
29 from Screens.InputBox import InputBox
30 from Screens.MessageBox import MessageBox
31 from Screens.MinuteInput import MinuteInput
32 from Screens.TimerSelection import TimerSelection
33 from Screens.PictureInPicture import PictureInPicture
34 from Screens.SubtitleDisplay import SubtitleDisplay
35 from Screens.SleepTimerEdit import SleepTimerEdit
36 from ServiceReference import ServiceReference
38 from Tools import Notifications
39 from Tools.Directories import SCOPE_HDD, resolveFilename
41 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
42 iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation
45 from os import stat as os_stat
46 from bisect import insort
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
71 self.__state = self.STATE_SHOWN
74 self.onExecBegin.append(self.show)
76 self.hideTimer = eTimer()
77 self.hideTimer.timeout.get().append(self.doTimerHide)
78 self.hideTimer.start(5000, True)
80 self.onShow.append(self.__onShow)
81 self.onHide.append(self.__onHide)
84 self.__state = self.STATE_SHOWN
87 def startHideTimer(self):
88 if self.__state == self.STATE_SHOWN and not self.__locked:
89 idx = config.usage.infobar_timeout.index
91 self.hideTimer.start(idx*1000, True)
94 self.__state = self.STATE_HIDDEN
100 def doTimerHide(self):
101 self.hideTimer.stop()
102 if self.__state == self.STATE_SHOWN:
105 def toggleShow(self):
106 if self.__state == self.STATE_SHOWN:
108 self.hideTimer.stop()
109 elif self.__state == self.STATE_HIDDEN:
113 self.__locked = self.__locked + 1
116 self.hideTimer.stop()
118 def unlockShow(self):
119 self.__locked = self.__locked - 1
121 self.startHideTimer()
123 # def startShow(self):
124 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
125 # self.__state = self.STATE_SHOWN
127 # def startHide(self):
128 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
129 # self.__state = self.STATE_HIDDEN
131 class NumberZap(Screen):
138 self.close(int(self["number"].getText()))
140 def keyNumberGlobal(self, number):
141 self.Timer.start(3000, True) #reset timer
142 self.field = self.field + str(number)
143 self["number"].setText(self.field)
144 if len(self.field) >= 4:
147 def __init__(self, session, number):
148 Screen.__init__(self, session)
149 self.field = str(number)
151 self["channel"] = Label(_("Channel:"))
153 self["number"] = Label(self.field)
155 self["actions"] = NumberActionMap( [ "SetupActions" ],
159 "1": self.keyNumberGlobal,
160 "2": self.keyNumberGlobal,
161 "3": self.keyNumberGlobal,
162 "4": self.keyNumberGlobal,
163 "5": self.keyNumberGlobal,
164 "6": self.keyNumberGlobal,
165 "7": self.keyNumberGlobal,
166 "8": self.keyNumberGlobal,
167 "9": self.keyNumberGlobal,
168 "0": self.keyNumberGlobal
171 self.Timer = eTimer()
172 self.Timer.timeout.get().append(self.keyOK)
173 self.Timer.start(3000, True)
175 class InfoBarNumberZap:
176 """ Handles an initial number for NumberZapping """
178 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
180 "1": self.keyNumberGlobal,
181 "2": self.keyNumberGlobal,
182 "3": self.keyNumberGlobal,
183 "4": self.keyNumberGlobal,
184 "5": self.keyNumberGlobal,
185 "6": self.keyNumberGlobal,
186 "7": self.keyNumberGlobal,
187 "8": self.keyNumberGlobal,
188 "9": self.keyNumberGlobal,
189 "0": self.keyNumberGlobal,
192 def keyNumberGlobal(self, number):
193 # print "You pressed number " + str(number)
195 self.servicelist.recallPrevService()
196 if config.usage.show_infobar_on_zap.value:
199 self.session.openWithCallback(self.numberEntered, NumberZap, number)
201 def numberEntered(self, retval):
202 # print self.servicelist
204 self.zapToNumber(retval)
206 def searchNumberHelper(self, serviceHandler, num, bouquet):
207 servicelist = serviceHandler.list(bouquet)
208 if not servicelist is None:
210 serviceIterator = servicelist.getNext()
211 if not serviceIterator.valid(): #check end of list
213 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
216 if not num: #found service with searched number ?
217 return serviceIterator, 0
220 def zapToNumber(self, number):
221 bouquet = self.servicelist.bouquet_root
223 serviceHandler = eServiceCenter.getInstance()
224 if not config.usage.multibouquet.value:
225 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
227 bouquetlist = serviceHandler.list(bouquet)
228 if not bouquetlist is None:
230 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
231 if not bouquet.valid(): #check end of list
233 if bouquet.flags & eServiceReference.isDirectory:
234 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
235 if not service is None:
236 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
237 self.servicelist.clearPath()
238 if self.servicelist.bouquet_root != bouquet:
239 self.servicelist.enterPath(self.servicelist.bouquet_root)
240 self.servicelist.enterPath(bouquet)
241 self.servicelist.setCurrentSelection(service) #select the service in servicelist
242 self.servicelist.zap()
244 config.misc.initialchannelselection = ConfigBoolean(default = True)
246 class InfoBarChannelSelection:
247 """ ChannelSelection - handles the channelSelection dialog and the initial
248 channelChange actions which open the channelSelection dialog """
251 self.servicelist = self.session.instantiateDialog(ChannelSelection)
253 if config.misc.initialchannelselection.value:
254 self.onShown.append(self.firstRun)
256 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
258 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
259 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
260 "zapUp": (self.zapUp, _("previous channel")),
261 "zapDown": (self.zapDown, _("next channel")),
262 "historyBack": (self.historyBack, _("previous channel in history")),
263 "historyNext": (self.historyNext, _("next channel in history")),
264 "openServiceList": (self.openServiceList, _("open servicelist")),
267 def showTvChannelList(self, zap=False):
268 self.servicelist.setModeTv()
270 self.servicelist.zap()
271 self.session.execDialog(self.servicelist)
273 def showRadioChannelList(self, zap=False):
274 self.servicelist.setModeRadio()
276 self.servicelist.zap()
277 self.session.execDialog(self.servicelist)
280 self.onShown.remove(self.firstRun)
281 config.misc.initialchannelselection.value = False
282 config.misc.initialchannelselection.save()
283 self.switchChannelDown()
285 def historyBack(self):
286 self.servicelist.historyBack()
288 def historyNext(self):
289 self.servicelist.historyNext()
291 def switchChannelUp(self):
292 self.servicelist.moveUp()
293 self.session.execDialog(self.servicelist)
295 def switchChannelDown(self):
296 self.servicelist.moveDown()
297 self.session.execDialog(self.servicelist)
299 def openServiceList(self):
300 self.session.execDialog(self.servicelist)
303 if self.servicelist.inBouquet():
304 prev = self.servicelist.getCurrentSelection()
306 prev = prev.toString()
308 if config.usage.quickzap_bouquet_change.value:
309 if self.servicelist.atBegin():
310 self.servicelist.prevBouquet()
311 self.servicelist.moveUp()
312 cur = self.servicelist.getCurrentSelection()
313 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
316 self.servicelist.moveUp()
317 self.servicelist.zap()
318 if config.usage.show_infobar_on_zap.value:
322 if self.servicelist.inBouquet():
323 prev = self.servicelist.getCurrentSelection()
325 prev = prev.toString()
327 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
328 self.servicelist.nextBouquet()
330 self.servicelist.moveDown()
331 cur = self.servicelist.getCurrentSelection()
332 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
335 self.servicelist.moveDown()
336 self.servicelist.zap()
337 if config.usage.show_infobar_on_zap.value:
341 """ Handles a menu action, to open the (main) menu """
343 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
345 "mainMenu": (self.mainMenu, _("Enter main menu...")),
347 self.session.infobar = None
350 print "loading mainmenu XML..."
351 menu = mdom.childNodes[0]
352 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
354 self.session.infobar = self
355 # so we can access the currently active infobar from screens opened from within the mainmenu
356 # at the moment used from the SubserviceSelection
358 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
360 def mainMenuClosed(self, *val):
361 self.session.infobar = None
363 class InfoBarSimpleEventView:
364 """ Opens the Eventview for now/next """
366 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
368 "showEventInfo": (self.openEventView, _("show event details")),
371 def openEventView(self):
373 service = self.session.nav.getCurrentService()
374 ref = self.session.nav.getCurrentlyPlayingServiceReference()
375 info = service.info()
378 self.epglist.append(ptr)
381 self.epglist.append(ptr)
382 if len(self.epglist) > 0:
383 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
385 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
386 if len(self.epglist) > 1:
387 tmp = self.epglist[0]
388 self.epglist[0]=self.epglist[1]
390 setEvent(self.epglist[0])
393 """ EPG - Opens an EPG list when the showEPGList action fires """
395 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
397 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
400 self.is_now_next = False
402 self.bouquetSel = None
403 self.eventView = None
404 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
406 "showEventInfo": (self.openEventView, _("show EPG...")),
409 def zapToService(self, service):
410 if not service is None:
411 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
412 self.servicelist.clearPath()
413 if self.servicelist.bouquet_root != self.epg_bouquet:
414 self.servicelist.enterPath(self.servicelist.bouquet_root)
415 self.servicelist.enterPath(self.epg_bouquet)
416 self.servicelist.setCurrentSelection(service) #select the service in servicelist
417 self.servicelist.zap()
419 def getBouquetServices(self, bouquet):
421 servicelist = eServiceCenter.getInstance().list(bouquet)
422 if not servicelist is None:
424 service = servicelist.getNext()
425 if not service.valid(): #check if end of list
427 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
429 services.append(ServiceReference(service))
432 def openBouquetEPG(self, bouquet, withCallback=True):
433 services = self.getBouquetServices(bouquet)
435 self.epg_bouquet = bouquet
437 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
439 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
441 def changeBouquetCB(self, direction, epg):
444 self.bouquetSel.down()
447 bouquet = self.bouquetSel.getCurrent()
448 services = self.getBouquetServices(bouquet)
450 self.epg_bouquet = bouquet
451 epg.setServices(services)
453 def closed(self, ret=False):
454 closedScreen = self.dlg_stack.pop()
455 if self.bouquetSel and closedScreen == self.bouquetSel:
456 self.bouquetSel = None
457 elif self.eventView and closedScreen == self.eventView:
458 self.eventView = None
460 dlgs=len(self.dlg_stack)
462 self.dlg_stack[dlgs-1].close(dlgs > 1)
464 def openMultiServiceEPG(self, withCallback=True):
465 bouquets = self.servicelist.getBouquetList()
470 if cnt > 1: # show bouquet list
472 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
473 self.dlg_stack.append(self.bouquetSel)
475 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
477 self.openBouquetEPG(bouquets[0][1], withCallback)
479 def openSingleServiceEPG(self):
480 ref=self.session.nav.getCurrentlyPlayingServiceReference()
481 self.session.open(EPGSelection, ref)
483 def openSimilarList(self, eventid, refstr):
484 self.session.open(EPGSelection, refstr, None, eventid)
486 def getNowNext(self):
488 service = self.session.nav.getCurrentService()
489 info = service and service.info()
490 ptr = info and info.getEvent(0)
492 self.epglist.append(ptr)
493 ptr = info and info.getEvent(1)
495 self.epglist.append(ptr)
497 def __evEventInfoChanged(self):
498 if self.is_now_next and len(self.dlg_stack) == 1:
500 assert self.eventView
501 if len(self.epglist):
502 self.eventView.setEvent(self.epglist[0])
504 def openEventView(self):
505 ref = self.session.nav.getCurrentlyPlayingServiceReference()
507 if len(self.epglist) == 0:
508 self.is_now_next = False
509 epg = eEPGCache.getInstance()
510 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
512 self.epglist.append(ptr)
513 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
515 self.epglist.append(ptr)
517 self.is_now_next = True
518 if len(self.epglist) > 0:
519 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
520 self.dlg_stack.append(self.eventView)
522 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
523 self.openMultiServiceEPG(False)
525 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
526 if len(self.epglist) > 1:
527 tmp = self.epglist[0]
528 self.epglist[0]=self.epglist[1]
530 setEvent(self.epglist[0])
533 """provides a snr/agc/ber display"""
535 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
538 """provides a current/next event info display"""
540 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
541 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
543 class InfoBarRadioText:
544 """provides radio (RDS) text info display"""
546 self["RadioText"] = RadioText(self.session.nav)
548 class InfoBarServiceName:
550 self["CurrentService"] = CurrentService(self.session.nav)
553 """handles actions like seeking, pause"""
555 # ispause, isff, issm
556 SEEK_STATE_PLAY = (0, 0, 0, ">")
557 SEEK_STATE_PAUSE = (1, 0, 0, "||")
558 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
559 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
560 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
561 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
562 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
563 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
565 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
566 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
567 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
568 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
570 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
571 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
572 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
575 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
577 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
578 iPlayableService.evStart: self.__serviceStarted,
580 iPlayableService.evEOF: self.__evEOF,
581 iPlayableService.evSOF: self.__evSOF,
584 class InfoBarSeekActionMap(HelpableActionMap):
585 def __init__(self, screen, *args, **kwargs):
586 HelpableActionMap.__init__(self, screen, *args, **kwargs)
589 def action(self, contexts, action):
590 if action[:5] == "seek:":
591 time = int(action[5:])
592 self.screen.seekRelative(time * 90000)
595 return HelpableActionMap.action(self, contexts, action)
597 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
599 "pauseService": (self.pauseService, _("pause")),
600 "unPauseService": (self.unPauseService, _("continue")),
602 "seekFwd": (self.seekFwd, _("skip forward")),
603 "seekFwdDown": self.seekFwdDown,
604 "seekFwdUp": self.seekFwdUp,
605 "seekBack": (self.seekBack, _("skip backward")),
606 "seekBackDown": self.seekBackDown,
607 "seekBackUp": self.seekBackUp,
609 # give them a little more priority to win over color buttons
611 self.seekstate = self.SEEK_STATE_PLAY
612 self.onClose.append(self.delTimer)
614 self.fwdtimer = False
615 self.fwdKeyTimer = eTimer()
616 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
618 self.rwdtimer = False
619 self.rwdKeyTimer = eTimer()
620 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
622 self.onPlayStateChanged = [ ]
624 self.lockedBecauseOfSkipping = False
637 service = self.session.nav.getCurrentService()
641 seek = service.seek()
643 if seek is None or not seek.isCurrentlySeekable():
648 def isSeekable(self):
649 if self.getSeek() is None:
653 def __seekableStatusChanged(self):
654 print "seekable status changed!"
655 if not self.isSeekable():
656 self["SeekActions"].setEnabled(False)
657 print "not seekable, return to play"
658 self.setSeekState(self.SEEK_STATE_PLAY)
660 self["SeekActions"].setEnabled(True)
663 def __serviceStarted(self):
664 self.seekstate = self.SEEK_STATE_PLAY
666 def setSeekState(self, state):
667 service = self.session.nav.getCurrentService()
672 if not self.isSeekable():
673 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
674 state = self.SEEK_STATE_PLAY
676 pauseable = service.pause()
678 if pauseable is None:
679 print "not pauseable."
680 state = self.SEEK_STATE_PLAY
682 oldstate = self.seekstate
683 self.seekstate = state
686 if oldstate[i] != self.seekstate[i]:
687 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
689 for c in self.onPlayStateChanged:
692 self.checkSkipShowHideLock()
696 def pauseService(self):
697 if self.seekstate == self.SEEK_STATE_PAUSE:
698 print "pause, but in fact unpause"
699 self.unPauseService()
701 if self.seekstate == self.SEEK_STATE_PLAY:
702 print "yes, playing."
704 print "no", self.seekstate
706 self.setSeekState(self.SEEK_STATE_PAUSE);
708 def unPauseService(self):
710 if self.seekstate == self.SEEK_STATE_PLAY:
712 self.setSeekState(self.SEEK_STATE_PLAY)
714 def doSeek(self, seektime):
715 print "doseek", seektime
716 service = self.session.nav.getCurrentService()
720 seekable = self.getSeek()
724 seekable.seekTo(90 * seektime)
726 def seekFwdDown(self):
727 print "start fwd timer"
729 self.fwdKeyTimer.start(1000)
731 def seekBackDown(self):
732 print "start rewind timer"
734 self.rwdKeyTimer.start(1000)
739 self.fwdKeyTimer.stop()
740 self.fwdtimer = False
745 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
746 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
747 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
748 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
749 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
750 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
751 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
752 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
753 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
754 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
755 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
756 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
757 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
758 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
759 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
761 self.setSeekState(lookup[self.seekstate])
763 def seekBackUp(self):
766 self.rwdKeyTimer.stop()
767 self.rwdtimer = False
772 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
773 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
774 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
775 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
776 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
777 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
778 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
779 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
780 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
781 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
782 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
783 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
784 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
785 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
786 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
788 self.setSeekState(lookup[self.seekstate])
790 if self.seekstate == self.SEEK_STATE_PAUSE:
791 seekable = self.getSeek()
792 if seekable is not None:
793 seekable.seekRelative(-1, 3)
795 def fwdTimerFire(self):
796 print "Display seek fwd"
797 self.fwdKeyTimer.stop()
798 self.fwdtimer = False
799 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
801 def fwdSeekTo(self, minutes):
802 print "Seek", minutes, "minutes forward"
804 seekable = self.getSeek()
805 if seekable is not None:
806 seekable.seekRelative(1, minutes * 60 * 90000)
808 def rwdTimerFire(self):
810 self.rwdKeyTimer.stop()
811 self.rwdtimer = False
812 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
814 def rwdSeekTo(self, minutes):
816 self.fwdSeekTo(0 - minutes)
818 def checkSkipShowHideLock(self):
819 wantlock = self.seekstate != self.SEEK_STATE_PLAY
821 if config.usage.show_infobar_on_zap.value:
822 if self.lockedBecauseOfSkipping and not wantlock:
824 self.lockedBecauseOfSkipping = False
826 if wantlock and not self.lockedBecauseOfSkipping:
828 self.lockedBecauseOfSkipping = True
831 if self.seekstate != self.SEEK_STATE_PLAY:
832 self.setSeekState(self.SEEK_STATE_PAUSE)
834 #self.getSeek().seekRelative(1, -90000)
835 self.setSeekState(self.SEEK_STATE_PLAY)
837 self.setSeekState(self.SEEK_STATE_PAUSE)
840 self.setSeekState(self.SEEK_STATE_PLAY)
843 def seekRelative(self, diff):
844 seekable = self.getSeek()
845 if seekable is not None:
846 seekable.seekRelative(1, diff)
848 def seekAbsolute(self, abs):
849 seekable = self.getSeek()
850 if seekable is not None:
853 from Screens.PVRState import PVRState, TimeshiftState
855 class InfoBarPVRState:
856 def __init__(self, screen=PVRState):
857 self.onPlayStateChanged.append(self.__playStateChanged)
858 self.pvrStateDialog = self.session.instantiateDialog(screen)
859 self.onShow.append(self.__mayShow)
860 self.onHide.append(self.pvrStateDialog.hide)
863 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
864 self.pvrStateDialog.show()
866 def __playStateChanged(self, state):
867 playstateString = state[3]
868 self.pvrStateDialog["state"].setText(playstateString)
871 class InfoBarTimeshiftState(InfoBarPVRState):
873 InfoBarPVRState.__init__(self, screen=TimeshiftState)
875 class InfoBarShowMovies:
877 # i don't really like this class.
878 # it calls a not further specified "movie list" on up/down/movieList,
879 # so this is not more than an action map
881 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
883 "movieList": (self.showMovies, "movie list"),
884 "up": (self.showMovies, "movie list"),
885 "down": (self.showMovies, "movie list")
888 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
892 # Timeshift works the following way:
893 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
894 # - normal playback TUNER unused PLAY enable disable disable
895 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
896 # - user presess pause again FILE record PLAY enable disable enable
897 # - user fast forwards FILE record FF enable disable enable
898 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
899 # - user backwards FILE record BACK # !! enable disable enable
903 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
904 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
905 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
906 # - the user can now PVR around
907 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
908 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
910 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
911 # - if the user rewinds, or press pause, timeshift will be activated again
913 # note that a timeshift can be enabled ("recording") and
914 # activated (currently time-shifting).
916 class InfoBarTimeshift:
918 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
920 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
921 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
923 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
925 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
926 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
927 }, prio=-1) # priority over record
929 self.timeshift_enabled = 0
930 self.timeshift_state = 0
931 self.ts_pause_timer = eTimer()
932 self.ts_pause_timer.timeout.get().append(self.pauseService)
934 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
936 iPlayableService.evStart: self.__serviceStarted,
937 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
940 def getTimeshift(self):
941 service = self.session.nav.getCurrentService()
942 return service and service.timeshift()
944 def startTimeshift(self):
945 print "enable timeshift"
946 ts = self.getTimeshift()
948 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
949 print "no ts interface"
952 if self.timeshift_enabled:
953 print "hu, timeshift already enabled?"
955 if not ts.startTimeshift():
956 self.timeshift_enabled = 1
958 # we remove the "relative time" for now.
959 #self.pvrStateDialog["timeshift"].setRelative(time.time())
962 self.setSeekState(self.SEEK_STATE_PAUSE)
964 # enable the "TimeshiftEnableActions", which will override
965 # the startTimeshift actions
966 self.__seekableStatusChanged()
968 print "timeshift failed"
970 def stopTimeshift(self):
971 if not self.timeshift_enabled:
973 print "disable timeshift"
974 ts = self.getTimeshift()
977 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
979 def stopTimeshiftConfirmed(self, confirmed):
983 ts = self.getTimeshift()
988 self.timeshift_enabled = 0
991 self.__seekableStatusChanged()
993 # activates timeshift, and seeks to (almost) the end
994 def activateTimeshiftEnd(self):
995 ts = self.getTimeshift()
1000 if ts.isTimeshiftActive():
1001 print "!! activate timeshift called - but shouldn't this be a normal pause?"
1004 self.setSeekState(self.SEEK_STATE_PLAY)
1005 ts.activateTimeshift()
1006 self.seekRelative(0)
1008 # same as activateTimeshiftEnd, but pauses afterwards.
1009 def activateTimeshiftEndAndPause(self):
1010 state = self.seekstate
1011 self.activateTimeshiftEnd()
1013 # well, this is "andPause", but it could be pressed from pause,
1014 # when pausing on the (fake-)"live" picture, so an un-pause
1017 print "now, pauseService"
1018 if state == self.SEEK_STATE_PLAY:
1019 print "is PLAYING, start pause timer"
1020 self.ts_pause_timer.start(200, 1)
1023 self.unPauseService()
1025 def __seekableStatusChanged(self):
1028 print "self.isSeekable", self.isSeekable()
1029 print "self.timeshift_enabled", self.timeshift_enabled
1031 # when this service is not seekable, but timeshift
1032 # is enabled, this means we can activate
1034 if not self.isSeekable() and self.timeshift_enabled:
1037 print "timeshift activate:", enabled
1038 self["TimeshiftActivateActions"].setEnabled(enabled)
1040 def __serviceStarted(self):
1041 self.timeshift_enabled = False
1042 self.__seekableStatusChanged()
1044 from Screens.PiPSetup import PiPSetup
1046 class InfoBarExtensions:
1047 EXTENSION_SINGLE = 0
1053 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1055 "extensions": (self.showExtensionSelection, _("view extensions...")),
1058 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1059 self.list.append((type, extension, key))
1061 def updateExtension(self, extension, key = None):
1062 self.extensionsList.append(extension)
1064 if self.extensionKeys.has_key(key):
1068 for x in self.availableKeys:
1069 if not self.extensionKeys.has_key(x):
1074 self.extensionKeys[key] = len(self.extensionsList) - 1
1076 def updateExtensions(self):
1077 self.extensionsList = []
1078 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1079 self.extensionKeys = {}
1081 if x[0] == self.EXTENSION_SINGLE:
1082 self.updateExtension(x[1], x[2])
1085 self.updateExtension(y[0], y[1])
1088 def showExtensionSelection(self):
1089 self.updateExtensions()
1090 extensionsList = self.extensionsList[:]
1093 for x in self.availableKeys:
1094 if self.extensionKeys.has_key(x):
1095 entry = self.extensionKeys[x]
1096 extension = self.extensionsList[entry]
1098 name = str(extension[0]())
1099 list.append((extension[0](), extension))
1101 extensionsList.remove(extension)
1103 extensionsList.remove(extension)
1104 for x in extensionsList:
1105 list.append((x[0](), x))
1106 keys += [""] * len(extensionsList)
1107 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1109 def extensionCallback(self, answer):
1110 if answer is not None:
1113 from Tools.BoundFunction import boundFunction
1115 # depends on InfoBarExtensions
1116 from Components.PluginComponent import plugins
1118 class InfoBarPlugins:
1120 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1122 def getPluginName(self, name):
1125 def getPluginList(self):
1127 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1128 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1131 def runPlugin(self, plugin):
1132 plugin(session = self.session)
1134 # depends on InfoBarExtensions
1135 class InfoBarSleepTimer:
1137 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")
1139 def available(self):
1142 def getSleepTimerName(self):
1143 return _("Sleep Timer")
1145 def showSleepTimerSetup(self):
1146 self.session.open(SleepTimerEdit)
1148 # depends on InfoBarExtensions
1151 self.session.pipshown = False
1153 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1154 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1155 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1157 def available(self):
1161 return self.session.pipshown
1163 def getShowHideName(self):
1164 if self.session.pipshown:
1165 return _("Disable Picture in Picture")
1167 return _("Activate Picture in Picture")
1169 def getSwapName(self):
1170 return _("Swap Services")
1172 def getMoveName(self):
1173 return _("Move Picture in Picture")
1176 if self.session.pipshown:
1177 del self.session.pip
1178 self.session.pipshown = False
1180 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1181 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1182 if self.session.pip.playService(newservice):
1183 self.session.pipshown = True
1184 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1186 self.session.pipshown = False
1187 del self.session.pip
1188 self.session.nav.playService(newservice)
1191 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1192 if self.session.pip.servicePath:
1193 servicepath = self.servicelist.getCurrentServicePath()
1194 ref=servicepath[len(servicepath)-1]
1195 pipref=self.session.pip.getCurrentService()
1196 self.session.pip.playService(swapservice)
1197 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1198 if pipref.toString() != ref.toString(): # is a subservice ?
1199 self.session.nav.stopService() # stop portal
1200 self.session.nav.playService(pipref) # start subservice
1201 self.session.pip.servicePath=servicepath
1204 self.session.open(PiPSetup, pip = self.session.pip)
1206 from RecordTimer import parseEvent
1208 class InfoBarInstantRecord:
1209 """Instant Record - handles the instantRecord action in order to
1210 start/stop instant records"""
1212 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1214 "instantRecord": (self.instantRecord, _("Instant Record...")),
1217 self["BlinkingPoint"] = BlinkingPixmapConditional()
1218 self["BlinkingPoint"].hide()
1219 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1221 def stopCurrentRecording(self, entry = -1):
1222 if entry is not None and entry != -1:
1223 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1224 self.recording.remove(self.recording[entry])
1226 def startInstantRecording(self, limitEvent = False):
1227 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1229 # try to get event info
1232 service = self.session.nav.getCurrentService()
1233 epg = eEPGCache.getInstance()
1234 event = epg.lookupEventTime(serviceref, -1, 0)
1236 info = service.info()
1237 ev = info.getEvent(0)
1243 end = time() + 3600 * 10
1244 name = "instant record"
1248 if event is not None:
1249 curEvent = parseEvent(event)
1251 description = curEvent[3]
1252 eventid = curEvent[4]
1257 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1259 data = (begin, end, name, description, eventid)
1261 recording = self.session.nav.recordWithTimer(serviceref, *data)
1262 recording.dontSave = True
1263 self.recording.append(recording)
1265 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1267 def isInstantRecordRunning(self):
1268 print "self.recording:", self.recording
1269 if len(self.recording) > 0:
1270 for x in self.recording:
1275 def recordQuestionCallback(self, answer):
1276 print "pre:\n", self.recording
1278 if answer is None or answer[1] == "no":
1281 recording = self.recording[:]
1283 if not x in self.session.nav.RecordTimer.timer_list:
1284 self.recording.remove(x)
1285 elif x.dontSave and x.isRunning():
1286 list.append(TimerEntryComponent(x, False))
1288 if answer[1] == "changeduration":
1289 if len(self.recording) == 1:
1290 self.changeDuration(0)
1292 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1293 elif answer[1] == "stop":
1294 if len(self.recording) == 1:
1295 self.stopCurrentRecording(0)
1297 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1298 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1300 if answer[1] == "event":
1302 if answer[1] == "manualduration":
1303 self.selectedEntry = len(self.recording)
1304 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1305 self.startInstantRecording(limitEvent = limitEvent)
1307 print "after:\n", self.recording
1309 def changeDuration(self, entry):
1310 if entry is not None:
1311 self.selectedEntry = entry
1312 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1314 def inputCallback(self, value):
1315 if value is not None:
1316 print "stopping recording after", int(value), "minutes."
1317 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1318 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1320 def instantRecord(self):
1322 stat = os_stat(resolveFilename(SCOPE_HDD))
1324 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1327 if self.isInstantRecordRunning():
1328 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("A recording is currently running.\nWhat do you want to do?"), list=[(_("stop recording"), "stop"), (_("change recording (duration)"), "changeduration"), (_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"), (_("do nothing"), "no")])
1330 self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Start recording?"), list=[(_("add recording (indefinitely)"), "indefinitely"), (_("add recording (stop after current event)"), "event"), (_("add recording (enter recording duration)"), "manualduration"),(_("don't record"), "no")])
1332 from Tools.ISO639 import LanguageCodes
1334 class InfoBarAudioSelection:
1336 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1338 "audioSelection": (self.audioSelection, _("Audio Options...")),
1341 def audioSelection(self):
1342 service = self.session.nav.getCurrentService()
1343 audio = service and service.audioTracks()
1344 self.audioTracks = audio
1345 n = audio and audio.getNumberOfTracks() or 0
1346 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1348 print "tlist:", tlist
1350 self.audioChannel = service.audioChannel()
1353 i = audio.getTrackInfo(x)
1354 language = i.getLanguage()
1355 description = i.getDescription()
1357 if LanguageCodes.has_key(language):
1358 language = LanguageCodes[language][0]
1360 if len(description):
1361 description += " (" + language + ")"
1363 description = language
1365 tlist.append((description, x))
1367 selectedAudio = tlist[0][1]
1368 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1372 if x[1] != selectedAudio:
1377 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1378 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1380 del self.audioTracks
1382 def audioSelected(self, audio):
1383 if audio is not None:
1384 if isinstance(audio[1], str):
1385 if audio[1] == "mode":
1386 keys = ["red", "green", "yellow"]
1387 selection = self.audioChannel.getCurrentChannel()
1388 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1389 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1391 del self.audioChannel
1392 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1393 self.audioTracks.selectTrack(audio[1])
1395 del self.audioChannel
1396 del self.audioTracks
1398 def modeSelected(self, mode):
1399 if mode is not None:
1400 self.audioChannel.selectChannel(mode[1])
1401 del self.audioChannel
1403 class InfoBarSubserviceSelection:
1405 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1407 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1410 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1412 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1413 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1415 self["SubserviceQuickzapAction"].setEnabled(False)
1417 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1421 def checkSubservicesAvail(self, ev):
1422 if ev == iPlayableService.evUpdatedEventInfo:
1423 service = self.session.nav.getCurrentService()
1424 subservices = service and service.subServices()
1425 if not subservices or subservices.getNumberOfSubservices() == 0:
1426 self["SubserviceQuickzapAction"].setEnabled(False)
1428 def nextSubservice(self):
1429 self.changeSubservice(+1)
1431 def prevSubservice(self):
1432 self.changeSubservice(-1)
1434 def changeSubservice(self, direction):
1435 service = self.session.nav.getCurrentService()
1436 subservices = service and service.subServices()
1437 n = subservices and subservices.getNumberOfSubservices()
1440 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1442 if subservices.getSubservice(x).toString() == ref.toString():
1445 selection += direction
1450 newservice = subservices.getSubservice(selection)
1451 if newservice.valid():
1454 if config.usage.show_infobar_on_zap.value:
1456 self.session.nav.playService(newservice)
1458 def subserviceSelection(self):
1459 service = self.session.nav.getCurrentService()
1460 subservices = service and service.subServices()
1461 self.bouquets = self.servicelist.getBouquetList()
1462 n = subservices and subservices.getNumberOfSubservices()
1465 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1468 i = subservices.getSubservice(x)
1469 if i.toString() == ref.toString():
1471 tlist.append((i.getName(), i))
1473 if self.bouquets and len(self.bouquets):
1474 keys = ["red", "green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1475 if config.usage.multibouquet.value:
1476 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1478 tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1481 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1482 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1485 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1487 def subserviceSelected(self, service):
1489 if not service is None:
1490 if isinstance(service[1], str):
1491 if service[1] == "quickzap":
1492 from Screens.SubservicesQuickzap import SubservicesQuickzap
1493 self.session.open(SubservicesQuickzap, service[2])
1495 self["SubserviceQuickzapAction"].setEnabled(True)
1496 if config.usage.show_infobar_on_zap.value:
1498 self.session.nav.playService(service[1])
1500 def addSubserviceToBouquetCallback(self, service):
1501 if len(service) > 1 and isinstance(service[1], eServiceReference):
1502 self.selectedSubservice = service
1503 if self.bouquets is None:
1506 cnt = len(self.bouquets)
1507 if cnt > 1: # show bouquet list
1508 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1509 elif cnt == 1: # add to only one existing bouquet
1510 self.addSubserviceToBouquet(self.bouquets[0][1])
1511 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1513 def bouquetSelClosed(self, confirmed):
1515 del self.selectedSubservice
1517 self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1519 def addSubserviceToBouquet(self, dest):
1520 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1522 self.bsel.close(True)
1524 del self.selectedSubservice
1526 class InfoBarAdditionalInfo:
1528 self["NimA"] = Pixmap()
1529 self["NimB"] = Pixmap()
1530 self["NimA_Active"] = Pixmap()
1531 self["NimB_Active"] = Pixmap()
1533 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1534 self["TimeshiftPossible"] = self["RecordingPossible"]
1535 self["ExtensionsAvailable"] = Boolean(fixed=1)
1537 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1538 res_mgr = eDVBResourceManager.getInstance()
1540 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1542 def tunerUseMaskChanged(self, mask):
1544 self["NimA_Active"].show()
1546 self["NimA_Active"].hide()
1548 self["NimB_Active"].show()
1550 self["NimB_Active"].hide()
1552 def checkTunerState(self, service):
1553 info = service.frontendInfo()
1554 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1555 if feNumber is None:
1565 def gotServiceEvent(self, ev):
1566 service = self.session.nav.getCurrentService()
1567 if ev == iPlayableService.evStart:
1568 self.checkTunerState(service)
1570 class InfoBarNotifications:
1572 self.onExecBegin.append(self.checkNotifications)
1573 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1574 self.onClose.append(self.__removeNotification)
1576 def __removeNotification(self):
1577 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1579 def checkNotificationsIfExecing(self):
1581 self.checkNotifications()
1583 def checkNotifications(self):
1584 if len(Notifications.notifications):
1585 n = Notifications.notifications[0]
1587 Notifications.notifications = Notifications.notifications[1:]
1590 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1592 dlg = self.session.open(n[1], *n[2], **n[3])
1594 # remember that this notification is currently active
1596 Notifications.current_notifications.append(d)
1597 dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1599 def __notificationClosed(self, d):
1600 Notifications.current_notifications.remove(d)
1602 class InfoBarServiceNotifications:
1604 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1606 iPlayableService.evEnd: self.serviceHasEnded
1609 def serviceHasEnded(self):
1610 print "service end!"
1613 self.setSeekState(self.SEEK_STATE_PLAY)
1617 class InfoBarCueSheetSupport:
1623 ENABLE_RESUME_SUPPORT = False
1626 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1628 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1629 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1630 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1634 self.is_closing = False
1635 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1637 iPlayableService.evStart: self.__serviceStarted,
1640 def __serviceStarted(self):
1643 print "new service started! trying to download cuts!"
1644 self.downloadCuesheet()
1646 if self.ENABLE_RESUME_SUPPORT:
1649 for (pts, what) in self.cut_list:
1650 if what == self.CUT_TYPE_LAST:
1653 if last is not None:
1654 self.resume_point = last
1655 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1657 def playLastCB(self, answer):
1659 seekable = self.__getSeekable()
1660 if seekable is not None:
1661 seekable.seekTo(self.resume_point)
1663 def __getSeekable(self):
1664 service = self.session.nav.getCurrentService()
1667 return service.seek()
1669 def cueGetCurrentPosition(self):
1670 seek = self.__getSeekable()
1673 r = seek.getPlayPosition()
1678 def jumpPreviousNextMark(self, cmp, alternative=None):
1679 current_pos = self.cueGetCurrentPosition()
1680 if current_pos is None:
1682 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1683 if mark is not None:
1685 elif alternative is not None:
1690 seekable = self.__getSeekable()
1691 if seekable is not None:
1692 seekable.seekTo(pts)
1694 def jumpPreviousMark(self):
1695 # we add 2 seconds, so if the play position is <2s after
1696 # the mark, the mark before will be used
1697 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1699 def jumpNextMark(self):
1700 self.jumpPreviousNextMark(lambda x: x)
1702 def getNearestCutPoint(self, pts, cmp=abs):
1705 for cp in self.cut_list:
1706 diff = cmp(cp[0] - pts)
1707 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1711 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1712 current_pos = self.cueGetCurrentPosition()
1713 if current_pos is None:
1714 print "not seekable"
1717 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1719 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1721 return nearest_cutpoint
1723 self.removeMark(nearest_cutpoint)
1724 elif not onlyremove and not onlyreturn:
1725 self.addMark((current_pos, self.CUT_TYPE_MARK))
1730 def addMark(self, point):
1731 insort(self.cut_list, point)
1732 self.uploadCuesheet()
1734 def removeMark(self, point):
1735 self.cut_list.remove(point)
1736 self.uploadCuesheet()
1738 def __getCuesheet(self):
1739 service = self.session.nav.getCurrentService()
1742 return service.cueSheet()
1744 def uploadCuesheet(self):
1745 cue = self.__getCuesheet()
1748 print "upload failed, no cuesheet interface"
1750 cue.setCutList(self.cut_list)
1752 def downloadCuesheet(self):
1753 cue = self.__getCuesheet()
1756 print "upload failed, no cuesheet interface"
1758 self.cut_list = cue.getCutList()
1760 class InfoBarSummary(Screen):
1762 <screen position="0,0" size="132,64">
1763 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1764 <convert type="ClockToText">WithSeconds</convert>
1766 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1767 <convert type="ServiceName">Name</convert>
1771 def __init__(self, session, parent):
1772 Screen.__init__(self, session)
1773 self["CurrentService"] = CurrentService(self.session.nav)
1774 self["CurrentTime"] = Clock()
1776 class InfoBarSummarySupport:
1780 def createSummary(self):
1781 return InfoBarSummary
1783 class InfoBarTeletextPlugin:
1785 self.teletext_plugin = None
1787 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1788 self.teletext_plugin = p
1790 if self.teletext_plugin is not None:
1791 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1793 "startTeletext": (self.startTeletext, _("View teletext..."))
1796 print "no teletext plugin found!"
1798 def startTeletext(self):
1799 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1801 class InfoBarSubtitleSupport(object):
1803 object.__init__(self)
1804 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1805 self.__subtitles_enabled = False
1807 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1809 iPlayableService.evEnd: self.__serviceStopped,
1810 iPlayableService.evUpdatedInfo: self.__updatedInfo
1812 self.cached_subtitle_checked = False
1814 def __serviceStopped(self):
1815 self.subtitle_window.hide()
1816 self.__subtitles_enabled = False
1817 self.cached_subtitle_checked = False
1819 def __updatedInfo(self):
1820 if not self.cached_subtitle_checked:
1821 subtitle = self.getCurrentServiceSubtitle()
1822 self.cached_subtitle_checked = True
1824 self.__selected_subtitle = subtitle.getCachedSubtitle()
1825 if self.__selected_subtitle:
1826 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1827 self.subtitle_window.show()
1828 self.__subtitles_enabled = True
1830 def getCurrentServiceSubtitle(self):
1831 service = self.session.nav.getCurrentService()
1832 return service and service.subtitle()
1834 def setSubtitlesEnable(self, enable=True):
1835 subtitle = self.getCurrentServiceSubtitle()
1836 if enable and self.__selected_subtitle is not None:
1837 if subtitle and not self.__subtitles_enabled:
1838 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1839 self.subtitle_window.show()
1840 self.__subtitles_enabled = True
1843 subtitle.disableSubtitles(self.subtitle_window.instance)
1844 self.__subtitles_enabled = False
1845 self.subtitle_window.hide()
1847 def setSelectedSubtitle(self, subtitle):
1848 self.__selected_subtitle = subtitle
1850 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1851 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1853 class InfoBarServiceErrorPopupSupport:
1855 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1857 iPlayableService.evTuneFailed: self.__tuneFailed,
1858 iPlayableService.evStart: self.__serviceStarted
1860 self.__serviceStarted()
1862 def __serviceStarted(self):
1863 self.last_error = None
1864 Notifications.RemovePopup(id = "ZapError")
1866 def __tuneFailed(self):
1867 service = self.session.nav.getCurrentService()
1868 info = service and service.info()
1869 error = info and info.getInfo(iServiceInformation.sDVBState)
1871 if error == self.last_error:
1874 self.last_error = error
1877 eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1878 eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1879 eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1880 eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1881 eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1882 eDVBServicePMTHandler.eventNewProgramInfo: None,
1883 eDVBServicePMTHandler.eventTuned: None,
1884 eDVBServicePMTHandler.eventSOF: None,
1885 eDVBServicePMTHandler.eventEOF: None
1888 if error not in errors:
1891 error = error and errors[error]
1893 if error is not None:
1894 Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1896 Notifications.RemovePopup(id = "ZapError")